Update Matrix Room API and allow media swipe on pinned event only.

This commit is contained in:
Benoit Marty 2025-02-17 16:45:05 +01:00
parent 728a2c1a32
commit 2e9a158fb0
30 changed files with 268 additions and 181 deletions

View file

@ -71,6 +71,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.alias.matches
import io.element.android.libraries.matrix.api.room.joinedRoomMembers
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.ui.messages.LocalRoomMemberProfilesCache
import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
@ -187,8 +188,11 @@ class MessagesFlowNode @AssistedInject constructor(
callbacks.forEach { it.onRoomDetailsClick() }
}
override fun onEventClick(event: TimelineItem.Event): Boolean {
return processEventClick(event)
override fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
return processEventClick(
timelineMode = if (isLive) Timeline.Mode.LIVE else Timeline.Mode.FOCUSED_ON_EVENT,
event = event,
)
}
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
@ -316,7 +320,10 @@ class MessagesFlowNode @AssistedInject constructor(
NavTarget.PinnedMessagesList -> {
val callback = object : PinnedMessagesListNode.Callback {
override fun onEventClick(event: TimelineItem.Event) {
processEventClick(event)
processEventClick(
timelineMode = Timeline.Mode.PINNED_EVENTS,
event = event,
)
}
override fun onUserDataClick(userId: UserId) {
@ -358,11 +365,14 @@ class MessagesFlowNode @AssistedInject constructor(
callbacks.forEach { it.onPermalinkClick(permalinkData, pushToBackstack = false) }
}
private fun processEventClick(event: TimelineItem.Event): Boolean {
private fun processEventClick(
timelineMode: Timeline.Mode,
event: TimelineItem.Event,
): Boolean {
val navTarget = when (event.content) {
is TimelineItemImageContent -> {
buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event,
content = event.content,
mediaSource = event.content.mediaSource,
@ -374,7 +384,7 @@ class MessagesFlowNode @AssistedInject constructor(
if encrypted on certain bridges */
event.content.preferredMediaSource?.let { preferredMediaSource ->
buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event,
content = event.content,
mediaSource = preferredMediaSource,
@ -384,7 +394,7 @@ class MessagesFlowNode @AssistedInject constructor(
}
is TimelineItemVideoContent -> {
buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos,
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event,
content = event.content,
mediaSource = event.content.mediaSource,
@ -393,7 +403,7 @@ class MessagesFlowNode @AssistedInject constructor(
}
is TimelineItemFileContent -> {
buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios,
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
event = event,
content = event.content,
mediaSource = event.content.mediaSource,
@ -402,7 +412,7 @@ class MessagesFlowNode @AssistedInject constructor(
}
is TimelineItemAudioContent -> {
buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios,
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
event = event,
content = event.content,
mediaSource = event.content.mediaSource,

View file

@ -89,7 +89,7 @@ class MessagesNode @AssistedInject constructor(
interface Callback : Plugin {
fun onRoomDetailsClick()
fun onEventClick(event: TimelineItem.Event): Boolean
fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean
fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
fun onUserDataClick(userId: UserId)
fun onPermalinkClick(data: PermalinkData)
@ -120,12 +120,12 @@ class MessagesNode @AssistedInject constructor(
callbacks.forEach { it.onRoomDetailsClick() }
}
private fun onEventClick(event: TimelineItem.Event): Boolean {
private fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
// Note: cannot use `callbacks.all { it.onEventClick(event) }` because:
// - if callbacks is empty, it will return true and we want to return false.
// - if a callback returns false, the other callback will not be invoked.
return callbacks.takeIf { it.isNotEmpty() }
?.map { it.onEventClick(event) }
?.map { it.onEventClick(isLive, event) }
?.all { it }
.orFalse()
}

View file

@ -109,7 +109,7 @@ fun MessagesView(
state: MessagesState,
onBackClick: () -> Unit,
onRoomDetailsClick: () -> Unit,
onEventContentClick: (event: TimelineItem.Event) -> Boolean,
onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean,
onUserDataClick: (UserId) -> Unit,
onLinkClick: (String, Boolean) -> Unit,
onSendLocationClick: () -> Unit,
@ -140,7 +140,7 @@ fun MessagesView(
fun onContentClick(event: TimelineItem.Event) {
Timber.v("onMessageClick= ${event.id}")
val hideKeyboard = onEventContentClick(event)
val hideKeyboard = onEventContentClick(state.timelineState.isLive, event)
if (hideKeyboard) {
localView.hideKeyboard()
}
@ -535,7 +535,7 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
state = state,
onBackClick = {},
onRoomDetailsClick = {},
onEventContentClick = { false },
onEventContentClick = { _, _ -> false },
onUserDataClick = {},
onLinkClick = { _, _ -> },
onSendLocationClick = {},

View file

@ -33,7 +33,7 @@ internal fun MessagesViewWithIdentityChangePreview(
),
onBackClick = {},
onRoomDetailsClick = {},
onEventContentClick = { false },
onEventContentClick = { _, _ -> false },
onUserDataClick = {},
onLinkClick = { _, _ -> },
onSendLocationClick = {},

View file

@ -104,7 +104,7 @@ class PinnedEventsTimelineProvider @Inject constructor(
is AsyncData.Uninitialized, is AsyncData.Failure -> {
timelineStateFlow.emit(AsyncData.Loading())
withContext(dispatchers.io) {
room.pinnedEventsTimeline()
room.createTimeline(onlyPinnedEvents = true)
}
.fold(
{ timelineStateFlow.emit(AsyncData.Success(it)) },

View file

@ -64,7 +64,7 @@ class TimelineController @Inject constructor(
}
suspend fun focusOnEvent(eventId: EventId): Result<Unit> {
return room.timelineFocusedOnEvent(eventId)
return room.createTimeline(focusedOnEventId = eventId)
.onFailure {
if (it is CancellationException) {
throw it