Skip to content

Commit c12ef0c

Browse files
committed
use fetchers over raw requests in a few places and differentiate main status from asc/descendants in thread view
1 parent f73b9bb commit c12ef0c

9 files changed

Lines changed: 170 additions & 86 deletions

File tree

shared/src/commonMain/kotlin/site/remlit/snowdrop/component/Avatar.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,30 @@ import io.kamel.image.asyncPainterResource
1616
import site.remlit.snowdrop.model.Account
1717

1818
const val bigAvatarSize = 84
19-
const val smallAvatarSize = 24
2019
const val avatarSize = 48
20+
const val smallAvatarSize = 36
21+
const val smallerAvatarSize = 24
2122

2223
const val bigAvatarRadius = 20
23-
const val smallAvatarRadius = 8
2424
const val avatarRadius = 15
25+
const val smallAvatarRadius = 10
26+
const val smallerAvatarRadius = 8
2527

2628
@Composable
2729
fun Avatar(
2830
account: Account,
2931
big: Boolean = false,
30-
small: Boolean = false
32+
small: Boolean = false,
33+
smaller: Boolean = false
3134
) {
32-
val size = if (big) bigAvatarSize.dp else if (small) smallAvatarSize.dp else avatarSize.dp
33-
val radius = if (big) bigAvatarRadius.dp else if (small) smallAvatarRadius.dp else avatarRadius.dp
35+
val size = if (big) bigAvatarSize.dp
36+
else if (small) smallAvatarSize.dp
37+
else if (smaller) smallerAvatarSize.dp
38+
else avatarSize.dp
39+
val radius = if (big) bigAvatarRadius.dp
40+
else if (small) smallAvatarRadius.dp
41+
else if (smaller) smallerAvatarRadius.dp
42+
else avatarRadius.dp
3443

3544
@Composable
3645
fun fallback() {

shared/src/commonMain/kotlin/site/remlit/snowdrop/component/MiniStatus.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fun MiniStatus(status: Status) {
4444
horizontalArrangement = Arrangement.spacedBy(5.dp),
4545
verticalAlignment = Alignment.CenterVertically
4646
) {
47-
Avatar(status.account!!, small = true)
47+
Avatar(status.account!!, smaller = true)
4848
Text(
4949
status.account.displayName ?: status.account.username,
5050
fontWeight = FontWeight.Bold,

shared/src/commonMain/kotlin/site/remlit/snowdrop/component/Status.kt

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import androidx.compose.runtime.setValue
2626
import androidx.compose.ui.Alignment
2727
import androidx.compose.ui.Modifier
2828
import androidx.compose.ui.draw.clip
29+
import androidx.compose.ui.graphics.Color
2930
import androidx.compose.ui.platform.LocalClipboardManager
3031
import androidx.compose.ui.platform.LocalUriHandler
3132
import androidx.compose.ui.text.AnnotatedString
@@ -34,6 +35,7 @@ import androidx.compose.ui.text.style.TextOverflow
3435
import androidx.compose.ui.unit.dp
3536
import androidx.compose.ui.unit.sp
3637
import androidx.lifecycle.compose.collectAsStateWithLifecycle
38+
import androidx.navigation.toRoute
3739
import com.russhwolf.settings.ExperimentalSettingsApi
3840
import org.jetbrains.compose.resources.painterResource
3941
import site.remlit.snowdrop.ProfileRoute
@@ -99,6 +101,13 @@ fun Status(status: Status) {
99101
var cwOpen by remember { mutableStateOf(false) }
100102
var showDropdown by remember { mutableStateOf(false) }
101103

104+
var inThreadView by remember { mutableStateOf(false) }
105+
var threadViewMainStatus by remember { mutableStateOf(false) }
106+
107+
inThreadView = atRoute<ThreadRoute>(currentDest)
108+
threadViewMainStatus = inThreadView && navHandler.currentBackStackEntry
109+
?.toRoute<ThreadRoute>()?.id == realStatus.id
110+
102111

103112
@Composable
104113
fun FooterButton(
@@ -118,50 +127,50 @@ fun Status(status: Status) {
118127

119128
Column(
120129
modifier = Modifier.clickable(
121-
// todo: fix this when we add ascendants/descendants (idk how to get the id of the current view)
122-
enabled = !atRoute<ThreadRoute>(currentDest),
123-
onClick = {
124-
navHandler.navigate(ThreadRoute(realStatus.id!!))
125-
}
126-
)
130+
enabled = !inThreadView || (inThreadView && !threadViewMainStatus),
131+
onClick = { navHandler.navigate(ThreadRoute(realStatus.id!!)) }
132+
).background(
133+
if (threadViewMainStatus) MaterialTheme.colorScheme.surfaceContainerLow
134+
else Color.Unspecified
135+
)
127136
) {
128137
Column(
129138
modifier = Modifier.fillMaxWidth()
130139
.padding(top = 5.dp, bottom = 5.dp, start = 10.dp, end = 10.dp)
131140
// todo: not vertically centered correctly
132141
) {
133142
if (isReblog && rebloggingAccount != null) {
134-
Row(
135-
modifier = Modifier.padding(start = 35.dp),
136-
verticalAlignment = Alignment.CenterVertically
137-
) {
138-
Icon(
139-
painterResource(Res.drawable.icon_repeat_24px),
140-
null,
141-
modifier = Modifier.padding(end = 5.dp),
142-
tint = MaterialTheme.colorScheme.secondary
143-
)
144-
Row(
145-
modifier = Modifier.weight(1f, fill = false),
146-
verticalAlignment = Alignment.CenterVertically
147-
) {
148-
Text(
149-
rebloggingAccount!!.displayName ?: rebloggingAccount!!.username,
150-
color = MaterialTheme.colorScheme.secondary,
151-
fontSize = 14.sp,
152-
fontWeight = FontWeight.Medium,
153-
overflow = TextOverflow.Ellipsis,
154-
maxLines = 1,
155-
modifier = Modifier.weight(1f, fill = false)
156-
)
157-
Text(
158-
" boosted",
159-
color = MaterialTheme.colorScheme.secondary,
160-
fontSize = 14.sp,
161-
fontWeight = FontWeight.Medium
162-
)
163-
}
164-
}
143+
Row(
144+
modifier = Modifier.padding(start = 35.dp),
145+
verticalAlignment = Alignment.CenterVertically
146+
) {
147+
Icon(
148+
painterResource(Res.drawable.icon_repeat_24px),
149+
null,
150+
modifier = Modifier.padding(end = 5.dp),
151+
tint = MaterialTheme.colorScheme.secondary
152+
)
153+
Row(
154+
modifier = Modifier.weight(1f, fill = false),
155+
verticalAlignment = Alignment.CenterVertically
156+
) {
157+
Text(
158+
rebloggingAccount!!.displayName ?: rebloggingAccount!!.username,
159+
color = MaterialTheme.colorScheme.secondary,
160+
fontSize = 14.sp,
161+
fontWeight = FontWeight.Medium,
162+
overflow = TextOverflow.Ellipsis,
163+
maxLines = 1,
164+
modifier = Modifier.weight(1f, fill = false)
165+
)
166+
Text(
167+
" boosted",
168+
color = MaterialTheme.colorScheme.secondary,
169+
fontSize = 14.sp,
170+
fontWeight = FontWeight.Medium
171+
)
172+
}
173+
}
165174
}
166175

167176
/*
@@ -178,7 +187,10 @@ fun Status(status: Status) {
178187
navHandler.navigate(ProfileRoute(realStatus.account?.id!!))
179188
})
180189
) {
181-
Avatar(realStatus.account!!)
190+
Avatar(
191+
realStatus.account!!,
192+
small = inThreadView && !threadViewMainStatus
193+
)
182194
}
183195

184196
Column(
@@ -400,6 +412,24 @@ fun Status(status: Status) {
400412

401413
HorizontalDivider()
402414

415+
DropdownMenuItem(
416+
text = { Text("Show boosts") },
417+
leadingIcon = {
418+
Icon(painterResource(Res.drawable.icon_repeat_24px), null)
419+
},
420+
onClick = { }
421+
)
422+
423+
DropdownMenuItem(
424+
text = { Text("Show likes") },
425+
leadingIcon = {
426+
Icon(painterResource(Res.drawable.icon_star_24px), null)
427+
},
428+
onClick = { }
429+
)
430+
431+
HorizontalDivider()
432+
403433
if (realStatus.bookmarked) {
404434
DropdownMenuItem(
405435
text = { Text("Unbookmark") },
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package site.remlit.snowdrop.util
2+
3+
import kotlinx.coroutines.CoroutineName
4+
import kotlinx.coroutines.CoroutineScope
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.IO
7+
import kotlinx.coroutines.launch
8+
9+
val bgScope = CoroutineScope(Dispatchers.Default + CoroutineName("Background"))
10+
val bgIOScope = CoroutineScope(Dispatchers.IO + CoroutineName("BackgroundIO"))
11+
12+
/**
13+
* Run block in the background on a default dispatcher thread.
14+
* */
15+
fun bg(block: suspend () -> Unit) = bgScope.launch { block() }
16+
17+
/**
18+
* Run block in the background on an IO dispatcher thread.
19+
* */
20+
fun bgIO(block: suspend () -> Unit) = bgIOScope.launch { block() }

shared/src/commonMain/kotlin/site/remlit/snowdrop/util/Settings.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.russhwolf.settings.coroutines.FlowSettings
88
import com.russhwolf.settings.coroutines.toBlockingSettings
99
import kotlinx.coroutines.flow.Flow
1010
import kotlinx.coroutines.flow.FlowCollector
11+
import kotlinx.coroutines.flow.flow
1112
import site.remlit.snowdrop.api.verifyCredentials
1213
import site.remlit.snowdrop.model.Account
1314
import site.remlit.snowdrop.util.cache.getCacheEntry
@@ -51,15 +52,15 @@ fun setupAppSettings() {
5152
* @return User
5253
* */
5354
@OptIn(ExperimentalSettingsApi::class)
54-
fun getCurrentAccountObjectFlow(): Flow<Account> = object : Flow<Account> {
55-
override suspend fun collect(collector: FlowCollector<Account>) = safe {
56-
if (getCurrentAccountId() == "")
57-
return@safe
55+
fun getCurrentAccountObjectFlow(): Flow<Account> = flow {
56+
if (getCurrentAccountId() == "")
57+
return@flow
5858

59-
if (getCacheEntry("account_${getCurrentAccountId()}") == null)
60-
updateCurrentAccountObject()
59+
if (getCacheEntry("account_${getCurrentAccountId()}") == null)
60+
updateCurrentAccountObject()
6161

62-
collector.emit(
62+
safe {
63+
emit(
6364
getCacheEntry("account_${getCurrentAccountId()}")!!
6465
.getContent<Account>()
6566
)

shared/src/commonMain/kotlin/site/remlit/snowdrop/util/cache/Fetchers.kt

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,43 @@ package site.remlit.snowdrop.util.cache
22

33
import kotlinx.coroutines.flow.Flow
44
import kotlinx.coroutines.flow.FlowCollector
5+
import kotlinx.coroutines.flow.flow
56
import site.remlit.snowdrop.api.accounts.getAccount
7+
import site.remlit.snowdrop.api.statuses.getStatus
68
import site.remlit.snowdrop.model.Account
9+
import site.remlit.snowdrop.model.Status
710
import site.remlit.snowdrop.util.safe
811

912
/**
1013
* Gets the cached representation of an account (if available) before
1114
* the request to get a fresh version finishes.
1215
* */
13-
fun fetchAccount(id: String): Flow<Account> = object : Flow<Account> {
14-
override suspend fun collect(collector: FlowCollector<Account>) = safe {
15-
val cached = getCacheEntry("account_$id")
16-
if (cached != null) safe {
17-
collector.emit(cached.getContent<Account>())
18-
}
19-
20-
// todo: fix this failing
21-
val req = getAccount(id)
22-
if (!req.error && req.response != null)
23-
collector.emit(req.response)
16+
fun fetchAccount(id: String): Flow<Account> = flow {
17+
val cached = getCacheEntry("account_$id")
18+
if (cached != null) safe {
19+
emit(cached.getContent<Account>())
20+
}
2421

22+
val req = getAccount(id)
23+
if (!req.error && req.response != null) {
24+
emit(req.response)
2525
putCacheEntry("account_$id", req.response)
2626
}
2727
}
28+
29+
/**
30+
* Gets the cached representation of a status (if available) before
31+
* the request to get a fresh version finishes.
32+
* */
33+
fun fetchStatus(id: String): Flow<Status> = flow {
34+
val cached = getCacheEntry("status_$id")
35+
if (cached != null) safe {
36+
emit(cached.getContent<Status>())
37+
}
38+
39+
val req = getStatus(id)
40+
if (!req.error && req.response != null) {
41+
emit(req.response)
42+
putCacheEntry("status_$id", req.response)
43+
}
44+
}

shared/src/commonMain/kotlin/site/remlit/snowdrop/view/LoginView.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import site.remlit.snowdrop.api.oauth.redirectUri
4040
import site.remlit.snowdrop.component.ViewSurface
4141
import site.remlit.snowdrop.model.response.CreateAppResponse
4242
import site.remlit.snowdrop.model.response.OauthToken
43+
import site.remlit.snowdrop.util.bg
4344
import site.remlit.snowdrop.util.blockingSettings
4445
import site.remlit.snowdrop.util.cache.blockingCache
4546
import site.remlit.snowdrop.util.cache.setupCache
@@ -83,7 +84,7 @@ fun LoginView(
8384
waitingForNext = true
8485

8586
// todo: this blocking is annoying
86-
runBlocking {
87+
bg {
8788
val existingAccounts = settings.getString("accounts", "")
8889
val accountId = "_S-${Uuid.random()}"
8990
settings.putString("accounts", "$existingAccounts $accountId")
@@ -92,8 +93,8 @@ fun LoginView(
9293

9394
// get link you must visit to get token
9495
val res = createApp()
95-
if (res.error) return@runBlocking
96-
if (res.response !is CreateAppResponse) return@runBlocking
96+
if (res.error) return@bg
97+
if (res.response !is CreateAppResponse) return@bg
9798

9899
settings.putString("account_${accountId}_token", "")
99100
settings.putString("account_${accountId}_client_id", res.response.clientId)

shared/src/commonMain/kotlin/site/remlit/snowdrop/view/ProfileView.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ fun ProfileView(id: String) = ViewSurface {
7777
.collectAsStateWithLifecycle(null)
7878

7979
val account by fetchAccount(id).collectAsStateWithLifecycle(null)
80-
var ready by remember { mutableStateOf(false) }
8180

8281
var isMe by remember { mutableStateOf(false) }
8382
if (currentAccount != null && currentAccount?.id == account?.id)
@@ -87,7 +86,7 @@ fun ProfileView(id: String) = ViewSurface {
8786

8887
/* todo: relationships on profile view
8988
* var relationships by remember { mutableStateOf<List<RelationshipResponse>?>(null) }
90-
if (ready && !isMe) runBlocking {
89+
if (!isMe) runBlocking {
9190
val req = getRelationships(listOf(currentAccount!!.id, account!!.id))
9291
if (req.error) return@runBlocking
9392
if (req.response == null) return@runBlocking
@@ -129,7 +128,7 @@ fun ProfileView(id: String) = ViewSurface {
129128
}
130129
)
131130

132-
if (!ready || account == null) {
131+
if (account == null) {
133132
Column(
134133
modifier = Modifier.fillMaxHeight().fillMaxWidth(),
135134
horizontalAlignment = Alignment.CenterHorizontally,

0 commit comments

Comments
 (0)