Skip to content

Commit a8a6a51

Browse files
authored
Allow replying to a message with an attachment (#5261)
1 parent 670c929 commit a8a6a51

File tree

10 files changed

+57
-34
lines changed

10 files changed

+57
-34
lines changed

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class MessagesFlowNode(
142142
) : NavTarget
143143

144144
@Parcelize
145-
data class AttachmentPreview(val timelineMode: Timeline.Mode, val attachment: Attachment) : NavTarget
145+
data class AttachmentPreview(val timelineMode: Timeline.Mode, val attachment: Attachment, val inReplyToEventId: EventId?) : NavTarget
146146

147147
@Parcelize
148148
data class LocationViewer(val location: Location, val description: String?) : NavTarget
@@ -224,10 +224,11 @@ class MessagesFlowNode(
224224
)
225225
}
226226

227-
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
227+
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) {
228228
backstack.push(NavTarget.AttachmentPreview(
229229
attachment = attachments.first(),
230230
timelineMode = Timeline.Mode.Live,
231+
inReplyToEventId = inReplyToEventId,
231232
))
232233
}
233234

@@ -314,6 +315,7 @@ class MessagesFlowNode(
314315
val inputs = AttachmentsPreviewNode.Inputs(
315316
attachment = navTarget.attachment,
316317
timelineMode = navTarget.timelineMode,
318+
inReplyToEventId = navTarget.inReplyToEventId,
317319
)
318320
createNode<AttachmentsPreviewNode>(buildContext, listOf(inputs))
319321
}
@@ -416,10 +418,11 @@ class MessagesFlowNode(
416418
)
417419
}
418420

419-
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
421+
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) {
420422
backstack.push(NavTarget.AttachmentPreview(
421423
attachment = attachments.first(),
422-
timelineMode = Timeline.Mode.Thread(navTarget.threadRootId)
424+
timelineMode = Timeline.Mode.Thread(navTarget.threadRootId),
425+
inReplyToEventId = inReplyToEventId,
423426
))
424427
}
425428

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface MessagesNavigator {
2020
fun onForwardEventClick(eventId: EventId)
2121
fun onReportContentClick(eventId: EventId, senderId: UserId)
2222
fun onEditPollClick(eventId: EventId)
23-
fun onPreviewAttachment(attachments: ImmutableList<Attachment>)
23+
fun onPreviewAttachment(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?)
2424
fun onNavigateToRoom(roomId: RoomId, serverNames: List<String>)
2525
fun onOpenThread(threadRootId: ThreadId, focusedEventId: EventId?)
2626
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class MessagesNode(
112112
interface Callback : Plugin {
113113
fun onRoomDetailsClick()
114114
fun onEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean
115-
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
115+
fun onPreviewAttachments(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?)
116116
fun onUserDataClick(userId: UserId)
117117
fun onPermalinkClick(data: PermalinkData)
118118
fun onShowEventDebugInfoClick(eventId: EventId?, debugInfo: TimelineItemDebugInfo)
@@ -219,8 +219,8 @@ class MessagesNode(
219219
callbacks.forEach { it.onEditPollClick(eventId) }
220220
}
221221

222-
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>) {
223-
callbacks.forEach { it.onPreviewAttachments(attachments) }
222+
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) {
223+
callbacks.forEach { it.onPreviewAttachments(attachments, inReplyToEventId) }
224224
}
225225

226226
override fun onNavigateToRoom(roomId: RoomId, serverNames: List<String>) {

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewNode.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.element.android.features.messages.impl.attachments.Attachment
2020
import io.element.android.libraries.architecture.NodeInputs
2121
import io.element.android.libraries.architecture.inputs
2222
import io.element.android.libraries.di.RoomScope
23+
import io.element.android.libraries.matrix.api.core.EventId
2324
import io.element.android.libraries.matrix.api.timeline.Timeline
2425
import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer
2526

@@ -34,6 +35,7 @@ class AttachmentsPreviewNode(
3435
data class Inputs(
3536
val attachment: Attachment,
3637
val timelineMode: Timeline.Mode,
38+
val inReplyToEventId: EventId?,
3739
) : NodeInputs
3840

3941
private val inputs: Inputs = inputs()
@@ -46,6 +48,7 @@ class AttachmentsPreviewNode(
4648
attachment = inputs.attachment,
4749
timelineMode = inputs.timelineMode,
4850
onDoneListener = onDoneListener,
51+
inReplyToEventId = inputs.inReplyToEventId,
4952
)
5053

5154
@Composable

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/attachments/preview/AttachmentsPreviewPresenter.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class AttachmentsPreviewPresenter(
5454
@Assisted private val attachment: Attachment,
5555
@Assisted private val onDoneListener: OnDoneListener,
5656
@Assisted private val timelineMode: Timeline.Mode,
57+
@Assisted private val inReplyToEventId: EventId?,
5758
mediaSenderFactory: MediaSender.Factory,
5859
private val permalinkBuilder: PermalinkBuilder,
5960
private val temporaryUriDeleter: TemporaryUriDeleter,
@@ -67,6 +68,7 @@ class AttachmentsPreviewPresenter(
6768
attachment: Attachment,
6869
timelineMode: Timeline.Mode,
6970
onDoneListener: OnDoneListener,
71+
inReplyToEventId: EventId?,
7072
): AttachmentsPreviewPresenter
7173
}
7274

@@ -182,7 +184,7 @@ class AttachmentsPreviewPresenter(
182184
caption = caption,
183185
sendActionState = sendActionState,
184186
dismissAfterSend = false,
185-
inReplyToEventId = null,
187+
inReplyToEventId = inReplyToEventId,
186188
)
187189

188190
// Clean up the pre-processed media after it's been sent

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

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes
4545
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
4646
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
4747
import io.element.android.libraries.di.annotations.SessionCoroutineScope
48+
import io.element.android.libraries.matrix.api.core.EventId
4849
import io.element.android.libraries.matrix.api.core.UserId
4950
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
5051
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
@@ -54,12 +55,10 @@ import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
5455
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
5556
import io.element.android.libraries.matrix.api.room.getDirectRoomMember
5657
import io.element.android.libraries.matrix.api.room.isDm
57-
import io.element.android.libraries.matrix.api.room.roomMembers
5858
import io.element.android.libraries.matrix.api.timeline.TimelineException
5959
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
6060
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
6161
import io.element.android.libraries.matrix.ui.messages.reply.map
62-
import io.element.android.libraries.matrix.ui.room.getDirectRoomMember
6362
import io.element.android.libraries.mediapickers.api.PickerProvider
6463
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
6564
import io.element.android.libraries.mediaupload.api.MediaSender
@@ -247,16 +246,23 @@ class MessageComposerPresenter(
247246
richTextEditorState = richTextEditorState,
248247
)
249248
}
250-
is MessageComposerEvents.SendUri -> sessionCoroutineScope.sendAttachment(
251-
attachment = Attachment.Media(
252-
localMedia = localMediaFactory.createFromUri(
253-
uri = event.uri,
254-
mimeType = null,
255-
name = null,
256-
formattedFileSize = null
249+
is MessageComposerEvents.SendUri -> {
250+
val inReplyToEventId = (messageComposerContext.composerMode as? MessageComposerMode.Reply)?.eventId
251+
sessionCoroutineScope.sendAttachment(
252+
attachment = Attachment.Media(
253+
localMedia = localMediaFactory.createFromUri(
254+
uri = event.uri,
255+
mimeType = null,
256+
name = null,
257+
formattedFileSize = null
258+
),
257259
),
258-
),
259-
)
260+
inReplyToEventId = inReplyToEventId,
261+
)
262+
263+
// Reset composer since the attachment has been sent
264+
messageComposerContext.composerMode = MessageComposerMode.Normal
265+
}
260266
is MessageComposerEvents.SetMode -> {
261267
localCoroutineScope.setMode(event.composerMode, markdownTextEditorState, richTextEditorState)
262268
}
@@ -497,12 +503,14 @@ class MessageComposerPresenter(
497503

498504
private fun CoroutineScope.sendAttachment(
499505
attachment: Attachment,
506+
inReplyToEventId: EventId?,
500507
) = when (attachment) {
501508
is Attachment.Media -> {
502509
launch {
503510
sendMedia(
504511
uri = attachment.localMedia.uri,
505512
mimeType = attachment.localMedia.info.mimeType,
513+
inReplyToEventId = inReplyToEventId,
506514
)
507515
}
508516
}
@@ -521,17 +529,23 @@ class MessageComposerPresenter(
521529
formattedFileSize = null
522530
)
523531
val mediaAttachment = Attachment.Media(localMedia)
524-
navigator.onPreviewAttachment(persistentListOf(mediaAttachment))
532+
val inReplyToEventId = (messageComposerContext.composerMode as? MessageComposerMode.Reply)?.eventId
533+
navigator.onPreviewAttachment(persistentListOf(mediaAttachment), inReplyToEventId)
534+
535+
// Reset composer since the attachment will be sent in a separate flow
536+
messageComposerContext.composerMode = MessageComposerMode.Normal
525537
}
526538

527539
private suspend fun sendMedia(
528540
uri: Uri,
529541
mimeType: String,
542+
inReplyToEventId: EventId?,
530543
) = runCatchingExceptions {
531544
mediaSender.sendMedia(
532545
uri = uri,
533546
mimeType = mimeType,
534547
mediaOptimizationConfig = mediaOptimizationConfigProvider.get(),
548+
inReplyToEventId = inReplyToEventId,
535549
).getOrThrow()
536550
}
537551
.onFailure { cause ->

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class ThreadedMessagesNode(
115115

116116
interface Callback : Plugin {
117117
fun onEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean
118-
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
118+
fun onPreviewAttachments(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?)
119119
fun onUserDataClick(userId: UserId)
120120
fun onPermalinkClick(data: PermalinkData)
121121
fun onShowEventDebugInfoClick(eventId: EventId?, debugInfo: TimelineItemDebugInfo)
@@ -215,8 +215,8 @@ class ThreadedMessagesNode(
215215
callbacks.forEach { it.onEditPollClick(eventId) }
216216
}
217217

218-
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>) {
219-
callbacks.forEach { it.onPreviewAttachments(attachments) }
218+
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) {
219+
callbacks.forEach { it.onPreviewAttachments(attachments, inReplyToEventId) }
220220
}
221221

222222
override fun onNavigateToRoom(roomId: RoomId, serverNames: List<String>) = Unit

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/FakeMessagesNavigator.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class FakeMessagesNavigator(
2121
private val onForwardEventClickLambda: (eventId: EventId) -> Unit = { _ -> lambdaError() },
2222
private val onReportContentClickLambda: (eventId: EventId, senderId: UserId) -> Unit = { _, _ -> lambdaError() },
2323
private val onEditPollClickLambda: (eventId: EventId) -> Unit = { _ -> lambdaError() },
24-
private val onPreviewAttachmentLambda: (attachments: ImmutableList<Attachment>) -> Unit = { _ -> lambdaError() },
24+
private val onPreviewAttachmentLambda: (attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) -> Unit = { _, _ -> lambdaError() },
2525
private val onNavigateToRoomLambda: (roomId: RoomId, serverNames: List<String>) -> Unit = { _, _ -> lambdaError() },
2626
private val onOpenThreadLambda: (threadRootId: ThreadId, focusedEventId: EventId?) -> Unit = { _, _ -> lambdaError() },
2727
) : MessagesNavigator {
@@ -41,8 +41,8 @@ class FakeMessagesNavigator(
4141
onEditPollClickLambda(eventId)
4242
}
4343

44-
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>) {
45-
onPreviewAttachmentLambda(attachments)
44+
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>, inReplyToEventId: EventId?) {
45+
onPreviewAttachmentLambda(attachments, inReplyToEventId)
4646
}
4747

4848
override fun onNavigateToRoom(roomId: RoomId, serverNames: List<String>) {

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ class AttachmentsPreviewPresenterTest {
618618
dispatchers = testCoroutineDispatchers(),
619619
mediaOptimizationSelectorPresenterFactory = mediaOptimizationSelectorPresenterFactory,
620620
timelineMode = timelineMode,
621+
inReplyToEventId = null,
621622
)
622623
}
623624

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ class MessageComposerPresenterTest {
688688
val room = FakeJoinedRoom(
689689
typingNoticeResult = { Result.success(Unit) }
690690
)
691-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
691+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
692692
val navigator = FakeMessagesNavigator(
693693
onPreviewAttachmentLambda = onPreviewAttachmentLambda
694694
)
@@ -728,7 +728,7 @@ class MessageComposerPresenterTest {
728728
val room = FakeJoinedRoom(
729729
typingNoticeResult = { Result.success(Unit) }
730730
)
731-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
731+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
732732
val navigator = FakeMessagesNavigator(
733733
onPreviewAttachmentLambda = onPreviewAttachmentLambda
734734
)
@@ -785,7 +785,7 @@ class MessageComposerPresenterTest {
785785
val room = FakeJoinedRoom(
786786
typingNoticeResult = { Result.success(Unit) }
787787
)
788-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
788+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
789789
val navigator = FakeMessagesNavigator(
790790
onPreviewAttachmentLambda = onPreviewAttachmentLambda
791791
)
@@ -846,7 +846,7 @@ class MessageComposerPresenterTest {
846846
typingNoticeResult = { Result.success(Unit) }
847847
)
848848
val permissionPresenter = FakePermissionsPresenter().apply { setPermissionGranted() }
849-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
849+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
850850
val navigator = FakeMessagesNavigator(
851851
onPreviewAttachmentLambda = onPreviewAttachmentLambda
852852
)
@@ -870,7 +870,7 @@ class MessageComposerPresenterTest {
870870
typingNoticeResult = { Result.success(Unit) }
871871
)
872872
val permissionPresenter = FakePermissionsPresenter()
873-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
873+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
874874
val navigator = FakeMessagesNavigator(
875875
onPreviewAttachmentLambda = onPreviewAttachmentLambda
876876
)
@@ -896,7 +896,7 @@ class MessageComposerPresenterTest {
896896
typingNoticeResult = { Result.success(Unit) }
897897
)
898898
val permissionPresenter = FakePermissionsPresenter().apply { setPermissionGranted() }
899-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
899+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
900900
val navigator = FakeMessagesNavigator(
901901
onPreviewAttachmentLambda = onPreviewAttachmentLambda
902902
)
@@ -920,7 +920,7 @@ class MessageComposerPresenterTest {
920920
typingNoticeResult = { Result.success(Unit) }
921921
)
922922
val permissionPresenter = FakePermissionsPresenter()
923-
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment> -> }
923+
val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList<Attachment>, _: EventId? -> }
924924
val navigator = FakeMessagesNavigator(
925925
onPreviewAttachmentLambda = onPreviewAttachmentLambda
926926
)

0 commit comments

Comments
 (0)