From cc3b788b3e1e6272dda5311ec35d8e54f04cf816 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 21 Sep 2026 09:50:03 +0200 Subject: [PATCH] Animate user status state change --- .../impl/userstatus/UserStatusView.kt | 93 +++++++++++-------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/userstatus/UserStatusView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/userstatus/UserStatusView.kt index c25c159f33..aab06499a4 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/userstatus/UserStatusView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/userstatus/UserStatusView.kt @@ -7,12 +7,12 @@ package io.element.android.features.preferences.impl.userstatus +import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.shape.CircleShape @@ -72,47 +72,65 @@ fun UserStatusView( emojiPickerRenderer: EmojiPickerRenderer, modifier: Modifier = Modifier, ) { - when (val pickerState = state.pickerState) { - UserStatusPickerState.Hidden, UserStatusPickerState.ShowingPicker -> { - 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, - ) + AnimatedContent( + targetState = state, + contentKey = { + when (it.pickerState) { + UserStatusPickerState.Hidden, + UserStatusPickerState.ShowingPicker -> if (state.displayedStatus != null) 0 else 1 + is UserStatusPickerState.CustomInput -> 2 } - if (pickerState == UserStatusPickerState.ShowingPicker) { - UserStatusPickerBottomSheet( - currentRawStatus = state.rawStatus, - onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) }, - onSelectPredefinedStatus = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) }, - onSelectCustomStatus = { state.eventSink(UserStatusEvent.OpenCustomInput) }, + }, + ) { userStatusState -> + when (val pickerState = userStatusState.pickerState) { + UserStatusPickerState.Hidden, + UserStatusPickerState.ShowingPicker -> { + 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( - 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, + } + when (val pickerState = state.pickerState) { + UserStatusPickerState.Hidden -> Unit + UserStatusPickerState.ShowingPicker -> { + UserStatusPickerBottomSheet( + currentRawStatus = state.rawStatus, + onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) }, + onSelectPredefinedStatus = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) }, + onSelectCustomStatus = { state.eventSink(UserStatusEvent.OpenCustomInput) }, ) + } + is UserStatusPickerState.CustomInput -> { when (val sheet = pickerState.emojiPickerSheetState) { - EmojiPickerSheetState.Hidden, EmojiPickerSheetState.Loading -> Unit + EmojiPickerSheetState.Hidden, + EmojiPickerSheetState.Loading -> Unit is EmojiPickerSheetState.Shown -> EmojiPickerBottomSheet( pickerState = sheet.state, emojiPickerRenderer = emojiPickerRenderer, @@ -133,7 +151,6 @@ private fun EmptyStatusRow( content = { Text( text = stringResource(R.string.screen_settings_user_status_placeholder), - modifier = Modifier.padding(vertical = 16.dp), ) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Reaction())), @@ -153,7 +170,7 @@ private fun CurrentStatusRow( is DisplayedStatus.InCall -> "🎧" to stringResource(CommonStrings.common_on_a_call) } ListItem( - content = { Text(text = text, modifier = Modifier.padding(vertical = 16.dp)) }, + content = { Text(text = text) }, leadingContent = ListItemContent.Custom { EmojiText(emoji) }, trailingContent = ListItemContent.Custom({ IconButton(