mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 06:55:41 +00:00
Let user see an error dialog in the case a message fails to be sent.
Closes #7470
This commit is contained in:
+14
@@ -400,9 +400,23 @@ class MessagesPresenter(
|
|||||||
TimelineItemAction.Pin -> handlePinAction(targetEvent)
|
TimelineItemAction.Pin -> handlePinAction(targetEvent)
|
||||||
TimelineItemAction.Unpin -> handleUnpinAction(targetEvent)
|
TimelineItemAction.Unpin -> handleUnpinAction(targetEvent)
|
||||||
TimelineItemAction.ViewInTimeline -> Unit
|
TimelineItemAction.ViewInTimeline -> Unit
|
||||||
|
TimelineItemAction.RetrySending -> handleRetrySending(targetEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun handleRetrySending(targetEvent: TimelineItem.Event) {
|
||||||
|
val sendHandle = targetEvent.sendhandle ?: return Unit.also {
|
||||||
|
Timber.w("No send handle for event ${targetEvent.eventOrTransactionId}")
|
||||||
|
}
|
||||||
|
sendHandle.retry()
|
||||||
|
.onSuccess {
|
||||||
|
Timber.d("Succeed to add the message back to the send queue")
|
||||||
|
}
|
||||||
|
.onFailure {
|
||||||
|
Timber.e(it, "Failed to add the message back to the send queue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun handleRemoveCaption(targetEvent: TimelineItem.Event) {
|
private suspend fun handleRemoveCaption(targetEvent: TimelineItem.Event) {
|
||||||
timelineController.invokeOnCurrentTimeline {
|
timelineController.invokeOnCurrentTimeline {
|
||||||
editCaption(
|
editCaption(
|
||||||
|
|||||||
+34
-2
@@ -93,6 +93,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
|||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.sendfailure.SendFailureDialogView
|
||||||
import io.element.android.features.messages.impl.topbars.MessagesViewTopBar
|
import io.element.android.features.messages.impl.topbars.MessagesViewTopBar
|
||||||
import io.element.android.features.messages.impl.topbars.ThreadTopBar
|
import io.element.android.features.messages.impl.topbars.ThreadTopBar
|
||||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog
|
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog
|
||||||
@@ -429,6 +430,31 @@ fun MessagesView(
|
|||||||
},
|
},
|
||||||
state = state.linkState,
|
state = state.linkState,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SendFailureDialogView(
|
||||||
|
sendFailureDialogState = state.timelineState.sendFailureDialogState,
|
||||||
|
onDismiss = {
|
||||||
|
state.timelineState.eventSink(TimelineEvent.HideSendFailureDialog)
|
||||||
|
},
|
||||||
|
onRetry = { event ->
|
||||||
|
state.eventSink(
|
||||||
|
MessagesEvent.HandleAction(
|
||||||
|
action = TimelineItemAction.RetrySending,
|
||||||
|
event = event,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
state.timelineState.eventSink(TimelineEvent.HideSendFailureDialog)
|
||||||
|
},
|
||||||
|
onRemoveMessage = { event ->
|
||||||
|
state.eventSink(
|
||||||
|
MessagesEvent.HandleAction(
|
||||||
|
action = TimelineItemAction.Redact,
|
||||||
|
event = event,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
state.timelineState.eventSink(TimelineEvent.HideSendFailureDialog)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -590,13 +616,19 @@ private fun MessagesViewComposerBottomSheetContents(
|
|||||||
when {
|
when {
|
||||||
state.successorRoom != null -> {
|
state.successorRoom != null -> {
|
||||||
SuccessorRoomBanner(
|
SuccessorRoomBanner(
|
||||||
modifier = Modifier.fillMaxWidth().padding(contentPadding),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(contentPadding),
|
||||||
roomSuccessor = state.successorRoom,
|
roomSuccessor = state.successorRoom,
|
||||||
onRoomSuccessorClick = onRoomSuccessorClick
|
onRoomSuccessorClick = onRoomSuccessorClick
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
state.userEventPermissions.canSendMessage -> {
|
state.userEventPermissions.canSendMessage -> {
|
||||||
Column(modifier = Modifier.fillMaxWidth().padding(contentPadding)) {
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(contentPadding)
|
||||||
|
) {
|
||||||
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
||||||
if (state.composerState.suggestions.isEmpty() &&
|
if (state.composerState.suggestions.isEmpty() &&
|
||||||
state.composerState.textEditorState is TextEditorState.Markdown) {
|
state.composerState.textEditorState is TextEditorState.Markdown) {
|
||||||
|
|||||||
+3
@@ -36,4 +36,7 @@ enum class TimelineItemAction(
|
|||||||
EndPoll(CommonStrings.action_end_poll, CompoundDrawables.ic_compound_polls_end),
|
EndPoll(CommonStrings.action_end_poll, CompoundDrawables.ic_compound_polls_end),
|
||||||
Pin(CommonStrings.action_pin, CompoundDrawables.ic_compound_pin),
|
Pin(CommonStrings.action_pin, CompoundDrawables.ic_compound_pin),
|
||||||
Unpin(CommonStrings.action_unpin, CompoundDrawables.ic_compound_unpin),
|
Unpin(CommonStrings.action_unpin, CompoundDrawables.ic_compound_unpin),
|
||||||
|
|
||||||
|
// Note: this action is not used in UI for now
|
||||||
|
RetrySending(CommonStrings.action_retry, CompoundDrawables.ic_compound_send_solid),
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -34,6 +34,9 @@ sealed interface TimelineEvent {
|
|||||||
*/
|
*/
|
||||||
sealed interface TimelineItemEvent : TimelineEvent
|
sealed interface TimelineItemEvent : TimelineEvent
|
||||||
|
|
||||||
|
data class ShowSendFailureDialog(val event: TimelineItem.Event) : TimelineItemEvent
|
||||||
|
data object HideSendFailureDialog : TimelineEvent
|
||||||
|
|
||||||
data class ComputeVerifiedUserSendFailure(val event: TimelineItem.Event) : TimelineItemEvent
|
data class ComputeVerifiedUserSendFailure(val event: TimelineItem.Event) : TimelineItemEvent
|
||||||
data class ShowShieldDialog(val messageShieldData: MessageShieldData) : TimelineItemEvent
|
data class ShowShieldDialog(val messageShieldData: MessageShieldData) : TimelineItemEvent
|
||||||
data class LoadMore(val direction: Timeline.PaginationDirection) : TimelineItemEvent
|
data class LoadMore(val direction: Timeline.PaginationDirection) : TimelineItemEvent
|
||||||
|
|||||||
+41
@@ -37,6 +37,7 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline
|
|||||||
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemTypingNotificationModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemTypingNotificationModel
|
||||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
||||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
||||||
|
import io.element.android.features.messages.impl.timeline.sendfailure.SendFailureDialogState
|
||||||
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
||||||
import io.element.android.features.messages.impl.userEventPermissions
|
import io.element.android.features.messages.impl.userEventPermissions
|
||||||
import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager
|
import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager
|
||||||
@@ -56,6 +57,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsSta
|
|||||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
|
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
|
||||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||||
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.DisplayFirstTimelineItems
|
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.DisplayFirstTimelineItems
|
||||||
@@ -142,6 +144,7 @@ class TimelinePresenter(
|
|||||||
|
|
||||||
val newEventState = remember { mutableStateOf<NewEventState>(NewEventState.None) }
|
val newEventState = remember { mutableStateOf<NewEventState>(NewEventState.None) }
|
||||||
val messageShieldDialogData: MutableState<MessageShieldData?> = remember { mutableStateOf(null) }
|
val messageShieldDialogData: MutableState<MessageShieldData?> = remember { mutableStateOf(null) }
|
||||||
|
var sendFailureDialogState by remember { mutableStateOf<SendFailureDialogState>(SendFailureDialogState.Hidden) }
|
||||||
|
|
||||||
// Forces [JumpToUnreadState.Hidden] until the next RoomInfo push. Set after a
|
// Forces [JumpToUnreadState.Hidden] until the next RoomInfo push. Set after a
|
||||||
// [TimelineEvent.MarkAllAsRead] await completes so the FAB hides without waiting for
|
// [TimelineEvent.MarkAllAsRead] await completes so the FAB hides without waiting for
|
||||||
@@ -244,6 +247,43 @@ class TimelinePresenter(
|
|||||||
suppressJumpToUnread.value = true
|
suppressJumpToUnread.value = true
|
||||||
}
|
}
|
||||||
is TimelineEvent.ShowShieldDialog -> messageShieldDialogData.value = event.messageShieldData
|
is TimelineEvent.ShowShieldDialog -> messageShieldDialogData.value = event.messageShieldData
|
||||||
|
is TimelineEvent.ShowSendFailureDialog -> {
|
||||||
|
val sendStateFailure = event.event.localSendState as? LocalEventSendState.Failed ?: return
|
||||||
|
when (sendStateFailure) {
|
||||||
|
is LocalEventSendState.Failed.VerifiedUser -> {
|
||||||
|
// defer to the resolveVerifiedUserSendFailureState to handle this case,
|
||||||
|
// as it will show a dialog with the right information
|
||||||
|
resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvent.ComputeForMessage(event.event))
|
||||||
|
}
|
||||||
|
is LocalEventSendState.Failed.InvalidMimeType -> {
|
||||||
|
sendFailureDialogState = SendFailureDialogState.Show(
|
||||||
|
event = event.event,
|
||||||
|
message = "Invalid mime type: ${sendStateFailure.mimeType}",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LocalEventSendState.Failed.MissingMediaContent -> {
|
||||||
|
sendFailureDialogState = SendFailureDialogState.Show(
|
||||||
|
event = event.event,
|
||||||
|
message = "Missing media content",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LocalEventSendState.Failed.SendingFromUnverifiedDevice -> {
|
||||||
|
sendFailureDialogState = SendFailureDialogState.Show(
|
||||||
|
event = event.event,
|
||||||
|
message = "Sending from unverified device",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is LocalEventSendState.Failed.Unknown -> {
|
||||||
|
sendFailureDialogState = SendFailureDialogState.Show(
|
||||||
|
event = event.event,
|
||||||
|
message = sendStateFailure.error.takeIf { it.isNotBlank() } ?: "Unknown error",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is TimelineEvent.HideSendFailureDialog -> {
|
||||||
|
sendFailureDialogState = SendFailureDialogState.Hidden
|
||||||
|
}
|
||||||
is TimelineEvent.ComputeVerifiedUserSendFailure -> {
|
is TimelineEvent.ComputeVerifiedUserSendFailure -> {
|
||||||
resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvent.ComputeForMessage(event.event))
|
resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvent.ComputeForMessage(event.event))
|
||||||
}
|
}
|
||||||
@@ -408,6 +448,7 @@ class TimelinePresenter(
|
|||||||
focusRequestState = focusRequestState.value,
|
focusRequestState = focusRequestState.value,
|
||||||
messageShieldDialogData = messageShieldDialogData.value,
|
messageShieldDialogData = messageShieldDialogData.value,
|
||||||
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
|
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
|
||||||
|
sendFailureDialogState = sendFailureDialogState,
|
||||||
displayThreadSummaries = displayThreadSummaries,
|
displayThreadSummaries = displayThreadSummaries,
|
||||||
displayJumpToUnread = displayJumpToUnread,
|
displayJumpToUnread = displayJumpToUnread,
|
||||||
jumpToUnread = jumpToUnread.value,
|
jumpToUnread = jumpToUnread.value,
|
||||||
|
|||||||
+2
@@ -13,6 +13,7 @@ import io.element.android.features.messages.impl.crypto.sendfailure.resolve.Reso
|
|||||||
import io.element.android.features.messages.impl.timeline.components.MessageShieldData
|
import io.element.android.features.messages.impl.timeline.components.MessageShieldData
|
||||||
import io.element.android.features.messages.impl.timeline.model.NewEventState
|
import io.element.android.features.messages.impl.timeline.model.NewEventState
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import io.element.android.features.messages.impl.timeline.sendfailure.SendFailureDialogState
|
||||||
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
||||||
import io.element.android.features.roomcall.api.RoomCallState
|
import io.element.android.features.roomcall.api.RoomCallState
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
@@ -32,6 +33,7 @@ data class TimelineState(
|
|||||||
// If not null, info will be rendered in a dialog
|
// If not null, info will be rendered in a dialog
|
||||||
val messageShieldDialogData: MessageShieldData?,
|
val messageShieldDialogData: MessageShieldData?,
|
||||||
val resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState,
|
val resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState,
|
||||||
|
val sendFailureDialogState: SendFailureDialogState,
|
||||||
val displayThreadSummaries: Boolean,
|
val displayThreadSummaries: Boolean,
|
||||||
val displayJumpToUnread: Boolean,
|
val displayJumpToUnread: Boolean,
|
||||||
val jumpToUnread: JumpToUnreadState,
|
val jumpToUnread: JumpToUnreadState,
|
||||||
|
|||||||
+3
@@ -25,6 +25,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
|
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
|
||||||
|
import io.element.android.features.messages.impl.timeline.sendfailure.SendFailureDialogState
|
||||||
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
import io.element.android.features.messages.impl.typing.TypingNotificationState
|
||||||
import io.element.android.features.messages.impl.typing.aTypingNotificationState
|
import io.element.android.features.messages.impl.typing.aTypingNotificationState
|
||||||
import io.element.android.features.roomcall.api.aStandByCallState
|
import io.element.android.features.roomcall.api.aStandByCallState
|
||||||
@@ -57,6 +58,7 @@ fun aTimelineState(
|
|||||||
isLive: Boolean = true,
|
isLive: Boolean = true,
|
||||||
messageShield: MessageShield? = null,
|
messageShield: MessageShield? = null,
|
||||||
resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState = aResolveVerifiedUserSendFailureState(),
|
resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState = aResolveVerifiedUserSendFailureState(),
|
||||||
|
sendFailureDialogState: SendFailureDialogState = SendFailureDialogState.Hidden,
|
||||||
displayThreadSummaries: Boolean = false,
|
displayThreadSummaries: Boolean = false,
|
||||||
displayJumpToUnread: Boolean = false,
|
displayJumpToUnread: Boolean = false,
|
||||||
jumpToUnread: JumpToUnreadState = JumpToUnreadState.Hidden,
|
jumpToUnread: JumpToUnreadState = JumpToUnreadState.Hidden,
|
||||||
@@ -78,6 +80,7 @@ fun aTimelineState(
|
|||||||
focusRequestState = focusRequestState,
|
focusRequestState = focusRequestState,
|
||||||
messageShieldDialogData = messageShield?.let { MessageShieldData(it) },
|
messageShieldDialogData = messageShield?.let { MessageShieldData(it) },
|
||||||
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
|
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
|
||||||
|
sendFailureDialogState = sendFailureDialogState,
|
||||||
displayThreadSummaries = displayThreadSummaries,
|
displayThreadSummaries = displayThreadSummaries,
|
||||||
displayJumpToUnread = displayJumpToUnread,
|
displayJumpToUnread = displayJumpToUnread,
|
||||||
jumpToUnread = jumpToUnread,
|
jumpToUnread = jumpToUnread,
|
||||||
|
|||||||
+1
-2
@@ -70,10 +70,9 @@ fun TimelineEventTimestampView(
|
|||||||
}
|
}
|
||||||
hasError -> Modifier
|
hasError -> Modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
enabled = isVerifiedUserSendFailure,
|
|
||||||
onClickLabel = onClickLabel,
|
onClickLabel = onClickLabel,
|
||||||
) {
|
) {
|
||||||
eventSink(TimelineEvent.ComputeVerifiedUserSendFailure(event))
|
eventSink(TimelineEvent.ShowSendFailureDialog(event))
|
||||||
}
|
}
|
||||||
else -> Modifier
|
else -> Modifier
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -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.messages.impl.timeline.sendfailure
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
sealed interface SendFailureDialogState {
|
||||||
|
data object Hidden : SendFailureDialogState
|
||||||
|
|
||||||
|
data class Show(
|
||||||
|
val event: TimelineItem.Event,
|
||||||
|
val message: String,
|
||||||
|
) : SendFailureDialogState
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.messages.impl.timeline.sendfailure
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SendFailureDialogView(
|
||||||
|
sendFailureDialogState: SendFailureDialogState,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onRetry: (TimelineItem.Event) -> Unit,
|
||||||
|
onRemoveMessage: (TimelineItem.Event) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
when (sendFailureDialogState) {
|
||||||
|
is SendFailureDialogState.Hidden -> Unit
|
||||||
|
is SendFailureDialogState.Show -> {
|
||||||
|
// Show the dialog with the message and actions
|
||||||
|
ConfirmationDialog(
|
||||||
|
modifier = modifier,
|
||||||
|
title = stringResource(id = CommonStrings.common_sending_failed),
|
||||||
|
content = sendFailureDialogState.message,
|
||||||
|
onDismiss = onDismiss,
|
||||||
|
submitText = stringResource(id = CommonStrings.action_retry),
|
||||||
|
onSubmitClick = { onRetry(sendFailureDialogState.event) },
|
||||||
|
onCancelClick = onDismiss,
|
||||||
|
thirdButtonText = stringResource(id = CommonStrings.action_remove_message),
|
||||||
|
onThirdButtonClick = { onRemoveMessage(sendFailureDialogState.event) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user