Force last owner of a room to pass ownership when leaving (#5094)
* Move `ChangeRoles*` classes to their own module so they can be shared * Hook the change roles screen to the leave room action, add confirmation dialogs * Use enum instead of sealed interface for `ChangeRoomMemberRolesListType` * Try to improve communications between nodes * refactor (leave room) : makes sure to expose only necessary code from api module * Add `:libraries:previewutils` module to share some test fixtures used for UI previews * Update screenshots --------- Co-authored-by: ElementBot <android@element.io> Co-authored-by: ganfra <francoisg@matrix.org>
This commit is contained in:
parent
a87bbdd91c
commit
955263bee1
112 changed files with 1337 additions and 513 deletions
|
|
@ -9,9 +9,6 @@ package io.element.android.features.leaveroom.api
|
|||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
sealed interface LeaveRoomEvent {
|
||||
data class ShowConfirmation(val roomId: RoomId) : LeaveRoomEvent
|
||||
data object HideConfirmation : LeaveRoomEvent
|
||||
data class LeaveRoom(val roomId: RoomId) : LeaveRoomEvent
|
||||
data object HideError : LeaveRoomEvent
|
||||
interface LeaveRoomEvent {
|
||||
data class LeaveRoom(val roomId: RoomId, val needsConfirmation: Boolean) : LeaveRoomEvent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector 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.leaveroom.api
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
interface LeaveRoomRenderer {
|
||||
@Composable
|
||||
fun Render(
|
||||
state: LeaveRoomState,
|
||||
onSelectNewOwners: (RoomId) -> Unit,
|
||||
modifier: Modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -7,29 +7,6 @@
|
|||
|
||||
package io.element.android.features.leaveroom.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
data class LeaveRoomState(
|
||||
val confirmation: Confirmation,
|
||||
val progress: Progress,
|
||||
val error: Error,
|
||||
val eventSink: (LeaveRoomEvent) -> Unit,
|
||||
) {
|
||||
sealed interface Confirmation {
|
||||
data object Hidden : Confirmation
|
||||
data class Dm(val roomId: RoomId) : Confirmation
|
||||
data class Generic(val roomId: RoomId) : Confirmation
|
||||
data class PrivateRoom(val roomId: RoomId) : Confirmation
|
||||
data class LastUserInRoom(val roomId: RoomId) : Confirmation
|
||||
}
|
||||
|
||||
sealed interface Progress {
|
||||
data object Hidden : Progress
|
||||
data object Shown : Progress
|
||||
}
|
||||
|
||||
sealed interface Error {
|
||||
data object Hidden : Error
|
||||
data object Shown : Error
|
||||
}
|
||||
interface LeaveRoomState {
|
||||
val eventSink: (LeaveRoomEvent) -> Unit
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.leaveroom.api
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
class LeaveRoomStateProvider : PreviewParameterProvider<LeaveRoomState> {
|
||||
override val values: Sequence<LeaveRoomState>
|
||||
get() = sequenceOf(
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.Hidden,
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.Generic(roomId = A_ROOM_ID),
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.PrivateRoom(roomId = A_ROOM_ID),
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.LastUserInRoom(roomId = A_ROOM_ID),
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.Hidden,
|
||||
progress = LeaveRoomState.Progress.Shown,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.Hidden,
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Shown,
|
||||
),
|
||||
aLeaveRoomState(
|
||||
confirmation = LeaveRoomState.Confirmation.Dm(roomId = A_ROOM_ID),
|
||||
progress = LeaveRoomState.Progress.Hidden,
|
||||
error = LeaveRoomState.Error.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private val A_ROOM_ID = RoomId("!aRoomId:aDomain")
|
||||
|
||||
fun aLeaveRoomState(
|
||||
confirmation: LeaveRoomState.Confirmation = LeaveRoomState.Confirmation.Hidden,
|
||||
progress: LeaveRoomState.Progress = LeaveRoomState.Progress.Hidden,
|
||||
error: LeaveRoomState.Error = LeaveRoomState.Error.Hidden,
|
||||
eventSink: (LeaveRoomEvent) -> Unit = {},
|
||||
) = LeaveRoomState(
|
||||
confirmation = confirmation,
|
||||
progress = progress,
|
||||
error = error,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector 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.leaveroom.api
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun LeaveRoomView(
|
||||
state: LeaveRoomState
|
||||
) {
|
||||
LeaveRoomConfirmationDialog(state)
|
||||
LeaveRoomProgressDialog(state)
|
||||
LeaveRoomErrorDialog(state)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveRoomConfirmationDialog(
|
||||
state: LeaveRoomState,
|
||||
) {
|
||||
when (state.confirmation) {
|
||||
is LeaveRoomState.Confirmation.Hidden -> {}
|
||||
|
||||
is LeaveRoomState.Confirmation.Dm -> LeaveRoomConfirmationDialog(
|
||||
text = R.string.leave_room_alert_private_subtitle,
|
||||
roomId = state.confirmation.roomId,
|
||||
isDm = false,
|
||||
eventSink = state.eventSink,
|
||||
)
|
||||
|
||||
is LeaveRoomState.Confirmation.PrivateRoom -> LeaveRoomConfirmationDialog(
|
||||
text = R.string.leave_room_alert_private_subtitle,
|
||||
roomId = state.confirmation.roomId,
|
||||
isDm = false,
|
||||
eventSink = state.eventSink,
|
||||
)
|
||||
|
||||
is LeaveRoomState.Confirmation.LastUserInRoom -> LeaveRoomConfirmationDialog(
|
||||
text = R.string.leave_room_alert_empty_subtitle,
|
||||
roomId = state.confirmation.roomId,
|
||||
isDm = false,
|
||||
eventSink = state.eventSink,
|
||||
)
|
||||
|
||||
is LeaveRoomState.Confirmation.Generic -> LeaveRoomConfirmationDialog(
|
||||
text = R.string.leave_room_alert_subtitle,
|
||||
roomId = state.confirmation.roomId,
|
||||
isDm = false,
|
||||
eventSink = state.eventSink,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveRoomConfirmationDialog(
|
||||
@StringRes text: Int,
|
||||
roomId: RoomId,
|
||||
isDm: Boolean,
|
||||
eventSink: (LeaveRoomEvent) -> Unit,
|
||||
) {
|
||||
ConfirmationDialog(
|
||||
title = stringResource(if (isDm) CommonStrings.action_leave_conversation else CommonStrings.action_leave_room),
|
||||
content = stringResource(text),
|
||||
submitText = stringResource(CommonStrings.action_leave),
|
||||
onSubmitClick = { eventSink(LeaveRoomEvent.LeaveRoom(roomId)) },
|
||||
onDismiss = { eventSink(LeaveRoomEvent.HideConfirmation) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveRoomProgressDialog(
|
||||
state: LeaveRoomState,
|
||||
) {
|
||||
when (state.progress) {
|
||||
is LeaveRoomState.Progress.Hidden -> {}
|
||||
is LeaveRoomState.Progress.Shown -> ProgressDialog(
|
||||
text = stringResource(CommonStrings.common_leaving_room),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LeaveRoomErrorDialog(
|
||||
state: LeaveRoomState,
|
||||
) {
|
||||
when (state.error) {
|
||||
is LeaveRoomState.Error.Hidden -> {}
|
||||
is LeaveRoomState.Error.Shown -> ErrorDialog(
|
||||
content = stringResource(CommonStrings.error_unknown),
|
||||
onSubmit = { state.eventSink(LeaveRoomEvent.HideError) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun LeaveRoomViewPreview(
|
||||
@PreviewParameter(LeaveRoomStateProvider::class) state: LeaveRoomState
|
||||
) = ElementPreview {
|
||||
Box(
|
||||
modifier = Modifier.size(300.dp, 300.dp),
|
||||
propagateMinConstraints = true,
|
||||
) {
|
||||
LeaveRoomView(state = state)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue