From f95c808aa0d70a638d7e8b37eff5e6a1e2b14d62 Mon Sep 17 00:00:00 2001 From: Shinokuni Date: Mon, 22 Jul 2024 17:56:02 +0200 Subject: [PATCH] Improve reliability of markItemsReadOnScroll pref implementation in TimelineTab --- .../app/timelime/TimelineScreenModel.kt | 11 +++- .../com/readrops/app/timelime/TimelineTab.kt | 62 +++++++++++++++---- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt b/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt index d3ada4bf..de006449 100644 --- a/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt +++ b/app/src/main/java/com/readrops/app/timelime/TimelineScreenModel.kt @@ -48,6 +48,11 @@ class TimelineScreenModel( private val _timelineState = MutableStateFlow(TimelineState()) val timelineState = _timelineState.asStateFlow() + // separate this from main Timeline state for performances + // as it will be very often updated + private val _listIndexState = MutableStateFlow(0) + val listIndexState = _listIndexState.asStateFlow() + private val filters = MutableStateFlow(_timelineState.value.filters) init { @@ -80,11 +85,12 @@ class TimelineScreenModel( } .cachedIn(screenModelScope), isAccountLocal = account.isLocal, - lastFirstVisibleItemIndex = 0, scrollToTop = true ) } + _listIndexState.update { 0 } + preferences.hideReadFeeds.flow .flatMapLatest { hideReadFeeds -> getFoldersWithFeeds.get( @@ -371,7 +377,7 @@ class TimelineScreenModel( } fun updateLastFirstVisibleItemIndex(index: Int) { - _timelineState.update { it.copy(lastFirstVisibleItemIndex = index) } + _listIndexState.update { index } } } @@ -395,7 +401,6 @@ data class TimelineState( val isAccountLocal: Boolean = false, val hideReadAllFAB: Boolean = false, val itemSize: TimelineItemSize = TimelineItemSize.LARGE, - val lastFirstVisibleItemIndex: Int = 0, val markReadOnScroll: Boolean = false ) { diff --git a/app/src/main/java/com/readrops/app/timelime/TimelineTab.kt b/app/src/main/java/com/readrops/app/timelime/TimelineTab.kt index 5a63aacf..f06ab699 100644 --- a/app/src/main/java/com/readrops/app/timelime/TimelineTab.kt +++ b/app/src/main/java/com/readrops/app/timelime/TimelineTab.kt @@ -8,6 +8,7 @@ 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.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Menu @@ -65,6 +66,7 @@ import com.readrops.app.util.theme.spacing import com.readrops.db.filters.ListSortType import com.readrops.db.filters.MainFilter import com.readrops.db.filters.SubFilter +import com.readrops.db.pojo.ItemWithFeed import kotlinx.coroutines.flow.filter @@ -340,18 +342,12 @@ object TimelineTab : Tab { else -> { if (items.itemCount > 0) { - LaunchedEffect(Unit) { - snapshotFlow { lazyListState.firstVisibleItemIndex } - .filter { it > state.lastFirstVisibleItemIndex } - .collect { - val item = items[state.lastFirstVisibleItemIndex]!!.item - if (!item.isRead && state.markReadOnScroll) { - screenModel.setItemRead(item) - } - - screenModel.updateLastFirstVisibleItemIndex(it) - } - } + MarkItemsRead( + lazyListState = lazyListState, + items = items, + markReadOnScroll = state.markReadOnScroll, + screenModel = screenModel + ) LazyColumn( state = lazyListState, @@ -422,6 +418,48 @@ object TimelineTab : Tab { } } } + + @Composable + private fun MarkItemsRead( + lazyListState: LazyListState, + items: LazyPagingItems, + markReadOnScroll: Boolean, + screenModel: TimelineScreenModel + ) { + val lastFirstVisibleItemIndex by screenModel.listIndexState.collectAsStateWithLifecycle() + + LaunchedEffect(Unit) { + snapshotFlow { lazyListState.firstVisibleItemIndex } + .filter { + if (it < lastFirstVisibleItemIndex) { + screenModel.updateLastFirstVisibleItemIndex(it) + } + + it > lastFirstVisibleItemIndex + } + .collect { newLastFirstVisibleItemIndex -> + if (newLastFirstVisibleItemIndex - lastFirstVisibleItemIndex > 1) { + val difference = newLastFirstVisibleItemIndex - lastFirstVisibleItemIndex + + for (subCount in 0 until difference) { + val item = items[lastFirstVisibleItemIndex + subCount]?.item + + if (item != null && !item.isRead && markReadOnScroll) { + screenModel.setItemRead(item) + } + } + } else { + val item = items[lastFirstVisibleItemIndex]?.item + + if (item != null && !item.isRead && markReadOnScroll) { + screenModel.setItemRead(item) + } + } + + screenModel.updateLastFirstVisibleItemIndex(newLastFirstVisibleItemIndex) + } + } + } }