tangled
alpha
login
or
join now
geesawra.industries
/
jerry-no
8
fork
atom
A cheap attempt at a native Bluesky client for Android
8
fork
atom
overview
issues
pulls
pipelines
*: make refresh experience more linear
geesawra.industries
5 months ago
de3a5906
c834efb6
+36
-28
4 changed files
expand all
collapse all
unified
split
app
src
main
java
industries
geesawra
monarch
MainView.kt
NotificationsView.kt
ShowSkeets.kt
datalayer
TimelineViewModel.kt
+19
-7
app/src/main/java/industries/geesawra/monarch/MainView.kt
···
194
194
isRefreshing.value = true
195
195
when (currentDestination) {
196
196
TabBarDestinations.TIMELINE -> {
197
197
-
timelineViewModel.fetchTimeline {
198
198
-
isRefreshing.value = false
197
197
+
timelineViewModel.fetchTimeline(fresh = true) {
198
198
+
coroutineScope.launch {
199
199
+
isRefreshing.value = false
200
200
+
timelineState.scrollToItem(0)
201
201
+
}
199
202
}
200
203
}
201
204
202
205
TabBarDestinations.NOTIFICATIONS -> {
203
203
-
timelineViewModel.fetchNotifications {
204
204
-
isRefreshing.value = false
206
206
+
timelineViewModel.fetchNotifications(fresh = true) {
207
207
+
coroutineScope.launch {
208
208
+
isRefreshing.value = false
209
209
+
timelineState.scrollToItem(0)
210
210
+
}
205
211
}
206
212
}
207
213
}
···
218
224
uri,
219
225
displayName,
220
226
avatar
221
221
-
) { isRefreshing.value = false }
227
227
+
) {
228
228
+
coroutineScope.launch {
229
229
+
isRefreshing.value = false
230
230
+
timelineState.scrollToItem(0)
231
231
+
}
232
232
+
}
233
233
+
222
234
coroutineScope.launch {
223
235
drawerState.close()
224
236
}
···
366
378
state = timelineState,
367
379
modifier = Modifier.padding(values),
368
380
onReplyTap = onReplyTap,
369
369
-
isScrollEnabled = remember { mutableStateOf(isScrollEnabled) }
381
381
+
isScrollEnabled = isScrollEnabled
370
382
)
371
383
372
384
TabBarDestinations.NOTIFICATIONS -> NotificationsView(
373
385
viewModel = timelineViewModel,
374
386
state = notificationsState,
375
387
modifier = Modifier.padding(values),
376
376
-
isScrollEnabled = remember { mutableStateOf(isScrollEnabled) },
388
388
+
isScrollEnabled = isScrollEnabled,
377
389
onReplyTap = onReplyTap
378
390
)
379
391
}
+2
-3
app/src/main/java/industries/geesawra/monarch/NotificationsView.kt
···
11
11
import androidx.compose.material3.CircularProgressIndicator
12
12
import androidx.compose.runtime.Composable
13
13
import androidx.compose.runtime.LaunchedEffect
14
14
-
import androidx.compose.runtime.MutableState
15
14
import androidx.compose.runtime.derivedStateOf
16
15
import androidx.compose.runtime.getValue
17
16
import androidx.compose.runtime.remember
···
29
28
viewModel: TimelineViewModel,
30
29
state: LazyListState,
31
30
modifier: Modifier = Modifier,
32
32
-
isScrollEnabled: MutableState<Boolean>,
31
31
+
isScrollEnabled: Boolean,
33
32
onReplyTap: (SkeetData, Boolean) -> Unit = { _, _ -> },
34
33
) {
35
34
LazyColumn(
36
35
state = state,
37
36
modifier = modifier.fillMaxSize(),
38
38
-
userScrollEnabled = isScrollEnabled.value,
37
37
+
userScrollEnabled = isScrollEnabled,
39
38
verticalArrangement = Arrangement.spacedBy(8.dp),
40
39
) {
41
40
viewModel.uiState.notifications.forEach { notif ->
+2
-3
app/src/main/java/industries/geesawra/monarch/ShowSkeets.kt
···
15
15
import androidx.compose.material3.VerticalDivider
16
16
import androidx.compose.runtime.Composable
17
17
import androidx.compose.runtime.LaunchedEffect
18
18
-
import androidx.compose.runtime.MutableState
19
18
import androidx.compose.runtime.derivedStateOf
20
19
import androidx.compose.runtime.getValue
21
20
import androidx.compose.runtime.remember
···
30
29
fun ShowSkeets(
31
30
modifier: Modifier = Modifier,
32
31
viewModel: TimelineViewModel,
33
33
-
isScrollEnabled: MutableState<Boolean>,
32
32
+
isScrollEnabled: Boolean,
34
33
state: LazyListState = rememberLazyListState(),
35
34
onReplyTap: (SkeetData, Boolean) -> Unit = { _, _ -> },
36
35
) {
37
36
LazyColumn(
38
37
state = state,
39
39
-
userScrollEnabled = isScrollEnabled.value,
38
38
+
userScrollEnabled = isScrollEnabled,
40
39
modifier = modifier.fillMaxSize(),
41
40
verticalArrangement = Arrangement.spacedBy(8.dp),
42
41
) {
+13
-15
app/src/main/java/industries/geesawra/monarch/datalayer/TimelineViewModel.kt
···
117
117
118
118
timelineFetchJob = viewModelScope.launch {
119
119
bskyConn.fetchTimeline(
120
120
-
{
121
121
-
if (uiState.selectedFeed == "Following") {
122
122
-
""
123
123
-
} else {
124
124
-
uiState.selectedFeed
125
125
-
}
126
126
-
}(), if (fresh) {
120
120
+
if (uiState.selectedFeed == "Following") {
121
121
+
""
122
122
+
} else {
123
123
+
uiState.selectedFeed
124
124
+
}, if (fresh) {
127
125
null
128
126
} else {
129
127
uiState.timelineCursor
130
128
}
131
131
-
).onSuccess { it ->
132
132
-
if (fresh) {
133
133
-
uiState = uiState.copy(skeets = listOf())
129
129
+
).onSuccess { response ->
130
130
+
val newSkeets = if (fresh) {
131
131
+
response.feed.map { SkeetData.fromFeedViewPost(it) }.distinctBy { it.cid }
132
132
+
} else {
133
133
+
(uiState.skeets + response.feed.map { SkeetData.fromFeedViewPost(it) }).distinctBy { it.cid }
134
134
}
135
135
-
val newData =
136
136
-
(uiState.skeets + it.feed.map { SkeetData.fromFeedViewPost(it) }).distinctBy { it.cid }
137
135
138
136
uiState = uiState.copy(
139
139
-
skeets = newData,
140
140
-
timelineCursor = it.cursor,
137
137
+
skeets = newSkeets,
138
138
+
timelineCursor = response.cursor,
141
139
isFetchingMoreTimeline = false
142
140
)
143
141
then()
···
337
335
}
338
336
}
339
337
}
340
340
-
}
338
338
+
}