Address quality issues on user status

This commit is contained in:
ganfra
2026-06-19 15:14:37 +02:00
parent 4a143c1053
commit 29b8068d4a
7 changed files with 40 additions and 17 deletions
@@ -24,8 +24,8 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.preferences.impl.R
import io.element.android.features.preferences.impl.user.UserPreferences
import io.element.android.features.preferences.impl.userstatus.UserStatusRow
import io.element.android.features.preferences.impl.userstatus.UserStatusState
import io.element.android.features.preferences.impl.userstatus.UserStatusView
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.list.ListItemContent
@@ -143,7 +143,7 @@ private fun ColumnScope.UserStatusSection(
color = ElementTheme.colors.bgSubtleSecondary,
)
}
UserStatusRow(
UserStatusView(
state = userStatusState,
modifier = Modifier.fillMaxWidth(),
)
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.preferences.impl.userstatus
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.SessionScope
@ContributesTo(SessionScope::class)
@BindingContainer
interface UserStatusBindingContainer {
@Binds
fun bindUserStatusPresenter(presenter: UserStatusPresenter): Presenter<UserStatusState>
}
@@ -17,13 +17,12 @@ import androidx.compose.runtime.mutableStateOf
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 kotlinx.coroutines.launch
@ContributesBinding(SessionScope::class)
@Inject
class UserStatusPresenter(
private val matrixClient: MatrixClient,
) : Presenter<UserStatusState> {
@@ -9,6 +9,7 @@ package io.element.android.features.preferences.impl.userstatus
import androidx.annotation.StringRes
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.Immutable
import io.element.android.features.preferences.impl.R
import io.element.android.libraries.matrix.api.user.DisplayedStatus
import io.element.android.libraries.matrix.api.user.UserStatus
@@ -20,6 +21,7 @@ data class UserStatusState(
val eventSink: (UserStatusEvent) -> Unit,
)
@Immutable
sealed interface UserStatusPickerState {
data object Hidden : UserStatusPickerState
data object ShowingPicker : UserStatusPickerState
@@ -29,7 +31,7 @@ sealed interface UserStatusPickerState {
) : UserStatusPickerState
}
enum class PredefinedUserStatus(val emoji: String, @param:StringRes val labelRes: Int) {
enum class PredefinedUserStatus(val emoji: String, @StringRes val labelRes: Int) {
IN_A_MEETING("💬", R.string.common_user_status_in_a_meeting),
FOCUS_TIME("💡", R.string.common_user_status_focus_time),
ON_THE_ROAD("🚙", R.string.common_user_status_on_the_road),
@@ -61,7 +61,7 @@ import io.element.android.libraries.matrix.api.user.UserStatus
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun UserStatusRow(
fun UserStatusView(
state: UserStatusState,
modifier: Modifier = Modifier,
) {
@@ -85,8 +85,8 @@ fun UserStatusRow(
UserStatusPickerBottomSheet(
currentRawStatus = state.rawStatus,
onDismiss = { state.eventSink(UserStatusEvent.DismissPicker) },
onSelectPredefined = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) },
onSelectCustom = { state.eventSink(UserStatusEvent.OpenCustomInput) },
onSelectPredefinedStatus = { status -> state.eventSink(UserStatusEvent.SetStatus(status)) },
onSelectCustomStatus = { state.eventSink(UserStatusEvent.OpenCustomInput) },
)
}
}
@@ -95,7 +95,6 @@ fun UserStatusRow(
emoji = pickerState.emoji,
textFieldState = pickerState.textFieldState,
rawStatus = state.rawStatus,
onEmojiChange = { state.eventSink(UserStatusEvent.UpdateCustomEmoji(it)) },
onConfirm = {
state.eventSink(
UserStatusEvent.SetStatus(UserStatus(pickerState.emoji, pickerState.textFieldState.text.toString()))
@@ -159,8 +158,8 @@ private fun CurrentStatusRow(
private fun UserStatusPickerBottomSheet(
currentRawStatus: UserStatus?,
onDismiss: () -> Unit,
onSelectPredefined: (UserStatus) -> Unit,
onSelectCustom: () -> Unit,
onSelectPredefinedStatus: (UserStatus) -> Unit,
onSelectCustomStatus: () -> Unit,
modifier: Modifier = Modifier,
) {
val sheetState = rememberModalBottomSheetState()
@@ -191,7 +190,7 @@ private fun UserStatusPickerBottomSheet(
},
onClick = {
sheetState.hide(coroutineScope) {
onSelectPredefined(predefinedUserStatus)
onSelectPredefinedStatus(predefinedUserStatus)
}
},
)
@@ -203,7 +202,7 @@ private fun UserStatusPickerBottomSheet(
leadingContent = ListItemContent.Text(text = "✏️"),
onClick = {
sheetState.hide(coroutineScope) {
onSelectCustom()
onSelectCustomStatus()
}
},
)
@@ -217,7 +216,6 @@ private fun CustomStatusInputRow(
emoji: String,
textFieldState: TextFieldState,
rawStatus: UserStatus?,
onEmojiChange: (String) -> Unit,
onConfirm: () -> Unit,
onCancel: () -> Unit,
modifier: Modifier = Modifier,
@@ -299,6 +297,6 @@ private fun CustomStatusInputRow(
@PreviewsDayNight
@Composable
internal fun UserStatusRowPreview(@PreviewParameter(UserStatusStateProvider::class) state: UserStatusState) = ElementPreview {
UserStatusRow(state = state)
internal fun UserStatusViewPreview(@PreviewParameter(UserStatusStateProvider::class) state: UserStatusState) = ElementPreview {
UserStatusView(state = state)
}
@@ -8,8 +8,10 @@
package io.element.android.libraries.matrix.api.user
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
@Immutable
sealed interface DisplayedStatus : Parcelable {
/** Status set manually by the user via m.status. */
@Parcelize
@@ -138,6 +138,7 @@ import org.matrix.rustcomponents.sdk.CreateRoomParameters as RustCreateRoomParam
import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
@Suppress("LargeClass")
class RustMatrixClient(
override val sessionPaths: SessionPaths,
private val innerClient: Client,