Animate user status state change

This commit is contained in:
Benoit Marty
2026-09-21 09:50:03 +02:00
parent ae36cc3b1e
commit cc3b788b3e
@@ -7,12 +7,12 @@
package io.element.android.features.preferences.impl.userstatus package io.element.android.features.preferences.impl.userstatus
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
@@ -72,47 +72,65 @@ fun UserStatusView(
emojiPickerRenderer: EmojiPickerRenderer, emojiPickerRenderer: EmojiPickerRenderer,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
when (val pickerState = state.pickerState) { AnimatedContent(
UserStatusPickerState.Hidden, UserStatusPickerState.ShowingPicker -> { targetState = state,
val displayedStatus = state.displayedStatus contentKey = {
if (displayedStatus != null) { when (it.pickerState) {
CurrentStatusRow( UserStatusPickerState.Hidden,
displayedStatus = displayedStatus, UserStatusPickerState.ShowingPicker -> if (state.displayedStatus != null) 0 else 1
onClick = { state.eventSink(UserStatusEvent.OpenPicker) }, is UserStatusPickerState.CustomInput -> 2
onClear = { state.eventSink(UserStatusEvent.ClearStatus) },
modifier = modifier,
)
} else {
EmptyStatusRow(
onClick = { state.eventSink(UserStatusEvent.OpenPicker) },
modifier = modifier,
)
} }
if (pickerState == UserStatusPickerState.ShowingPicker) { },
UserStatusPickerBottomSheet( ) { userStatusState ->
currentRawStatus = state.rawStatus, when (val pickerState = userStatusState.pickerState) {
onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) }, UserStatusPickerState.Hidden,
onSelectPredefinedStatus = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) }, UserStatusPickerState.ShowingPicker -> {
onSelectCustomStatus = { state.eventSink(UserStatusEvent.OpenCustomInput) }, val displayedStatus = state.displayedStatus
if (displayedStatus != null) {
CurrentStatusRow(
displayedStatus = displayedStatus,
onClick = { state.eventSink(UserStatusEvent.OpenPicker) },
onClear = { state.eventSink(UserStatusEvent.ClearStatus) },
modifier = modifier,
)
} else {
EmptyStatusRow(
onClick = { state.eventSink(UserStatusEvent.OpenPicker) },
modifier = modifier,
)
}
}
is UserStatusPickerState.CustomInput -> {
CustomStatusInputRow(
emoji = pickerState.emoji,
textFieldState = pickerState.textFieldState,
rawStatus = state.rawStatus,
onConfirm = {
state.eventSink(
UserStatusEvent.SetStatus(UserStatus(pickerState.emoji, pickerState.textFieldState.text.toString()))
)
},
onCancel = { state.eventSink(UserStatusEvent.CancelCustomInput) },
onEmojiClick = { state.eventSink(UserStatusEvent.OpenEmojiPicker) },
modifier = modifier,
) )
} }
} }
is UserStatusPickerState.CustomInput -> { }
CustomStatusInputRow( when (val pickerState = state.pickerState) {
emoji = pickerState.emoji, UserStatusPickerState.Hidden -> Unit
textFieldState = pickerState.textFieldState, UserStatusPickerState.ShowingPicker -> {
rawStatus = state.rawStatus, UserStatusPickerBottomSheet(
onConfirm = { currentRawStatus = state.rawStatus,
state.eventSink( onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) },
UserStatusEvent.SetStatus(UserStatus(pickerState.emoji, pickerState.textFieldState.text.toString())) onSelectPredefinedStatus = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) },
) onSelectCustomStatus = { state.eventSink(UserStatusEvent.OpenCustomInput) },
},
onCancel = { state.eventSink(UserStatusEvent.CancelCustomInput) },
onEmojiClick = { state.eventSink(UserStatusEvent.OpenEmojiPicker) },
modifier = modifier,
) )
}
is UserStatusPickerState.CustomInput -> {
when (val sheet = pickerState.emojiPickerSheetState) { when (val sheet = pickerState.emojiPickerSheetState) {
EmojiPickerSheetState.Hidden, EmojiPickerSheetState.Loading -> Unit EmojiPickerSheetState.Hidden,
EmojiPickerSheetState.Loading -> Unit
is EmojiPickerSheetState.Shown -> EmojiPickerBottomSheet( is EmojiPickerSheetState.Shown -> EmojiPickerBottomSheet(
pickerState = sheet.state, pickerState = sheet.state,
emojiPickerRenderer = emojiPickerRenderer, emojiPickerRenderer = emojiPickerRenderer,
@@ -133,7 +151,6 @@ private fun EmptyStatusRow(
content = { content = {
Text( Text(
text = stringResource(R.string.screen_settings_user_status_placeholder), text = stringResource(R.string.screen_settings_user_status_placeholder),
modifier = Modifier.padding(vertical = 16.dp),
) )
}, },
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Reaction())), leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Reaction())),
@@ -153,7 +170,7 @@ private fun CurrentStatusRow(
is DisplayedStatus.InCall -> "🎧" to stringResource(CommonStrings.common_on_a_call) is DisplayedStatus.InCall -> "🎧" to stringResource(CommonStrings.common_on_a_call)
} }
ListItem( ListItem(
content = { Text(text = text, modifier = Modifier.padding(vertical = 16.dp)) }, content = { Text(text = text) },
leadingContent = ListItemContent.Custom { EmojiText(emoji) }, leadingContent = ListItemContent.Custom { EmojiText(emoji) },
trailingContent = ListItemContent.Custom({ trailingContent = ListItemContent.Custom({
IconButton( IconButton(