From fdf40120a79b54929007e2218410f44b74eaa651 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 09:58:34 +0100 Subject: [PATCH 01/10] Add ability to swipe between media when opened from the timeline. --- .../messages/impl/MessagesFlowNode.kt | 11 +- .../libraries/matrix/api/room/MatrixRoom.kt | 3 +- .../matrix/impl/room/RustMatrixRoom.kt | 16 ++- .../matrix/test/room/FakeMatrixRoom.kt | 6 +- .../mediaviewer/api/MediaViewerEntryPoint.kt | 1 + ...edTimelineMediaGalleryDataSourceFactory.kt | 44 +++++++ .../impl/gallery/MediaGalleryDataSource.kt | 16 ++- .../impl/gallery/MediaGalleryView.kt | 37 +++--- .../mediaviewer/impl/gallery/MediaTimeline.kt | 115 ++++++++++++++++++ .../gallery/SingleMediaGalleryDataSource.kt | 102 ++++++++-------- .../impl/viewer/MediaViewerDataSource.kt | 9 +- .../impl/viewer/MediaViewerNode.kt | 24 +++- .../impl/viewer/MediaViewerState.kt | 13 ++ .../impl/viewer/MediaViewerStateProvider.kt | 2 + .../impl/viewer/MediaViewerView.kt | 1 + .../impl/viewer/PagerKeysHandler.kt | 86 +++++++++++++ .../TimelineMediaGalleryDataSourceTest.kt | 1 + .../impl/viewer/MediaViewerDataSourceTest.kt | 3 + .../impl/viewer/MediaViewerPresenterTest.kt | 1 + .../impl/viewer/PagerKeysHandlerTest.kt | 76 ++++++++++++ 20 files changed, 485 insertions(+), 82 deletions(-) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt create mode 100644 libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index f9d9bbf27f..6b84423d44 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -123,6 +123,7 @@ class MessagesFlowNode @AssistedInject constructor( @Parcelize data class MediaViewer( + val mode: MediaViewerEntryPoint.MediaViewerMode, val eventId: EventId?, val mediaInfo: MediaInfo, val mediaSource: MediaSource, @@ -248,8 +249,7 @@ class MessagesFlowNode @AssistedInject constructor( } is NavTarget.MediaViewer -> { val params = MediaViewerEntryPoint.Params( - // TODO When we will be able to load a media timeline from a EventId, change mode here (and use a mixed mode?) - mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia, + mode = navTarget.mode, eventId = navTarget.eventId, mediaInfo = navTarget.mediaInfo, mediaSource = navTarget.mediaSource, @@ -362,6 +362,7 @@ class MessagesFlowNode @AssistedInject constructor( val navTarget = when (event.content) { is TimelineItemImageContent -> { buildMediaViewerNavTarget( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, event = event, content = event.content, mediaSource = event.content.mediaSource, @@ -373,6 +374,7 @@ class MessagesFlowNode @AssistedInject constructor( if encrypted on certain bridges */ event.content.preferredMediaSource?.let { preferredMediaSource -> buildMediaViewerNavTarget( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, event = event, content = event.content, mediaSource = preferredMediaSource, @@ -382,6 +384,7 @@ class MessagesFlowNode @AssistedInject constructor( } is TimelineItemVideoContent -> { buildMediaViewerNavTarget( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, event = event, content = event.content, mediaSource = event.content.mediaSource, @@ -390,6 +393,7 @@ class MessagesFlowNode @AssistedInject constructor( } is TimelineItemFileContent -> { buildMediaViewerNavTarget( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios, event = event, content = event.content, mediaSource = event.content.mediaSource, @@ -398,6 +402,7 @@ class MessagesFlowNode @AssistedInject constructor( } is TimelineItemAudioContent -> { buildMediaViewerNavTarget( + mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios, event = event, content = event.content, mediaSource = event.content.mediaSource, @@ -426,12 +431,14 @@ class MessagesFlowNode @AssistedInject constructor( } private fun buildMediaViewerNavTarget( + mode: MediaViewerEntryPoint.MediaViewerMode, event: TimelineItem.Event, content: TimelineItemEventContentWithAttachment, mediaSource: MediaSource, thumbnailSource: MediaSource?, ): NavTarget { return NavTarget.MediaViewer( + mode = mode, eventId = event.eventId, mediaInfo = MediaInfo( filename = content.filename, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index bb86684be0..4d5f8c7a19 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -118,8 +118,9 @@ interface MatrixRoom : Closeable { /** * Create a new timeline for the media events of the room. + * @param eventId The event to focus on, if any. */ - suspend fun mediaTimeline(): Result + suspend fun mediaTimeline(eventId: EventId?): Result fun destroy() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index ab16ac383f..911a62f376 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -253,11 +253,21 @@ class RustMatrixRoom( } } - override suspend fun mediaTimeline(): Result = withContext(roomDispatcher) { + override suspend fun mediaTimeline( + eventId: EventId?, + ): Result = withContext(roomDispatcher) { + val focus = if (eventId != null) { + TimelineFocus.Event( + eventId = eventId.value, + numContextEvents = 50u, + ) + } else { + TimelineFocus.Live + } runCatching { innerRoom.timelineWithConfiguration( configuration = TimelineConfiguration( - focus = TimelineFocus.Live, + focus = focus, allowedMessageTypes = AllowedMessageTypes.Only( types = listOf( RoomMessageEventMessageType.FILE, @@ -270,7 +280,7 @@ class RustMatrixRoom( dateDividerMode = DateDividerMode.MONTHLY, ) ).let { inner -> - createTimeline(inner, mode = Timeline.Mode.MEDIA) + createTimeline(inner, mode = if (eventId != null) Timeline.Mode.FOCUSED_ON_EVENT else Timeline.Mode.MEDIA) } }.onFailure { if (it is CancellationException) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 62d19bd66c..1fd95da36b 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -137,7 +137,7 @@ class FakeMatrixRoom( private val getMembersResult: (Int) -> Result> = { lambdaError() }, private val timelineFocusedOnEventResult: (EventId) -> Result = { lambdaError() }, private val pinnedEventsTimelineResult: () -> Result = { lambdaError() }, - private val mediaTimelineResult: () -> Result = { lambdaError() }, + private val mediaTimelineResult: (EventId?) -> Result = { lambdaError() }, private val setSendQueueEnabledLambda: (Boolean) -> Unit = { _: Boolean -> }, private val saveComposerDraftLambda: (ComposerDraft) -> Result = { _: ComposerDraft -> Result.success(Unit) }, private val loadComposerDraftLambda: () -> Result = { Result.success(null) }, @@ -215,8 +215,8 @@ class FakeMatrixRoom( pinnedEventsTimelineResult() } - override suspend fun mediaTimeline(): Result = simulateLongTask { - mediaTimelineResult() + override suspend fun mediaTimeline(eventId: EventId?): Result = simulateLongTask { + mediaTimelineResult(eventId) } override suspend fun subscribeToSync() { diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt index a824fc5540..bbcd931410 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt @@ -39,6 +39,7 @@ interface MediaViewerEntryPoint : FeatureEntryPoint { val canShowInfo: Boolean, ) : NodeInputs + // TODO convert to sealed class and add eventId to the 2nd and 3rd items enum class MediaViewerMode { SingleMedia, TimelineImagesAndVideos, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt new file mode 100644 index 0000000000..a8a4d0380d --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import javax.inject.Inject + +interface FocusedTimelineMediaGalleryDataSourceFactory { + fun createFor( + eventId: EventId, + mediaItem: MediaItem.Event, + ): MediaGalleryDataSource +} + +@ContributesBinding(RoomScope::class) +class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor( + private val room: MatrixRoom, + private val timelineMediaItemsFactory: TimelineMediaItemsFactory, + private val mediaItemsPostProcessor: MediaItemsPostProcessor, +) : FocusedTimelineMediaGalleryDataSourceFactory { + override fun createFor( + eventId: EventId, + mediaItem: MediaItem.Event, + ): MediaGalleryDataSource { + return TimelineMediaGalleryDataSource( + room = room, + mediaTimeline = FocusedMediaTimeline( + room = room, + eventId = eventId, + initialMediaItem = mediaItem, + ), + timelineMediaItemsFactory = timelineMediaItemsFactory, + mediaItemsPostProcessor = mediaItemsPostProcessor, + ) + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt index 0e12653108..204f140eda 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt @@ -39,6 +39,7 @@ interface MediaGalleryDataSource { @ContributesBinding(RoomScope::class) class TimelineMediaGalleryDataSource @Inject constructor( private val room: MatrixRoom, + private val mediaTimeline: MediaTimeline, private val timelineMediaItemsFactory: TimelineMediaItemsFactory, private val mediaItemsPostProcessor: MediaItemsPostProcessor, ) : MediaGalleryDataSource { @@ -48,7 +49,9 @@ class TimelineMediaGalleryDataSource @Inject constructor( override fun groupedMediaItemsFlow(): Flow> = groupedMediaItemsFlow - override fun getLastData(): AsyncData = groupedMediaItemsFlow.replayCache.firstOrNull() ?: AsyncData.Uninitialized + override fun getLastData(): AsyncData = groupedMediaItemsFlow.replayCache.firstOrNull() + ?: mediaTimeline.getCache()?.let { AsyncData.Success(it) } + ?: AsyncData.Uninitialized private val isStarted = AtomicBoolean(false) @@ -58,8 +61,13 @@ class TimelineMediaGalleryDataSource @Inject constructor( return } flow { - groupedMediaItemsFlow.emit(AsyncData.Loading()) - room.mediaTimeline().fold( + val cache = mediaTimeline.getCache() + if (cache != null) { + groupedMediaItemsFlow.emit(AsyncData.Success(cache)) + } else { + groupedMediaItemsFlow.emit(AsyncData.Loading()) + } + mediaTimeline.getTimeline().fold( { timeline = it emit(it) @@ -78,6 +86,8 @@ class TimelineMediaGalleryDataSource @Inject constructor( timelineMediaItemsFactory.timelineItems }.map { timelineItems -> mediaItemsPostProcessor.process(mediaItems = timelineItems) + }.map { + mediaTimeline.orCache(it) }.onEach { groupedMediaItems -> groupedMediaItemsFlow.emit(AsyncData.Success(groupedMediaItems)) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt index 3f5e1fc107..3eb5281c43 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt @@ -108,15 +108,15 @@ fun MediaGalleryView( ) { paddingValues -> Column( modifier = Modifier - .padding(paddingValues) - .consumeWindowInsets(paddingValues) - .fillMaxSize(), + .padding(paddingValues) + .consumeWindowInsets(paddingValues) + .fillMaxSize(), verticalArrangement = Arrangement.spacedBy(2.dp), ) { SingleChoiceSegmentedButtonRow( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + .fillMaxWidth() + .padding(horizontal = 16.dp), ) { MediaGalleryMode.entries.forEach { mode -> SegmentedButton( @@ -354,8 +354,8 @@ private fun MediaGalleryImageGrid( ) { LazyVerticalGrid( modifier = Modifier - .fillMaxSize() - .padding(horizontal = 16.dp), + .fillMaxSize() + .padding(horizontal = 16.dp), columns = GridCells.Adaptive(80.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp), @@ -426,9 +426,9 @@ private fun LoadingMoreIndicator( Timeline.PaginationDirection.FORWARDS -> { LinearProgressIndicator( modifier = Modifier - .fillMaxWidth() - .padding(top = 2.dp) - .height(1.dp) + .fillMaxWidth() + .padding(top = 2.dp) + .height(1.dp) ) } Timeline.PaginationDirection.BACKWARDS -> { @@ -440,7 +440,10 @@ private fun LoadingMoreIndicator( } val latestEventSink by rememberUpdatedState(eventSink) LaunchedEffect(item.timestamp) { - latestEventSink(MediaGalleryEvents.LoadMore(item.direction)) + // TODO Add isFake to the model instead of using -1 for timestamp + if (item.timestamp != -1L) { + latestEventSink(MediaGalleryEvents.LoadMore(item.direction)) + } } } } @@ -466,9 +469,9 @@ private fun EmptyContent( OnboardingBackground() PageTitle( modifier = Modifier - .fillMaxWidth() - .padding(top = 44.dp) - .padding(24.dp), + .fillMaxWidth() + .padding(top = 44.dp) + .padding(24.dp), title = stringResource(titleRes), iconStyle = BigIcon.Style.Default(icon), subtitle = stringResource(subtitleRes), @@ -486,9 +489,9 @@ private fun LoadingContent( OnboardingBackground() Column( modifier = Modifier - .fillMaxSize() - .padding(top = 48.dp) - .padding(24.dp), + .fillMaxSize() + .padding(top = 48.dp) + .padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt new file mode 100644 index 0000000000..521f585202 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.UniqueId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.Timeline +import kotlinx.collections.immutable.persistentListOf +import javax.inject.Inject + +interface MediaTimeline { + suspend fun getTimeline(): Result + fun getCache(): GroupedMediaItems? + fun orCache(data: GroupedMediaItems): GroupedMediaItems +} + +/** + * A timeline holder that can be used by the gallery and the media viewer. + * When opening the Media Viewer, if the held timeline knows the Event, it will + * be used, else a FocusedMediaTimeline will be used. + */ +@SingleIn(RoomScope::class) +@ContributesBinding(RoomScope::class) +class LiveMediaTimeline @Inject constructor( + private val room: MatrixRoom, +) : MediaTimeline { + private var timeline: Timeline? = null + override suspend fun getTimeline(): Result { + return if (timeline == null) { + room.mediaTimeline(null).fold( + { + timeline = it + Result.success(it) + }, + { + Result.failure(it) + }, + ) + } else { + Result.success(timeline!!) + } + } + + // No cache for LiveMediaTimeline + override fun getCache(): GroupedMediaItems? = null + override fun orCache(data: GroupedMediaItems) = data +} + +/** + * A class that will provide a media timeline that is focused on a particular event. + */ +class FocusedMediaTimeline( + private val room: MatrixRoom, + private val eventId: EventId, + private val initialMediaItem: MediaItem.Event, +) : MediaTimeline { + override suspend fun getTimeline(): Result { + return room.mediaTimeline(eventId) + } + + override fun getCache(): GroupedMediaItems { + // TODO Cleanup + return GroupedMediaItems( + fileItems = persistentListOf( + MediaItem.LoadingIndicator( + id = UniqueId("loading_forwards"), + direction = Timeline.PaginationDirection.FORWARDS, + timestamp = -1L, + ), + initialMediaItem, + MediaItem.LoadingIndicator( + id = UniqueId("loading_backwards"), + direction = Timeline.PaginationDirection.BACKWARDS, + timestamp = -1L, + ), + ), + imageAndVideoItems = persistentListOf( + MediaItem.LoadingIndicator( + id = UniqueId("loading_forwards"), + direction = Timeline.PaginationDirection.FORWARDS, + timestamp = -1L, + ), + initialMediaItem, + MediaItem.LoadingIndicator( + id = UniqueId("loading_backwards"), + direction = Timeline.PaginationDirection.BACKWARDS, + timestamp = -1L, + ), + ), + ) + } + + override fun orCache(data: GroupedMediaItems): GroupedMediaItems { + return if (data.hasEvent(eventId)) { + data + } else { + getCache() + } + } +} + +fun GroupedMediaItems.hasEvent(eventId: EventId): Boolean { + return (fileItems + imageAndVideoItems) + .filterIsInstance() + .any { it.eventId() == eventId } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt index 8e6b708a7f..91ee02966e 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt @@ -29,57 +29,57 @@ class SingleMediaGalleryDataSource( companion object { fun createFrom(params: MediaViewerEntryPoint.Params) = SingleMediaGalleryDataSource( - data = when { - params.mediaInfo.mimeType.isMimeTypeImage() -> { - MediaItem.Image( - id = UniqueId("dummy"), - eventId = params.eventId, - mediaInfo = params.mediaInfo, - mediaSource = params.mediaSource, - thumbnailSource = params.thumbnailSource, - ) - } - params.mediaInfo.mimeType.isMimeTypeVideo() -> { - MediaItem.Video( - id = UniqueId("dummy"), - eventId = params.eventId, - mediaInfo = params.mediaInfo, - mediaSource = params.mediaSource, - thumbnailSource = params.thumbnailSource, - ) - } - params.mediaInfo.mimeType.isMimeTypeAudio() -> { - if (params.mediaInfo.waveform == null) { - MediaItem.Audio( - id = UniqueId("dummy"), - eventId = params.eventId, - mediaInfo = params.mediaInfo, - mediaSource = params.mediaSource, - ) - } else { - MediaItem.Voice( - id = UniqueId("dummy"), - eventId = params.eventId, - mediaInfo = params.mediaInfo, - mediaSource = params.mediaSource, - ) - } - } - else -> { - MediaItem.File( - id = UniqueId("dummy"), - eventId = params.eventId, - mediaInfo = params.mediaInfo, - mediaSource = params.mediaSource, - ) - } - }.let { mediaItem -> - GroupedMediaItems( - // Always use imageAndVideoItems, in Single mode, this is the data that will be used - imageAndVideoItems = persistentListOf(mediaItem), - fileItems = persistentListOf(), - ) - } + data = GroupedMediaItems( + // Always use imageAndVideoItems, in Single mode, this is the data that will be used + imageAndVideoItems = persistentListOf(params.toMediaItem()), + fileItems = persistentListOf(), + ) + ) + } +} + +fun MediaViewerEntryPoint.Params.toMediaItem() = when { + mediaInfo.mimeType.isMimeTypeImage() -> { + MediaItem.Image( + id = UniqueId("dummy"), + eventId = eventId, + mediaInfo = mediaInfo, + mediaSource = mediaSource, + thumbnailSource = thumbnailSource, + ) + } + mediaInfo.mimeType.isMimeTypeVideo() -> { + MediaItem.Video( + id = UniqueId("dummy"), + eventId = eventId, + mediaInfo = mediaInfo, + mediaSource = mediaSource, + thumbnailSource = thumbnailSource, + ) + } + mediaInfo.mimeType.isMimeTypeAudio() -> { + if (mediaInfo.waveform == null) { + MediaItem.Audio( + id = UniqueId("dummy"), + eventId = eventId, + mediaInfo = mediaInfo, + mediaSource = mediaSource, + ) + } else { + MediaItem.Voice( + id = UniqueId("dummy"), + eventId = eventId, + mediaInfo = mediaInfo, + mediaSource = mediaSource, + ) + } + } + else -> { + MediaItem.File( + id = UniqueId("dummy"), + eventId = eventId, + mediaInfo = mediaInfo, + mediaSource = mediaSource, ) } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index b185834c3e..b69105930d 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -44,6 +44,7 @@ class MediaViewerDataSource( private val mediaLoader: MatrixMediaLoader, private val localMediaFactory: LocalMediaFactory, private val systemClock: SystemClock, + private val pagerKeysHandler: PagerKeysHandler, ) { // List of media files that are currently being loaded private val mediaFiles: MutableList = mutableListOf() @@ -78,6 +79,7 @@ class MediaViewerDataSource( MediaViewerPageData.Loading( direction = Timeline.PaginationDirection.BACKWARDS, timestamp = systemClock.epochMillis(), + pagerKey = Long.MIN_VALUE, ) ) } @@ -108,7 +110,10 @@ class MediaViewerDataSource( * will be used to render the downloaded media (see [loadMedia] which will update this value). */ private fun buildMediaViewerPageList(groupedItems: List) = buildList { - groupedItems.forEach { mediaItem -> + // Filter out DateSeparator items, we do not need them for the media viewer + val groupedItemsNoDateSeparator = groupedItems.filterNot { it is MediaItem.DateSeparator } + pagerKeysHandler.accept(groupedItemsNoDateSeparator) + groupedItemsNoDateSeparator.forEach { mediaItem -> when (mediaItem) { is MediaItem.DateSeparator -> Unit is MediaItem.Event -> { @@ -123,6 +128,7 @@ class MediaViewerDataSource( mediaSource = mediaItem.mediaSource(), thumbnailSource = mediaItem.thumbnailSource(), downloadedMedia = localMedia, + pagerKey = pagerKeysHandler.getKey(mediaItem), ) ) } @@ -130,6 +136,7 @@ class MediaViewerDataSource( MediaViewerPageData.Loading( direction = mediaItem.direction, timestamp = systemClock.epochMillis(), + pagerKey = pagerKeysHandler.getKey(mediaItem), ) ) } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index e06b691520..a9df9073ed 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -24,9 +24,12 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory +import io.element.android.libraries.mediaviewer.impl.gallery.FocusedTimelineMediaGalleryDataSourceFactory import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.gallery.SingleMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.TimelineMediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.gallery.hasEvent +import io.element.android.libraries.mediaviewer.impl.gallery.toMediaItem import io.element.android.services.toolbox.api.systemclock.SystemClock @ContributesNode(RoomScope::class) @@ -35,10 +38,12 @@ class MediaViewerNode @AssistedInject constructor( @Assisted plugins: List, presenterFactory: MediaViewerPresenter.Factory, timelineMediaGalleryDataSource: TimelineMediaGalleryDataSource, + focusedTimelineMediaGalleryDataSourceFactory: FocusedTimelineMediaGalleryDataSourceFactory, mediaLoader: MatrixMediaLoader, localMediaFactory: LocalMediaFactory, coroutineDispatchers: CoroutineDispatchers, systemClock: SystemClock, + pagerKeysHandler: PagerKeysHandler, ) : Node(buildContext, plugins = plugins), MediaViewerNavigator { private val inputs = inputs() @@ -62,7 +67,23 @@ class MediaViewerNode @AssistedInject constructor( private val mediaGallerySource = if (inputs.mode == MediaViewerEntryPoint.MediaViewerMode.SingleMedia) { SingleMediaGalleryDataSource.createFrom(inputs) } else { - timelineMediaGalleryDataSource + val eventId = inputs.eventId + if (eventId == null) { + // 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(), + ) + } + } } private val galleryMode = when (inputs.mode) { @@ -81,6 +102,7 @@ class MediaViewerNode @AssistedInject constructor( mediaLoader = mediaLoader, localMediaFactory = localMediaFactory, systemClock = systemClock, + pagerKeysHandler = pagerKeysHandler, ) ) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt index cf363a70f1..4eeda0c352 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt @@ -28,13 +28,17 @@ data class MediaViewerState( ) sealed interface MediaViewerPageData { + val pagerKey: Long + data class Failure( val throwable: Throwable, + override val pagerKey: Long = 0, ) : MediaViewerPageData data class Loading( val direction: Timeline.PaginationDirection, val timestamp: Long, + override val pagerKey: Long, ) : MediaViewerPageData data class MediaViewerData( @@ -43,5 +47,14 @@ sealed interface MediaViewerPageData { val mediaSource: MediaSource, val thumbnailSource: MediaSource?, val downloadedMedia: State>, + override val pagerKey: Long, ) : MediaViewerPageData } + +fun MediaViewerPageData.toKey(): String { + return when (this) { + is MediaViewerPageData.Failure -> "Failure" + is MediaViewerPageData.Loading -> "Loading_${direction}" + is MediaViewerPageData.MediaViewerData -> eventId?.value ?: mediaSource.url + } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt index 2c54751fed..95557c13d6 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerStateProvider.kt @@ -169,6 +169,7 @@ fun aMediaViewerPageDataLoading( return MediaViewerPageData.Loading( direction = direction, timestamp = timestamp, + pagerKey = 0L, ) } @@ -182,6 +183,7 @@ fun aMediaViewerPageData( mediaSource = mediaSource, thumbnailSource = null, downloadedMedia = mutableStateOf(downloadedMedia), + pagerKey = 0L, ) fun aMediaViewerState( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 51476193d0..3ba57cae33 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -114,6 +114,7 @@ fun MediaViewerView( modifier = Modifier, // Pre-load previous and next pages beyondViewportPageCount = 1, + key = { index -> state.listData[index].pagerKey }, ) { page -> when (val dataForPage = state.listData[page]) { is MediaViewerPageData.Failure -> { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt new file mode 100644 index 0000000000..23ba312b0a --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.viewer + +import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.gallery.eventId +import javax.inject.Inject + +/** + * x and y are loading items. + * Capital letters are media items. + * First list emitted + * x F G H y + * indexes will be + * 0 1 2 3 4 + * (keyOffset = 0) + * New items added to the end of the list + * x F G H I J K y + * indexes will be + * 0 1 2 3 4 5 6 7 + * (keyOffset = 0) + * New items added to the beginning of the list + * x D E F G H I J K y + * indexes will be + * -2 -1 0 1 2 3 4 5 6 7 + * (keyOffset = -2) + * loader item vanishes + * D E F G H I J K + * indexes will be + * -1 0 1 2 3 4 5 6 + * (keyOffset = -1) + */ +class PagerKeysHandler @Inject constructor() { + private data class Data( + val mediaItems: List, + val keyOffset: Long, + ) + + // Will store the list of media items and the key offset of the first item in the list + private var cachedData: Data = Data(emptyList(), 0) + + fun accept(mediaItems: List) { + if (cachedData.mediaItems.isEmpty()) { + cachedData = Data(mediaItems, 0) + } else { + // Search a common item in both lists, i.e. an item with the same eventId + val itemInCacheIndex = cachedData.mediaItems.indexOfFirst { mediaItem -> + mediaItem is MediaItem.Event && mediaItems + .filterIsInstance() + .any { mediaItem.eventId() == it.eventId() } + } + cachedData = if (itemInCacheIndex == -1) { + // If the item is not found, start with a new cache + Data(mediaItems, 0) + } else { + val cachedItem = cachedData.mediaItems[itemInCacheIndex] + val eventId = (cachedItem as? MediaItem.Event)?.eventId() + if (eventId == null) { + // Should not happen, but in this case, start with a new cache + Data(mediaItems, 0) + } else { + // Search the index of the item in the new list + val itemIndex = mediaItems.indexOfFirst { mediaItem -> + mediaItem is MediaItem.Event && mediaItem.eventId() == eventId + } + if (itemIndex == -1) { + // If the item is not found, start with a new cache + Data(mediaItems, 0) + } else { + // Update the cache with the new list and the new offset + Data(mediaItems, cachedData.keyOffset + itemInCacheIndex - itemIndex.toLong()) + } + } + } + } + } + + fun getKey(mediaItem: MediaItem): Long { + return cachedData.mediaItems.indexOf(mediaItem) + cachedData.keyOffset + } +} diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt index 2f8cd634ec..27155ccc3e 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt @@ -260,6 +260,7 @@ class TimelineMediaGalleryDataSourceTest { ): TimelineMediaGalleryDataSource { return TimelineMediaGalleryDataSource( room = room, + mediaTimeline = LiveMediaTimeline(room), timelineMediaItemsFactory = TimelineMediaItemsFactory( dispatchers = testCoroutineDispatchers(), virtualItemFactory = VirtualItemFactory( diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt index 5348eb2aa3..e43afbf80e 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt @@ -122,10 +122,12 @@ class MediaViewerDataSourceTest { MediaViewerPageData.Loading( direction = Timeline.PaginationDirection.BACKWARDS, timestamp = A_FAKE_TIMESTAMP, + pagerKey = 0L, ), MediaViewerPageData.Loading( direction = Timeline.PaginationDirection.FORWARDS, timestamp = A_FAKE_TIMESTAMP, + pagerKey = 1L, ), ) } @@ -274,5 +276,6 @@ class MediaViewerDataSourceTest { mediaLoader = mediaLoader, localMediaFactory = localMediaFactory, systemClock = FakeSystemClock(), + pagerKeysHandler = PagerKeysHandler(), ) } diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index 8a2d536a78..079788c1bc 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -792,6 +792,7 @@ class MediaViewerPresenterTest { mediaLoader = matrixMediaLoader, localMediaFactory = localMediaFactory, systemClock = FakeSystemClock(), + pagerKeysHandler = PagerKeysHandler(), ), room = room, localMediaActions = localMediaActions, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt new file mode 100644 index 0000000000..056a62c86f --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.viewer + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator +import org.junit.Test + +class PagerKeysHandlerTest { + private val image1 = aMediaItemImage( + eventId = AN_EVENT_ID, + ) + private val image2 = aMediaItemImage( + eventId = AN_EVENT_ID_2, + ) + private val aBackwardLoadingIndicator = aMediaItemLoadingIndicator( + direction = Timeline.PaginationDirection.BACKWARDS + ) + private val aForwardLoadingIndicator = aMediaItemLoadingIndicator( + direction = Timeline.PaginationDirection.FORWARDS + ) + + @Test + fun `when new items are inserted after existing items, keys are not shifted`() { + val sut = PagerKeysHandler() + sut.accept(listOf(aBackwardLoadingIndicator, image1, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(2) + sut.accept(listOf(aBackwardLoadingIndicator, image1, image2, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(image2)).isEqualTo(2) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(3) + } + + @Test + fun `when new items are inserted before existing items, keys are not shifted`() { + val sut = PagerKeysHandler() + sut.accept(listOf(aBackwardLoadingIndicator, image1, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(2) + sut.accept(listOf(aBackwardLoadingIndicator, image2, image1, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(-1) + assertThat(sut.getKey(image2)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(2) + // Accepting the same list should not change the keys + sut.accept(listOf(aBackwardLoadingIndicator, image2, image1, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(-1) + assertThat(sut.getKey(image2)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(2) + } + + @Test + fun `when loaders are removed, keys are not shifted`() { + val sut = PagerKeysHandler() + sut.accept(listOf(aBackwardLoadingIndicator, image1, aForwardLoadingIndicator)) + assertThat(sut.getKey(aBackwardLoadingIndicator)).isEqualTo(0) + assertThat(sut.getKey(image1)).isEqualTo(1) + assertThat(sut.getKey(aForwardLoadingIndicator)).isEqualTo(2) + sut.accept(listOf(image1)) + assertThat(sut.getKey(image1)).isEqualTo(1) + } +} From e9a9e79b40458a8ecefd9f607a53ea1bcc9b0bcc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 11:33:07 +0100 Subject: [PATCH 02/10] Cleanup --- .../mediaviewer/api/MediaViewerEntryPoint.kt | 1 - .../impl/gallery/MediaGalleryDataSource.kt | 4 +- .../impl/gallery/MediaGalleryState.kt | 7 +++ .../impl/gallery/MediaGalleryView.kt | 5 +- .../mediaviewer/impl/gallery/MediaTimeline.kt | 59 +++++++------------ .../impl/viewer/MediaViewerState.kt | 8 --- .../tests/konsist/KonsistClassNameTest.kt | 1 + 7 files changed, 31 insertions(+), 54 deletions(-) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt index bbcd931410..a824fc5540 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt @@ -39,7 +39,6 @@ interface MediaViewerEntryPoint : FeatureEntryPoint { val canShowInfo: Boolean, ) : NodeInputs - // TODO convert to sealed class and add eventId to the 2nd and 3rd items enum class MediaViewerMode { SingleMedia, TimelineImagesAndVideos, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt index 204f140eda..3cf6823fd7 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt @@ -50,7 +50,7 @@ class TimelineMediaGalleryDataSource @Inject constructor( override fun groupedMediaItemsFlow(): Flow> = groupedMediaItemsFlow override fun getLastData(): AsyncData = groupedMediaItemsFlow.replayCache.firstOrNull() - ?: mediaTimeline.getCache()?.let { AsyncData.Success(it) } + ?: mediaTimeline.cache?.let { AsyncData.Success(it) } ?: AsyncData.Uninitialized private val isStarted = AtomicBoolean(false) @@ -61,7 +61,7 @@ class TimelineMediaGalleryDataSource @Inject constructor( return } flow { - val cache = mediaTimeline.getCache() + val cache = mediaTimeline.cache if (cache != null) { groupedMediaItemsFlow.emit(AsyncData.Success(cache)) } else { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt index 750dbe1038..2cb3b40b9b 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage +import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.mediaviewer.impl.R import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState import kotlinx.collections.immutable.ImmutableList @@ -34,6 +35,12 @@ data class GroupedMediaItems( } } +fun GroupedMediaItems.hasEvent(eventId: EventId): Boolean { + return (fileItems + imageAndVideoItems) + .filterIsInstance() + .any { it.eventId() == eventId } +} + enum class MediaGalleryMode(val stringResource: Int) { Images(R.string.screen_media_browser_list_mode_media), Files(R.string.screen_media_browser_list_mode_files), diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt index 3eb5281c43..38712c3ea3 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt @@ -440,10 +440,7 @@ private fun LoadingMoreIndicator( } val latestEventSink by rememberUpdatedState(eventSink) LaunchedEffect(item.timestamp) { - // TODO Add isFake to the model instead of using -1 for timestamp - if (item.timestamp != -1L) { - latestEventSink(MediaGalleryEvents.LoadMore(item.direction)) - } + latestEventSink(MediaGalleryEvents.LoadMore(item.direction)) } } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt index 521f585202..eba170f473 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt @@ -19,7 +19,7 @@ import javax.inject.Inject interface MediaTimeline { suspend fun getTimeline(): Result - fun getCache(): GroupedMediaItems? + val cache: GroupedMediaItems? fun orCache(data: GroupedMediaItems): GroupedMediaItems } @@ -51,7 +51,7 @@ class LiveMediaTimeline @Inject constructor( } // No cache for LiveMediaTimeline - override fun getCache(): GroupedMediaItems? = null + override val cache = null override fun orCache(data: GroupedMediaItems) = data } @@ -61,41 +61,28 @@ class LiveMediaTimeline @Inject constructor( class FocusedMediaTimeline( private val room: MatrixRoom, private val eventId: EventId, - private val initialMediaItem: MediaItem.Event, + initialMediaItem: MediaItem.Event, ) : MediaTimeline { override suspend fun getTimeline(): Result { return room.mediaTimeline(eventId) } - override fun getCache(): GroupedMediaItems { - // TODO Cleanup - return GroupedMediaItems( - fileItems = persistentListOf( - MediaItem.LoadingIndicator( - id = UniqueId("loading_forwards"), - direction = Timeline.PaginationDirection.FORWARDS, - timestamp = -1L, - ), - initialMediaItem, - MediaItem.LoadingIndicator( - id = UniqueId("loading_backwards"), - direction = Timeline.PaginationDirection.BACKWARDS, - timestamp = -1L, - ), - ), - imageAndVideoItems = persistentListOf( - MediaItem.LoadingIndicator( - id = UniqueId("loading_forwards"), - direction = Timeline.PaginationDirection.FORWARDS, - timestamp = -1L, - ), - initialMediaItem, - MediaItem.LoadingIndicator( - id = UniqueId("loading_backwards"), - direction = Timeline.PaginationDirection.BACKWARDS, - timestamp = -1L, - ), - ), + override val cache = persistentListOf( + MediaItem.LoadingIndicator( + id = UniqueId("loading_forwards"), + direction = Timeline.PaginationDirection.FORWARDS, + timestamp = 0L, + ), + initialMediaItem, + MediaItem.LoadingIndicator( + id = UniqueId("loading_backwards"), + direction = Timeline.PaginationDirection.BACKWARDS, + timestamp = 0L, + ), + ).let { + GroupedMediaItems( + fileItems = it, + imageAndVideoItems = it, ) } @@ -103,13 +90,7 @@ class FocusedMediaTimeline( return if (data.hasEvent(eventId)) { data } else { - getCache() + cache } } } - -fun GroupedMediaItems.hasEvent(eventId: EventId): Boolean { - return (fileItems + imageAndVideoItems) - .filterIsInstance() - .any { it.eventId() == eventId } -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt index 4eeda0c352..32c22b0470 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerState.kt @@ -50,11 +50,3 @@ sealed interface MediaViewerPageData { override val pagerKey: Long, ) : MediaViewerPageData } - -fun MediaViewerPageData.toKey(): String { - return when (this) { - is MediaViewerPageData.Failure -> "Failure" - is MediaViewerPageData.Loading -> "Loading_${direction}" - is MediaViewerPageData.MediaViewerData -> eventId?.value ?: mediaSource.url - } -} diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt index d140d3fea4..b5e75b904d 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistClassNameTest.kt @@ -136,6 +136,7 @@ class KonsistClassNameTest { "Enterprise", "Fdroid", "FileExtensionExtractor", + "LiveMediaTimeline", "KeyStore", "Matrix", "Noop", From c57b2777dc5d53472e807b6153809edcd8669fe6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 12:23:59 +0100 Subject: [PATCH 03/10] Add tests on FocusedMediaTimeline --- .../impl/gallery/FocusedMediaTimelineTest.kt | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt new file mode 100644 index 0000000000..77cbcd3aaf --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.Timeline +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.timeline.FakeTimeline +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class FocusedMediaTimelineTest { + @Test + fun `check the returned cache data`() { + val media = aMediaItemImage() + val sut = createFocusedMediaTimeline( + initialMediaItem = media, + ) + val cache = sut.cache + assertThat(cache.imageAndVideoItems.size).isEqualTo(3) + assertThat(cache.fileItems.size).isEqualTo(3) + assertThat(cache.imageAndVideoItems[1]).isEqualTo(media) + assertThat(cache.fileItems[1]).isEqualTo(media) + } + + @Test + fun `when event is not found, the cache is returned`() { + val media = aMediaItemImage( + eventId = AN_EVENT_ID, + ) + val sut = createFocusedMediaTimeline( + initialMediaItem = media, + ) + val cache = sut.orCache( + GroupedMediaItems( + imageAndVideoItems = persistentListOf(), + fileItems = persistentListOf(), + ) + ) + assertThat(cache.imageAndVideoItems.size).isEqualTo(3) + assertThat(cache.fileItems.size).isEqualTo(3) + } + + @Test + fun `when event is found, the data is returned`() { + val media = aMediaItemImage( + eventId = AN_EVENT_ID, + ) + val sut = createFocusedMediaTimeline( + initialMediaItem = media, + ) + val cache = sut.orCache( + GroupedMediaItems( + imageAndVideoItems = persistentListOf(media), + fileItems = persistentListOf(), + ) + ) + assertThat(cache.imageAndVideoItems.size).isEqualTo(1) + assertThat(cache.fileItems).isEmpty() + } + + @Test + fun `getTimeline returns the timeline provided by the room`() = runTest { + val mediaTimelineResult = lambdaRecorder> { + Result.success(FakeTimeline()) + } + val room = FakeMatrixRoom( + mediaTimelineResult = mediaTimelineResult, + ) + val sut = createFocusedMediaTimeline( + room = room, + eventId = AN_EVENT_ID, + ) + val timeline = sut.getTimeline() + assertThat(timeline.isSuccess).isTrue() + mediaTimelineResult.assertions().isCalledOnce().with(value(AN_EVENT_ID)) + } + + private fun createFocusedMediaTimeline( + room: MatrixRoom = FakeMatrixRoom(), + eventId: EventId = AN_EVENT_ID, + initialMediaItem: MediaItem.Event = aMediaItemImage(), + ) = FocusedMediaTimeline( + room = room, + eventId = eventId, + initialMediaItem = initialMediaItem, + ) +} From 0365497b98d39c79cad31e618238148b975dd347 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 12:33:19 +0100 Subject: [PATCH 04/10] Add tests on LiveMediaTimeline --- .../impl/gallery/LiveMediaTimelineTest.kt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt new file mode 100644 index 0000000000..6267d87b93 --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class LiveMediaTimelineTest { + @Test + fun `LiveMediaTimeline cache is always null`() = runTest { + val sut = createLiveMediaTimeline() + assertThat(sut.cache).isNull() + } + + @Test + fun `getTimeline returns the timeline provided by the room, then from cache`() = runTest { + val mediaTimelineResult = lambdaRecorder> { + Result.success(FakeTimeline()) + } + val room = FakeMatrixRoom( + mediaTimelineResult = mediaTimelineResult, + ) + val sut = createLiveMediaTimeline( + room = room, + ) + val timeline = sut.getTimeline() + assertThat(timeline.isSuccess).isTrue() + mediaTimelineResult.assertions().isCalledOnce().with(value(null)) + val timeline2 = sut.getTimeline() + assertThat(timeline2.isSuccess).isTrue() + // No called another time + mediaTimelineResult.assertions().isCalledOnce() + } + + private fun createLiveMediaTimeline( + room: MatrixRoom = FakeMatrixRoom(), + ) = LiveMediaTimeline( + room = room, + ) +} From 01345312ad495b8f110182461658752ca3c59dd1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 12:42:30 +0100 Subject: [PATCH 05/10] Add tests on DefaultFocusedTimelineMediaGalleryDataSourceFactory --- ...melineMediaGalleryDataSourceFactoryTest.kt | 31 +++++++++++++++++++ .../TimelineMediaGalleryDataSourceTest.kt | 24 +++++++------- 2 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt new file mode 100644 index 0000000000..ddd39ce1bc --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest { + @Test + fun `createFor should create a TimelineMediaGalleryDataSource`() = runTest { + val sut = DefaultFocusedTimelineMediaGalleryDataSourceFactory( + room = FakeMatrixRoom(), + timelineMediaItemsFactory = createTimelineMediaItemsFactory(), + mediaItemsPostProcessor = MediaItemsPostProcessor(), + ) + val result = sut.createFor( + eventId = AN_EVENT_ID, + mediaItem = aMediaItemImage(), + ) + assertThat(result).isInstanceOf(TimelineMediaGalleryDataSource::class.java) + } +} diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt index 27155ccc3e..d1a0c408ec 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt @@ -261,18 +261,20 @@ class TimelineMediaGalleryDataSourceTest { return TimelineMediaGalleryDataSource( room = room, mediaTimeline = LiveMediaTimeline(room), - timelineMediaItemsFactory = TimelineMediaItemsFactory( - dispatchers = testCoroutineDispatchers(), - virtualItemFactory = VirtualItemFactory( - dateFormatter = FakeDateFormatter(), - ), - eventItemFactory = EventItemFactory( - fileSizeFormatter = FakeFileSizeFormatter(), - fileExtensionExtractor = FileExtensionExtractorWithoutValidation(), - dateFormatter = FakeDateFormatter(), - ), - ), + timelineMediaItemsFactory = createTimelineMediaItemsFactory(), mediaItemsPostProcessor = MediaItemsPostProcessor(), ) } } + +fun TestScope.createTimelineMediaItemsFactory() = TimelineMediaItemsFactory( + dispatchers = testCoroutineDispatchers(), + virtualItemFactory = VirtualItemFactory( + dateFormatter = FakeDateFormatter(), + ), + eventItemFactory = EventItemFactory( + fileSizeFormatter = FakeFileSizeFormatter(), + fileExtensionExtractor = FileExtensionExtractorWithoutValidation(), + dateFormatter = FakeDateFormatter(), + ), +) From 9b1d0aadbe66dc039624c8eaf7ab1f464891aa8e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 28 Jan 2025 12:47:05 +0100 Subject: [PATCH 06/10] Add tests on GroupedMediaItems.hasEvent --- .../android/libraries/matrix/test/TestData.kt | 1 + .../impl/gallery/ui/MediaItemAudioProvider.kt | 4 ++- .../impl/gallery/GroupedMediaItemsTest.kt | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt index 1946d2259b..509fac833c 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt @@ -48,6 +48,7 @@ val A_THREAD_ID = ThreadId("\$aThreadId") val A_THREAD_ID_2 = ThreadId("\$aThreadId2") val AN_EVENT_ID = EventId("\$anEventId") val AN_EVENT_ID_2 = EventId("\$anEventId2") +val AN_EVENT_ID_3 = EventId("\$anEventId3") val A_ROOM_ALIAS = RoomAlias("#alias1:domain") val A_TRANSACTION_ID = TransactionId("aTransactionId") val A_DEVICE_ID = DeviceId("ILAKNDNASDLK") diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt index 7a0f6282ce..84eb7eadca 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.preview.loremIpsum +import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo @@ -30,12 +31,13 @@ class MediaItemAudioProvider : PreviewParameterProvider { fun aMediaItemAudio( id: UniqueId = UniqueId("fileId"), + eventId: EventId? = null, filename: String = "filename", caption: String? = null, ): MediaItem.Audio { return MediaItem.Audio( id = id, - eventId = null, + eventId = eventId, mediaInfo = anAudioMediaInfo( filename = filename, caption = caption, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt new file mode 100644 index 0000000000..5a7cc91490 --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 +import io.element.android.libraries.matrix.test.AN_EVENT_ID_3 +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemAudio +import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import kotlinx.collections.immutable.persistentListOf +import org.junit.Test + +class GroupedMediaItemsTest { + @Test + fun `hasEvent returns the expected value`() { + val sut = GroupedMediaItems( + imageAndVideoItems = persistentListOf( + aMediaItemImage(eventId = AN_EVENT_ID), + ), + fileItems = persistentListOf( + aMediaItemAudio(eventId = AN_EVENT_ID_2), + ), + ) + assertThat(sut.hasEvent(AN_EVENT_ID)).isTrue() + assertThat(sut.hasEvent(AN_EVENT_ID_2)).isTrue() + assertThat(sut.hasEvent(AN_EVENT_ID_3)).isFalse() + } +} From 82f7a256f3bd696dcfea446cf71ce68956660cb3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 29 Jan 2025 10:04:40 +0100 Subject: [PATCH 07/10] Move some classes in new packages - io.element.android.libraries.mediaviewer.impl.datasource - package io.element.android.libraries.mediaviewer.impl.model --- .../EventItemFactory.kt | 3 +- ...edTimelineMediaGalleryDataSourceFactory.kt | 3 +- .../MediaGalleryDataSource.kt | 3 +- .../MediaItemsPostProcessor.kt | 4 ++- .../{gallery => datasource}/MediaTimeline.kt | 5 +++- .../TimelineMediaItemsFactory.kt | 3 +- .../VirtualItemFactory.kt | 3 +- .../impl/gallery/MediaGalleryEvents.kt | 1 + .../impl/gallery/MediaGalleryNode.kt | 1 + .../impl/gallery/MediaGalleryPresenter.kt | 6 ++++ .../impl/gallery/MediaGalleryState.kt | 21 +------------ .../impl/gallery/MediaGalleryStateProvider.kt | 2 ++ .../impl/gallery/MediaGalleryView.kt | 3 ++ .../di/FakeTimelineItemPresenterFactories.kt | 2 +- .../gallery/di/MediaItemEventContentKey.kt | 2 +- .../gallery/di/MediaItemPresenterFactories.kt | 2 +- .../gallery/di/MediaItemPresenterFactory.kt | 2 +- .../impl/gallery/root/MediaGalleryRootNode.kt | 10 +++---- .../impl/gallery/ui/AudioItemView.kt | 2 +- .../impl/gallery/ui/DateItemView.kt | 2 +- .../impl/gallery/ui/FileItemView.kt | 2 +- .../impl/gallery/ui/ImageItemView.kt | 2 +- .../impl/gallery/ui/MediaItemAudioProvider.kt | 2 +- .../ui/MediaItemDateSeparatorProvider.kt | 2 +- .../impl/gallery/ui/MediaItemFileProvider.kt | 2 +- .../impl/gallery/ui/MediaItemImageProvider.kt | 2 +- .../ui/MediaItemLoadingIndicatorProvider.kt | 2 +- .../impl/gallery/ui/MediaItemVideoProvider.kt | 2 +- .../impl/gallery/ui/MediaItemVoiceProvider.kt | 2 +- .../impl/gallery/ui/VideoItemView.kt | 2 +- .../impl/gallery/ui/VoiceItemView.kt | 2 +- .../gallery/voice/VoiceMessagePresenter.kt | 2 +- .../impl/model/GroupedMediaItems.kt | 30 +++++++++++++++++++ .../impl/{gallery => model}/MediaItem.kt | 2 +- .../impl/viewer/MediaViewerDataSource.kt | 12 ++++---- .../impl/viewer/MediaViewerNode.kt | 8 ++--- .../impl/viewer/PagerKeysHandler.kt | 4 +-- .../SingleMediaGalleryDataSource.kt | 5 +++- .../DefaultEventItemFactoryTest.kt | 3 +- ...melineMediaGalleryDataSourceFactoryTest.kt | 2 +- .../FakeMediaGalleryDataSource.kt | 3 +- .../FocusedMediaTimelineTest.kt | 4 ++- .../LiveMediaTimelineTest.kt | 3 +- .../MediaItemsPostProcessorTest.kt | 4 ++- .../TimelineMediaGalleryDataSourceTest.kt | 4 ++- .../impl/gallery/MediaGalleryPresenterTest.kt | 2 ++ .../GroupedMediaItemsTest.kt | 2 +- .../impl/viewer/MediaViewerDataSourceTest.kt | 4 +-- .../impl/viewer/MediaViewerPresenterTest.kt | 6 ++-- .../SingleMediaGalleryDataSourceTest.kt | 4 ++- 50 files changed, 127 insertions(+), 79 deletions(-) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/EventItemFactory.kt (98%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/FocusedTimelineMediaGalleryDataSourceFactory.kt (91%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/MediaGalleryDataSource.kt (96%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/MediaItemsPostProcessor.kt (92%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/MediaTimeline.kt (91%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/TimelineMediaItemsFactory.kt (96%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/VirtualItemFactory.kt (92%) create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItems.kt rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => model}/MediaItem.kt (98%) rename libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => viewer}/SingleMediaGalleryDataSource.kt (91%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/DefaultEventItemFactoryTest.kt (99%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt (94%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/FakeMediaGalleryDataSource.kt (91%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/FocusedMediaTimelineTest.kt (94%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/LiveMediaTimelineTest.kt (92%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/MediaItemsPostProcessorTest.kt (96%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => datasource}/TimelineMediaGalleryDataSourceTest.kt (98%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => model}/GroupedMediaItemsTest.kt (95%) rename libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/{gallery => viewer}/SingleMediaGalleryDataSourceTest.kt (96%) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/EventItemFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt similarity index 98% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/EventItemFactory.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt index 293329c2dd..705921db8b 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/EventItemFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactory.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import io.element.android.libraries.androidutils.filesize.FileSizeFormatter import io.element.android.libraries.dateformatter.api.DateFormatter @@ -40,6 +40,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import timber.log.Timber import javax.inject.Inject diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt similarity index 91% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt index a8a4d0380d..f7426aa4e9 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedTimelineMediaGalleryDataSourceFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt @@ -5,12 +5,13 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import javax.inject.Inject interface FocusedTimelineMediaGalleryDataSourceFactory { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt similarity index 96% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt index 3cf6823fd7..4ad36d8827 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.architecture.AsyncData @@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessor.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessor.kt similarity index 92% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessor.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessor.kt index 3fb8d81b1f..1d3fd09a6c 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessor.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessor.kt @@ -5,8 +5,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt similarity index 91% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt index eba170f473..5b26b50d62 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaTimeline.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.RoomScope @@ -14,6 +14,9 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.hasEvent import kotlinx.collections.immutable.persistentListOf import javax.inject.Inject diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaItemsFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt similarity index 96% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaItemsFactory.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt index 0313390ddd..a759ba4d76 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaItemsFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaItemsFactory.kt @@ -5,13 +5,14 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import io.element.android.libraries.androidutils.diff.DefaultDiffCacheInvalidator import io.element.android.libraries.androidutils.diff.DiffCacheUpdater import io.element.android.libraries.androidutils.diff.MutableListDiffCache import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.Flow diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/VirtualItemFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/VirtualItemFactory.kt similarity index 92% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/VirtualItemFactory.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/VirtualItemFactory.kt index f364b06cb6..0c45edcf37 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/VirtualItemFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/VirtualItemFactory.kt @@ -5,12 +5,13 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import io.element.android.libraries.dateformatter.api.DateFormatter import io.element.android.libraries.dateformatter.api.DateFormatterMode import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import javax.inject.Inject class VirtualItemFactory @Inject constructor( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryEvents.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryEvents.kt index 8978059a51..df7d82c7b2 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryEvents.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryEvents.kt @@ -11,6 +11,7 @@ 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.MediaInfo +import io.element.android.libraries.mediaviewer.impl.model.MediaItem sealed interface MediaGalleryEvents { data class ChangeMode(val mode: MediaGalleryMode) : MediaGalleryEvents diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryNode.kt index c4519fcc0f..77520763f5 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryNode.kt @@ -21,6 +21,7 @@ import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.mediaviewer.impl.gallery.di.LocalMediaItemPresenterFactories import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresenterFactories +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @ContributesNode(RoomScope::class) class MediaGalleryNode @AssistedInject constructor( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt index e094e1b9fb..6617a8b9cb 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt @@ -32,8 +32,14 @@ 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.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.eventId +import io.element.android.libraries.mediaviewer.impl.model.mediaInfo +import io.element.android.libraries.mediaviewer.impl.model.mediaSource import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.launch diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt index 2cb3b40b9b..62877368d7 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryState.kt @@ -9,10 +9,9 @@ package io.element.android.libraries.mediaviewer.impl.gallery import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage -import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.mediaviewer.impl.R import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState -import kotlinx.collections.immutable.ImmutableList +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems data class MediaGalleryState( val roomName: String, @@ -23,24 +22,6 @@ data class MediaGalleryState( val eventSink: (MediaGalleryEvents) -> Unit, ) -data class GroupedMediaItems( - val imageAndVideoItems: ImmutableList, - val fileItems: ImmutableList, -) { - fun getItems(mode: MediaGalleryMode): ImmutableList { - return when (mode) { - MediaGalleryMode.Images -> imageAndVideoItems - MediaGalleryMode.Files -> fileItems - } - } -} - -fun GroupedMediaItems.hasEvent(eventId: EventId): Boolean { - return (fileItems + imageAndVideoItems) - .filterIsInstance() - .any { it.eventId() == eventId } -} - enum class MediaGalleryMode(val stringResource: Int) { Images(R.string.screen_media_browser_list_mode_media), Files(R.string.screen_media_browser_list_mode_files), diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt index 5a1b5fcca8..32c3e85322 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt @@ -20,6 +20,8 @@ import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVideo import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVoice +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.toImmutableList open class MediaGalleryStateProvider : PreviewParameterProvider { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt index 38712c3ea3..38eed3252f 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt @@ -72,6 +72,9 @@ import io.element.android.libraries.mediaviewer.impl.gallery.ui.FileItemView import io.element.android.libraries.mediaviewer.impl.gallery.ui.ImageItemView import io.element.android.libraries.mediaviewer.impl.gallery.ui.VideoItemView import io.element.android.libraries.mediaviewer.impl.gallery.ui.VoiceItemView +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.id import io.element.android.libraries.voiceplayer.api.VoiceMessageState import kotlinx.collections.immutable.ImmutableList diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/FakeTimelineItemPresenterFactories.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/FakeTimelineItemPresenterFactories.kt index bde6a57ad5..7a2094d890 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/FakeTimelineItemPresenterFactories.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/FakeTimelineItemPresenterFactories.kt @@ -8,7 +8,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.di import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.voiceplayer.api.VoiceMessageState import io.element.android.libraries.voiceplayer.api.aVoiceMessageState diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemEventContentKey.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemEventContentKey.kt index d76a631689..ad2e49f16f 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemEventContentKey.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemEventContentKey.kt @@ -8,7 +8,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.di import dagger.MapKey -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlin.reflect.KClass /** diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactories.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactories.kt index a2f7296135..02c0441d18 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactories.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactories.kt @@ -15,7 +15,7 @@ import dagger.multibindings.Multibinds import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import javax.inject.Inject /** diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactory.kt index 1216a2dea6..9730fb4c05 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/di/MediaItemPresenterFactory.kt @@ -8,7 +8,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.di import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem /** * A factory for a [Presenter] associated with a timeline item. diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryRootNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryRootNode.kt index 71a4057f4b..7317920005 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryRootNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryRootNode.kt @@ -31,11 +31,11 @@ import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint import io.element.android.libraries.mediaviewer.api.MediaInfo import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryNode -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem -import io.element.android.libraries.mediaviewer.impl.gallery.eventId -import io.element.android.libraries.mediaviewer.impl.gallery.mediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.mediaSource -import io.element.android.libraries.mediaviewer.impl.gallery.thumbnailSource +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.eventId +import io.element.android.libraries.mediaviewer.impl.model.mediaInfo +import io.element.android.libraries.mediaviewer.impl.model.mediaSource +import io.element.android.libraries.mediaviewer.impl.model.thumbnailSource import kotlinx.parcelize.Parcelize @ContributesNode(RoomScope::class) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/AudioItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/AudioItemView.kt index f25337343d..2cbbe6826c 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/AudioItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/AudioItemView.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @Composable fun AudioItemView( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/DateItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/DateItemView.kt index c6488b42a5..84fe175fc9 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/DateItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/DateItemView.kt @@ -18,7 +18,7 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @Composable fun DateItemView( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/FileItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/FileItemView.kt index a6af3f5ad7..bdb6539ecc 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/FileItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/FileItemView.kt @@ -35,7 +35,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @Composable fun FileItemView( diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt index 51610a8bd0..30c909eb9a 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt @@ -28,7 +28,7 @@ import coil.compose.AsyncImagePainter import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt index 84eb7eadca..7bfc09d1b9 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt @@ -13,7 +13,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem class MediaItemAudioProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt index 77f789310a..f39b5f33a9 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem class MediaItemDateSeparatorProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemFileProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemFileProvider.kt index c80e287c30..996147bf20 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemFileProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemFileProvider.kt @@ -13,7 +13,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem class MediaItemFileProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt index ceb934fbe2..f462276b60 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt @@ -12,7 +12,7 @@ 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.media.MediaSource import io.element.android.libraries.mediaviewer.api.anImageMediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem fun aMediaItemImage( id: UniqueId = UniqueId("imageId"), diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt index 2c78898325..1dd2d8f8c8 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.Timeline -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem fun aMediaItemLoadingIndicator( id: UniqueId = UniqueId("loadingId"), diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt index 8e59b925b7..7ab8e46718 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt @@ -11,7 +11,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem class MediaItemVideoProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt index 43e04491de..8c14464b73 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt @@ -13,7 +13,7 @@ import io.element.android.libraries.designsystem.components.media.aWaveForm import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.mediaviewer.api.aVoiceMediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem class MediaItemVoiceProvider : PreviewParameterProvider { override val values: Sequence diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VideoItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VideoItemView.kt index 6b394e7c55..f23be0f382 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VideoItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VideoItemView.kt @@ -38,7 +38,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview 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.Text -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt index d34555e175..384947b078 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt @@ -46,7 +46,7 @@ import io.element.android.libraries.designsystem.theme.components.HorizontalDivi 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.Text -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.voiceplayer.api.VoiceMessageEvents import io.element.android.libraries.voiceplayer.api.VoiceMessageState diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt index 4d215bc197..92acc754fc 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/voice/VoiceMessagePresenter.kt @@ -17,9 +17,9 @@ import dagger.assisted.AssistedInject import dagger.multibindings.IntoMap import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemEventContentKey import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresenterFactory +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory import io.element.android.libraries.voiceplayer.api.VoiceMessageState import kotlin.time.Duration diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItems.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItems.kt new file mode 100644 index 0000000000..448426f374 --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItems.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.model + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode +import kotlinx.collections.immutable.ImmutableList + +data class GroupedMediaItems( + val imageAndVideoItems: ImmutableList, + val fileItems: ImmutableList, +) { + fun getItems(mode: MediaGalleryMode): ImmutableList { + return when (mode) { + MediaGalleryMode.Images -> imageAndVideoItems + MediaGalleryMode.Files -> fileItems + } + } +} + +fun GroupedMediaItems.hasEvent(eventId: EventId): Boolean { + return (fileItems + imageAndVideoItems) + .filterIsInstance() + .any { it.eventId() == eventId } +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItem.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItem.kt similarity index 98% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItem.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItem.kt index e1bd4d779a..bf89486964 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItem.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItem.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.model import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index b69105930d..f66521fb16 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -20,13 +20,13 @@ import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem -import io.element.android.libraries.mediaviewer.impl.gallery.eventId -import io.element.android.libraries.mediaviewer.impl.gallery.mediaInfo -import io.element.android.libraries.mediaviewer.impl.gallery.mediaSource -import io.element.android.libraries.mediaviewer.impl.gallery.thumbnailSource +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.eventId +import io.element.android.libraries.mediaviewer.impl.model.mediaInfo +import io.element.android.libraries.mediaviewer.impl.model.mediaSource +import io.element.android.libraries.mediaviewer.impl.model.thumbnailSource import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index a9df9073ed..b3f95e2b37 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -24,12 +24,10 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory -import io.element.android.libraries.mediaviewer.impl.gallery.FocusedTimelineMediaGalleryDataSourceFactory +import io.element.android.libraries.mediaviewer.impl.datasource.FocusedTimelineMediaGalleryDataSourceFactory +import io.element.android.libraries.mediaviewer.impl.datasource.TimelineMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode -import io.element.android.libraries.mediaviewer.impl.gallery.SingleMediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.TimelineMediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.hasEvent -import io.element.android.libraries.mediaviewer.impl.gallery.toMediaItem +import io.element.android.libraries.mediaviewer.impl.model.hasEvent import io.element.android.services.toolbox.api.systemclock.SystemClock @ContributesNode(RoomScope::class) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt index 23ba312b0a..2c73ab2657 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandler.kt @@ -7,8 +7,8 @@ package io.element.android.libraries.mediaviewer.impl.viewer -import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem -import io.element.android.libraries.mediaviewer.impl.gallery.eventId +import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.eventId import javax.inject.Inject /** diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt similarity index 91% rename from libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt rename to libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt index 91ee02966e..94ac0fea21 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSource.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.viewer import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio @@ -15,6 +15,9 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.flowOf diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt similarity index 99% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt index a0bc4c1f0f..40e6721c10 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultEventItemFactoryTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter @@ -48,6 +48,7 @@ import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageCo import io.element.android.libraries.matrix.test.timeline.aStickerContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt similarity index 94% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt index ddd39ce1bc..7cac3fa869 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FakeMediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FakeMediaGalleryDataSource.kt similarity index 91% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FakeMediaGalleryDataSource.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FakeMediaGalleryDataSource.kt index 419c2c568a..ea4bdfbad8 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FakeMediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FakeMediaGalleryDataSource.kt @@ -5,11 +5,12 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.tests.testutils.lambda.lambdaError import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt similarity index 94% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt index 77cbcd3aaf..1b17a8df46 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/FocusedMediaTimelineTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.EventId @@ -15,6 +15,8 @@ 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.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.collections.immutable.persistentListOf diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt similarity index 92% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt index 6267d87b93..95b62a5824 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/LiveMediaTimelineTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.EventId @@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.test.runTest diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessorTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt similarity index 96% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessorTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt index 4c823350ce..afee17b6fc 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaItemsPostProcessorTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.UniqueId @@ -16,6 +16,8 @@ import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVideo import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVoice +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import kotlinx.collections.immutable.toImmutableList import org.junit.Test diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt similarity index 98% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt index d1a0c408ec..736fd309f3 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/TimelineMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.datasource import app.cash.turbine.test import com.google.common.truth.Truth.assertThat @@ -34,6 +34,8 @@ import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt index 0f304f209e..8625c0ac55 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt @@ -21,6 +21,8 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline +import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt similarity index 95% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt index 5a7cc91490..94ec4680dd 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/GroupedMediaItemsTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.model import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt index e43afbf80e..5a66501c92 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt @@ -18,8 +18,8 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory -import io.element.android.libraries.mediaviewer.impl.gallery.FakeMediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index 079788c1bc..e1e5818f2b 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -29,13 +29,13 @@ import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.impl.R +import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource +import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState -import io.element.android.libraries.mediaviewer.impl.gallery.FakeMediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.GroupedMediaItems -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator +import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory import io.element.android.services.toolbox.test.systemclock.FakeSystemClock diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt similarity index 96% rename from libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSourceTest.kt rename to libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt index d616322ddc..778d267697 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/SingleMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.mediaviewer.impl.gallery +package io.element.android.libraries.mediaviewer.impl.viewer import app.cash.turbine.test import com.google.common.truth.Truth.assertThat @@ -22,8 +22,10 @@ import io.element.android.libraries.mediaviewer.api.aVoiceMediaInfo import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo import io.element.android.libraries.mediaviewer.api.anImageMediaInfo +import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest import org.junit.Rule From 5a96406f1ae0140f01daec030d47ff9d1307a619 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 29 Jan 2025 10:13:08 +0100 Subject: [PATCH 08/10] Move galleryMode computation to MediaViewerDataSource --- .../mediaviewer/impl/viewer/MediaViewerDataSource.kt | 9 ++++++++- .../mediaviewer/impl/viewer/MediaViewerNode.kt | 9 +-------- .../impl/viewer/MediaViewerDataSourceTest.kt | 10 +++++----- .../impl/viewer/MediaViewerPresenterTest.kt | 7 +------ 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index f66521fb16..ebaba4cdcd 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint.MediaViewerMode import io.element.android.libraries.mediaviewer.api.local.LocalMedia import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource @@ -38,7 +39,7 @@ import kotlinx.coroutines.withContext import timber.log.Timber class MediaViewerDataSource( - private val galleryMode: MediaGalleryMode, + mode: MediaViewerMode, private val dispatcher: CoroutineDispatcher, private val galleryDataSource: MediaGalleryDataSource, private val mediaLoader: MatrixMediaLoader, @@ -49,6 +50,12 @@ class MediaViewerDataSource( // List of media files that are currently being loaded private val mediaFiles: MutableList = mutableListOf() + private val galleryMode = when (mode) { + MediaViewerMode.SingleMedia, + MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images + MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files + } + // Map of sourceUrl to local media state private val localMediaStates: MutableMap>> = mutableMapOf() diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index b3f95e2b37..7876641051 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -26,7 +26,6 @@ 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 import io.element.android.libraries.mediaviewer.impl.datasource.TimelineMediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.model.hasEvent import io.element.android.services.toolbox.api.systemclock.SystemClock @@ -84,18 +83,12 @@ class MediaViewerNode @AssistedInject constructor( } } - private val galleryMode = when (inputs.mode) { - MediaViewerEntryPoint.MediaViewerMode.SingleMedia, - MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images - MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files - } - private val presenter = presenterFactory.create( inputs = inputs, navigator = this, dataSource = MediaViewerDataSource( + mode = inputs.mode, dispatcher = coroutineDispatchers.computation, - galleryMode = galleryMode, galleryDataSource = mediaGallerySource, mediaLoader = mediaLoader, localMediaFactory = localMediaFactory, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt index 5a66501c92..9e2320cb61 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt @@ -17,10 +17,10 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader +import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint.MediaViewerMode import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile @@ -137,7 +137,7 @@ class MediaViewerDataSourceTest { fun `test dataFlow with data galleryMode image`() = runTest { val galleryDataSource = FakeMediaGalleryDataSource() val sut = createMediaViewerDataSource( - galleryMode = MediaGalleryMode.Images, + mode = MediaViewerMode.TimelineImagesAndVideos, galleryDataSource = galleryDataSource, ) sut.dataFlow().test { @@ -159,7 +159,7 @@ class MediaViewerDataSourceTest { fun `test dataFlow with data galleryMode files`() = runTest { val galleryDataSource = FakeMediaGalleryDataSource() val sut = createMediaViewerDataSource( - galleryMode = MediaGalleryMode.Files, + mode = MediaViewerMode.TimelineFilesAndAudios, galleryDataSource = galleryDataSource, ) sut.dataFlow().test { @@ -265,12 +265,12 @@ class MediaViewerDataSourceTest { } private fun TestScope.createMediaViewerDataSource( - galleryMode: MediaGalleryMode = MediaGalleryMode.Images, + mode: MediaViewerMode = MediaViewerMode.TimelineImagesAndVideos, galleryDataSource: MediaGalleryDataSource = FakeMediaGalleryDataSource(), mediaLoader: MatrixMediaLoader = FakeMatrixMediaLoader(), localMediaFactory: LocalMediaFactory = FakeLocalMediaFactory(mockMediaUrl), ) = MediaViewerDataSource( - galleryMode = galleryMode, + mode = mode, dispatcher = testCoroutineDispatchers().computation, galleryDataSource = galleryDataSource, mediaLoader = mediaLoader, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index e1e5818f2b..9f6b636cc6 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -32,7 +32,6 @@ import io.element.android.libraries.mediaviewer.impl.R import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState -import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems @@ -782,11 +781,7 @@ class MediaViewerPresenterTest { ), navigator = mediaViewerNavigator, dataSource = MediaViewerDataSource( - galleryMode = when (mode) { - MediaViewerEntryPoint.MediaViewerMode.SingleMedia -> MediaGalleryMode.Images - MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images - MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files - }, + mode = mode, dispatcher = testCoroutineDispatchers().computation, galleryDataSource = mediaGalleryDataSource, mediaLoader = matrixMediaLoader, From a668e7e7b1cc3460021cef2f63c8265654fceea7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 29 Jan 2025 10:24:58 +0100 Subject: [PATCH 09/10] Move factory method to a dedicated files as they are used by tests also. --- .../impl/gallery/MediaGalleryStateProvider.kt | 14 +- .../impl/gallery/ui/ImageItemView.kt | 1 + .../impl/gallery/ui/MediaItemAudioProvider.kt | 22 +-- .../ui/MediaItemDateSeparatorProvider.kt | 12 +- .../impl/gallery/ui/MediaItemFileProvider.kt | 22 +-- .../impl/gallery/ui/MediaItemImageProvider.kt | 32 ----- .../ui/MediaItemLoadingIndicatorProvider.kt | 23 ---- .../impl/gallery/ui/MediaItemVideoProvider.kt | 20 +-- .../impl/gallery/ui/MediaItemVoiceProvider.kt | 25 +--- .../impl/gallery/ui/VoiceItemView.kt | 1 + .../impl/model/MediaItemFactories.kt | 128 ++++++++++++++++++ ...melineMediaGalleryDataSourceFactoryTest.kt | 2 +- .../datasource/FocusedMediaTimelineTest.kt | 2 +- .../datasource/MediaItemsPostProcessorTest.kt | 14 +- .../impl/gallery/MediaGalleryPresenterTest.kt | 2 +- .../impl/model/GroupedMediaItemsTest.kt | 2 - .../impl/viewer/MediaViewerDataSourceTest.kt | 8 +- .../impl/viewer/MediaViewerPresenterTest.kt | 4 +- .../impl/viewer/PagerKeysHandlerTest.kt | 4 +- .../SingleMediaGalleryDataSourceTest.kt | 4 +- 20 files changed, 162 insertions(+), 180 deletions(-) delete mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt delete mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt create mode 100644 libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt index 32c3e85322..aedea1eb75 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryStateProvider.kt @@ -13,15 +13,15 @@ import io.element.android.libraries.designsystem.components.media.aWaveForm import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState import io.element.android.libraries.mediaviewer.impl.details.aMediaDetailsBottomSheetState -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemAudio -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVideo -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVoice import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemAudio +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemDateSeparator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemFile +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemLoadingIndicator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVideo +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVoice import kotlinx.collections.immutable.toImmutableList open class MediaGalleryStateProvider : PreviewParameterProvider { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt index 30c909eb9a..8df451abd6 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/ImageItemView.kt @@ -29,6 +29,7 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage @OptIn(ExperimentalFoundationApi::class) @Composable diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt index 7bfc09d1b9..ccbc9079cd 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemAudioProvider.kt @@ -9,11 +9,8 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.preview.loremIpsum -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemAudio class MediaItemAudioProvider : PreviewParameterProvider { override val values: Sequence @@ -28,20 +25,3 @@ class MediaItemAudioProvider : PreviewParameterProvider { ), ) } - -fun aMediaItemAudio( - id: UniqueId = UniqueId("fileId"), - eventId: EventId? = null, - filename: String = "filename", - caption: String? = null, -): MediaItem.Audio { - return MediaItem.Audio( - id = id, - eventId = eventId, - mediaInfo = anAudioMediaInfo( - filename = filename, - caption = caption, - ), - mediaSource = MediaSource(""), - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt index f39b5f33a9..13d49a9919 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemDateSeparatorProvider.kt @@ -8,8 +8,8 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemDateSeparator class MediaItemDateSeparatorProvider : PreviewParameterProvider { override val values: Sequence @@ -18,13 +18,3 @@ class MediaItemDateSeparatorProvider : PreviewParameterProvider { override val values: Sequence @@ -28,20 +25,3 @@ class MediaItemFileProvider : PreviewParameterProvider { ), ) } - -fun aMediaItemFile( - id: UniqueId = UniqueId("fileId"), - eventId: EventId? = null, - filename: String = "filename", - caption: String? = null, -): MediaItem.File { - return MediaItem.File( - id = id, - eventId = eventId, - mediaInfo = aPdfMediaInfo( - filename = filename, - caption = caption, - ), - mediaSource = MediaSource(""), - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt deleted file mode 100644 index f462276b60..0000000000 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemImageProvider.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.mediaviewer.impl.gallery.ui - -import io.element.android.libraries.matrix.api.core.EventId -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.media.MediaSource -import io.element.android.libraries.mediaviewer.api.anImageMediaInfo -import io.element.android.libraries.mediaviewer.impl.model.MediaItem - -fun aMediaItemImage( - id: UniqueId = UniqueId("imageId"), - eventId: EventId? = null, - senderId: UserId? = null, - mediaSourceUrl: String = "", -): MediaItem.Image { - return MediaItem.Image( - id = id, - eventId = eventId, - mediaInfo = anImageMediaInfo( - senderId = senderId, - ), - mediaSource = MediaSource(mediaSourceUrl), - thumbnailSource = null, - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt deleted file mode 100644 index 1dd2d8f8c8..0000000000 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemLoadingIndicatorProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.mediaviewer.impl.gallery.ui - -import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.timeline.Timeline -import io.element.android.libraries.mediaviewer.impl.model.MediaItem - -fun aMediaItemLoadingIndicator( - id: UniqueId = UniqueId("loadingId"), - direction: Timeline.PaginationDirection = Timeline.PaginationDirection.BACKWARDS, -): MediaItem.LoadingIndicator { - return MediaItem.LoadingIndicator( - id = id, - direction = direction, - timestamp = 123, - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt index 7ab8e46718..34eef52479 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVideoProvider.kt @@ -8,10 +8,8 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVideo class MediaItemVideoProvider : PreviewParameterProvider { override val values: Sequence @@ -22,19 +20,3 @@ class MediaItemVideoProvider : PreviewParameterProvider { ), ) } - -fun aMediaItemVideo( - id: UniqueId = UniqueId("videoId"), - mediaSource: MediaSource = MediaSource(""), - duration: String? = "1:23", -): MediaItem.Video { - return MediaItem.Video( - id = id, - eventId = null, - mediaInfo = aVideoMediaInfo( - duration = duration - ), - mediaSource = mediaSource, - thumbnailSource = null, - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt index 8c14464b73..8353e5bfca 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/MediaItemVoiceProvider.kt @@ -9,11 +9,8 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.preview.loremIpsum -import io.element.android.libraries.designsystem.components.media.aWaveForm -import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.mediaviewer.api.aVoiceMediaInfo import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVoice class MediaItemVoiceProvider : PreviewParameterProvider { override val values: Sequence @@ -31,23 +28,3 @@ class MediaItemVoiceProvider : PreviewParameterProvider { ), ) } - -fun aMediaItemVoice( - id: UniqueId = UniqueId("fileId"), - filename: String = "filename.ogg", - caption: String? = null, - duration: String? = "1:23", - waveform: List = aWaveForm(), -): MediaItem.Voice { - return MediaItem.Voice( - id = id, - eventId = null, - mediaInfo = aVoiceMediaInfo( - filename = filename, - caption = caption, - duration = duration, - waveForm = waveform, - ), - mediaSource = MediaSource(""), - ) -} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt index 384947b078..89f9a30f40 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/ui/VoiceItemView.kt @@ -47,6 +47,7 @@ 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.Text import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVoice import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.voiceplayer.api.VoiceMessageEvents import io.element.android.libraries.voiceplayer.api.VoiceMessageState diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt new file mode 100644 index 0000000000..b04973322a --- /dev/null +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/model/MediaItemFactories.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.model + +import io.element.android.libraries.designsystem.components.media.aWaveForm +import io.element.android.libraries.matrix.api.core.EventId +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.media.MediaSource +import io.element.android.libraries.matrix.api.timeline.Timeline +import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo +import io.element.android.libraries.mediaviewer.api.aVideoMediaInfo +import io.element.android.libraries.mediaviewer.api.aVoiceMediaInfo +import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo +import io.element.android.libraries.mediaviewer.api.anImageMediaInfo + +fun aMediaItemImage( + id: UniqueId = UniqueId("imageId"), + eventId: EventId? = null, + senderId: UserId? = null, + mediaSourceUrl: String = "", +): MediaItem.Image { + return MediaItem.Image( + id = id, + eventId = eventId, + mediaInfo = anImageMediaInfo( + senderId = senderId, + ), + mediaSource = MediaSource(mediaSourceUrl), + thumbnailSource = null, + ) +} + +fun aMediaItemVideo( + id: UniqueId = UniqueId("videoId"), + mediaSource: MediaSource = MediaSource(""), + duration: String? = "1:23", +): MediaItem.Video { + return MediaItem.Video( + id = id, + eventId = null, + mediaInfo = aVideoMediaInfo( + duration = duration + ), + mediaSource = mediaSource, + thumbnailSource = null, + ) +} + +fun aMediaItemFile( + id: UniqueId = UniqueId("fileId"), + eventId: EventId? = null, + filename: String = "filename", + caption: String? = null, +): MediaItem.File { + return MediaItem.File( + id = id, + eventId = eventId, + mediaInfo = aPdfMediaInfo( + filename = filename, + caption = caption, + ), + mediaSource = MediaSource(""), + ) +} + +fun aMediaItemAudio( + id: UniqueId = UniqueId("fileId"), + eventId: EventId? = null, + filename: String = "filename", + caption: String? = null, +): MediaItem.Audio { + return MediaItem.Audio( + id = id, + eventId = eventId, + mediaInfo = anAudioMediaInfo( + filename = filename, + caption = caption, + ), + mediaSource = MediaSource(""), + ) +} + +fun aMediaItemVoice( + id: UniqueId = UniqueId("fileId"), + filename: String = "filename.ogg", + caption: String? = null, + duration: String? = "1:23", + waveform: List = aWaveForm(), +): MediaItem.Voice { + return MediaItem.Voice( + id = id, + eventId = null, + mediaInfo = aVoiceMediaInfo( + filename = filename, + caption = caption, + duration = duration, + waveForm = waveform, + ), + mediaSource = MediaSource(""), + ) +} + +fun aMediaItemDateSeparator( + id: UniqueId = UniqueId("dateId"), + formattedDate: String = "October 2024", +): MediaItem.DateSeparator { + return MediaItem.DateSeparator( + id = id, + formattedDate = formattedDate, + ) +} + +fun aMediaItemLoadingIndicator( + id: UniqueId = UniqueId("loadingId"), + direction: Timeline.PaginationDirection = Timeline.PaginationDirection.BACKWARDS, +): MediaItem.LoadingIndicator { + return MediaItem.LoadingIndicator( + id = id, + direction = direction, + timestamp = 123, + ) +} diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt index 7cac3fa869..a2ab9b162f 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage import kotlinx.coroutines.test.runTest import org.junit.Test diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt index 1b17a8df46..1d4fd3adbe 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt @@ -14,9 +14,9 @@ import io.element.android.libraries.matrix.api.timeline.Timeline 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.timeline.FakeTimeline -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.collections.immutable.persistentListOf diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt index afee17b6fc..a8903394b3 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaItemsPostProcessorTest.kt @@ -9,15 +9,15 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemAudio -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVideo -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemVoice import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemAudio +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemDateSeparator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemFile +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemLoadingIndicator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVideo +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemVoice import kotlinx.collections.immutable.toImmutableList import org.junit.Test diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt index 8625c0ac55..1a43bbacf6 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt @@ -24,7 +24,7 @@ import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory import io.element.android.tests.testutils.WarmUpRule diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt index 94ec4680dd..16f0777994 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/model/GroupedMediaItemsTest.kt @@ -11,8 +11,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.AN_EVENT_ID_3 -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemAudio -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import kotlinx.collections.immutable.persistentListOf import org.junit.Test diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt index 9e2320cb61..b49c174d21 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSourceTest.kt @@ -22,10 +22,10 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemDateSeparator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemFile +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP import io.element.android.services.toolbox.test.systemclock.FakeSystemClock diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index 9f6b636cc6..03d66992bf 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -32,9 +32,9 @@ import io.element.android.libraries.mediaviewer.impl.R import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemLoadingIndicator import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory import io.element.android.services.toolbox.test.systemclock.FakeSystemClock diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt index 056a62c86f..807c7b51cd 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/PagerKeysHandlerTest.kt @@ -11,8 +11,8 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemLoadingIndicator import org.junit.Test class PagerKeysHandlerTest { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt index 778d267697..540f107601 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/SingleMediaGalleryDataSourceTest.kt @@ -23,9 +23,9 @@ import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo import io.element.android.libraries.mediaviewer.api.anImageMediaInfo import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile -import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage import io.element.android.libraries.mediaviewer.impl.model.MediaItem +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemFile +import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest import org.junit.Rule From 243ce23055ee06982238dda5fe0b6c8f8cc2cb92 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 29 Jan 2025 10:35:52 +0100 Subject: [PATCH 10/10] Protect access to member timeline with a Mutex and clean the code. --- .../impl/datasource/MediaTimeline.kt | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt index 5b26b50d62..6dc4136193 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt @@ -18,6 +18,8 @@ import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.impl.model.hasEvent import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject interface MediaTimeline { @@ -37,19 +39,15 @@ class LiveMediaTimeline @Inject constructor( private val room: MatrixRoom, ) : MediaTimeline { private var timeline: Timeline? = null - override suspend fun getTimeline(): Result { - return if (timeline == null) { - room.mediaTimeline(null).fold( - { - timeline = it - Result.success(it) - }, - { - Result.failure(it) - }, - ) + private val mutex = Mutex() + + override suspend fun getTimeline(): Result = mutex.withLock { + val currentTimeline = timeline + if (currentTimeline == null) { + room.mediaTimeline(null) + .onSuccess { timeline = it } } else { - Result.success(timeline!!) + Result.success(currentTimeline) } }