Skip to content

Commit 37f3e25

Browse files
committed
Add "Copy caption" action for Event with Caption
1 parent b013b31 commit 37f3e25

File tree

4 files changed

+65
-3
lines changed

4 files changed

+65
-3
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ class MessagesPresenter @AssistedInject constructor(
273273
) = launch {
274274
when (action) {
275275
TimelineItemAction.CopyText -> handleCopyContents(targetEvent)
276+
TimelineItemAction.CopyCaption -> handleCopyCaption(targetEvent)
276277
TimelineItemAction.CopyLink -> handleCopyLink(targetEvent)
277278
TimelineItemAction.Redact -> handleActionRedact(targetEvent)
278279
TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting)
@@ -488,11 +489,17 @@ class MessagesPresenter @AssistedInject constructor(
488489
is TimelineItemStateContent -> event.content.body
489490
else -> return
490491
}
491-
492492
clipboardHelper.copyPlainText(content)
493-
494493
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
495494
snackbarDispatcher.post(SnackbarMessage(R.string.screen_room_timeline_message_copied))
496495
}
497496
}
497+
498+
private suspend fun handleCopyCaption(event: TimelineItem.Event) {
499+
val content = (event.content as? TimelineItemEventContentWithAttachment)?.caption ?: return
500+
clipboardHelper.copyPlainText(content)
501+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
502+
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_copied_to_clipboard))
503+
}
504+
}
498505
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class DefaultActionListPresenter @AssistedInject constructor(
137137
}
138138
}
139139

140+
// See order in https://www.figma.com/design/ux3tYoZV9WghC7hHT9Fhk0/Compound-iOS-Components?node-id=2946-2392
140141
private suspend fun buildActions(
141142
timelineItem: TimelineItem.Event,
142143
usersEventPermissions: UserEventPermissions,
@@ -184,6 +185,8 @@ class DefaultActionListPresenter @AssistedInject constructor(
184185
}
185186
if (timelineItem.content.canBeCopied()) {
186187
add(TimelineItemAction.CopyText)
188+
} else if ((timelineItem.content as? TimelineItemEventContentWithAttachment)?.caption.isNullOrBlank().not()) {
189+
add(TimelineItemAction.CopyCaption)
187190
}
188191
if (timelineItem.isRemote) {
189192
add(TimelineItemAction.CopyLink)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ sealed class TimelineItemAction(
2323
data object ViewInTimeline : TimelineItemAction(CommonStrings.action_view_in_timeline, CompoundDrawables.ic_compound_visibility_on)
2424
data object Forward : TimelineItemAction(CommonStrings.action_forward, CompoundDrawables.ic_compound_forward)
2525
data object CopyText : TimelineItemAction(CommonStrings.action_copy_text, CompoundDrawables.ic_compound_copy)
26+
data object CopyCaption : TimelineItemAction(CommonStrings.action_copy_caption, CompoundDrawables.ic_compound_copy)
2627
data object CopyLink : TimelineItemAction(CommonStrings.action_copy_link_to_message, CompoundDrawables.ic_compound_link)
2728
data object Redact : TimelineItemAction(CommonStrings.action_remove, CompoundDrawables.ic_compound_delete, destructive = true)
2829
data object Reply : TimelineItemAction(CommonStrings.action_reply, CompoundDrawables.ic_compound_reply)

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ class ActionListPresenterTest {
647647
TimelineItemAction.Reply,
648648
TimelineItemAction.Forward,
649649
TimelineItemAction.EditCaption,
650+
TimelineItemAction.CopyCaption,
650651
TimelineItemAction.RemoveCaption,
651652
TimelineItemAction.Pin,
652653
TimelineItemAction.CopyLink,
@@ -660,6 +661,54 @@ class ActionListPresenterTest {
660661
}
661662
}
662663

664+
@Test
665+
fun `present - compute for a media with caption item - other user event`() = runTest {
666+
val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true)
667+
moleculeFlow(RecompositionMode.Immediate) {
668+
presenter.present()
669+
}.test {
670+
val initialState = awaitItem()
671+
val messageEvent = aMessageEvent(
672+
isMine = false,
673+
isEditable = false,
674+
content = aTimelineItemImageContent(
675+
caption = A_CAPTION,
676+
),
677+
)
678+
initialState.eventSink.invoke(
679+
ActionListEvents.ComputeForMessage(
680+
event = messageEvent,
681+
userEventPermissions = aUserEventPermissions(
682+
canRedactOwn = true,
683+
canRedactOther = false,
684+
canSendMessage = true,
685+
canSendReaction = true,
686+
canPinUnpin = true,
687+
),
688+
)
689+
)
690+
val successState = awaitItem()
691+
assertThat(successState.target).isEqualTo(
692+
ActionListState.Target.Success(
693+
event = messageEvent,
694+
displayEmojiReactions = true,
695+
verifiedUserSendFailure = VerifiedUserSendFailure.None,
696+
actions = persistentListOf(
697+
TimelineItemAction.Reply,
698+
TimelineItemAction.Forward,
699+
TimelineItemAction.CopyCaption,
700+
TimelineItemAction.Pin,
701+
TimelineItemAction.CopyLink,
702+
TimelineItemAction.ViewSource,
703+
TimelineItemAction.Redact,
704+
)
705+
)
706+
)
707+
initialState.eventSink.invoke(ActionListEvents.Clear)
708+
assertThat(awaitItem().target).isEqualTo(ActionListState.Target.None)
709+
}
710+
}
711+
663712
@Test
664713
fun `present - compute for a state item in debug build`() = runTest {
665714
val presenter = createActionListPresenter(isDeveloperModeEnabled = true, isPinFeatureEnabled = true)
@@ -1105,7 +1154,9 @@ class ActionListPresenterTest {
11051154
val messageEvent = aMessageEvent(
11061155
isMine = true,
11071156
isEditable = false,
1108-
content = aTimelineItemVoiceContent(),
1157+
content = aTimelineItemVoiceContent(
1158+
caption = null,
1159+
),
11091160
)
11101161
initialState.eventSink.invoke(
11111162
ActionListEvents.ComputeForMessage(

0 commit comments

Comments
 (0)