Merge pull request #3701 from element-hq/renovate/org.matrix.rustcomponents-sdk-android-0.x

Update dependency org.matrix.rustcomponents:sdk-android to v0.2.55
This commit is contained in:
Benoit Marty 2024-10-18 09:30:26 +02:00 committed by GitHub
commit 3cdf533c33
26 changed files with 176 additions and 148 deletions

View file

@ -22,6 +22,8 @@ import io.element.android.features.location.impl.common.permissions.PermissionsS
import io.element.android.features.messages.test.FakeMessageComposerContext import io.element.android.features.messages.test.FakeMessageComposerContext
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.MessageComposerMode
@ -397,8 +399,7 @@ class SendLocationPresenterTest {
) )
fakeMessageComposerContext.apply { fakeMessageComposerContext.apply {
composerMode = MessageComposerMode.Edit( composerMode = MessageComposerMode.Edit(
eventId = null, eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(),
transactionId = null,
content = "" content = ""
) )
} }
@ -446,8 +447,7 @@ class SendLocationPresenterTest {
) )
fakeMessageComposerContext.apply { fakeMessageComposerContext.apply {
composerMode = MessageComposerMode.Edit( composerMode = MessageComposerMode.Edit(
eventId = null, eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(),
transactionId = null,
content = "" content = ""
) )
} }

View file

@ -9,11 +9,11 @@ package io.element.android.features.messages.impl
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
sealed interface MessagesEvents { sealed interface MessagesEvents {
data class HandleAction(val action: TimelineItemAction, val event: TimelineItem.Event) : MessagesEvents data class HandleAction(val action: TimelineItemAction, val event: TimelineItem.Event) : MessagesEvents
data class ToggleReaction(val emoji: String, val uniqueId: UniqueId) : MessagesEvents data class ToggleReaction(val emoji: String, val eventOrTransactionId: EventOrTransactionId) : MessagesEvents
data class InviteDialogDismissed(val action: InviteDialogAction) : MessagesEvents data class InviteDialogDismissed(val action: InviteDialogAction) : MessagesEvents
data object Dismiss : MessagesEvents data object Dismiss : MessagesEvents
} }

View file

@ -62,7 +62,6 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
@ -73,6 +72,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.ui.messages.reply.map import io.element.android.libraries.matrix.ui.messages.reply.map
import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.room.canCall import io.element.android.libraries.matrix.ui.room.canCall
@ -191,7 +191,7 @@ class MessagesPresenter @AssistedInject constructor(
) )
} }
is MessagesEvents.ToggleReaction -> { is MessagesEvents.ToggleReaction -> {
localCoroutineScope.toggleReaction(event.emoji, event.uniqueId) localCoroutineScope.toggleReaction(event.emoji, event.eventOrTransactionId)
} }
is MessagesEvents.InviteDialogDismissed -> { is MessagesEvents.InviteDialogDismissed -> {
hasDismissedInviteDialog = true hasDismissedInviteDialog = true
@ -327,10 +327,10 @@ class MessagesPresenter @AssistedInject constructor(
private fun CoroutineScope.toggleReaction( private fun CoroutineScope.toggleReaction(
emoji: String, emoji: String,
uniqueId: UniqueId, eventOrTransactionId: EventOrTransactionId,
) = launch(dispatchers.io) { ) = launch(dispatchers.io) {
timelineController.invokeOnCurrentTimeline { timelineController.invokeOnCurrentTimeline {
toggleReaction(emoji, uniqueId) toggleReaction(emoji, eventOrTransactionId)
.onFailure { Timber.e(it) } .onFailure { Timber.e(it) }
} }
} }
@ -360,7 +360,7 @@ class MessagesPresenter @AssistedInject constructor(
private suspend fun handleActionRedact(event: TimelineItem.Event) { private suspend fun handleActionRedact(event: TimelineItem.Event) {
timelineController.invokeOnCurrentTimeline { timelineController.invokeOnCurrentTimeline {
redactEvent(eventId = event.eventId, transactionId = event.transactionId, reason = null) redactEvent(eventOrTransactionId = event.eventOrTransactionId, reason = null)
.onFailure { Timber.e(it) } .onFailure { Timber.e(it) }
} }
} }
@ -377,8 +377,7 @@ class MessagesPresenter @AssistedInject constructor(
} }
else -> { else -> {
val composerMode = MessageComposerMode.Edit( val composerMode = MessageComposerMode.Edit(
targetEvent.eventId, targetEvent.eventOrTransactionId,
targetEvent.transactionId,
(targetEvent.content as? TimelineItemTextBasedContent)?.let { (targetEvent.content as? TimelineItemTextBasedContent)?.let {
if (enableTextFormatting) { if (enableTextFormatting) {
it.htmlBody ?: it.body it.htmlBody ?: it.body

View file

@ -168,7 +168,7 @@ fun MessagesView(
} }
fun onEmojiReactionClick(emoji: String, event: TimelineItem.Event) { fun onEmojiReactionClick(emoji: String, event: TimelineItem.Event) {
state.eventSink(MessagesEvents.ToggleReaction(emoji, event.id)) state.eventSink(MessagesEvents.ToggleReaction(emoji, event.eventOrTransactionId))
} }
fun onEmojiReactionLongClick(emoji: String, event: TimelineItem.Event) { fun onEmojiReactionLongClick(emoji: String, event: TimelineItem.Event) {

View file

@ -53,6 +53,7 @@ import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.timeline.TimelineException import io.element.android.libraries.matrix.api.timeline.TimelineException
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.matrix.ui.messages.reply.map import io.element.android.libraries.matrix.ui.messages.reply.map
@ -442,12 +443,11 @@ class MessageComposerPresenter @Inject constructor(
intentionalMentions = message.intentionalMentions intentionalMentions = message.intentionalMentions
) )
is MessageComposerMode.Edit -> { is MessageComposerMode.Edit -> {
val eventId = capturedMode.eventId
val transactionId = capturedMode.transactionId
timelineController.invokeOnCurrentTimeline { timelineController.invokeOnCurrentTimeline {
// First try to edit the message in the current timeline // First try to edit the message in the current timeline
editMessage(eventId, transactionId, message.markdown, message.html, message.intentionalMentions) editMessage(capturedMode.eventOrTransactionId, message.markdown, message.html, message.intentionalMentions)
.onFailure { cause -> .onFailure { cause ->
val eventId = capturedMode.eventOrTransactionId.eventId
if (cause is TimelineException.EventNotFound && eventId != null) { if (cause is TimelineException.EventNotFound && eventId != null) {
// if the event is not found in the timeline, try to edit the message directly // if the event is not found in the timeline, try to edit the message directly
room.editMessage(eventId, message.markdown, message.html, message.intentionalMentions) room.editMessage(eventId, message.markdown, message.html, message.intentionalMentions)
@ -581,8 +581,7 @@ class MessageComposerPresenter @Inject constructor(
when (val draftType = draft.draftType) { when (val draftType = draft.draftType) {
ComposerDraftType.NewMessage -> messageComposerContext.composerMode = MessageComposerMode.Normal ComposerDraftType.NewMessage -> messageComposerContext.composerMode = MessageComposerMode.Normal
is ComposerDraftType.Edit -> messageComposerContext.composerMode = MessageComposerMode.Edit( is ComposerDraftType.Edit -> messageComposerContext.composerMode = MessageComposerMode.Edit(
eventId = draftType.eventId, eventOrTransactionId = draftType.eventId.toEventOrTransactionId(),
transactionId = null,
content = htmlText ?: markdownText content = htmlText ?: markdownText
) )
is ComposerDraftType.Reply -> { is ComposerDraftType.Reply -> {
@ -611,7 +610,7 @@ class MessageComposerPresenter @Inject constructor(
val draftType = when (val mode = messageComposerContext.composerMode) { val draftType = when (val mode = messageComposerContext.composerMode) {
is MessageComposerMode.Normal -> ComposerDraftType.NewMessage is MessageComposerMode.Normal -> ComposerDraftType.NewMessage
is MessageComposerMode.Edit -> { is MessageComposerMode.Edit -> {
mode.eventId?.let { eventId -> ComposerDraftType.Edit(eventId) } mode.eventOrTransactionId.eventId?.let { eventId -> ComposerDraftType.Edit(eventId) }
} }
is MessageComposerMode.Reply -> ComposerDraftType.Reply(mode.eventId) is MessageComposerMode.Reply -> ComposerDraftType.Reply(mode.eventId)
} }

View file

@ -16,13 +16,13 @@ import androidx.compose.ui.Modifier
import io.element.android.emojibasebindings.Emoji import io.element.android.emojibasebindings.Emoji
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet
import io.element.android.libraries.designsystem.theme.components.hide import io.element.android.libraries.designsystem.theme.components.hide
import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CustomReactionBottomSheet( fun CustomReactionBottomSheet(
state: CustomReactionState, state: CustomReactionState,
onSelectEmoji: (UniqueId, Emoji) -> Unit, onSelectEmoji: (EventOrTransactionId, Emoji) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val sheetState = rememberModalBottomSheetState() val sheetState = rememberModalBottomSheetState()
@ -37,7 +37,7 @@ fun CustomReactionBottomSheet(
if (target?.event == null) return if (target?.event == null) return
sheetState.hide(coroutineScope) { sheetState.hide(coroutineScope) {
state.eventSink(CustomReactionEvents.DismissCustomReactionSheet) state.eventSink(CustomReactionEvents.DismissCustomReactionSheet)
onSelectEmoji(target.event.id, emoji) onSelectEmoji(target.event.eventOrTransactionId, emoji)
} }
} }

View file

@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShieldProvider import io.element.android.libraries.matrix.api.timeline.item.event.MessageShieldProvider
@ -92,6 +93,9 @@ sealed interface TimelineItem {
val isRemote = eventId != null val isRemote = eventId != null
val eventOrTransactionId: EventOrTransactionId
get() = EventOrTransactionId.from(eventId = eventId, transactionId = transactionId)
// No need to be lazy here? // No need to be lazy here?
val messageShield: MessageShield? = messageShieldProvider(strict = false) val messageShield: MessageShield? = messageShieldProvider(strict = false)

View file

@ -47,8 +47,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkParser
@ -56,13 +54,14 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID_2 import io.element.android.libraries.matrix.test.A_SESSION_ID_2
import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
@ -164,8 +163,9 @@ class MessagesPresenterTest {
@Test @Test
fun `present - handle toggling a reaction`() = runTest { fun `present - handle toggling a reaction`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
val toggleReactionSuccess = lambdaRecorder { _: String, _: UniqueId -> Result.success(Unit) } val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId -> Result.success(Unit) }
val toggleReactionFailure = lambdaRecorder { _: String, _: UniqueId -> Result.failure<Unit>(IllegalStateException("Failed to send reaction")) } val toggleReactionFailure =
lambdaRecorder { _: String, _: EventOrTransactionId -> Result.failure<Unit>(IllegalStateException("Failed to send reaction")) }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
this.toggleReactionLambda = toggleReactionSuccess this.toggleReactionLambda = toggleReactionSuccess
@ -185,23 +185,23 @@ class MessagesPresenterTest {
}.test { }.test {
skipItems(1) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(MessagesEvents.ToggleReaction("👍", A_UNIQUE_ID)) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
assert(toggleReactionSuccess) assert(toggleReactionSuccess)
.isCalledOnce() .isCalledOnce()
.with(value("👍"), value(A_UNIQUE_ID)) .with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId()))
// No crashes when sending a reaction failed // No crashes when sending a reaction failed
timeline.apply { toggleReactionLambda = toggleReactionFailure } timeline.apply { toggleReactionLambda = toggleReactionFailure }
initialState.eventSink(MessagesEvents.ToggleReaction("👍", A_UNIQUE_ID)) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
assert(toggleReactionFailure) assert(toggleReactionFailure)
.isCalledOnce() .isCalledOnce()
.with(value("👍"), value(A_UNIQUE_ID)) .with(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId()))
} }
} }
@Test @Test
fun `present - handle toggling a reaction twice`() = runTest { fun `present - handle toggling a reaction twice`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
val toggleReactionSuccess = lambdaRecorder { _: String, _: UniqueId -> Result.success(Unit) } val toggleReactionSuccess = lambdaRecorder { _: String, _: EventOrTransactionId -> Result.success(Unit) }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
this.toggleReactionLambda = toggleReactionSuccess this.toggleReactionLambda = toggleReactionSuccess
@ -220,13 +220,13 @@ class MessagesPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(MessagesEvents.ToggleReaction("👍", A_UNIQUE_ID)) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
initialState.eventSink(MessagesEvents.ToggleReaction("👍", A_UNIQUE_ID)) initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId()))
assert(toggleReactionSuccess) assert(toggleReactionSuccess)
.isCalledExactly(2) .isCalledExactly(2)
.withSequence( .withSequence(
listOf(value("👍"), value(A_UNIQUE_ID)), listOf(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId())),
listOf(value("👍"), value(A_UNIQUE_ID)), listOf(value("👍"), value(AN_EVENT_ID.toEventOrTransactionId())),
) )
skipItems(1) skipItems(1)
} }
@ -452,8 +452,7 @@ class MessagesPresenterTest {
composerRecorder.assertSingle( composerRecorder.assertSingle(
MessageComposerEvents.SetMode( MessageComposerEvents.SetMode(
composerMode = MessageComposerMode.Edit( composerMode = MessageComposerMode.Edit(
eventId = AN_EVENT_ID, eventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(),
transactionId = null,
content = (aMessageEvent().content as TimelineItemTextContent).body content = (aMessageEvent().content as TimelineItemTextContent).body
) )
) )
@ -506,7 +505,7 @@ class MessagesPresenterTest {
canUserPinUnpinResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) },
) )
val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(Unit) } val redactEventLambda = lambdaRecorder { _: EventOrTransactionId, _: String? -> Result.success(Unit) }
liveTimeline.redactEventLambda = redactEventLambda liveTimeline.redactEventLambda = redactEventLambda
val presenter = createMessagesPresenter( val presenter = createMessagesPresenter(
matrixRoom = matrixRoom, matrixRoom = matrixRoom,
@ -521,7 +520,7 @@ class MessagesPresenterTest {
awaitItem() awaitItem()
assert(redactEventLambda) assert(redactEventLambda)
.isCalledOnce() .isCalledOnce()
.with(value(messageEvent.eventId), value(messageEvent.transactionId), value(null)) .with(value(messageEvent.eventOrTransactionId), value(null))
} }
} }

View file

@ -355,7 +355,7 @@ class MessagesViewTest {
state = state, state = state,
) )
rule.onAllNodesWithText("👍️").onFirst().performClick() rule.onAllNodesWithText("👍️").onFirst().performClick()
eventsRecorder.assertSingle(MessagesEvents.ToggleReaction("👍️", timelineItem.id)) eventsRecorder.assertSingle(MessagesEvents.ToggleReaction("👍️", timelineItem.eventOrTransactionId))
} }
@Test @Test
@ -484,7 +484,7 @@ class MessagesViewTest {
// Give time for the close animation to complete // Give time for the close animation to complete
rule.mainClock.advanceTimeBy(milliseconds = 1_000) rule.mainClock.advanceTimeBy(milliseconds = 1_000)
customReactionStateEventsRecorder.assertSingle(CustomReactionEvents.DismissCustomReactionSheet) customReactionStateEventsRecorder.assertSingle(CustomReactionEvents.DismissCustomReactionSheet)
eventsRecorder.assertSingle(MessagesEvents.ToggleReaction(aUnicode, timelineItem.id)) eventsRecorder.assertSingle(MessagesEvents.ToggleReaction(aUnicode, timelineItem.eventOrTransactionId))
} }
@Test @Test

View file

@ -32,7 +32,6 @@ import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.ImageInfo
import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.media.VideoInfo
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
@ -44,7 +43,9 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
import io.element.android.libraries.matrix.api.timeline.TimelineException import io.element.android.libraries.matrix.api.timeline.TimelineException
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.test.ANOTHER_MESSAGE import io.element.android.libraries.matrix.test.ANOTHER_MESSAGE
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_MESSAGE
@ -355,7 +356,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - edit sent message`() = runTest { fun `present - edit sent message`() = runTest {
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<IntentionalMention> -> val editMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> ->
Result.success(Unit) Result.success(Unit)
} }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
@ -392,7 +393,7 @@ class MessageComposerPresenterTest {
assert(editMessageLambda) assert(editMessageLambda)
.isCalledOnce() .isCalledOnce()
.with(value(AN_EVENT_ID), value(null), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any()) .with(value(AN_EVENT_ID.toEventOrTransactionId()), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any())
assertThat(analyticsService.capturedEvents).containsExactly( assertThat(analyticsService.capturedEvents).containsExactly(
Composer( Composer(
@ -407,7 +408,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - edit sent message event not found`() = runTest { fun `present - edit sent message event not found`() = runTest {
val timelineEditMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<IntentionalMention> -> val timelineEditMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> ->
Result.failure<Unit>(TimelineException.EventNotFound) Result.failure<Unit>(TimelineException.EventNotFound)
} }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
@ -448,7 +449,7 @@ class MessageComposerPresenterTest {
assert(timelineEditMessageLambda) assert(timelineEditMessageLambda)
.isCalledOnce() .isCalledOnce()
.with(value(AN_EVENT_ID), value(null), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any()) .with(value(AN_EVENT_ID.toEventOrTransactionId()), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any())
assert(roomEditMessageLambda) assert(roomEditMessageLambda)
.isCalledOnce() .isCalledOnce()
@ -467,7 +468,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - edit not sent message`() = runTest { fun `present - edit not sent message`() = runTest {
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<IntentionalMention> -> val editMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> ->
Result.success(Unit) Result.success(Unit)
} }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
@ -487,7 +488,7 @@ class MessageComposerPresenterTest {
}.test { }.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.textEditorState.messageHtml()).isEqualTo("") assertThat(initialState.textEditorState.messageHtml()).isEqualTo("")
val mode = anEditMode(eventId = null, transactionId = A_TRANSACTION_ID) val mode = anEditMode(eventOrTransactionId = A_TRANSACTION_ID.toEventOrTransactionId())
initialState.eventSink.invoke(MessageComposerEvents.SetMode(mode)) initialState.eventSink.invoke(MessageComposerEvents.SetMode(mode))
val withMessageState = awaitItem() val withMessageState = awaitItem()
assertThat(withMessageState.mode).isEqualTo(mode) assertThat(withMessageState.mode).isEqualTo(mode)
@ -504,7 +505,7 @@ class MessageComposerPresenterTest {
assert(editMessageLambda) assert(editMessageLambda)
.isCalledOnce() .isCalledOnce()
.with(value(null), value(A_TRANSACTION_ID), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any()) .with(value(A_TRANSACTION_ID.toEventOrTransactionId()), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any())
assertThat(analyticsService.capturedEvents).containsExactly( assertThat(analyticsService.capturedEvents).containsExactly(
Composer( Composer(
@ -1058,7 +1059,7 @@ class MessageComposerPresenterTest {
val replyMessageLambda = lambdaRecorder { _: EventId, _: String, _: String?, _: List<IntentionalMention>, _: Boolean -> val replyMessageLambda = lambdaRecorder { _: EventId, _: String, _: String?, _: List<IntentionalMention>, _: Boolean ->
Result.success(Unit) Result.success(Unit)
} }
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<IntentionalMention> -> val editMessageLambda = lambdaRecorder { _: EventOrTransactionId, _: String, _: String?, _: List<IntentionalMention> ->
Result.success(Unit) Result.success(Unit)
} }
val timeline = FakeTimeline().apply { val timeline = FakeTimeline().apply {
@ -1128,7 +1129,7 @@ class MessageComposerPresenterTest {
assert(editMessageLambda) assert(editMessageLambda)
.isCalledOnce() .isCalledOnce()
.with(any(), any(), any(), any(), value(listOf(IntentionalMention.User(A_USER_ID_3)))) .with(any(), any(), any(), value(listOf(IntentionalMention.User(A_USER_ID_3))))
skipItems(1) skipItems(1)
} }
@ -1516,10 +1517,9 @@ class MessageComposerPresenterTest {
} }
fun anEditMode( fun anEditMode(
eventId: EventId? = AN_EVENT_ID, eventOrTransactionId: EventOrTransactionId = AN_EVENT_ID.toEventOrTransactionId(),
message: String = A_MESSAGE, message: String = A_MESSAGE,
transactionId: TransactionId? = null, ) = MessageComposerMode.Edit(eventOrTransactionId, message)
) = MessageComposerMode.Edit(eventId, transactionId, message)
fun aReplyMode() = MessageComposerMode.Reply( fun aReplyMode() = MessageComposerMode.Reply(
replyToDetails = InReplyToDetails.Loading(AN_EVENT_ID), replyToDetails = InReplyToDetails.Loading(AN_EVENT_ID),

View file

@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.TimelineProvider import io.element.android.libraries.matrix.api.timeline.TimelineProvider
import io.element.android.libraries.matrix.api.timeline.getActiveTimeline import io.element.android.libraries.matrix.api.timeline.getActiveTimeline
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import javax.inject.Inject import javax.inject.Inject
@ -63,8 +64,7 @@ class PollRepository @Inject constructor(
timelineProvider timelineProvider
.getActiveTimeline() .getActiveTimeline()
.redactEvent( .redactEvent(
eventId = pollStartId, eventOrTransactionId = pollStartId.toEventOrTransactionId(),
transactionId = null,
reason = null, reason = null,
) )
} }

View file

@ -20,10 +20,11 @@ import io.element.android.features.poll.impl.aPollTimelineItems
import io.element.android.features.poll.impl.anOngoingPollContent import io.element.android.features.poll.impl.anOngoingPollContent
import io.element.android.features.poll.impl.data.PollRepository import io.element.android.features.poll.impl.data.PollRepository
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.matrix.api.poll.PollKind
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
@ -466,7 +467,7 @@ class CreatePollPresenterTest {
@Test @Test
fun `delete confirms`() = runTest { fun `delete confirms`() = runTest {
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId)) val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId))
val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(Unit) } val redactEventLambda = lambdaRecorder { _: EventOrTransactionId, _: String? -> Result.success(Unit) }
timeline.redactEventLambda = redactEventLambda timeline.redactEventLambda = redactEventLambda
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -481,7 +482,7 @@ class CreatePollPresenterTest {
@Test @Test
fun `delete can be cancelled`() = runTest { fun `delete can be cancelled`() = runTest {
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId)) val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId))
val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(Unit) } val redactEventLambda = lambdaRecorder { _: EventOrTransactionId, _: String? -> Result.success(Unit) }
timeline.redactEventLambda = redactEventLambda timeline.redactEventLambda = redactEventLambda
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -499,7 +500,7 @@ class CreatePollPresenterTest {
@Test @Test
fun `delete can be confirmed`() = runTest { fun `delete can be confirmed`() = runTest {
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId)) val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId))
val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(Unit) } val redactEventLambda = lambdaRecorder { _: EventOrTransactionId, _: String? -> Result.success(Unit) }
timeline.redactEventLambda = redactEventLambda timeline.redactEventLambda = redactEventLambda
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -512,7 +513,7 @@ class CreatePollPresenterTest {
} }
assert(redactEventLambda) assert(redactEventLambda)
.isCalledOnce() .isCalledOnce()
.with(value(pollEventId), value(null), any()) .with(value(pollEventId.toEventOrTransactionId()), any())
} }
} }

View file

@ -168,7 +168,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
timber = "com.jakewharton.timber:timber:5.0.1" timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.54" matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.55"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }

View file

@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
@ -29,6 +28,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerL
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
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.EventOrTransactionId
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -150,7 +150,7 @@ interface MatrixRoom : Closeable {
suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit>
suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit>

View file

@ -11,7 +11,6 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.ImageInfo
@ -20,7 +19,9 @@ import io.element.android.libraries.matrix.api.media.VideoInfo
import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.matrix.api.poll.PollKind
import io.element.android.libraries.matrix.api.room.IntentionalMention import io.element.android.libraries.matrix.api.room.IntentionalMention
import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import java.io.File import java.io.File
@ -57,8 +58,7 @@ interface Timeline : AutoCloseable {
): Result<Unit> ): Result<Unit>
suspend fun editMessage( suspend fun editMessage(
originalEventId: EventId?, eventOrTransactionId: EventOrTransactionId,
transactionId: TransactionId?,
body: String, htmlBody: String?, body: String, htmlBody: String?,
intentionalMentions: List<IntentionalMention>, intentionalMentions: List<IntentionalMention>,
): Result<Unit> ): Result<Unit>
@ -89,17 +89,18 @@ interface Timeline : AutoCloseable {
progressCallback: ProgressCallback? progressCallback: ProgressCallback?
): Result<MediaUploadHandler> ): Result<MediaUploadHandler>
suspend fun redactEvent(eventId: EventId?, transactionId: TransactionId?, reason: String?): Result<Unit> suspend fun redactEvent(eventOrTransactionId: EventOrTransactionId, reason: String?): Result<Unit>
suspend fun sendAudio(file: File, audioInfo: AudioInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> suspend fun sendAudio(file: File, audioInfo: AudioInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler>
suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit>
suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit>
suspend fun cancelSend(transactionId: TransactionId): Result<Unit> suspend fun cancelSend(transactionId: TransactionId): Result<Unit> =
redactEvent(transactionId.toEventOrTransactionId(), reason = null)
/** /**
* Share a location message in the room. * Share a location message in the room.

View file

@ -0,0 +1,37 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.timeline.item.event
import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId
@Immutable
sealed interface EventOrTransactionId {
@JvmInline
value class Event(val id: EventId) : EventOrTransactionId
@JvmInline
value class Transaction(val id: TransactionId) : EventOrTransactionId
val eventId: EventId?
get() = (this as? Event)?.id
companion object {
fun from(eventId: EventId?, transactionId: TransactionId?): EventOrTransactionId {
return when {
eventId != null -> Event(eventId)
transactionId != null -> Transaction(transactionId)
else -> throw IllegalArgumentException("EventId and TransactionId are both null")
}
}
}
}
fun EventId.toEventOrTransactionId() = EventOrTransactionId.Event(this)
fun TransactionId.toEventOrTransactionId() = EventOrTransactionId.Transaction(this)

View file

@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
@ -42,6 +41,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.room.roomNotificationSettings import io.element.android.libraries.matrix.api.room.roomNotificationSettings
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.EventOrTransactionId
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import io.element.android.libraries.matrix.impl.mapper.map import io.element.android.libraries.matrix.impl.mapper.map
@ -471,8 +471,8 @@ class RustMatrixRoom(
return liveTimeline.sendFile(file, fileInfo, progressCallback) return liveTimeline.sendFile(file, fileInfo, progressCallback)
} }
override suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> { override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> {
return liveTimeline.toggleReaction(emoji, uniqueId) return liveTimeline.toggleReaction(emoji, eventOrTransactionId)
} }
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> { override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> {

View file

@ -0,0 +1,16 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.timeline
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import org.matrix.rustcomponents.sdk.EventOrTransactionId as RustEventOrTransactionId
fun EventOrTransactionId.toRustEventOrTransactionId() = when (this) {
is EventOrTransactionId.Event -> RustEventOrTransactionId.EventId(id.value)
is EventOrTransactionId.Transaction -> RustEventOrTransactionId.TransactionId(id.value)
}

View file

@ -23,7 +23,7 @@ class MatrixTimelineItemMapper(
private val eventTimelineItemMapper: EventTimelineItemMapper, private val eventTimelineItemMapper: EventTimelineItemMapper,
) { ) {
fun map(timelineItem: TimelineItem): MatrixTimelineItem = timelineItem.use { fun map(timelineItem: TimelineItem): MatrixTimelineItem = timelineItem.use {
val uniqueId = UniqueId(timelineItem.uniqueId()) val uniqueId = UniqueId(timelineItem.uniqueId().id)
val asEvent = it.asEvent() val asEvent = it.asEvent()
if (asEvent != null) { if (asEvent != null) {
val eventTimelineItem = eventTimelineItemMapper.map(asEvent) val eventTimelineItem = eventTimelineItemMapper.map(asEvent)

View file

@ -10,8 +10,6 @@ package io.element.android.libraries.matrix.impl.timeline
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.ImageInfo
@ -26,6 +24,7 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
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.TimelineException import io.element.android.libraries.matrix.api.timeline.TimelineException
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.impl.core.toProgressWatcher import io.element.android.libraries.matrix.impl.core.toProgressWatcher
import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl
@ -65,8 +64,6 @@ import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.EditedContent import org.matrix.rustcomponents.sdk.EditedContent
import org.matrix.rustcomponents.sdk.EventOrTransactionId
import org.matrix.rustcomponents.sdk.EventTimelineItem
import org.matrix.rustcomponents.sdk.FormattedBody import org.matrix.rustcomponents.sdk.FormattedBody
import org.matrix.rustcomponents.sdk.MessageFormat import org.matrix.rustcomponents.sdk.MessageFormat
import org.matrix.rustcomponents.sdk.PollData import org.matrix.rustcomponents.sdk.PollData
@ -75,6 +72,7 @@ import org.matrix.rustcomponents.sdk.use
import timber.log.Timber import timber.log.Timber
import uniffi.matrix_sdk_ui.LiveBackPaginationStatus import uniffi.matrix_sdk_ui.LiveBackPaginationStatus
import java.io.File import java.io.File
import org.matrix.rustcomponents.sdk.EventOrTransactionId as RustEventOrTransactionId
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
private const val PAGINATION_SIZE = 50 private const val PAGINATION_SIZE = 50
@ -280,31 +278,23 @@ class RustTimeline(
} }
} }
override suspend fun redactEvent(eventId: EventId?, transactionId: TransactionId?, reason: String?): Result<Unit> = withContext(dispatcher) { override suspend fun redactEvent(eventOrTransactionId: EventOrTransactionId, reason: String?): Result<Unit> = withContext(dispatcher) {
runCatching { runCatching {
val eventOrTransactionId = if (eventId != null) { inner.redactEvent(
EventOrTransactionId.EventId(eventId.value) eventOrTransactionId = eventOrTransactionId.toRustEventOrTransactionId(),
} else { reason = reason,
EventOrTransactionId.TransactionId(transactionId!!.value) )
}
inner.redactEvent(eventOrTransactionId = eventOrTransactionId, reason = reason)
} }
} }
override suspend fun editMessage( override suspend fun editMessage(
originalEventId: EventId?, eventOrTransactionId: EventOrTransactionId,
transactionId: TransactionId?,
body: String, body: String,
htmlBody: String?, htmlBody: String?,
intentionalMentions: List<IntentionalMention>, intentionalMentions: List<IntentionalMention>,
): Result<Unit> = ): Result<Unit> =
withContext(dispatcher) { withContext(dispatcher) {
runCatching<Unit> { runCatching<Unit> {
val eventOrTransactionId = if (originalEventId != null) {
EventOrTransactionId.EventId(originalEventId.value)
} else {
EventOrTransactionId.TransactionId(transactionId!!.value)
}
val editedContent = EditedContent.RoomMessage( val editedContent = EditedContent.RoomMessage(
content = MessageEventContent.from( content = MessageEventContent.from(
body = body, body = body,
@ -314,7 +304,7 @@ class RustTimeline(
) )
inner.edit( inner.edit(
newContent = editedContent, newContent = editedContent,
eventOrTransactionId = eventOrTransactionId, eventOrTransactionId = eventOrTransactionId.toRustEventOrTransactionId(),
) )
} }
} }
@ -354,21 +344,6 @@ class RustTimeline(
} }
} }
@Throws
@Suppress("UnusedPrivateMember")
private suspend fun getEventTimelineItem(eventId: EventId?, transactionId: TransactionId?): EventTimelineItem {
return try {
when {
eventId != null -> inner.getEventTimelineItemByEventId(eventId.value)
transactionId != null -> inner.getEventTimelineItemByTransactionId(transactionId.value)
else -> error("Either eventId or transactionId must be non-null")
}
} catch (e: Exception) {
Timber.e(e, "Failed to get event timeline item")
throw TimelineException.EventNotFound
}
}
override suspend fun sendVideo( override suspend fun sendVideo(
file: File, file: File,
thumbnailFile: File?, thumbnailFile: File?,
@ -410,9 +385,12 @@ class RustTimeline(
} }
} }
override suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> = withContext(dispatcher) { override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> = withContext(dispatcher) {
runCatching { runCatching {
inner.toggleReaction(key = emoji, uniqueId = uniqueId.value) inner.toggleReaction(
key = emoji,
itemId = eventOrTransactionId.toRustEventOrTransactionId(),
)
} }
} }
@ -424,9 +402,6 @@ class RustTimeline(
} }
} }
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> =
redactEvent(eventId = null, transactionId = transactionId, reason = null)
override suspend fun sendLocation( override suspend fun sendLocation(
body: String, body: String,
geoUri: String, geoUri: String,
@ -479,7 +454,7 @@ class RustTimeline(
) )
inner.edit( inner.edit(
newContent = editedContent, newContent = editedContent,
eventOrTransactionId = EventOrTransactionId.EventId(pollStartId.value), eventOrTransactionId = RustEventOrTransactionId.EventId(pollStartId.value),
) )
}.map { } }.map { }
} }

View file

@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.fixtures.fakes
import org.matrix.rustcomponents.sdk.EventTimelineItem import org.matrix.rustcomponents.sdk.EventTimelineItem
import org.matrix.rustcomponents.sdk.NoPointer import org.matrix.rustcomponents.sdk.NoPointer
import org.matrix.rustcomponents.sdk.TimelineItem import org.matrix.rustcomponents.sdk.TimelineItem
import org.matrix.rustcomponents.sdk.TimelineUniqueId
import org.matrix.rustcomponents.sdk.VirtualTimelineItem import org.matrix.rustcomponents.sdk.VirtualTimelineItem
class FakeRustTimelineItem( class FakeRustTimelineItem(
@ -18,5 +19,5 @@ class FakeRustTimelineItem(
override fun asEvent(): EventTimelineItem? = asEventResult override fun asEvent(): EventTimelineItem? = asEventResult
override fun asVirtual(): VirtualTimelineItem? = null override fun asVirtual(): VirtualTimelineItem? = null
override fun fmtDebug(): String = "fmtDebug" override fun fmtDebug(): String = "fmtDebug"
override fun uniqueId(): String = "uniqueId" override fun uniqueId(): TimelineUniqueId = TimelineUniqueId("uniqueId")
} }

View file

@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
@ -38,6 +37,7 @@ import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerL
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
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.EventOrTransactionId
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
@ -95,7 +95,7 @@ class FakeMatrixRoom(
private val editMessageLambda: (EventId, String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _, _ -> lambdaError() }, private val editMessageLambda: (EventId, String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _, _ -> lambdaError() },
private val sendMessageResult: (String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _ -> lambdaError() }, private val sendMessageResult: (String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _ -> lambdaError() },
private val updateUserRoleResult: () -> Result<Unit> = { lambdaError() }, private val updateUserRoleResult: () -> Result<Unit> = { lambdaError() },
private val toggleReactionResult: (String, UniqueId) -> Result<Unit> = { _, _ -> lambdaError() }, private val toggleReactionResult: (String, EventOrTransactionId) -> Result<Unit> = { _, _ -> lambdaError() },
private val retrySendMessageResult: (TransactionId) -> Result<Unit> = { lambdaError() }, private val retrySendMessageResult: (TransactionId) -> Result<Unit> = { lambdaError() },
private val cancelSendResult: (TransactionId) -> Result<Unit> = { lambdaError() }, private val cancelSendResult: (TransactionId) -> Result<Unit> = { lambdaError() },
private val forwardEventResult: (EventId, List<RoomId>) -> Result<Unit> = { _, _ -> lambdaError() }, private val forwardEventResult: (EventId, List<RoomId>) -> Result<Unit> = { _, _ -> lambdaError() },
@ -236,8 +236,8 @@ class FakeMatrixRoom(
sendMessageResult(body, htmlBody, intentionalMentions) sendMessageResult(body, htmlBody, intentionalMentions)
} }
override suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> { override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> {
return toggleReactionResult(emoji, uniqueId) return toggleReactionResult(emoji, eventOrTransactionId)
} }
override suspend fun retrySendMessage(transactionId: TransactionId): Result<Unit> = simulateLongTask { override suspend fun retrySendMessage(transactionId: TransactionId): Result<Unit> = simulateLongTask {

View file

@ -10,8 +10,6 @@ package io.element.android.libraries.matrix.test.timeline
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.TransactionId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.AudioInfo
import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.ImageInfo
@ -23,6 +21,7 @@ import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
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.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
@ -63,35 +62,31 @@ class FakeTimeline(
intentionalMentions: List<IntentionalMention>, intentionalMentions: List<IntentionalMention>,
): Result<Unit> = sendMessageLambda(body, htmlBody, intentionalMentions) ): Result<Unit> = sendMessageLambda(body, htmlBody, intentionalMentions)
var redactEventLambda: (eventId: EventId?, transactionId: TransactionId?, reason: String?) -> Result<Unit> = { _, _, _ -> var redactEventLambda: (eventOrTransactionId: EventOrTransactionId, reason: String?) -> Result<Unit> = { _, _ ->
Result.success(Unit) Result.success(Unit)
} }
override suspend fun redactEvent( override suspend fun redactEvent(
eventId: EventId?, eventOrTransactionId: EventOrTransactionId,
transactionId: TransactionId?,
reason: String? reason: String?
): Result<Unit> = redactEventLambda(eventId, transactionId, reason) ): Result<Unit> = redactEventLambda(eventOrTransactionId, reason)
var editMessageLambda: ( var editMessageLambda: (
originalEventId: EventId?, eventOrTransactionId: EventOrTransactionId,
transactionId: TransactionId?,
body: String, body: String,
htmlBody: String?, htmlBody: String?,
intentionalMentions: List<IntentionalMention>, intentionalMentions: List<IntentionalMention>,
) -> Result<Unit> = { _, _, _, _, _ -> ) -> Result<Unit> = { _, _, _, _ ->
Result.success(Unit) Result.success(Unit)
} }
override suspend fun editMessage( override suspend fun editMessage(
originalEventId: EventId?, eventOrTransactionId: EventOrTransactionId,
transactionId: TransactionId?,
body: String, body: String,
htmlBody: String?, htmlBody: String?,
intentionalMentions: List<IntentionalMention>, intentionalMentions: List<IntentionalMention>,
): Result<Unit> = editMessageLambda( ): Result<Unit> = editMessageLambda(
originalEventId, eventOrTransactionId,
transactionId,
body, body,
htmlBody, htmlBody,
intentionalMentions intentionalMentions
@ -211,14 +206,15 @@ class FakeTimeline(
progressCallback progressCallback
) )
var toggleReactionLambda: (emoji: String, uniqueId: UniqueId) -> Result<Unit> = { _, _ -> Result.success(Unit) } var toggleReactionLambda: (emoji: String, eventOrTransactionId: EventOrTransactionId) -> Result<Unit> = { _, _ -> Result.success(Unit) }
override suspend fun toggleReaction(emoji: String, uniqueId: UniqueId): Result<Unit> = toggleReactionLambda(emoji, uniqueId) override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> = toggleReactionLambda(
emoji,
eventOrTransactionId
)
var forwardEventLambda: (eventId: EventId, roomIds: List<RoomId>) -> Result<Unit> = { _, _ -> Result.success(Unit) } var forwardEventLambda: (eventId: EventId, roomIds: List<RoomId>) -> Result<Unit> = { _, _ -> Result.success(Unit) }
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> = forwardEventLambda(eventId, roomIds) override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> = forwardEventLambda(eventId, roomIds)
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> = redactEvent(null, transactionId, null)
var sendLocationLambda: ( var sendLocationLambda: (
body: String, body: String,
geoUri: String, geoUri: String,

View file

@ -42,7 +42,8 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetailsProvider import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetailsProvider
import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.TestTags
@ -719,12 +720,10 @@ fun aRichTextEditorState(
) )
fun aMessageComposerModeEdit( fun aMessageComposerModeEdit(
eventId: EventId? = EventId("$1234"), eventOrTransactionId: EventOrTransactionId = EventId("$1234").toEventOrTransactionId(),
transactionId: TransactionId? = TransactionId("1234"),
content: String = "Some text", content: String = "Some text",
) = MessageComposerMode.Edit( ) = MessageComposerMode.Edit(
eventId = eventId, eventOrTransactionId = eventOrTransactionId,
transactionId = transactionId,
content = content content = content
) )

View file

@ -26,6 +26,8 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@ -77,7 +79,7 @@ internal fun SendButton(
@Composable @Composable
internal fun SendButtonPreview() = ElementPreview { internal fun SendButtonPreview() = ElementPreview {
val normalMode = MessageComposerMode.Normal val normalMode = MessageComposerMode.Normal
val editMode = MessageComposerMode.Edit(null, null, "") val editMode = MessageComposerMode.Edit(EventId("\$id").toEventOrTransactionId(), "")
Row { Row {
SendButton(canSendMessage = true, onClick = {}, composerMode = normalMode) SendButton(canSendMessage = true, onClick = {}, composerMode = normalMode)
SendButton(canSendMessage = false, onClick = {}, composerMode = normalMode) SendButton(canSendMessage = false, onClick = {}, composerMode = normalMode)

View file

@ -9,7 +9,7 @@ package io.element.android.libraries.textcomposer.model
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.matrix.ui.messages.reply.eventId import io.element.android.libraries.matrix.ui.messages.reply.eventId
@ -21,8 +21,7 @@ sealed interface MessageComposerMode {
sealed interface Special : MessageComposerMode sealed interface Special : MessageComposerMode
data class Edit( data class Edit(
val eventId: EventId?, val eventOrTransactionId: EventOrTransactionId,
val transactionId: TransactionId?,
val content: String val content: String
) : Special ) : Special
@ -36,7 +35,7 @@ sealed interface MessageComposerMode {
val relatedEventId: EventId? val relatedEventId: EventId?
get() = when (this) { get() = when (this) {
is Normal -> null is Normal -> null
is Edit -> eventId is Edit -> eventOrTransactionId.eventId
is Reply -> eventId is Reply -> eventId
} }