Rename Event

This commit is contained in:
ganfra
2026-06-17 11:05:53 +02:00
parent 2a0e41652a
commit 553a4785e1
5 changed files with 24 additions and 34 deletions
@@ -10,18 +10,11 @@ package io.element.android.features.preferences.impl.userstatus
import io.element.android.libraries.matrix.api.user.UserStatus
sealed interface UserStatusEvent {
/** User tapped the status row — open the picker bottom sheet. */
data object Open : UserStatusEvent
/** User dismissed the bottom sheet without selecting. */
data object Dismiss : UserStatusEvent
/** User selected a predefined or confirmed a custom status. */
data class Set(val status: UserStatus) : UserStatusEvent
/** User tapped "Custom…" in the bottom sheet. */
data object OpenPicker : UserStatusEvent
data object DismissPicker : UserStatusEvent
data class SetStatus(val status: UserStatus) : UserStatusEvent
data object OpenCustomInput : UserStatusEvent
/** User tapped Cancel in the inline custom input row. */
data object CancelCustomInput : UserStatusEvent
/** User changed the emoji in the custom input row. */
data class UpdateCustomEmoji(val emoji: String) : UserStatusEvent
/** User tapped the clear action on an existing status. */
data object Clear : UserStatusEvent
data object ClearStatus : UserStatusEvent
}
@@ -7,8 +7,8 @@
package io.element.android.features.preferences.impl.userstatus
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.clearText
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -18,11 +18,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.user.UserStatus
import kotlinx.coroutines.launch
@ContributesBinding(SessionScope::class)
@@ -34,13 +32,13 @@ class UserStatusPresenter(
override fun present(): UserStatusState {
val userProfile by matrixClient.userProfile.collectAsState()
var pickerState by remember { mutableStateOf<UserStatusPickerState>(UserStatusPickerState.Hidden) }
val customTextFieldState = remember { TextFieldState() }
val customTextFieldState = rememberTextFieldState()
val coroutineScope = rememberCoroutineScope()
fun handleEvent(event: UserStatusEvent) {
when (event) {
UserStatusEvent.Open -> pickerState = UserStatusPickerState.ShowingPicker
UserStatusEvent.Dismiss -> pickerState = UserStatusPickerState.Hidden
UserStatusEvent.OpenPicker -> pickerState = UserStatusPickerState.ShowingPicker
UserStatusEvent.DismissPicker -> pickerState = UserStatusPickerState.Hidden
UserStatusEvent.OpenCustomInput -> {
val raw = userProfile.rawStatus
if (raw != null) {
@@ -53,11 +51,11 @@ class UserStatusPresenter(
textFieldState = customTextFieldState,
)
}
is UserStatusEvent.Set -> {
is UserStatusEvent.SetStatus -> {
pickerState = UserStatusPickerState.Hidden
coroutineScope.launch { matrixClient.setUserStatus(event.status) }
}
UserStatusEvent.Clear -> {
UserStatusEvent.ClearStatus -> {
pickerState = UserStatusPickerState.Hidden
coroutineScope.launch { matrixClient.clearUserStatus() }
}
@@ -22,7 +22,7 @@ sealed interface UserStatusPickerState {
data object Hidden : UserStatusPickerState
data object ShowingPicker : UserStatusPickerState
data class CustomInput(
val emoji: String = "😀",
val emoji: String,
val textFieldState: TextFieldState,
) : UserStatusPickerState
}
@@ -65,20 +65,20 @@ fun UserStatusRow(
if (displayedStatus != null) {
CurrentStatusRow(
displayedStatus = displayedStatus,
onClick = { state.eventSink(UserStatusEvent.Open) },
onClear = { state.eventSink(UserStatusEvent.Clear) },
onClick = { state.eventSink(UserStatusEvent.OpenPicker) },
onClear = { state.eventSink(UserStatusEvent.ClearStatus) },
modifier = modifier,
)
} else {
EmptyStatusRow(
onClick = { state.eventSink(UserStatusEvent.Open) },
onClick = { state.eventSink(UserStatusEvent.OpenPicker) },
modifier = modifier,
)
}
if (pickerState == UserStatusPickerState.ShowingPicker) {
UserStatusPickerBottomSheet(
onDismiss = { state.eventSink(UserStatusEvent.Dismiss) },
onSelectPredefined = { status -> state.eventSink(UserStatusEvent.Set(status)) },
onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) },
onSelectPredefined = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) },
onSelectCustom = { state.eventSink(UserStatusEvent.OpenCustomInput) },
)
}
@@ -90,7 +90,7 @@ fun UserStatusRow(
onEmojiChange = { state.eventSink(UserStatusEvent.UpdateCustomEmoji(it)) },
onConfirm = {
state.eventSink(
UserStatusEvent.Set(UserStatus(pickerState.emoji, pickerState.textFieldState.text.toString()))
UserStatusEvent.SetStatus(UserStatus(pickerState.emoji, pickerState.textFieldState.text.toString()))
)
},
onCancel = { state.eventSink(UserStatusEvent.CancelCustomInput) },
@@ -16,7 +16,6 @@ import io.element.android.libraries.matrix.api.user.UserStatus
import io.element.android.libraries.matrix.test.FakeMatrixClient
import kotlinx.coroutines.test.runTest
import org.junit.Test
import androidx.compose.foundation.text.input.TextFieldState
class UserStatusPresenterTest {
@@ -40,7 +39,7 @@ class UserStatusPresenterTest {
createPresenter().present()
}.test {
val state = awaitItem()
state.eventSink(UserStatusEvent.Open)
state.eventSink(UserStatusEvent.OpenPicker)
assertThat(awaitItem().pickerState).isEqualTo(UserStatusPickerState.ShowingPicker)
}
}
@@ -51,9 +50,9 @@ class UserStatusPresenterTest {
createPresenter().present()
}.test {
val state = awaitItem()
state.eventSink(UserStatusEvent.Open)
state.eventSink(UserStatusEvent.OpenPicker)
awaitItem() // ShowingPicker
state.eventSink(UserStatusEvent.Dismiss)
state.eventSink(UserStatusEvent.DismissPicker)
assertThat(awaitItem().pickerState).isEqualTo(UserStatusPickerState.Hidden)
}
}
@@ -65,7 +64,7 @@ class UserStatusPresenterTest {
createPresenter(client).present()
}.test {
val status = UserStatus(emoji = "💬", text = "In a meeting")
awaitItem().eventSink(UserStatusEvent.Set(status))
awaitItem().eventSink(UserStatusEvent.SetStatus(status))
val newState = awaitItem()
assertThat(newState.pickerState).isEqualTo(UserStatusPickerState.Hidden)
assertThat(newState.displayedStatus).isEqualTo(DisplayedStatus.UserSet(status))
@@ -93,7 +92,7 @@ class UserStatusPresenterTest {
createPresenter(client).present()
}.test {
val status = UserStatus(emoji = "🌴", text = "Away")
awaitItem().eventSink(UserStatusEvent.Set(status))
awaitItem().eventSink(UserStatusEvent.SetStatus(status))
// Single emission: pickerState=Hidden and displayedStatus both set in one recomposition
awaitItem().eventSink(UserStatusEvent.OpenCustomInput)
val state = awaitItem()
@@ -133,9 +132,9 @@ class UserStatusPresenterTest {
createPresenter(client).present()
}.test {
val status = UserStatus(emoji = "", text = "Be right back")
awaitItem().eventSink(UserStatusEvent.Set(status))
awaitItem().eventSink(UserStatusEvent.SetStatus(status))
// Single emission: pickerState=Hidden and displayedStatus both set in one recomposition
awaitItem().eventSink(UserStatusEvent.Clear)
awaitItem().eventSink(UserStatusEvent.ClearStatus)
val clearedState = awaitItem()
assertThat(clearedState.pickerState).isEqualTo(UserStatusPickerState.Hidden)
assertThat(clearedState.displayedStatus).isNull()