ability to use more animations (experimental);

fix online friends loading;
conversation avatar in messages history screen;
test second tap on conversations item in bottom bar to scroll to top;
etc
This commit is contained in:
2024-12-17 20:51:02 +03:00
parent 85cda2065e
commit 6a69f28256
21 changed files with 299 additions and 85 deletions
@@ -1,10 +1,8 @@
package dev.meloda.fast.messageshistory
import android.content.SharedPreferences
import android.util.Log
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.core.content.edit
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -19,9 +17,9 @@ import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkMemoryCache
import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.datastore.SettingsKeys
import dev.meloda.fast.datastore.UserSettings
import dev.meloda.fast.domain.ConversationsUseCase
import dev.meloda.fast.domain.LoadConversationsByIdUseCase
import dev.meloda.fast.domain.LongPollUpdatesParser
import dev.meloda.fast.domain.MessagesUseCase
import dev.meloda.fast.messageshistory.model.ActionMode
@@ -60,15 +58,14 @@ interface MessagesHistoryViewModel {
fun onActionButtonClicked()
fun onPaginationConditionsMet()
fun onToggleAnimationsDropdownItemClicked(enableAnimations: Boolean)
}
class MessagesHistoryViewModelImpl(
private val messagesUseCase: MessagesUseCase,
private val conversationsUseCase: ConversationsUseCase,
private val preferences: SharedPreferences,
private val resourceProvider: ResourceProvider,
private val userSettings: UserSettings,
private val loadConversationsByIdUseCase: LoadConversationsByIdUseCase,
updatesParser: LongPollUpdatesParser,
savedStateHandle: SavedStateHandle
) : MessagesHistoryViewModel, ViewModel() {
@@ -159,15 +156,6 @@ class MessagesHistoryViewModelImpl(
loadMessagesHistory()
}
override fun onToggleAnimationsDropdownItemClicked(enableAnimations: Boolean) {
preferences.edit {
putBoolean(
SettingsKeys.KEY_ENABLE_ANIMATIONS_IN_MESSAGES,
enableAnimations
)
}
}
private fun handleNewMessage(event: LongPollEvent.VkMessageNewEvent) {
val message = event.message
@@ -18,6 +18,7 @@ data class MessagesHistoryScreenState(
val isPaginating: Boolean,
val isPaginationExhausted: Boolean,
val actionMode: ActionMode,
val chatImageUrl: String?
) {
companion object {
@@ -33,6 +34,7 @@ data class MessagesHistoryScreenState(
isPaginating = false,
isPaginationExhausted = false,
actionMode = ActionMode.Record,
chatImageUrl = null
)
}
}
@@ -1,10 +1,12 @@
package dev.meloda.fast.messageshistory.presentation
import android.content.SharedPreferences
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -23,9 +25,11 @@ import androidx.compose.foundation.layout.imeNestedScroll
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
@@ -59,6 +63,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
@@ -71,12 +76,12 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.core.view.HapticFeedbackConstantsCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.hazeChild
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import dev.chrisbanes.haze.materials.HazeMaterials
import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.datastore.SettingsKeys
import dev.meloda.fast.datastore.UserSettings
import dev.meloda.fast.messageshistory.MessagesHistoryViewModel
import dev.meloda.fast.messageshistory.MessagesHistoryViewModelImpl
@@ -88,6 +93,7 @@ import dev.meloda.fast.model.BaseError
import dev.meloda.fast.ui.components.IconButton
import dev.meloda.fast.ui.theme.LocalThemeConfig
import dev.meloda.fast.ui.util.ImmutableList
import dev.meloda.fast.ui.util.getImage
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel
import org.koin.compose.koinInject
@@ -115,7 +121,6 @@ fun MessagesHistoryRoute(
onBack = onBack,
onChatMaterialsDropdownItemClicked = onChatMaterialsDropdownItemClicked,
onRefreshDropdownItemClicked = viewModel::onRefresh,
onToggleAnimationsDropdownItemClicked = viewModel::onToggleAnimationsDropdownItemClicked,
onPaginationConditionsMet = viewModel::onPaginationConditionsMet,
onMessageInputChanged = viewModel::onMessageInputChanged,
onAttachmentButtonClicked = viewModel::onAttachmentButtonClicked,
@@ -174,15 +179,6 @@ fun MessagesHistoryScreen(
val hazeState = remember { HazeState() }
var animationsEnabled by remember {
mutableStateOf(
preferences.getBoolean(
SettingsKeys.KEY_ENABLE_ANIMATIONS_IN_MESSAGES,
false
)
)
}
val toolbarColorAlpha by animateFloatAsState(
targetValue = if (!listState.canScrollForward) 1f else 0f,
label = "toolbarColorAlpha",
@@ -212,14 +208,42 @@ fun MessagesHistoryScreen(
)
.fillMaxWidth(),
title = {
Text(
text =
if (screenState.isLoading) stringResource(id = UiR.string.title_loading)
else screenState.title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.headlineSmall
)
Row(
modifier = Modifier
.weight(1f),
verticalAlignment = Alignment.CenterVertically
) {
val avatar = screenState.avatar.getImage()
if (avatar is Painter) {
Image(
painter = avatar,
contentDescription = null,
modifier = Modifier
.size(36.dp)
.clip(CircleShape)
)
} else {
AsyncImage(
model = screenState.avatar.getImage(),
contentDescription = "Profile Image",
modifier = Modifier
.size(36.dp)
.clip(CircleShape),
placeholder = painterResource(id = UiR.drawable.ic_account_circle_cut),
)
}
Spacer(modifier = Modifier.width(12.dp))
Text(
text =
if (screenState.isLoading) stringResource(id = UiR.string.title_loading)
else screenState.title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.headlineSmall
)
}
},
navigationIcon = {
IconButton(onClick = onBack) {
@@ -282,31 +306,19 @@ fun MessagesHistoryScreen(
)
}
)
if (preferences.getBoolean(
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
false
)
) {
HorizontalDivider()
DropdownMenuItem(
text = {
Text(text = if (animationsEnabled) "Disable animations" else "Enable animations")
},
onClick = {
dropDownMenuExpanded = false
animationsEnabled = !animationsEnabled
onToggleAnimationsDropdownItemClicked(animationsEnabled)
}
)
}
}
}
)
if (screenState.isLoading && screenState.messages.isNotEmpty()) {
val showHorizontalProgressBar by remember(screenState) {
derivedStateOf { screenState.isLoading && screenState.messages.isNotEmpty() }
}
if (showHorizontalProgressBar) {
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
}
AnimatedVisibility(!showHorizontalProgressBar) {
HorizontalDivider()
}
}
}
) { padding ->
@@ -322,7 +334,6 @@ fun MessagesHistoryScreen(
listState = listState,
immutableMessages = ImmutableList.copyOf(screenState.messages),
isPaginating = screenState.isPaginating,
enableAnimations = animationsEnabled,
messageBarHeight = messageBarHeight,
onRequestScrollToCmId = { cmId ->
coroutineScope.launch {
@@ -13,12 +13,14 @@ import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.haze
import dev.meloda.fast.datastore.AppSettings
import dev.meloda.fast.messageshistory.model.UiItem
import dev.meloda.fast.ui.theme.LocalThemeConfig
import dev.meloda.fast.ui.util.ImmutableList
@@ -30,11 +32,15 @@ fun MessagesList(
listState: LazyListState,
immutableMessages: ImmutableList<UiItem>,
isPaginating: Boolean,
enableAnimations: Boolean,
messageBarHeight: Dp,
onRequestScrollToCmId: (cmId: Int) -> Unit = {}
) {
val messages = immutableMessages.toList()
val enableAnimations = remember {
AppSettings.Experimental.moreAnimations
}
val messages = remember(immutableMessages) {
immutableMessages.toList()
}
val currentTheme = LocalThemeConfig.current
LazyColumn(