Merge pull request #2653 from element-hq/feature/bma/copyPermalink

Copy permalink
This commit is contained in:
Benoit Marty 2024-04-03 17:38:38 +02:00 committed by GitHub
commit 4a2703810b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 122 additions and 36 deletions

1
changelog.d/2650.feature Normal file
View file

@ -0,0 +1 @@
Add action to copy permalink

View file

@ -89,6 +89,7 @@ import io.element.android.libraries.matrix.ui.room.canRedactOtherAsState
import io.element.android.libraries.matrix.ui.room.canRedactOwnAsState
import io.element.android.libraries.matrix.ui.room.canSendMessageAsState
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -273,6 +274,7 @@ class MessagesPresenter @AssistedInject constructor(
) = launch {
when (action) {
TimelineItemAction.Copy -> handleCopyContents(targetEvent)
TimelineItemAction.CopyLink -> handleCopyLink(targetEvent)
TimelineItemAction.Redact -> handleActionRedact(targetEvent)
TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState, enableTextFormatting)
TimelineItemAction.Reply,
@ -435,6 +437,20 @@ class MessagesPresenter @AssistedInject constructor(
event.eventId?.let { timelineState.eventSink(TimelineEvents.PollEndClicked(it)) }
}
private suspend fun handleCopyLink(event: TimelineItem.Event) {
event.eventId ?: return
room.getPermalinkFor(event.eventId).fold(
onSuccess = { permalink ->
clipboardHelper.copyPlainText(permalink)
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_link_copied_to_clipboard))
},
onFailure = {
Timber.e(it, "Failed to get permalink for event ${event.eventId}")
snackbarDispatcher.post(SnackbarMessage(CommonStrings.common_error))
}
)
}
private suspend fun handleCopyContents(event: TimelineItem.Event) {
val content = when (event.content) {
is TimelineItemTextBasedContent -> event.content.body

View file

@ -96,6 +96,7 @@ class ActionListPresenter @Inject constructor(
is TimelineItemStateContent -> {
buildList {
add(TimelineItemAction.Copy)
add(TimelineItemAction.CopyLink)
if (isDeveloperModeEnabled) {
add(TimelineItemAction.ViewSource)
}
@ -119,6 +120,7 @@ class ActionListPresenter @Inject constructor(
if (timelineItem.content.canBeCopied()) {
add(TimelineItemAction.Copy)
}
add(TimelineItemAction.CopyLink)
if (isDeveloperModeEnabled) {
add(TimelineItemAction.ViewSource)
}
@ -136,6 +138,7 @@ class ActionListPresenter @Inject constructor(
add(TimelineItemAction.Reply)
add(TimelineItemAction.Forward)
}
add(TimelineItemAction.CopyLink)
if (isDeveloperModeEnabled) {
add(TimelineItemAction.ViewSource)
}
@ -176,6 +179,7 @@ class ActionListPresenter @Inject constructor(
if (timelineItem.content.canBeCopied()) {
add(TimelineItemAction.Copy)
}
add(TimelineItemAction.CopyLink)
if (isDeveloperModeEnabled) {
add(TimelineItemAction.ViewSource)
}

View file

@ -135,6 +135,7 @@ fun aTimelineItemActionList(): ImmutableList<TimelineItemAction> {
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.Edit,
TimelineItemAction.Redact,
TimelineItemAction.ReportContent,
@ -146,6 +147,7 @@ fun aTimelineItemPollActionList(): ImmutableList<TimelineItemAction> {
TimelineItemAction.EndPoll,
TimelineItemAction.Reply,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.ReportContent,
TimelineItemAction.Redact,

View file

@ -31,6 +31,7 @@ sealed class TimelineItemAction(
) {
data object Forward : TimelineItemAction(CommonStrings.action_forward, CompoundDrawables.ic_compound_forward)
data object Copy : TimelineItemAction(CommonStrings.action_copy, CompoundDrawables.ic_compound_copy)
data object CopyLink : TimelineItemAction(CommonStrings.action_copy_link_to_message, CompoundDrawables.ic_compound_link)
data object Redact : TimelineItemAction(CommonStrings.action_remove, CompoundDrawables.ic_compound_delete, destructive = true)
data object Reply : TimelineItemAction(CommonStrings.action_reply, CompoundDrawables.ic_compound_reply)
data object ReplyInThread : TimelineItemAction(CommonStrings.action_reply_in_thread, CompoundDrawables.ic_compound_reply)

View file

@ -231,6 +231,27 @@ class MessagesPresenterTest {
}
}
@Test
fun `present - handle action copy link`() = runTest {
val clipboardHelper = FakeClipboardHelper()
val event = aMessageEvent()
val matrixRoom = FakeMatrixRoom(
permalinkResult = { Result.success("a link") },
)
val presenter = createMessagesPresenter(
clipboardHelper = clipboardHelper,
matrixRoom = matrixRoom,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.CopyLink, event))
assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
assertThat(clipboardHelper.clipboardContents).isEqualTo("a link")
}
}
@Test
fun `present - handle action reply`() = runTest {
val presenter = createMessagesPresenter()

View file

@ -153,6 +153,7 @@ class ActionListPresenterTest {
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.ReportContent,
)
@ -193,6 +194,7 @@ class ActionListPresenterTest {
actions = persistentListOf(
TimelineItemAction.Forward,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.ReportContent,
)
@ -232,6 +234,7 @@ class ActionListPresenterTest {
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.ReportContent,
TimelineItemAction.Redact,
@ -272,6 +275,7 @@ class ActionListPresenterTest {
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.ReportContent,
TimelineItemAction.Redact,
@ -315,6 +319,7 @@ class ActionListPresenterTest {
TimelineItemAction.Forward,
TimelineItemAction.Edit,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.Redact,
)
@ -357,6 +362,7 @@ class ActionListPresenterTest {
TimelineItemAction.Forward,
TimelineItemAction.Edit,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
)
)
@ -396,6 +402,7 @@ class ActionListPresenterTest {
actions = persistentListOf(
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
TimelineItemAction.Redact,
)
@ -435,6 +442,7 @@ class ActionListPresenterTest {
displayEmojiReactions = false,
actions = persistentListOf(
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.ViewSource,
)
)
@ -473,6 +481,7 @@ class ActionListPresenterTest {
displayEmojiReactions = false,
actions = persistentListOf(
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
)
)
)
@ -513,6 +522,7 @@ class ActionListPresenterTest {
TimelineItemAction.Forward,
TimelineItemAction.Edit,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)
@ -595,6 +605,7 @@ class ActionListPresenterTest {
actions = persistentListOf(
TimelineItemAction.Edit,
TimelineItemAction.Copy,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)
@ -632,6 +643,7 @@ class ActionListPresenterTest {
TimelineItemAction.Reply,
TimelineItemAction.Edit,
TimelineItemAction.EndPoll,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)
@ -668,6 +680,7 @@ class ActionListPresenterTest {
actions = persistentListOf(
TimelineItemAction.Reply,
TimelineItemAction.EndPoll,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)
@ -703,6 +716,7 @@ class ActionListPresenterTest {
displayEmojiReactions = true,
actions = persistentListOf(
TimelineItemAction.Reply,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)
@ -738,6 +752,7 @@ class ActionListPresenterTest {
actions = persistentListOf(
TimelineItemAction.Reply,
TimelineItemAction.Forward,
TimelineItemAction.CopyLink,
TimelineItemAction.Redact,
)
)

View file

@ -328,5 +328,12 @@ interface MatrixRoom : Closeable {
*/
fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver>
/**
* Get the permalink for the provided [eventId].
* @param eventId The event id to get the permalink for.
* @return The permalink, or a failure.
*/
suspend fun getPermalinkFor(eventId: EventId): Result<String>
override fun close() = destroy()
}

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.matrix.impl.room
import io.element.android.appconfig.MatrixConfiguration
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.childScope
import io.element.android.libraries.matrix.api.core.EventId
@ -711,6 +712,19 @@ class RustMatrixRoom(
)
}
override suspend fun getPermalinkFor(eventId: EventId): Result<String> {
// FIXME Use the SDK API once https://github.com/matrix-org/matrix-rust-sdk/issues/3259 has been done
// Now use a simple builder
return runCatching {
buildString {
append(MatrixConfiguration.MATRIX_TO_PERMALINK_BASE_URL)
append(roomId.value)
append("/")
append(eventId.value)
}
}
}
private fun sendAttachment(files: List<File>, handle: () -> SendAttachmentJoinHandle): Result<MediaUploadHandler> {
return runCatching {
MediaUploadHandlerImpl(files, handle())

View file

@ -84,6 +84,7 @@ class FakeMatrixRoom(
override val activeMemberCount: Long = 234L,
val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(),
private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(),
private var permalinkResult: () -> Result<String> = { Result.success("link") },
canRedactOwn: Boolean = false,
canRedactOther: Boolean = false,
) : MatrixRoom {
@ -273,6 +274,10 @@ class FakeMatrixRoom(
return cancelSendResult
}
override suspend fun getPermalinkFor(eventId: EventId): Result<String> {
return permalinkResult()
}
override suspend fun editMessage(
originalEventId: EventId?,
transactionId: TransactionId?,

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:654d73d145ba000b0a58e1974206bd9c7970a5a384186336469504cd35b19890
size 29036
oid sha256:f5aa4c9aab5727c56ee6efcf8c136cca8276d54695d28a4f548af9d51f3df4b9
size 34264

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:32c2a61124bd68fc1921439f834744c1a40fa615de1270b8d97dd5c4365bbd25
size 39317
oid sha256:0d31d3549643b37a21f043f9ec9a33fa93e25f4004b077af713097855235effe
size 44276

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:17c00b93a8073bdc2741f0492623ffef80d37e3f3fc8744650233d489b6efc82
size 39866
oid sha256:dfe460e8bab0a27a31984ce8c85ed98aef2a994584f724375cd436d5c1c7c6ca
size 44758

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2bcd9a9db22a88210afa8ba3700abc1895d040c044ec11aa324d720651a3bc0b
size 40404
oid sha256:e287869aa819ff569ab187f8995260410c47c32817caba61ba7639d6b0a2fe44
size 45245

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:00804549fdbada3e48531ffab2bd5e013cd592d11c56e65eb2385b07910bc6e3
size 39998
oid sha256:1f6602e1e19e1c5b545522ff7444b294cc926d02b1910f196461a9770f64af4a
size 44882

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4f71497d55a8cb048b3249221e8b24c883e3015533f4e543650b742542b5daac
size 40645
oid sha256:4c321a39333a03b5eadf287e2a37e809da3620205d97caa1ae63f9ab99dc4f82
size 45464

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0d4ad5e2fb1b518495f23b70fde606d791536adbea3ffac76c5fbb54e4c22138
size 41343
oid sha256:135f36df3ade2a4e210fc5560b8a00593e842153424da5efcd25b5c64036f59c
size 46240

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:675bbd412179ad4960c6cf78f973c67fd11809340e414f7ebf3eef5e41434e0e
size 41201
oid sha256:ea154dca2cde0829bb70dbcf9e032e63d052c35194b159dd72db8c72a58863b0
size 46082

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33e82110711be0bdff074df90c93c3911e77bf53672df336c5fa6bf74f28d86f
size 28191
oid sha256:f2124f3afde9e0fc4e42733d3624f69a74b898a035e47e4369acfad2834d0e02
size 33378

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7220aa1b48506d58f800d71c0aa1b3ea1650fa2153246d1572213e5ff0170b04
size 27759
oid sha256:61da843a4fd576317ce1dab5a95cba47f269c96096157f880da5c6f3f8a944c7
size 32148

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:36262a1ed8e2029519eb519e64dd973a5170269c04ad509464596b87bcbd9247
size 37891
oid sha256:0345399ddbe34e4fb13468571921fb2de8db1b7db01cb6a7439970b15046d37e
size 42361

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c75a4422846ab1e4d12c48916a5f306b506cd1c082f1709104560634106a8ba
size 38420
oid sha256:63b40ee6d9b4fa6f049dedbfc628380069360e67129b8e53b94e04d25b5897bf
size 42898

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e28f6654d3fd5fb6e332a999fda8393bdff4988a87039e683cd94a251f4b9b07
size 38926
oid sha256:a5d9f66ab910df80652ef7658869ee05f570af134f1e05e8fc5b19d9a05a453e
size 43388

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9a2cd0f46f405978dda374ce865bc5f409280716830fcd2d29e290c11b36f118
size 38538
oid sha256:e37056a6b4d6416a77af752d04b040d1fc8dbd65bdaaae8d50c05e7a11309d05
size 43013

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eac8803bd70cc677841f124eeb19e70f50a257cf89360410618db2c2f601c27a
size 39178
oid sha256:995e4bfb172bbc09177d1427f63063f86348cedd5e497a5341eb0e8374e80cc9
size 43634

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:96c95a7ca59ed0d8bba59e735a2248d2cee3d0a8d4c045a0491fe1731c8c9574
size 39848
oid sha256:1d086a8c7b3f9e6dbbf30495ba1d209b8436a8ef5d31dc9a3605a0b2cd9ce72e
size 44276

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a395ca5f5dbf4647ad1b5dea90f3c7a1cada2e934c4053f5ecc1e793e4efa879
size 39718
oid sha256:013dce6e34f67c62a514b958b502a511c9975551eb745b4e502c5794584e730a
size 44150

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4bf2d4ecc1c9e67cd833ca5cd61b4f77e5da9381e4425f332b91e7fbf8d9d0f4
size 26781
oid sha256:cda82238c49b88bf0da5f462bcb05dee7fe2e659345c03997456be635ff4bae2
size 31287