mirror of https://github.com/readrops/Readrops.git
Add base of pagination in TimelineTab
This commit is contained in:
parent
413dba4db5
commit
304f3c02e0
|
@ -68,7 +68,7 @@ dependencies {
|
|||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
|
||||
def composeBom = platform('androidx.compose:compose-bom:2023.08.00')
|
||||
def composeBom = platform('androidx.compose:compose-bom:2023.10.01')
|
||||
implementation composeBom
|
||||
androidTestImplementation composeBom
|
||||
|
||||
|
@ -107,7 +107,9 @@ dependencies {
|
|||
implementation "io.coil-kt:coil:2.4.0"
|
||||
implementation "io.coil-kt:coil-compose:2.4.0"
|
||||
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
|
||||
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1"
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package com.readrops.app.compose.timelime
|
||||
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
|
@ -27,11 +24,12 @@ import androidx.compose.material3.rememberDrawerState
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.paging.LoadState
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
|
@ -42,6 +40,7 @@ import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
|||
import com.readrops.app.compose.R
|
||||
import com.readrops.app.compose.item.ItemScreen
|
||||
import com.readrops.app.compose.timelime.drawer.TimelineDrawer
|
||||
import com.readrops.app.compose.util.components.CenteredColumn
|
||||
import com.readrops.app.compose.util.theme.spacing
|
||||
import org.koin.androidx.compose.getViewModel
|
||||
|
||||
|
@ -60,11 +59,14 @@ object TimelineTab : Tab {
|
|||
override fun Content() {
|
||||
val viewModel = getViewModel<TimelineViewModel>()
|
||||
val state by viewModel.timelineState.collectAsStateWithLifecycle()
|
||||
val items = state.itemState.collectAsLazyPagingItems()
|
||||
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val context = LocalContext.current
|
||||
|
||||
val scrollState = rememberLazyListState()
|
||||
|
||||
// Use the depreciated refresh swipe as the material 3 one isn't available yet
|
||||
val swipeState = rememberSwipeRefreshState(state.isRefreshing)
|
||||
val drawerState = rememberDrawerState(
|
||||
initialValue = DrawerValue.Closed,
|
||||
|
@ -131,7 +133,9 @@ object TimelineTab : Tab {
|
|||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = { }) {
|
||||
IconButton(
|
||||
onClick = { viewModel.refreshTimeline() }
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_sync),
|
||||
contentDescription = null
|
||||
|
@ -154,21 +158,16 @@ object TimelineTab : Tab {
|
|||
onRefresh = { viewModel.refreshTimeline() },
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
) {
|
||||
when (val itemState = state.items) {
|
||||
is ItemState.Loading -> {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
when {
|
||||
items.isLoading() -> {
|
||||
Log.d("TAG", "loading")
|
||||
CenteredColumn {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
is ItemState.Error -> TODO()
|
||||
is ItemState.Loaded -> {
|
||||
val items = itemState.items.collectAsLazyPagingItems()
|
||||
|
||||
items.isError() -> Text(text = "error")
|
||||
else -> {
|
||||
LazyColumn(
|
||||
state = scrollState,
|
||||
contentPadding = PaddingValues(vertical = MaterialTheme.spacing.shortSpacing),
|
||||
|
@ -176,7 +175,7 @@ object TimelineTab : Tab {
|
|||
) {
|
||||
items(
|
||||
count = items.itemCount,
|
||||
key = { items[it]!!.item.id },
|
||||
//key = { items[it]!! },
|
||||
contentType = { "item_with_feed" }
|
||||
) { itemCount ->
|
||||
val itemWithFeed = items[itemCount]!!
|
||||
|
@ -192,6 +191,7 @@ object TimelineTab : Tab {
|
|||
onShare = {
|
||||
viewModel.shareItem(itemWithFeed.item, context)
|
||||
},
|
||||
compactLayout = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -203,20 +203,11 @@ object TimelineTab : Tab {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NoItemPlaceholder() {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
Text(
|
||||
text = "No item",
|
||||
style = MaterialTheme.typography.displayMedium
|
||||
)
|
||||
}
|
||||
fun <T : Any> LazyPagingItems<T>.isLoading(): Boolean {
|
||||
return loadState.append is LoadState.Loading //|| loadState.refresh is LoadState.Loading
|
||||
}
|
||||
|
||||
fun <T : Any> LazyPagingItems<T>.isError(): Boolean {
|
||||
return loadState.append is LoadState.Error //|| loadState.refresh is LoadState.Error
|
||||
}
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
@ -46,17 +47,17 @@ class TimelineViewModel(
|
|||
accountEvent.consumeAsFlow(),
|
||||
filters
|
||||
) { account, filters ->
|
||||
filters.accountId = account.id
|
||||
Pair(account, filters)
|
||||
}.collectLatest { (account, filters) ->
|
||||
val query = ItemsQueryBuilder.buildItemsQuery(filters.copy(accountId = account.id))
|
||||
val query = ItemsQueryBuilder.buildItemsQuery(filters)
|
||||
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
items = ItemState.Loaded(
|
||||
items = Pager(
|
||||
itemState = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = 100,
|
||||
prefetchDistance = 150
|
||||
pageSize = 10,
|
||||
prefetchDistance = 10
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
database.newItemDao().selectAll(query)
|
||||
|
@ -64,7 +65,6 @@ class TimelineViewModel(
|
|||
).flow
|
||||
.cachedIn(viewModelScope)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
getFoldersWithFeeds.get(account.id)
|
||||
|
@ -86,7 +86,12 @@ class TimelineViewModel(
|
|||
|
||||
}
|
||||
|
||||
_timelineState.update { it.copy(isRefreshing = false) }
|
||||
_timelineState.update {
|
||||
it.copy(
|
||||
isRefreshing = false,
|
||||
endSynchronizing = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,18 +188,8 @@ class TimelineViewModel(
|
|||
data class TimelineState(
|
||||
val isRefreshing: Boolean = false,
|
||||
val isDrawerOpen: Boolean = false,
|
||||
val endSynchronizing: Boolean = false,
|
||||
val filters: QueryFilters = QueryFilters(),
|
||||
val foldersAndFeeds: Map<Folder?, List<Feed>> = emptyMap(),
|
||||
val items: ItemState = ItemState.Loading
|
||||
val itemState: Flow<PagingData<ItemWithFeed>> = emptyFlow()
|
||||
)
|
||||
|
||||
sealed class ItemState {
|
||||
@Immutable
|
||||
object Loading : ItemState()
|
||||
|
||||
@Immutable
|
||||
data class Error(val exception: Exception) : ItemState()
|
||||
|
||||
@Immutable
|
||||
data class Loaded(val items: Flow<PagingData<ItemWithFeed>>) : ItemState()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package com.readrops.app.compose.util.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import com.readrops.app.compose.util.toDp
|
||||
|
||||
|
||||
@Composable
|
||||
fun CenteredColumn(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Placeholder(
|
||||
text: String,
|
||||
painter: Painter,
|
||||
) {
|
||||
CenteredColumn {
|
||||
Icon(
|
||||
painter = painter,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(MaterialTheme.typography.displayMedium.toDp() * 1.5f)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.displayMedium
|
||||
)
|
||||
}
|
||||
}
|
|
@ -97,9 +97,9 @@ dependencies {
|
|||
api "io.insert-koin:koin-androidx-compose:3.4.2"
|
||||
api "io.insert-koin:koin-android-compat:$rootProject.ext.koin_version"
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
|
||||
|
||||
api "androidx.paging:paging-runtime-ktx:3.2.0"
|
||||
api "androidx.paging:paging-compose:3.2.0"
|
||||
api "androidx.paging:paging-runtime-ktx:3.2.1"
|
||||
api "androidx.paging:paging-compose:3.2.1"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue