Avoids running through the entire filter when collection is Empty

This commit is contained in:
Vitor Pamplona
2023-05-28 17:53:08 -04:00
parent 446273de80
commit 02ad85a740
4 changed files with 28 additions and 12 deletions
@@ -290,6 +290,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
} }
fun <T> equalImmutableLists(list1: ImmutableList<T>, list2: ImmutableList<T>): Boolean { fun <T> equalImmutableLists(list1: ImmutableList<T>, list2: ImmutableList<T>): Boolean {
if (list1 === list2) return true
if (list1.size != list2.size) return false if (list1.size != list2.size) return false
for (i in 0 until list1.size) { for (i in 0 until list1.size) {
if (list1[i] !== list2[i]) { if (list1[i] !== list2[i]) {
@@ -2,10 +2,11 @@ package com.vitorpamplona.amethyst.ui.screen
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import kotlinx.collections.immutable.ImmutableList
sealed class FeedState { sealed class FeedState {
object Loading : FeedState() object Loading : FeedState()
class Loaded(val feed: MutableState<List<Note>>) : FeedState() class Loaded(val feed: MutableState<ImmutableList<Note>>) : FeedState()
object Empty : FeedState() object Empty : FeedState()
class FeedError(val errorMessage: String) : FeedState() class FeedError(val errorMessage: String) : FeedState()
} }
@@ -25,6 +25,8 @@ import com.vitorpamplona.amethyst.ui.dal.UserProfileConversationsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.UserProfileNewThreadFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileNewThreadFeedFilter
import com.vitorpamplona.amethyst.ui.dal.UserProfileReportsFeedFilter import com.vitorpamplona.amethyst.ui.dal.UserProfileReportsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -55,8 +57,8 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
private val _feedContent = MutableStateFlow<FeedState>(FeedState.Loading) private val _feedContent = MutableStateFlow<FeedState>(FeedState.Loading)
val feedContent = _feedContent.asStateFlow() val feedContent = _feedContent.asStateFlow()
fun newListFromDataSource(): List<Note> { fun newListFromDataSource(): ImmutableList<Note> {
return localFilter.loadTop() return localFilter.loadTop().toImmutableList()
} }
private fun refresh() { private fun refresh() {
@@ -71,8 +73,7 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
val oldNotesState = _feedContent.value val oldNotesState = _feedContent.value
if (oldNotesState is FeedState.Loaded) { if (oldNotesState is FeedState.Loaded) {
// Using size as a proxy for has changed. if (!equalImmutableLists(notes, oldNotesState.feed.value)) {
if (notes != oldNotesState.feed.value) {
updateFeed(notes) updateFeed(notes)
} }
} else { } else {
@@ -80,7 +81,7 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
} }
} }
private fun updateFeed(notes: List<Note>) { private fun updateFeed(notes: ImmutableList<Note>) {
val scope = CoroutineScope(Job() + Dispatchers.Main) val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch { scope.launch {
val currentState = _feedContent.value val currentState = _feedContent.value
@@ -97,10 +98,20 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
fun refreshFromOldState(newItems: Set<Note>) { fun refreshFromOldState(newItems: Set<Note>) {
val oldNotesState = _feedContent.value val oldNotesState = _feedContent.value
if (localFilter is AdditiveFeedFilter && oldNotesState is FeedState.Loaded) { if (localFilter is AdditiveFeedFilter) {
val newList = localFilter.updateListWith(oldNotesState.feed.value, newItems.toSet()) if (oldNotesState is FeedState.Loaded) {
if (newList !== oldNotesState.feed.value) { val newList = localFilter.updateListWith(oldNotesState.feed.value, newItems.toSet()).toImmutableList()
updateFeed(newList) if (!equalImmutableLists(newList, oldNotesState.feed.value)) {
updateFeed(newList)
}
} else if (oldNotesState is FeedState.Empty) {
val newList = localFilter.updateListWith(emptyList(), newItems.toSet()).toImmutableList()
if (newList.isNotEmpty()) {
updateFeed(newList)
}
} else {
// Refresh Everything
refreshSuspended()
} }
} else { } else {
// Refresh Everything // Refresh Everything
@@ -130,7 +141,9 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
init { init {
collectorJob = viewModelScope.launch(Dispatchers.IO) { collectorJob = viewModelScope.launch(Dispatchers.IO) {
LocalCache.live.newEventBundles.collect { newNotes -> LocalCache.live.newEventBundles.collect { newNotes ->
if (localFilter is AdditiveFeedFilter && _feedContent.value is FeedState.Loaded) { if (localFilter is AdditiveFeedFilter &&
(_feedContent.value is FeedState.Loaded || _feedContent.value is FeedState.Empty)
) {
invalidateInsertData(newNotes) invalidateInsertData(newNotes)
} else { } else {
// Refresh Everything // Refresh Everything
@@ -86,6 +86,7 @@ import com.vitorpamplona.amethyst.ui.screen.LoadingFeed
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -198,7 +199,7 @@ fun FeedView(
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun SlidingCarousel( fun SlidingCarousel(
feed: MutableState<List<Note>>, feed: MutableState<ImmutableList<Note>>,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: (String) -> Unit, nav: (String) -> Unit,
scrollStateKey: String? = null, scrollStateKey: String? = null,