Skip to content

Commit ff368b4

Browse files
committed
Send failure verified user : resolve ui and logic
1 parent 416810a commit ff368b4

File tree

29 files changed

+1103
-85
lines changed

29 files changed

+1103
-85
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents
3030
import io.element.android.features.messages.impl.actionlist.ActionListPresenter
3131
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
3232
import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor
33+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureState
3334
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
3435
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
3536
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
@@ -95,6 +96,7 @@ class MessagesPresenter @AssistedInject constructor(
9596
private val reactionSummaryPresenter: ReactionSummaryPresenter,
9697
private val readReceiptBottomSheetPresenter: ReadReceiptBottomSheetPresenter,
9798
private val pinnedMessagesBannerPresenter: Presenter<PinnedMessagesBannerState>,
99+
private val resolveVerifiedUserSendFailurePresenter: Presenter<ResolveVerifiedUserSendFailureState>,
98100
private val networkMonitor: NetworkMonitor,
99101
private val snackbarDispatcher: SnackbarDispatcher,
100102
private val dispatchers: CoroutineDispatchers,
@@ -128,6 +130,7 @@ class MessagesPresenter @AssistedInject constructor(
128130
val reactionSummaryState = reactionSummaryPresenter.present()
129131
val readReceiptBottomSheetState = readReceiptBottomSheetPresenter.present()
130132
val pinnedMessagesBannerState = pinnedMessagesBannerPresenter.present()
133+
val resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailurePresenter.present()
131134

132135
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
133136

@@ -227,6 +230,7 @@ class MessagesPresenter @AssistedInject constructor(
227230
appName = buildMeta.applicationName,
228231
callState = callState,
229232
pinnedMessagesBannerState = pinnedMessagesBannerState,
233+
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
230234
eventSink = { handleEvents(it) }
231235
)
232236
}

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesState.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package io.element.android.features.messages.impl
99

1010
import androidx.compose.runtime.Immutable
1111
import io.element.android.features.messages.impl.actionlist.ActionListState
12+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureState
1213
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
1314
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
1415
import io.element.android.features.messages.impl.timeline.TimelineState
@@ -47,6 +48,7 @@ data class MessagesState(
4748
val callState: RoomCallState,
4849
val appName: String,
4950
val pinnedMessagesBannerState: PinnedMessagesBannerState,
51+
val resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState,
5052
val eventSink: (MessagesEvents) -> Unit
5153
)
5254

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ package io.element.android.features.messages.impl
1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1111
import io.element.android.features.messages.impl.actionlist.ActionListState
1212
import io.element.android.features.messages.impl.actionlist.anActionListState
13+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureState
14+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.aResolveVerifiedUserSendFailureState
1315
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
1416
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
1517
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
@@ -113,6 +115,7 @@ fun aMessagesState(
113115
enableVoiceMessages: Boolean = true,
114116
callState: RoomCallState = RoomCallState.ENABLED,
115117
pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(),
118+
resolveVerifiedUserSendFailureState: ResolveVerifiedUserSendFailureState = aResolveVerifiedUserSendFailureState(),
116119
eventSink: (MessagesEvents) -> Unit = {},
117120
) = MessagesState(
118121
roomId = RoomId("!id:domain"),
@@ -137,6 +140,7 @@ fun aMessagesState(
137140
callState = callState,
138141
appName = "Element",
139142
pinnedMessagesBannerState = pinnedMessagesBannerState,
143+
resolveVerifiedUserSendFailureState = resolveVerifiedUserSendFailureState,
140144
eventSink = eventSink,
141145
)
142146

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ import io.element.android.features.messages.impl.actionlist.ActionListEvents
5757
import io.element.android.features.messages.impl.actionlist.ActionListView
5858
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
5959
import io.element.android.features.messages.impl.attachments.Attachment
60+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureEvents
61+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureView
6062
import io.element.android.features.messages.impl.messagecomposer.AttachmentsBottomSheet
6163
import io.element.android.features.messages.impl.messagecomposer.AttachmentsState
6264
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
@@ -242,8 +244,12 @@ fun MessagesView(
242244
},
243245
onEmojiReactionClick = ::onEmojiReactionClick,
244246
onVerifiedUserSendFailureClick = { event ->
247+
state.resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvents.ComputeForMessage(event))
248+
},
249+
)
245250

246-
}
251+
ResolveVerifiedUserSendFailureView(
252+
state = state.resolveVerifiedUserSendFailureState,
247253
)
248254

249255
CustomReactionBottomSheet(

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import io.element.android.features.messages.api.pinned.IsPinnedMessagesFeatureEn
2222
import io.element.android.features.messages.impl.UserEventPermissions
2323
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
2424
import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionPostProcessor
25+
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
26+
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
2527
import io.element.android.features.messages.impl.timeline.model.TimelineItem
2628
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
2729
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
@@ -36,7 +38,6 @@ import io.element.android.libraries.architecture.Presenter
3638
import io.element.android.libraries.di.RoomScope
3739
import io.element.android.libraries.matrix.api.core.EventId
3840
import io.element.android.libraries.matrix.api.room.MatrixRoom
39-
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
4041
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
4142
import kotlinx.collections.immutable.ImmutableList
4243
import kotlinx.collections.immutable.persistentListOf
@@ -57,6 +58,7 @@ class DefaultActionListPresenter @AssistedInject constructor(
5758
private val appPreferencesStore: AppPreferencesStore,
5859
private val isPinnedMessagesFeatureEnabled: IsPinnedMessagesFeatureEnabled,
5960
private val room: MatrixRoom,
61+
private val userSendFailureFactory: VerifiedUserSendFailureFactory,
6062
) : ActionListPresenter {
6163
@AssistedFactory
6264
@ContributesBinding(RoomScope::class)
@@ -116,10 +118,10 @@ class DefaultActionListPresenter @AssistedInject constructor(
116118
isEventPinned = pinnedEventIds.contains(timelineItem.eventId),
117119
)
118120

119-
val verifiedUserSendFailure = buildVerifiedUserSendFailure(timelineItem)
121+
val verifiedUserSendFailure = userSendFailureFactory.create(timelineItem.localSendState)
120122
val displayEmojiReactions = usersEventPermissions.canSendReaction && timelineItem.content.canReact()
121123

122-
if (actions.isNotEmpty() || displayEmojiReactions || verifiedUserSendFailure != ActionListState.VerifiedUserSendFailure.None) {
124+
if (actions.isNotEmpty() || displayEmojiReactions || verifiedUserSendFailure != VerifiedUserSendFailure.None) {
123125
target.value = ActionListState.Target.Success(
124126
event = timelineItem,
125127
displayEmojiReactions = displayEmojiReactions,
@@ -131,32 +133,6 @@ class DefaultActionListPresenter @AssistedInject constructor(
131133
}
132134
}
133135

134-
private suspend fun buildVerifiedUserSendFailure(
135-
timelineItem: TimelineItem.Event,
136-
): ActionListState.VerifiedUserSendFailure {
137-
return when (val sendState = timelineItem.localSendState) {
138-
is LocalEventSendState.Failed.VerifiedUserHasUnsignedDevice -> {
139-
val userId = sendState.devices.keys.firstOrNull()
140-
if (userId == null) {
141-
ActionListState.VerifiedUserSendFailure.None
142-
} else {
143-
val displayName = room.userDisplayName(userId).getOrNull() ?: userId.value
144-
ActionListState.VerifiedUserSendFailure.UnsignedDevice(displayName)
145-
}
146-
}
147-
is LocalEventSendState.Failed.VerifiedUserChangedIdentity -> {
148-
val userId = sendState.users.firstOrNull()
149-
if (userId == null) {
150-
ActionListState.VerifiedUserSendFailure.None
151-
} else {
152-
val displayName = room.userDisplayName(userId).getOrNull() ?: userId.value
153-
ActionListState.VerifiedUserSendFailure.ChangedIdentity(displayName)
154-
}
155-
}
156-
else -> ActionListState.VerifiedUserSendFailure.None
157-
}
158-
}
159-
160136
private fun buildActions(
161137
timelineItem: TimelineItem.Event,
162138
usersEventPermissions: UserEventPermissions,

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListState.kt

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77

88
package io.element.android.features.messages.impl.actionlist
99

10-
import androidx.compose.runtime.Composable
1110
import androidx.compose.runtime.Immutable
12-
import androidx.compose.ui.res.stringResource
1311
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
12+
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
1413
import io.element.android.features.messages.impl.timeline.model.TimelineItem
15-
import io.element.android.libraries.ui.strings.CommonStrings
1614
import kotlinx.collections.immutable.ImmutableList
1715

1816
@Immutable
@@ -31,20 +29,4 @@ data class ActionListState(
3129
val actions: ImmutableList<TimelineItemAction>,
3230
) : Target
3331
}
34-
35-
@Immutable
36-
sealed interface VerifiedUserSendFailure {
37-
data object None : VerifiedUserSendFailure
38-
data class UnsignedDevice(val displayName: String) : VerifiedUserSendFailure
39-
data class ChangedIdentity(val displayName: String) : VerifiedUserSendFailure
40-
41-
@Composable
42-
fun formatted(): String {
43-
return when (this) {
44-
is None -> ""
45-
is UnsignedDevice -> stringResource(CommonStrings.screen_timeline_item_menu_send_failure_unsigned_device, displayName)
46-
is ChangedIdentity -> stringResource(CommonStrings.screen_timeline_item_menu_send_failure_changed_identity, displayName)
47-
}
48-
}
49-
}
5032
}

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListStateProvider.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ package io.element.android.features.messages.impl.actionlist
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1111
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
12+
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
13+
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.anUnsignedDeviceSendFailure
1214
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
1315
import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
1416
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemAudioContent
@@ -18,8 +20,6 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI
1820
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
1921
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVideoContent
2022
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent
21-
import io.element.android.libraries.matrix.api.core.UserId
22-
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
2323
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
2424
import kotlinx.collections.immutable.ImmutableList
2525
import kotlinx.collections.immutable.persistentListOf
@@ -37,7 +37,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
3737
reactionsState = reactionsState
3838
),
3939
displayEmojiReactions = true,
40-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
40+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
4141
actions = aTimelineItemActionList(),
4242
)
4343
),
@@ -50,7 +50,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
5050
reactionsState = reactionsState,
5151
),
5252
displayEmojiReactions = true,
53-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
53+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
5454
actions = aTimelineItemActionList(),
5555
)
5656
),
@@ -60,7 +60,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
6060
reactionsState = reactionsState
6161
),
6262
displayEmojiReactions = true,
63-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
63+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
6464
actions = aTimelineItemActionList(),
6565
)
6666
),
@@ -70,7 +70,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
7070
reactionsState = reactionsState
7171
),
7272
displayEmojiReactions = true,
73-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
73+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
7474
actions = aTimelineItemActionList(),
7575
)
7676
),
@@ -80,7 +80,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
8080
reactionsState = reactionsState
8181
),
8282
displayEmojiReactions = true,
83-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
83+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
8484
actions = aTimelineItemActionList(),
8585
)
8686
),
@@ -90,7 +90,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
9090
reactionsState = reactionsState
9191
),
9292
displayEmojiReactions = true,
93-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
93+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
9494
actions = aTimelineItemActionList(),
9595
)
9696
),
@@ -100,7 +100,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
100100
reactionsState = reactionsState
101101
),
102102
displayEmojiReactions = true,
103-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
103+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
104104
actions = aTimelineItemActionList(),
105105
)
106106
),
@@ -110,7 +110,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
110110
reactionsState = reactionsState
111111
),
112112
displayEmojiReactions = false,
113-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
113+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
114114
actions = aTimelineItemActionList(),
115115
),
116116
),
@@ -120,7 +120,7 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
120120
reactionsState = reactionsState
121121
),
122122
displayEmojiReactions = false,
123-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
123+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
124124
actions = aTimelineItemPollActionList(),
125125
),
126126
),
@@ -131,15 +131,15 @@ open class ActionListStateProvider : PreviewParameterProvider<ActionListState> {
131131
messageShield = MessageShield.UnknownDevice(isCritical = true)
132132
),
133133
displayEmojiReactions = true,
134-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.None,
134+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
135135
actions = aTimelineItemActionList(),
136136
)
137137
),
138138
anActionListState().copy(
139139
target = ActionListState.Target.Success(
140140
event = aTimelineItemEvent(),
141141
displayEmojiReactions = true,
142-
verifiedUserSendFailure = ActionListState.VerifiedUserSendFailure.UnsignedDevice(displayName = "Alice"),
142+
verifiedUserSendFailure = anUnsignedDeviceSendFailure(),
143143
actions = aTimelineItemActionList(),
144144
)
145145
),

0 commit comments

Comments
 (0)