From 3801c7e2d8695274e23414048e0dba6f6267956b Mon Sep 17 00:00:00 2001 From: Diego Beraldin Date: Sat, 11 May 2024 11:47:14 +0200 Subject: [PATCH] fix: lazy list state issues when changing feed or sort type (#831) --- .../feature/settings/main/SettingsScreen.kt | 10 +-- .../unit/chat/InboxChatScreen.kt | 4 +- .../communitydetail/CommunityDetailScreen.kt | 36 ++++++---- .../CommunityDetailViewModel.kt | 4 ++ .../unit/explore/ExploreScreen.kt | 18 +++-- .../FilteredContentsScreen.kt | 16 +++-- .../unit/instanceinfo/InstanceInfoScreen.kt | 4 +- .../ManageSubscriptionsScreen.kt | 16 +++-- .../unit/mentions/InboxMentionsScreen.kt | 10 ++- .../unit/messages/InboxMessagesScreen.kt | 10 ++- .../unit/modlog/ModlogScreen.kt | 5 +- .../detail/MultiCommunityScreen.kt | 24 ++++--- .../detail/MultiCommunityViewModel.kt | 2 + .../unit/myaccount/ProfileLoggedScreen.kt | 6 +- .../unit/postdetail/PostDetailScreen.kt | 14 ++-- .../unit/postdetail/PostDetailViewModel.kt | 2 + .../unit/postlist/PostListScreen.kt | 44 +++++++----- .../unit/postlist/PostListViewModel.kt | 4 ++ .../unit/replies/InboxRepliesScreen.kt | 10 ++- .../unit/saveditems/SavedItemsMviModel.kt | 4 +- .../unit/saveditems/SavedItemsScreen.kt | 8 ++- .../unit/saveditems/SavedItemsViewModel.kt | 67 ++++++++++--------- .../unit/userdetail/UserDetailScreen.kt | 16 +++-- .../unit/userdetail/UserDetailViewModel.kt | 3 + 24 files changed, 212 insertions(+), 125 deletions(-) diff --git a/feature/settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/settings/main/SettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/settings/main/SettingsScreen.kt index b2f9c3022..3c5ed21b7 100644 --- a/feature/settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/settings/main/SettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/settings/main/SettingsScreen.kt @@ -98,10 +98,12 @@ class SettingsScreen : Screen { LaunchedEffect(Unit) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Settings) { - scrollState.scrollTo(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + if (section == TabNavigationSection.Settings) { + scrollState.scrollTo(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }.launchIn(this) } diff --git a/unit/chat/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/chat/InboxChatScreen.kt b/unit/chat/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/chat/InboxChatScreen.kt index 67f1e7cb3..7cc2441ae 100644 --- a/unit/chat/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/chat/InboxChatScreen.kt +++ b/unit/chat/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/chat/InboxChatScreen.kt @@ -118,7 +118,9 @@ class InboxChatScreen( } InboxChatMviModel.Effect.ScrollToBottom -> { - lazyListState.scrollToItem(0) + runCatching { + lazyListState.scrollToItem(0) + } } } }.launchIn(this) diff --git a/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailScreen.kt b/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailScreen.kt index ef8c2bf57..6e8b0425a 100644 --- a/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailScreen.kt +++ b/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailScreen.kt @@ -221,17 +221,21 @@ class CommunityDetailScreen( } CommunityDetailMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } is CommunityDetailMviModel.Effect.ZombieModeTick -> { - if (effect.index >= 0) { - lazyListState.animateScrollBy( - value = settings.zombieModeScrollAmount, - animationSpec = tween(350), - ) + runCatching { + if (effect.index >= 0) { + lazyListState.animateScrollBy( + value = settings.zombieModeScrollAmount, + animationSpec = tween(350), + ) + } } } @@ -577,9 +581,11 @@ class CommunityDetailScreen( text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) @@ -590,9 +596,11 @@ class CommunityDetailScreen( onSelected = rememberCallback { model.reduce(CommunityDetailMviModel.Intent.ClearRead) scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailViewModel.kt b/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailViewModel.kt index ac0829059..e1f273b87 100644 --- a/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailViewModel.kt +++ b/unit/communitydetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/communitydetail/CommunityDetailViewModel.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.IO import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -308,6 +309,7 @@ class CommunityDetailViewModel( private suspend fun refresh() { hideReadPosts = false val currentState = uiState.value + zombieModeHelper.pause() postPaginationManager.reset( PostPaginationSpecification.Community( id = currentState.community.id, @@ -338,6 +340,7 @@ class CommunityDetailViewModel( community = refreshedCommunity, moderators = moderators, loading = false, + zombieModeActive = false, ) } } @@ -352,6 +355,7 @@ class CommunityDetailViewModel( updateState { it.copy(sortType = value) } screenModelScope.launch(Dispatchers.IO) { emitEffect(CommunityDetailMviModel.Effect.BackToTop) + delay(50) refresh() } } diff --git a/unit/explore/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/explore/ExploreScreen.kt b/unit/explore/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/explore/ExploreScreen.kt index fa1ec1404..c5367f022 100644 --- a/unit/explore/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/explore/ExploreScreen.kt +++ b/unit/explore/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/explore/ExploreScreen.kt @@ -146,10 +146,12 @@ class ExploreScreen( LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Explore) { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + if (section == TabNavigationSection.Explore) { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }.launchIn(this) } @@ -157,9 +159,11 @@ class ExploreScreen( model.effects.onEach { when (it) { ExploreMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } ExploreMviModel.Effect.OperationFailure -> { diff --git a/unit/filteredcontents/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/filteredcontents/FilteredContentsScreen.kt b/unit/filteredcontents/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/filteredcontents/FilteredContentsScreen.kt index 95d1bc93f..edbb3564a 100644 --- a/unit/filteredcontents/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/filteredcontents/FilteredContentsScreen.kt +++ b/unit/filteredcontents/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/filteredcontents/FilteredContentsScreen.kt @@ -130,9 +130,11 @@ class FilteredContentsScreen( model.effects.onEach { effect -> when (effect) { FilteredContentsMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } } }.launchIn(this) @@ -200,9 +202,11 @@ class FilteredContentsScreen( text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/instanceinfo/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/instanceinfo/InstanceInfoScreen.kt b/unit/instanceinfo/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/instanceinfo/InstanceInfoScreen.kt index e59ce1f0c..72223a566 100644 --- a/unit/instanceinfo/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/instanceinfo/InstanceInfoScreen.kt +++ b/unit/instanceinfo/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/instanceinfo/InstanceInfoScreen.kt @@ -81,7 +81,9 @@ class InstanceInfoScreen( model.effects.onEach { effect -> when (effect) { InstanceInfoMviModel.Effect.BackToTop -> { - listState.scrollToItem(0) + runCatching { + listState.scrollToItem(0) + } } } }.launchIn(this) diff --git a/unit/managesubscriptions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/managesubscriptions/ManageSubscriptionsScreen.kt b/unit/managesubscriptions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/managesubscriptions/ManageSubscriptionsScreen.kt index 98d46fac8..88e866cb1 100644 --- a/unit/managesubscriptions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/managesubscriptions/ManageSubscriptionsScreen.kt +++ b/unit/managesubscriptions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/managesubscriptions/ManageSubscriptionsScreen.kt @@ -117,9 +117,11 @@ class ManageSubscriptionsScreen : Screen { model.effects.onEach { event -> when (event) { ManageSubscriptionsMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } ManageSubscriptionsMviModel.Effect.Success -> { @@ -171,9 +173,11 @@ class ManageSubscriptionsScreen : Screen { text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/mentions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/mentions/InboxMentionsScreen.kt b/unit/mentions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/mentions/InboxMentionsScreen.kt index e19e57f07..b6386422c 100644 --- a/unit/mentions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/mentions/InboxMentionsScreen.kt +++ b/unit/mentions/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/mentions/InboxMentionsScreen.kt @@ -84,8 +84,10 @@ class InboxMentionsScreen : Tab { LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Inbox) { - lazyListState.scrollToItem(0) + runCatching { + if (section == TabNavigationSection.Inbox) { + lazyListState.scrollToItem(0) + } } }.launchIn(this) } @@ -97,7 +99,9 @@ class InboxMentionsScreen : Tab { } InboxMentionsMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) + runCatching { + lazyListState.scrollToItem(0) + } } } }.launchIn(this) diff --git a/unit/messages/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/messages/InboxMessagesScreen.kt b/unit/messages/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/messages/InboxMessagesScreen.kt index 5666b97af..2f52d9506 100644 --- a/unit/messages/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/messages/InboxMessagesScreen.kt +++ b/unit/messages/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/messages/InboxMessagesScreen.kt @@ -61,8 +61,10 @@ class InboxMessagesScreen : Tab { LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Inbox) { - lazyListState.scrollToItem(0) + runCatching { + if (section == TabNavigationSection.Inbox) { + lazyListState.scrollToItem(0) + } } }.launchIn(this) } @@ -74,7 +76,9 @@ class InboxMessagesScreen : Tab { } InboxMessagesMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) + runCatching { + lazyListState.scrollToItem(0) + } } } }.launchIn(this) diff --git a/unit/modlog/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/modlog/ModlogScreen.kt b/unit/modlog/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/modlog/ModlogScreen.kt index 2abc37d85..26854733f 100644 --- a/unit/modlog/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/modlog/ModlogScreen.kt +++ b/unit/modlog/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/modlog/ModlogScreen.kt @@ -30,7 +30,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -65,7 +64,6 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.modlog.components.ModlogIte import com.github.diegoberaldin.raccoonforlemmy.unit.modlog.components.RemoveCommunityItem import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch import org.koin.core.parameter.parametersOf class ModlogScreen( @@ -80,7 +78,6 @@ class ModlogScreen( val topAppBarState = rememberTopAppBarState() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState) val navigationCoordinator = remember { getNavigationCoordinator() } - val scope = rememberCoroutineScope() val settingsRepository = remember { getSettingsRepository() } val settings by settingsRepository.currentSettings.collectAsState() val lazyListState = rememberLazyListState() @@ -96,7 +93,7 @@ class ModlogScreen( model.effects.onEach { effect -> when (effect) { ModlogMviModel.Effect.BackToTop -> { - scope.launch { + runCatching { lazyListState.scrollToItem(0) topAppBarState.heightOffset = 0f topAppBarState.contentOffset = 0f diff --git a/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityScreen.kt b/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityScreen.kt index 89b8f956a..468b826f5 100644 --- a/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityScreen.kt +++ b/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityScreen.kt @@ -137,9 +137,11 @@ class MultiCommunityScreen( } MultiCommunityMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } } }.launchIn(this) @@ -231,9 +233,11 @@ class MultiCommunityScreen( text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) @@ -243,9 +247,11 @@ class MultiCommunityScreen( onSelected = rememberCallback { model.reduce(MultiCommunityMviModel.Intent.ClearRead) scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityViewModel.kt b/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityViewModel.kt index 87c9f35a1..1a89c4a71 100644 --- a/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityViewModel.kt +++ b/unit/multicommunity/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/multicommunity/detail/MultiCommunityViewModel.kt @@ -24,6 +24,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepo import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -243,6 +244,7 @@ class MultiCommunityViewModel( updateState { it.copy(sortType = value) } screenModelScope.launch { emitEffect(MultiCommunityMviModel.Effect.BackToTop) + delay(50) refresh() } } diff --git a/unit/myaccount/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/myaccount/ProfileLoggedScreen.kt b/unit/myaccount/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/myaccount/ProfileLoggedScreen.kt index 2ea764e62..a90a03d54 100644 --- a/unit/myaccount/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/myaccount/ProfileLoggedScreen.kt +++ b/unit/myaccount/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/myaccount/ProfileLoggedScreen.kt @@ -93,8 +93,10 @@ object ProfileLoggedScreen : Tab { LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Profile) { - lazyListState.scrollToItem(0) + runCatching { + if (section == TabNavigationSection.Profile) { + lazyListState.scrollToItem(0) + } } }.launchIn(this) } diff --git a/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailScreen.kt b/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailScreen.kt index f5d9fc2c6..3c8523b1d 100644 --- a/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailScreen.kt +++ b/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailScreen.kt @@ -252,11 +252,13 @@ class PostDetailScreen( } is PostDetailMviModel.Effect.ScrollToComment -> { - lazyListState.scrollToItem(effect.index) + runCatching { + lazyListState.scrollToItem(effect.index) + } } PostDetailMviModel.Effect.BackToTop -> { - scope.launch { + runCatching { lazyListState.scrollToItem(0) topAppBarState.heightOffset = 0f topAppBarState.contentOffset = 0f @@ -595,9 +597,11 @@ class PostDetailScreen( text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailViewModel.kt b/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailViewModel.kt index 9cb9b7140..25cda0ccd 100644 --- a/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailViewModel.kt +++ b/unit/postdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postdetail/PostDetailViewModel.kt @@ -29,6 +29,7 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.postdetail.utils.sortToNest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -466,6 +467,7 @@ class PostDetailViewModel( updateState { it.copy(sortType = value) } screenModelScope.launch { emitEffect(PostDetailMviModel.Effect.BackToTop) + delay(50) refresh() } } diff --git a/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListScreen.kt b/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListScreen.kt index 38fa29ec7..e5351d932 100644 --- a/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListScreen.kt +++ b/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListScreen.kt @@ -144,9 +144,11 @@ class PostListScreen : Screen { LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> if (section == TabNavigationSection.Home) { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }.launchIn(this) } @@ -154,17 +156,21 @@ class PostListScreen : Screen { model.effects.onEach { effect -> when (effect) { PostListMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } is PostListMviModel.Effect.ZombieModeTick -> { - if (effect.index >= 0) { - lazyListState.animateScrollBy( - value = settings.zombieModeScrollAmount, - animationSpec = tween(350), - ) + runCatching { + if (effect.index >= 0) { + lazyListState.animateScrollBy( + value = settings.zombieModeScrollAmount, + animationSpec = tween(350), + ) + } } } @@ -256,9 +262,11 @@ class PostListScreen : Screen { text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) @@ -269,9 +277,11 @@ class PostListScreen : Screen { onSelected = rememberCallback { model.reduce(PostListMviModel.Intent.ClearRead) scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListViewModel.kt b/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListViewModel.kt index a16fd5887..750a52a46 100644 --- a/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListViewModel.kt +++ b/unit/postlist/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/postlist/PostListViewModel.kt @@ -271,6 +271,7 @@ class PostListViewModel( hideReadPosts = false val listingType = uiState.value.listingType ?: return val sortType = uiState.value.sortType ?: return + zombieModeHelper.pause() postPaginationManager.reset( PostPaginationSpecification.Listing( listingType = listingType, @@ -284,6 +285,7 @@ class PostListViewModel( canFetchMore = true, refreshing = true, loading = false, + zombieModeActive = false, ) } loadNextPage() @@ -331,6 +333,7 @@ class PostListViewModel( updateState { it.copy(sortType = value) } screenModelScope.launch { emitEffect(PostListMviModel.Effect.BackToTop) + delay(50) refresh() } } @@ -342,6 +345,7 @@ class PostListViewModel( updateState { it.copy(listingType = value) } screenModelScope.launch(Dispatchers.IO) { emitEffect(PostListMviModel.Effect.BackToTop) + delay(50) refresh() } } diff --git a/unit/replies/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/replies/InboxRepliesScreen.kt b/unit/replies/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/replies/InboxRepliesScreen.kt index 8c5ad8a84..ce5c51603 100644 --- a/unit/replies/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/replies/InboxRepliesScreen.kt +++ b/unit/replies/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/replies/InboxRepliesScreen.kt @@ -84,8 +84,10 @@ class InboxRepliesScreen : Tab { LaunchedEffect(navigationCoordinator) { navigationCoordinator.onDoubleTabSelection.onEach { section -> - if (section == TabNavigationSection.Inbox) { - lazyListState.scrollToItem(0) + runCatching { + if (section == TabNavigationSection.Inbox) { + lazyListState.scrollToItem(0) + } } }.launchIn(this) } @@ -97,7 +99,9 @@ class InboxRepliesScreen : Tab { } InboxRepliesMviModel.Effect.BackToTop -> { - lazyListState.scrollToItem(0) + runCatching { + lazyListState.scrollToItem(0) + } } } }.launchIn(this) diff --git a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsMviModel.kt b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsMviModel.kt index 29f074c53..278f86f1d 100644 --- a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsMviModel.kt +++ b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsMviModel.kt @@ -50,5 +50,7 @@ interface SavedItemsMviModel : val availableSortTypes: List = emptyList(), ) - sealed interface Effect + sealed interface Effect { + data object BackToTop : Effect + } } diff --git a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsScreen.kt b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsScreen.kt index 9c2e260be..ba67b34b9 100644 --- a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsScreen.kt +++ b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsScreen.kt @@ -158,9 +158,11 @@ class SavedItemsScreen : Screen { text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsViewModel.kt b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsViewModel.kt index 2f57d0bd2..bd9588524 100644 --- a/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsViewModel.kt +++ b/unit/saveditems/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/saveditems/SavedItemsViewModel.kt @@ -21,9 +21,9 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommentRepository import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.GetSortTypesUseCase import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepository -import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -31,7 +31,6 @@ import kotlinx.coroutines.launch class SavedItemsViewModel( private val identityRepository: IdentityRepository, private val apiConfigurationRepository: ApiConfigurationRepository, - private val siteRepository: SiteRepository, private val postPaginationManager: PostPaginationManager, private val commentPaginationManager: CommentPaginationManager, private val postRepository: PostRepository, @@ -92,8 +91,14 @@ class SavedItemsViewModel( override fun reduce(intent: SavedItemsMviModel.Intent) { when (intent) { - SavedItemsMviModel.Intent.LoadNextPage -> loadNextPage() - SavedItemsMviModel.Intent.Refresh -> refresh() + SavedItemsMviModel.Intent.LoadNextPage -> screenModelScope.launch { + loadNextPage() + } + + SavedItemsMviModel.Intent.Refresh -> screenModelScope.launch { + refresh() + } + is SavedItemsMviModel.Intent.ChangeSection -> changeSection(intent.section) is SavedItemsMviModel.Intent.DownVoteComment -> { if (intent.feedback) { @@ -160,7 +165,7 @@ class SavedItemsViewModel( } } - private fun refresh() { + private suspend fun refresh() { postPaginationManager.reset( PostPaginationSpecification.Saved(sortType = uiState.value.sortType) ) @@ -177,36 +182,34 @@ class SavedItemsViewModel( loadNextPage() } - private fun loadNextPage() { + private suspend fun loadNextPage() { val currentState = uiState.value if (!currentState.canFetchMore || currentState.loading) { updateState { it.copy(refreshing = false) } return } - screenModelScope.launch { - updateState { it.copy(loading = true) } - val section = currentState.section - if (section == SavedItemsSection.Posts) { - val posts = postPaginationManager.loadNextPage() - updateState { - it.copy( - posts = posts, - loading = false, - canFetchMore = postPaginationManager.canFetchMore, - refreshing = false, - ) - } - } else { - val comments = commentPaginationManager.loadNextPage() - updateState { - it.copy( - comments = comments, - loading = false, - canFetchMore = commentPaginationManager.canFetchMore, - refreshing = false, - ) - } + updateState { it.copy(loading = true) } + val section = currentState.section + if (section == SavedItemsSection.Posts) { + val posts = postPaginationManager.loadNextPage() + updateState { + it.copy( + posts = posts, + loading = false, + canFetchMore = postPaginationManager.canFetchMore, + refreshing = false, + ) + } + } else { + val comments = commentPaginationManager.loadNextPage() + updateState { + it.copy( + comments = comments, + loading = false, + canFetchMore = commentPaginationManager.canFetchMore, + refreshing = false, + ) } } } @@ -216,7 +219,11 @@ class SavedItemsViewModel( return } updateState { it.copy(sortType = value) } - refresh() + screenModelScope.launch { + emitEffect(SavedItemsMviModel.Effect.BackToTop) + delay(50) + refresh() + } } private fun handlePostUpdate(post: PostModel) { diff --git a/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailScreen.kt b/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailScreen.kt index 6b55e41e7..c84e3d05f 100644 --- a/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailScreen.kt +++ b/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailScreen.kt @@ -182,9 +182,11 @@ class UserDetailScreen( UserDetailMviModel.Effect.BackToTop -> { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } } @@ -374,9 +376,11 @@ class UserDetailScreen( text = LocalXmlStrings.current.actionBackToTop, onSelected = rememberCallback { scope.launch { - lazyListState.scrollToItem(0) - topAppBarState.heightOffset = 0f - topAppBarState.contentOffset = 0f + runCatching { + lazyListState.scrollToItem(0) + topAppBarState.heightOffset = 0f + topAppBarState.contentOffset = 0f + } } }, ) diff --git a/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailViewModel.kt b/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailViewModel.kt index 6ca0cd1d7..a9cdf178d 100644 --- a/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailViewModel.kt +++ b/unit/userdetail/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/unit/userdetail/UserDetailViewModel.kt @@ -34,6 +34,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -236,6 +237,8 @@ class UserDetailViewModel( updateState { it.copy(sortType = value) } screenModelScope.launch(Dispatchers.Main) { emitEffect(UserDetailMviModel.Effect.BackToTop) + delay(50) + refresh() } }