-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Media navigation with swipe gesture #4161
Merged
Merged
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
35cc5df
Create MediaGalleryDataSource and extract logic from MediaGalleryPres…
bmarty cbf7bf0
Let MediaGalleryDataSource be an interface
bmarty a06607f
Remove RetryLoading (use LoadMedia)
bmarty 32db42a
Suppress Detekt false positive (?)
bmarty 7df65b0
Add support for files navigation (when coming from the gallery)
bmarty ca5c06f
Open in SingleMedia mode when coming from the timeline
bmarty 8d6550b
If not displayed, make sure to pause the audio / video
bmarty 98a786b
media viewer : create MediaViewerDataSource
ganfra d26414f
Provide duration
bmarty bad4566
Remove unused import
bmarty 3248041
media viewer : use collectAsState in the DataSource
ganfra c0542c8
Fix and write tests
bmarty d6ebec8
Improve loading state and add preview.
bmarty 6c904a4
Add exception for Konsist
bmarty aa68a35
sync strings
bmarty a4cf1d7
Restore caption rendering
bmarty f286f6d
Small cleanup
bmarty 428b81c
Add test on SingleMediaGalleryDataSource
bmarty 18c3b5b
Add test on MediaViewerDataSource
bmarty 621558a
MediaViewer: add error case in the UI.
bmarty e496bc3
Introduce MediaViewerFlickToDismiss and extract to its own file
bmarty dfda13a
Restore overlay when user cancel the dragging
bmarty bac69c4
Add timestamp to trigger back pagination.
bmarty b72f4bb
Fix tests.
bmarty 74be5a5
Update screenshots
ElementBot 1580c73
Ensure gallery is paginating to get new items.
bmarty 77887f9
Fix formatting.
bmarty dff9005
Remove useless parameter
bmarty 54182b0
Simplify with code `coerceAtLeast(0)``
bmarty 2fde015
Simplify
bmarty afd8161
Add documentation on buildMediaViewerPageList.
bmarty a5515b0
Add name to argument for clarity.
bmarty 7dd797b
Use Black for code clarity.
bmarty beb835c
Fix color for media viewer according to Figma.
bmarty 05660fb
Cleanup
bmarty 4d2edfa
Improve code clarity
bmarty ba0502c
Update screenshots
ElementBot da22758
Fix pagination restart issue and cover by unit test.
bmarty File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
86 changes: 86 additions & 0 deletions
86
...in/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.gallery | ||
|
||
import io.element.android.libraries.architecture.AsyncData | ||
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.room.MatrixRoom | ||
import io.element.android.libraries.matrix.api.timeline.Timeline | ||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.flatMapLatest | ||
import kotlinx.coroutines.flow.flow | ||
import kotlinx.coroutines.flow.launchIn | ||
import kotlinx.coroutines.flow.map | ||
import kotlinx.coroutines.flow.onCompletion | ||
import kotlinx.coroutines.flow.onEach | ||
import java.util.concurrent.atomic.AtomicBoolean | ||
import javax.inject.Inject | ||
|
||
@SingleIn(RoomScope::class) | ||
class MediaGalleryDataSource @Inject constructor( | ||
private val room: MatrixRoom, | ||
private val timelineMediaItemsFactory: TimelineMediaItemsFactory, | ||
private val mediaItemsPostProcessor: MediaItemsPostProcessor, | ||
) { | ||
private var timeline: Timeline? = null | ||
|
||
private val groupedMediaItemsFlow = MutableSharedFlow<AsyncData<GroupedMediaItems>>(replay = 1) | ||
|
||
fun groupedMediaItemsFlow(): Flow<AsyncData<GroupedMediaItems>> = groupedMediaItemsFlow | ||
|
||
private val isStarted = AtomicBoolean(false) | ||
|
||
@OptIn(ExperimentalCoroutinesApi::class) | ||
fun start() { | ||
if (!isStarted.compareAndSet(false, true)) { | ||
return | ||
} | ||
flow { | ||
groupedMediaItemsFlow.emit(AsyncData.Loading()) | ||
room.mediaTimeline().fold( | ||
{ | ||
timeline = it | ||
emit(it) | ||
}, | ||
{ groupedMediaItemsFlow.emit(AsyncData.Failure(it)) }, | ||
) | ||
}.flatMapLatest { timeline -> | ||
timeline.timelineItems.onEach { | ||
timelineMediaItemsFactory.replaceWith( | ||
timelineItems = it, | ||
) | ||
} | ||
}.flatMapLatest { | ||
timelineMediaItemsFactory.timelineItems | ||
}.map { timelineItems -> | ||
mediaItemsPostProcessor.process(mediaItems = timelineItems) | ||
}.onEach { groupedMediaItems -> | ||
groupedMediaItemsFlow.emit(AsyncData.Success(groupedMediaItems)) | ||
} | ||
.onCompletion { | ||
timeline?.close() | ||
} | ||
.launchIn(room.roomCoroutineScope) | ||
} | ||
|
||
suspend fun loadMore(direction: Timeline.PaginationDirection) { | ||
timeline?.paginate(direction) | ||
} | ||
|
||
suspend fun deleteItem(eventId: EventId) { | ||
timeline?.redactEvent( | ||
eventOrTransactionId = eventId.toEventOrTransactionId(), | ||
reason = null, | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a way to stop this flow, i.e. when the user leaves the gallery screen? Or is it ok if the gallery keeps loading in bg while the user is checking the room?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no way so far, but the flow will complete when the room will be destroyed.
The idea is to share the flow between the gallery and the media viewer with swipe. This will have to be reworked a bit when we will open the viewer from the timeline.