forked from melod1n/fast-messenger
saving scroll position only while app is working & add divider with spacer on conversations screen
This commit is contained in:
+11
@@ -60,6 +60,9 @@ interface ConversationsViewModel {
|
|||||||
fun onOptionClicked(conversation: UiConversation, option: ConversationOption)
|
fun onOptionClicked(conversation: UiConversation, option: ConversationOption)
|
||||||
|
|
||||||
fun onErrorConsumed()
|
fun onErrorConsumed()
|
||||||
|
|
||||||
|
fun setScrollIndex(index: Int)
|
||||||
|
fun setScrollOffset(offset: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConversationsViewModelImpl(
|
class ConversationsViewModelImpl(
|
||||||
@@ -206,6 +209,14 @@ class ConversationsViewModelImpl(
|
|||||||
baseError.setValue { null }
|
baseError.setValue { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setScrollIndex(index: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollIndex = index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setScrollOffset(offset: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollOffset = offset) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun hideOptions(conversationId: Int) {
|
private fun hideOptions(conversationId: Int) {
|
||||||
screenState.setValue { old ->
|
screenState.setValue { old ->
|
||||||
old.copy(
|
old.copy(
|
||||||
|
|||||||
+6
-2
@@ -9,7 +9,9 @@ data class ConversationsScreenState(
|
|||||||
val isLoading: Boolean,
|
val isLoading: Boolean,
|
||||||
val isPaginating: Boolean,
|
val isPaginating: Boolean,
|
||||||
val isPaginationExhausted: Boolean,
|
val isPaginationExhausted: Boolean,
|
||||||
val profileImageUrl: String?
|
val profileImageUrl: String?,
|
||||||
|
val scrollIndex: Int,
|
||||||
|
val scrollOffset: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -19,7 +21,9 @@ data class ConversationsScreenState(
|
|||||||
isLoading = true,
|
isLoading = true,
|
||||||
isPaginating = false,
|
isPaginating = false,
|
||||||
isPaginationExhausted = false,
|
isPaginationExhausted = false,
|
||||||
profileImageUrl = null
|
profileImageUrl = null,
|
||||||
|
scrollIndex = 0,
|
||||||
|
scrollOffset = 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -45,8 +45,6 @@ fun ConversationsList(
|
|||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val conversations = screenState.conversations
|
|
||||||
|
|
||||||
val bottomPadding = LocalBottomPadding.current
|
val bottomPadding = LocalBottomPadding.current
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@@ -55,9 +53,10 @@ fun ConversationsList(
|
|||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(padding.calculateTopPadding()))
|
Spacer(modifier = Modifier.height(padding.calculateTopPadding()))
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
items = conversations,
|
items = screenState.conversations,
|
||||||
key = UiConversation::id,
|
key = UiConversation::id,
|
||||||
) { conversation ->
|
) { conversation ->
|
||||||
val isUserAccount by remember(conversation) {
|
val isUserAccount by remember(conversation) {
|
||||||
|
|||||||
+12
-22
@@ -1,6 +1,5 @@
|
|||||||
package dev.meloda.fast.conversations.presentation
|
package dev.meloda.fast.conversations.presentation
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.Animatable
|
import androidx.compose.animation.core.Animatable
|
||||||
@@ -29,6 +28,7 @@ import androidx.compose.material3.DropdownMenu
|
|||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
@@ -63,7 +63,6 @@ import androidx.compose.ui.unit.DpOffset
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.view.HapticFeedbackConstantsCompat
|
import androidx.core.view.HapticFeedbackConstantsCompat
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
@@ -88,7 +87,6 @@ import dev.meloda.fast.ui.util.isScrollingUp
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.compose.koinInject
|
|
||||||
import dev.meloda.fast.ui.R as UiR
|
import dev.meloda.fast.ui.R as UiR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -100,8 +98,6 @@ fun ConversationsRoute(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val prefs: SharedPreferences = koinInject()
|
|
||||||
|
|
||||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||||
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
|
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
|
||||||
val canPaginate by viewModel.canPaginate.collectAsStateWithLifecycle()
|
val canPaginate by viewModel.canPaginate.collectAsStateWithLifecycle()
|
||||||
@@ -121,8 +117,6 @@ fun ConversationsRoute(
|
|||||||
screenState = screenState,
|
screenState = screenState,
|
||||||
baseError = baseError,
|
baseError = baseError,
|
||||||
canPaginate = canPaginate,
|
canPaginate = canPaginate,
|
||||||
firstVisibleItemIndex = prefs.getInt("conversations_all_scroll_position", 0),
|
|
||||||
firstVisibleItemScrollOffset = prefs.getInt("conversations_all_scroll_offset", 0),
|
|
||||||
onSessionExpiredLogOutButtonClicked = { onError(BaseError.SessionExpired) },
|
onSessionExpiredLogOutButtonClicked = { onError(BaseError.SessionExpired) },
|
||||||
onConversationItemClicked = { id ->
|
onConversationItemClicked = { id ->
|
||||||
onConversationItemClicked(id)
|
onConversationItemClicked(id)
|
||||||
@@ -134,15 +128,10 @@ fun ConversationsRoute(
|
|||||||
onRefreshDropdownItemClicked = viewModel::onRefresh,
|
onRefreshDropdownItemClicked = viewModel::onRefresh,
|
||||||
onRefresh = viewModel::onRefresh,
|
onRefresh = viewModel::onRefresh,
|
||||||
onConversationPhotoClicked = onConversationPhotoClicked,
|
onConversationPhotoClicked = onConversationPhotoClicked,
|
||||||
onSaveScrollPosition = { index ->
|
setScrollIndex = viewModel::setScrollIndex,
|
||||||
prefs.edit { putInt("conversations_all_scroll_position", index) }
|
setScrollOffset = viewModel::setScrollOffset
|
||||||
},
|
|
||||||
onSaveScrollOffsetPosition = { offset ->
|
|
||||||
prefs.edit { putInt("conversations_all_scroll_offset", offset) }
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
HandleDialogs(
|
HandleDialogs(
|
||||||
screenState = screenState,
|
screenState = screenState,
|
||||||
viewModel = viewModel
|
viewModel = viewModel
|
||||||
@@ -158,8 +147,6 @@ fun ConversationsScreen(
|
|||||||
screenState: ConversationsScreenState = ConversationsScreenState.EMPTY,
|
screenState: ConversationsScreenState = ConversationsScreenState.EMPTY,
|
||||||
baseError: BaseError? = null,
|
baseError: BaseError? = null,
|
||||||
canPaginate: Boolean = false,
|
canPaginate: Boolean = false,
|
||||||
firstVisibleItemIndex: Int = 0,
|
|
||||||
firstVisibleItemScrollOffset: Int = 0,
|
|
||||||
onSessionExpiredLogOutButtonClicked: () -> Unit,
|
onSessionExpiredLogOutButtonClicked: () -> Unit,
|
||||||
onConversationItemClicked: (conversationId: Int) -> Unit = {},
|
onConversationItemClicked: (conversationId: Int) -> Unit = {},
|
||||||
onConversationItemLongClicked: (conversation: UiConversation) -> Unit = {},
|
onConversationItemLongClicked: (conversation: UiConversation) -> Unit = {},
|
||||||
@@ -168,8 +155,8 @@ fun ConversationsScreen(
|
|||||||
onRefreshDropdownItemClicked: () -> Unit = {},
|
onRefreshDropdownItemClicked: () -> Unit = {},
|
||||||
onRefresh: () -> Unit = {},
|
onRefresh: () -> Unit = {},
|
||||||
onConversationPhotoClicked: (url: String) -> Unit = {},
|
onConversationPhotoClicked: (url: String) -> Unit = {},
|
||||||
onSaveScrollPosition: (Int) -> Unit = {},
|
setScrollIndex: (Int) -> Unit = {},
|
||||||
onSaveScrollOffsetPosition: (Int) -> Unit = {}
|
setScrollOffset: (Int) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
val currentTheme = LocalThemeConfig.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
@@ -179,20 +166,20 @@ fun ConversationsScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val listState = rememberLazyListState(
|
val listState = rememberLazyListState(
|
||||||
initialFirstVisibleItemIndex = firstVisibleItemIndex,
|
initialFirstVisibleItemIndex = screenState.scrollIndex,
|
||||||
initialFirstVisibleItemScrollOffset = firstVisibleItemScrollOffset
|
initialFirstVisibleItemScrollOffset = screenState.scrollOffset
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(listState) {
|
LaunchedEffect(listState) {
|
||||||
snapshotFlow { listState.firstVisibleItemIndex }
|
snapshotFlow { listState.firstVisibleItemIndex }
|
||||||
.debounce(500L)
|
.debounce(500L)
|
||||||
.collectLatest(onSaveScrollPosition)
|
.collectLatest(setScrollIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(listState) {
|
LaunchedEffect(listState) {
|
||||||
snapshotFlow { listState.firstVisibleItemScrollOffset }
|
snapshotFlow { listState.firstVisibleItemScrollOffset }
|
||||||
.debounce(500L)
|
.debounce(500L)
|
||||||
.collectLatest(onSaveScrollOffsetPosition)
|
.collectLatest(setScrollOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
val paginationConditionMet by remember(canPaginate, listState) {
|
val paginationConditionMet by remember(canPaginate, listState) {
|
||||||
@@ -306,6 +293,9 @@ fun ConversationsScreen(
|
|||||||
AnimatedVisibility(showHorizontalProgressBar) {
|
AnimatedVisibility(showHorizontalProgressBar) {
|
||||||
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
||||||
}
|
}
|
||||||
|
AnimatedVisibility(!showHorizontalProgressBar) {
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ interface FriendsViewModel {
|
|||||||
fun onRefresh()
|
fun onRefresh()
|
||||||
|
|
||||||
fun onErrorConsumed()
|
fun onErrorConsumed()
|
||||||
|
|
||||||
|
fun setScrollIndex(index: Int)
|
||||||
|
fun setScrollOffset(offset: Int)
|
||||||
|
fun setScrollIndexOnline(index: Int)
|
||||||
|
fun setScrollOffsetOnline(offset: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
class FriendsViewModelImpl(
|
class FriendsViewModelImpl(
|
||||||
@@ -66,6 +71,22 @@ class FriendsViewModelImpl(
|
|||||||
baseError.setValue { null }
|
baseError.setValue { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setScrollIndex(index: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollIndex = index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setScrollOffset(offset: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollOffset = offset) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setScrollIndexOnline(index: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollIndexOnline = index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setScrollOffsetOnline(offset: Int) {
|
||||||
|
screenState.setValue { old -> old.copy(scrollOffsetOnline = offset) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadFriends(offset: Int = currentOffset.value) {
|
private fun loadFriends(offset: Int = currentOffset.value) {
|
||||||
friendsUseCase.getFriends(count = LOAD_COUNT, offset = offset)
|
friendsUseCase.getFriends(count = LOAD_COUNT, offset = offset)
|
||||||
.listenValue(viewModelScope) { state ->
|
.listenValue(viewModelScope) { state ->
|
||||||
|
|||||||
+10
-2
@@ -8,7 +8,11 @@ data class FriendsScreenState(
|
|||||||
val friends: List<UiFriend>,
|
val friends: List<UiFriend>,
|
||||||
val onlineFriends: List<UiFriend>,
|
val onlineFriends: List<UiFriend>,
|
||||||
val isPaginating: Boolean,
|
val isPaginating: Boolean,
|
||||||
val isPaginationExhausted: Boolean
|
val isPaginationExhausted: Boolean,
|
||||||
|
val scrollIndex: Int,
|
||||||
|
val scrollOffset: Int,
|
||||||
|
val scrollIndexOnline: Int,
|
||||||
|
val scrollOffsetOnline: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -17,7 +21,11 @@ data class FriendsScreenState(
|
|||||||
friends = emptyList(),
|
friends = emptyList(),
|
||||||
onlineFriends = emptyList(),
|
onlineFriends = emptyList(),
|
||||||
isPaginating = false,
|
isPaginating = false,
|
||||||
isPaginationExhausted = false
|
isPaginationExhausted = false,
|
||||||
|
scrollIndex = 0,
|
||||||
|
scrollOffset = 0,
|
||||||
|
scrollIndexOnline = 0,
|
||||||
|
scrollOffsetOnline = 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.IconButtonDefaults
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -35,8 +37,14 @@ fun FriendsList(
|
|||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
maxLines: Int,
|
maxLines: Int,
|
||||||
padding: PaddingValues,
|
padding: PaddingValues,
|
||||||
onPhotoClicked: (url: String) -> Unit
|
onPhotoClicked: (url: String) -> Unit,
|
||||||
|
setCanScrollBackward: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(listState) {
|
||||||
|
snapshotFlow { listState.canScrollBackward }
|
||||||
|
.collect(setCanScrollBackward)
|
||||||
|
}
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val friends = uiFriends.toList()
|
val friends = uiFriends.toList()
|
||||||
@@ -56,7 +64,6 @@ fun FriendsList(
|
|||||||
items = friends,
|
items = friends,
|
||||||
key = UiFriend::userId,
|
key = UiFriend::userId,
|
||||||
) { friend ->
|
) { friend ->
|
||||||
|
|
||||||
FriendItem(
|
FriendItem(
|
||||||
friend = friend,
|
friend = friend,
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
|
|||||||
+40
-28
@@ -1,6 +1,5 @@
|
|||||||
package dev.meloda.fast.friends.presentation
|
package dev.meloda.fast.friends.presentation
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.FastOutLinearInEasing
|
import androidx.compose.animation.core.FastOutLinearInEasing
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
@@ -35,6 +34,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -47,7 +47,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
@@ -69,7 +68,6 @@ import dev.meloda.fast.ui.util.ImmutableList
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
import org.koin.compose.koinInject
|
|
||||||
import dev.meloda.fast.ui.R as UiR
|
import dev.meloda.fast.ui.R as UiR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -80,8 +78,6 @@ fun FriendsRoute(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val prefs: SharedPreferences = koinInject()
|
|
||||||
|
|
||||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||||
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
|
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
|
||||||
val canPaginate by viewModel.canPaginate.collectAsStateWithLifecycle()
|
val canPaginate by viewModel.canPaginate.collectAsStateWithLifecycle()
|
||||||
@@ -101,23 +97,17 @@ fun FriendsRoute(
|
|||||||
screenState = screenState,
|
screenState = screenState,
|
||||||
baseError = baseError,
|
baseError = baseError,
|
||||||
canPaginate = canPaginate,
|
canPaginate = canPaginate,
|
||||||
firstVisibleItemIndex = prefs.getInt("friends_all_scroll_position", 0),
|
|
||||||
firstVisibleItemScrollOffset = prefs.getInt("friends_all_scroll_offset", 0),
|
|
||||||
onSessionExpiredLogOutButtonClicked = { onError(BaseError.SessionExpired) },
|
onSessionExpiredLogOutButtonClicked = { onError(BaseError.SessionExpired) },
|
||||||
onPaginationConditionsMet = viewModel::onPaginationConditionsMet,
|
onPaginationConditionsMet = viewModel::onPaginationConditionsMet,
|
||||||
onRefresh = viewModel::onRefresh,
|
onRefresh = viewModel::onRefresh,
|
||||||
onPhotoClicked = onPhotoClicked,
|
onPhotoClicked = onPhotoClicked,
|
||||||
onSaveScrollPosition = { index ->
|
setScrollIndex = viewModel::setScrollIndex,
|
||||||
prefs.edit { putInt("friends_all_scroll_position", index) }
|
setScrollOffset = viewModel::setScrollOffset,
|
||||||
},
|
setScrollIndexOnline = viewModel::setScrollIndexOnline,
|
||||||
onSaveScrollOffsetPosition = { offset ->
|
setScrollOffsetOnline = viewModel::setScrollOffsetOnline,
|
||||||
prefs.edit { putInt("friends_all_scroll_offset", offset) }
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: 13/07/2024, Danil Nikolaev: support for online
|
|
||||||
@OptIn(
|
@OptIn(
|
||||||
ExperimentalMaterial3Api::class,
|
ExperimentalMaterial3Api::class,
|
||||||
ExperimentalHazeMaterialsApi::class
|
ExperimentalHazeMaterialsApi::class
|
||||||
@@ -127,14 +117,14 @@ fun FriendsScreen(
|
|||||||
screenState: FriendsScreenState = FriendsScreenState.EMPTY,
|
screenState: FriendsScreenState = FriendsScreenState.EMPTY,
|
||||||
baseError: BaseError? = null,
|
baseError: BaseError? = null,
|
||||||
canPaginate: Boolean = false,
|
canPaginate: Boolean = false,
|
||||||
firstVisibleItemIndex: Int = 0,
|
|
||||||
firstVisibleItemScrollOffset: Int = 0,
|
|
||||||
onSessionExpiredLogOutButtonClicked: () -> Unit = {},
|
onSessionExpiredLogOutButtonClicked: () -> Unit = {},
|
||||||
onPaginationConditionsMet: () -> Unit = {},
|
onPaginationConditionsMet: () -> Unit = {},
|
||||||
onRefresh: () -> Unit = {},
|
onRefresh: () -> Unit = {},
|
||||||
onPhotoClicked: (url: String) -> Unit = {},
|
onPhotoClicked: (url: String) -> Unit = {},
|
||||||
onSaveScrollPosition: (Int) -> Unit = {},
|
setScrollIndex: (Int) -> Unit,
|
||||||
onSaveScrollOffsetPosition: (Int) -> Unit = {}
|
setScrollOffset: (Int) -> Unit,
|
||||||
|
setScrollIndexOnline: (Int) -> Unit,
|
||||||
|
setScrollOffsetOnline: (Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalThemeConfig.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
@@ -145,20 +135,36 @@ fun FriendsScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val listState = rememberLazyListState(
|
val listState = rememberLazyListState(
|
||||||
initialFirstVisibleItemIndex = firstVisibleItemIndex,
|
initialFirstVisibleItemIndex = screenState.scrollIndex,
|
||||||
initialFirstVisibleItemScrollOffset = firstVisibleItemScrollOffset
|
initialFirstVisibleItemScrollOffset = screenState.scrollOffset
|
||||||
|
)
|
||||||
|
val listStateOnline = rememberLazyListState(
|
||||||
|
initialFirstVisibleItemIndex = screenState.scrollIndexOnline,
|
||||||
|
initialFirstVisibleItemScrollOffset = screenState.scrollOffsetOnline
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(listState) {
|
LaunchedEffect(listState) {
|
||||||
snapshotFlow { listState.firstVisibleItemIndex }
|
snapshotFlow { listState.firstVisibleItemIndex }
|
||||||
.debounce(500L)
|
.debounce(500L)
|
||||||
.collectLatest(onSaveScrollPosition)
|
.collectLatest(setScrollIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(listState) {
|
LaunchedEffect(listState) {
|
||||||
snapshotFlow { listState.firstVisibleItemScrollOffset }
|
snapshotFlow { listState.firstVisibleItemScrollOffset }
|
||||||
.debounce(500L)
|
.debounce(500L)
|
||||||
.collectLatest(onSaveScrollOffsetPosition)
|
.collectLatest(setScrollOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(listStateOnline) {
|
||||||
|
snapshotFlow { listStateOnline.firstVisibleItemIndex }
|
||||||
|
.debounce(500L)
|
||||||
|
.collectLatest(setScrollIndexOnline)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(listStateOnline) {
|
||||||
|
snapshotFlow { listStateOnline.firstVisibleItemScrollOffset }
|
||||||
|
.debounce(500L)
|
||||||
|
.collectLatest(setScrollOffsetOnline)
|
||||||
}
|
}
|
||||||
|
|
||||||
val paginationConditionMet by remember(canPaginate, listState) {
|
val paginationConditionMet by remember(canPaginate, listState) {
|
||||||
@@ -177,8 +183,12 @@ fun FriendsScreen(
|
|||||||
|
|
||||||
val hazeState = LocalHazeState.current
|
val hazeState = LocalHazeState.current
|
||||||
|
|
||||||
|
var canScrollBackward by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
val topBarContainerColorAlpha by animateFloatAsState(
|
val topBarContainerColorAlpha by animateFloatAsState(
|
||||||
targetValue = if (!currentTheme.enableBlur || !listState.canScrollBackward) 1f else 0f,
|
targetValue = if (!currentTheme.enableBlur || !canScrollBackward) 1f else 0f,
|
||||||
label = "toolbarColorAlpha",
|
label = "toolbarColorAlpha",
|
||||||
animationSpec = tween(
|
animationSpec = tween(
|
||||||
durationMillis = 200,
|
durationMillis = 200,
|
||||||
@@ -187,8 +197,7 @@ fun FriendsScreen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val topBarContainerColor by animateColorAsState(
|
val topBarContainerColor by animateColorAsState(
|
||||||
targetValue =
|
targetValue = if (currentTheme.enableBlur || !canScrollBackward)
|
||||||
if (currentTheme.enableBlur || !listState.canScrollBackward)
|
|
||||||
MaterialTheme.colorScheme.surface
|
MaterialTheme.colorScheme.surface
|
||||||
else
|
else
|
||||||
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
||||||
@@ -341,10 +350,13 @@ fun FriendsScreen(
|
|||||||
}.fillMaxSize(),
|
}.fillMaxSize(),
|
||||||
screenState = screenState,
|
screenState = screenState,
|
||||||
uiFriends = ImmutableList.copyOf(friendsToDisplay),
|
uiFriends = ImmutableList.copyOf(friendsToDisplay),
|
||||||
listState = listState,
|
listState = if (index == 0) listState else listStateOnline,
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
padding = padding,
|
padding = padding,
|
||||||
onPhotoClicked = onPhotoClicked
|
onPhotoClicked = onPhotoClicked,
|
||||||
|
setCanScrollBackward = { can ->
|
||||||
|
canScrollBackward = can
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (friendsToDisplay.isEmpty()) {
|
if (friendsToDisplay.isEmpty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user