From 538f85e3d23fac987b453a5fcccb1a03cbf4218f Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Wed, 31 Aug 2022 14:53:27 -0700 Subject: [PATCH] add infinite loader to home feed --- .../app/omnivore/omnivore/ui/home/HomeView.kt | 41 ++++++++++++++++--- .../omnivore/ui/home/HomeViewModel.kt | 7 +++- .../app/omnivore/omnivore/ui/root/RootView.kt | 3 +- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeView.kt index 238e47c94..accd3acec 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeView.kt @@ -4,23 +4,24 @@ import android.annotation.SuppressLint import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Menu import androidx.compose.material3.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import app.omnivore.omnivore.Routes +import kotlinx.coroutines.flow.distinctUntilChanged @OptIn(ExperimentalMaterial3Api::class) -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable fun HomeView( homeViewModel: HomeViewModel, @@ -60,12 +61,11 @@ fun HomeViewContent( navController: NavHostController, modifier: Modifier ) { + val listState = rememberLazyListState() val linkedItems: List by homeViewModel.itemsLiveData.observeAsState(listOf()) - // Fetch items - homeViewModel.load() - LazyColumn( + state = listState, verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier @@ -82,4 +82,33 @@ fun HomeViewContent( ) } } + + InfiniteListHandler(listState = listState) { + homeViewModel.load() + } +} + +@Composable +fun InfiniteListHandler( + listState: LazyListState, + buffer: Int = 2, + onLoadMore: () -> Unit +) { + val loadMore = remember { + derivedStateOf { + val layoutInfo = listState.layoutInfo + val totalItemsNumber = layoutInfo.totalItemsCount + val lastVisibleItemIndex = (layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0) + 1 + + lastVisibleItemIndex > (totalItemsNumber - buffer) + } + } + + LaunchedEffect(loadMore) { + snapshotFlow { loadMore.value } + .distinctUntilChanged() + .collect { + onLoadMore() + } + } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeViewModel.kt index a7b9d4921..be3f1227a 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/home/HomeViewModel.kt @@ -31,6 +31,7 @@ import javax.inject.Inject class HomeViewModel @Inject constructor( private val datastoreRepo: DatastoreRepository ): ViewModel() { + var cursor: String? = null val itemsLiveData = MutableLiveData>(listOf()) private fun getAuthToken(): String? = runBlocking { @@ -48,10 +49,12 @@ class HomeViewModel @Inject constructor( val response = apolloClient.query( SearchQuery( - first = Optional.presentIfNotNull(20), + after = Optional.presentIfNotNull(cursor), + first = Optional.presentIfNotNull(15), ) ).execute() + cursor = response.data?.search?.onSearchSuccess?.pageInfo?.endCursor val itemList = response.data?.search?.onSearchSuccess?.edges ?: listOf() val newItems = itemList.map { @@ -68,7 +71,7 @@ class HomeViewModel @Inject constructor( ) } - itemsLiveData.value = newItems + itemsLiveData.value = (itemsLiveData.value ?: listOf()).plus(newItems) } } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/root/RootView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/root/RootView.kt index 956485e54..ac8e5e907 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/root/RootView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/root/RootView.kt @@ -4,16 +4,15 @@ import SettingsView import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import app.omnivore.omnivore.Routes import app.omnivore.omnivore.ui.auth.LoginViewModel import app.omnivore.omnivore.ui.auth.WelcomeScreen -import app.omnivore.omnivore.ui.home.ArticleWebView import app.omnivore.omnivore.ui.home.HomeView import app.omnivore.omnivore.ui.home.HomeViewModel +import app.omnivore.omnivore.ui.reader.ArticleWebView @Composable fun RootView(loginViewModel: LoginViewModel, homeViewModel: HomeViewModel) {