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

@ -18,6 +18,7 @@ interface FocusedTimelineMediaGalleryDataSourceFactory {
fun createFor(
eventId: EventId,
mediaItem: MediaItem.Event,
onlyPinnedEvents: Boolean,
): MediaGalleryDataSource
}
@ -30,6 +31,7 @@ class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor(
override fun createFor(
eventId: EventId,
mediaItem: MediaItem.Event,
onlyPinnedEvents: Boolean,
): MediaGalleryDataSource {
return TimelineMediaGalleryDataSource(
room = room,
@ -37,6 +39,7 @@ class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor(
room = room,
eventId = eventId,
initialMediaItem = mediaItem,
onlyPinnedEvents = onlyPinnedEvents,
),
timelineMediaItemsFactory = timelineMediaItemsFactory,
mediaItemsPostProcessor = mediaItemsPostProcessor,

View file

@ -44,7 +44,7 @@ class LiveMediaTimeline @Inject constructor(
override suspend fun getTimeline(): Result<Timeline> = mutex.withLock {
val currentTimeline = timeline
if (currentTimeline == null) {
room.mediaTimeline(null)
room.createTimeline(onlyMedia = true)
.onSuccess { timeline = it }
} else {
Result.success(currentTimeline)
@ -58,14 +58,20 @@ class LiveMediaTimeline @Inject constructor(
/**
* A class that will provide a media timeline that is focused on a particular event.
* Optionally, the timeline will only contain the pinned events.
*/
class FocusedMediaTimeline(
private val room: MatrixRoom,
private val eventId: EventId,
private val onlyPinnedEvents: Boolean,
initialMediaItem: MediaItem.Event,
) : MediaTimeline {
override suspend fun getTimeline(): Result<Timeline> {
return room.mediaTimeline(eventId)
return room.createTimeline(
focusedOnEventId = eventId,
onlyPinnedEvents = onlyPinnedEvents,
onlyMedia = true,
)
}
override val cache = persistentListOf(

View file

@ -27,6 +27,7 @@ import io.element.android.libraries.architecture.overlay.operation.show
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
@ -96,9 +97,9 @@ class MediaGalleryRootNode @AssistedInject constructor(
val mode = when (item) {
is MediaItem.Audio,
is MediaItem.Voice,
is MediaItem.File -> MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios
is MediaItem.File -> MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(Timeline.Mode.MEDIA)
is MediaItem.Image,
is MediaItem.Video -> MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos
is MediaItem.Video -> MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.MEDIA)
}
overlay.show(
NavTarget.MediaViewer(

View file

@ -52,8 +52,8 @@ class MediaViewerDataSource(
private val galleryMode = when (mode) {
MediaViewerMode.SingleMedia,
MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images
MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files
is MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images
is MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files
}
// Map of sourceUrl to local media state

View file

@ -22,6 +22,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
import io.element.android.libraries.mediaviewer.impl.datasource.FocusedTimelineMediaGalleryDataSourceFactory
@ -69,16 +70,40 @@ class MediaViewerNode @AssistedInject constructor(
// Should not happen
timelineMediaGalleryDataSource
} else {
// Does timelineMediaGalleryDataSource knows the eventId?
val lastData = timelineMediaGalleryDataSource.getLastData().dataOrNull()
val isEventKnown = lastData?.hasEvent(eventId) == true
if (isEventKnown) {
timelineMediaGalleryDataSource
} else {
focusedTimelineMediaGalleryDataSourceFactory.createFor(
eventId = eventId,
mediaItem = inputs.toMediaItem(),
)
// Can we use a specific timeline?
val timelineMode = when (val mode = inputs.mode) {
is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> mode.timelineMode
is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> mode.timelineMode
else -> null
}
when (timelineMode) {
null -> timelineMediaGalleryDataSource
Timeline.Mode.LIVE -> {
// Even if the timelineMediaGalleryDataSource does not know the eventId, the SDK will create the timeline faster
timelineMediaGalleryDataSource
}
Timeline.Mode.FOCUSED_ON_EVENT -> {
// Does timelineMediaGalleryDataSource knows the eventId?
val lastData = timelineMediaGalleryDataSource.getLastData().dataOrNull()
val isEventKnown = lastData?.hasEvent(eventId) == true
if (isEventKnown) {
timelineMediaGalleryDataSource
} else {
focusedTimelineMediaGalleryDataSourceFactory.createFor(
eventId = eventId,
mediaItem = inputs.toMediaItem(),
onlyPinnedEvents = false,
)
}
}
Timeline.Mode.PINNED_EVENTS -> {
focusedTimelineMediaGalleryDataSourceFactory.createFor(
eventId = eventId,
mediaItem = inputs.toMediaItem(),
onlyPinnedEvents = true,
)
}
Timeline.Mode.MEDIA -> timelineMediaGalleryDataSource
}
}
}

View file

@ -204,8 +204,8 @@ class MediaViewerPresenter @AssistedInject constructor(
private fun showNoMoreItemsSnackbar() {
val messageResId = when (inputs.mode) {
MediaViewerEntryPoint.MediaViewerMode.SingleMedia,
MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> R.string.screen_media_details_no_more_media_to_show
MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> R.string.screen_media_details_no_more_files_to_show
is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> R.string.screen_media_details_no_more_media_to_show
is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> R.string.screen_media_details_no_more_files_to_show
}
val message = SnackbarMessage(messageResId)
snackbarDispatcher.post(message)