Adds a list state saver to the messages screen

This commit is contained in:
Vitor Pamplona
2025-05-14 16:52:19 -04:00
parent 4ae86861f8
commit e0449a9d44
5 changed files with 19 additions and 13 deletions
@@ -41,6 +41,8 @@ object ScrollStateKeys {
const val VIDEO_SCREEN = "VideoFeed" const val VIDEO_SCREEN = "VideoFeed"
const val HOME_FOLLOWS = "HomeFollowsFeed" const val HOME_FOLLOWS = "HomeFollowsFeed"
const val HOME_REPLIES = "HomeFollowsRepliesFeed" const val HOME_REPLIES = "HomeFollowsRepliesFeed"
const val MESSAGES_KNOWN = "MessagesKnown"
const val MESSAGES_NEW = "MessagesNew"
const val PROFILE_GALLERY = "ProfileGalleryFeed" const val PROFILE_GALLERY = "ProfileGalleryFeed"
const val DRAFTS = "DraftsFeed" const val DRAFTS = "DraftsFeed"
@@ -24,8 +24,8 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedError
import com.vitorpamplona.amethyst.ui.feeds.FeedState import com.vitorpamplona.amethyst.ui.feeds.FeedState
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.ChatroomHeaderCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.ChatroomHeaderCompose
@@ -50,18 +50,22 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
@Composable @Composable
fun ChatroomListFeedView( fun ChatroomListFeedView(
feedContentState: FeedContentState, feedContentState: FeedContentState,
scrollStateKey: String,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
markAsRead: MutableState<Boolean>, markAsRead: MutableState<Boolean>,
) { ) {
RefresheableBox(feedContentState, true) { RefresheableBox(feedContentState, true) {
CrossFadeState(feedContentState, accountViewModel, nav, markAsRead) SaveableFeedContentState(feedContentState, scrollStateKey) { listState ->
CrossFadeState(feedContentState, listState, accountViewModel, nav, markAsRead)
}
} }
} }
@Composable @Composable
private fun CrossFadeState( private fun CrossFadeState(
feedContentState: FeedContentState, feedContentState: FeedContentState,
listState: LazyListState,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
markAsRead: MutableState<Boolean>, markAsRead: MutableState<Boolean>,
@@ -81,7 +85,7 @@ private fun CrossFadeState(
FeedError(state.errorMessage) { feedContentState.invalidateData() } FeedError(state.errorMessage) { feedContentState.invalidateData() }
} }
is FeedState.Loaded -> { is FeedState.Loaded -> {
FeedLoaded(state, feedContentState, accountViewModel, nav, markAsRead) FeedLoaded(state, listState, accountViewModel, nav, markAsRead)
} }
FeedState.Loading -> { FeedState.Loading -> {
LoadingFeed() LoadingFeed()
@@ -93,23 +97,19 @@ private fun CrossFadeState(
@Composable @Composable
private fun FeedLoaded( private fun FeedLoaded(
loaded: FeedState.Loaded, loaded: FeedState.Loaded,
feedContentState: FeedContentState, listState: LazyListState,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
markAsRead: MutableState<Boolean>, markAsRead: MutableState<Boolean>,
) { ) {
val items by loaded.feed.collectAsStateWithLifecycle() val items by loaded.feed.collectAsStateWithLifecycle()
val listState = rememberLazyListState()
LaunchedEffect(key1 = markAsRead.value) { LaunchedEffect(key1 = markAsRead.value) {
if (markAsRead.value) { if (markAsRead.value) {
accountViewModel.markAllAsRead(items.list, accountViewModel) { markAsRead.value = false } accountViewModel.markAllAsRead(items.list, accountViewModel) { markAsRead.value = false }
} }
} }
WatchScrollToTop(feedContentState, listState)
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
state = listState, state = listState,
@@ -60,6 +60,7 @@ import kotlinx.coroutines.launch
@Immutable @Immutable
class MessagesTabItem( class MessagesTabItem(
val resource: Int, val resource: Int,
val scrollStateKey: String,
val feedContentState: FeedContentState, val feedContentState: FeedContentState,
val markAsRead: MutableState<Boolean>, val markAsRead: MutableState<Boolean>,
) )
@@ -128,6 +129,7 @@ fun MessagesPager(
) { page -> ) { page ->
ChatroomListFeedView( ChatroomListFeedView(
feedContentState = tabs[page].feedContentState, feedContentState = tabs[page].feedContentState,
scrollStateKey = tabs[page].scrollStateKey,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
nav = nav, nav = nav,
markAsRead = tabs[page].markAsRead, markAsRead = tabs[page].markAsRead,
@@ -29,6 +29,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar import com.vitorpamplona.amethyst.ui.navigation.AppBottomBar
@@ -63,8 +64,8 @@ fun MessagesSinglePane(
remember(knownFeedContentState, markKnownAsRead) { remember(knownFeedContentState, markKnownAsRead) {
derivedStateOf { derivedStateOf {
listOf( listOf(
MessagesTabItem(R.string.known, knownFeedContentState, markKnownAsRead), MessagesTabItem(R.string.known, ScrollStateKeys.MESSAGES_KNOWN, knownFeedContentState, markKnownAsRead),
MessagesTabItem(R.string.new_requests, newFeedContentState, markNewAsRead), MessagesTabItem(R.string.new_requests, ScrollStateKeys.MESSAGES_NEW, newFeedContentState, markNewAsRead),
) )
} }
} }
@@ -31,6 +31,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -60,8 +61,8 @@ fun ChatroomList(
remember(knownFeedContentState, markKnownAsRead) { remember(knownFeedContentState, markKnownAsRead) {
derivedStateOf { derivedStateOf {
listOf( listOf(
MessagesTabItem(R.string.known, knownFeedContentState, markKnownAsRead), MessagesTabItem(R.string.known, ScrollStateKeys.MESSAGES_KNOWN, knownFeedContentState, markKnownAsRead),
MessagesTabItem(R.string.new_requests, newFeedContentState, markNewAsRead), MessagesTabItem(R.string.new_requests, ScrollStateKeys.MESSAGES_NEW, newFeedContentState, markNewAsRead),
) )
} }
} }