Reimplement "Natural media viewer swiping order" (#6715)

This commit is contained in:
bxdxnn 2026-05-05 17:02:52 +03:00 committed by GitHub
parent 6abb83547b
commit 8e8426b08c
4 changed files with 33 additions and 56 deletions

View file

@ -122,25 +122,11 @@ class MediaViewerDataSource(
*/
private fun buildMediaViewerPageList(groupedItems: List<MediaItem>) = buildList {
// Filter out DateSeparator items, we do not need them for the media viewer
val itemsNoDateSeparator = groupedItems.filterNot { it is MediaItem.DateSeparator }
// Separate loading indicators and media events
val loadingIndicators = itemsNoDateSeparator.filterIsInstance<MediaItem.LoadingIndicator>()
val mediaEvents = itemsNoDateSeparator.filterIsInstance<MediaItem.Event>()
// Determine backward and forward loading indicators
val backwardLoading = loadingIndicators.find { it.direction == Timeline.PaginationDirection.BACKWARDS }
val forwardLoading = loadingIndicators.find { it.direction == Timeline.PaginationDirection.FORWARDS }
// Build ordered list: backward loading, media events (oldest first), forward loading
// Media events are currently newest first, reverse to get oldest first
val orderedEvents = mediaEvents.reversed()
// Create new list of MediaItem in order: backwardLoading, orderedEvents, forwardLoading
val orderedItems = buildList {
backwardLoading?.let { add(it) }
addAll(orderedEvents)
forwardLoading?.let { add(it) }
}
pagerKeysHandler.accept(orderedItems)
orderedItems.forEach { mediaItem ->
val groupedItemsNoDateSeparator = groupedItems.filterNot { it is MediaItem.DateSeparator }
pagerKeysHandler.accept(groupedItemsNoDateSeparator)
groupedItemsNoDateSeparator.forEach { mediaItem ->
when (mediaItem) {
is MediaItem.DateSeparator -> Unit
is MediaItem.Event -> {
val sourceUrl = mediaItem.mediaSource().safeUrl
val localMedia = localMediaStates.getOrPut(sourceUrl) {
@ -164,7 +150,6 @@ class MediaViewerDataSource(
pagerKey = pagerKeysHandler.getKey(mediaItem),
)
)
is MediaItem.DateSeparator -> Unit // already filtered out
}
}
}.toImmutableList()

View file

@ -177,21 +177,18 @@ class MediaViewerPresenter(
currentIndex: IntState,
data: State<ImmutableList<MediaViewerPageData>>,
) {
// With newest-first ordering, backward loading indicator is at the last index
val isRenderingLoadingBackward by remember {
derivedStateOf {
currentIndex.intValue == 0 &&
currentIndex.intValue == data.value.lastIndex &&
data.value.size > 1 &&
data.value.firstOrNull() is MediaViewerPageData.Loading &&
(data.value.firstOrNull() as? MediaViewerPageData.Loading)?.direction == Timeline.PaginationDirection.BACKWARDS
data.value.lastOrNull() is MediaViewerPageData.Loading
}
}
if (isRenderingLoadingBackward) {
LaunchedEffect(Unit) {
// Observe the loading data vanishing
snapshotFlow {
val first = data.value.firstOrNull()
first is MediaViewerPageData.Loading && first.direction == Timeline.PaginationDirection.BACKWARDS
}
snapshotFlow { data.value.lastOrNull() is MediaViewerPageData.Loading }
.distinctUntilChanged()
.filter { !it }
.onEach { showNoMoreItemsSnackbar() }
@ -205,21 +202,18 @@ class MediaViewerPresenter(
currentIndex: IntState,
data: State<ImmutableList<MediaViewerPageData>>,
) {
// With newest-first ordering, forward loading indicator is at the first index
val isRenderingLoadingForward by remember {
derivedStateOf {
currentIndex.intValue == data.value.lastIndex &&
currentIndex.intValue == 0 &&
data.value.size > 1 &&
data.value.lastOrNull() is MediaViewerPageData.Loading &&
(data.value.lastOrNull() as? MediaViewerPageData.Loading)?.direction == Timeline.PaginationDirection.FORWARDS
data.value.firstOrNull() is MediaViewerPageData.Loading
}
}
if (isRenderingLoadingForward) {
LaunchedEffect(Unit) {
// Observe the loading data vanishing
snapshotFlow {
val last = data.value.lastOrNull()
last is MediaViewerPageData.Loading && last.direction == Timeline.PaginationDirection.FORWARDS
}
snapshotFlow { data.value.firstOrNull() is MediaViewerPageData.Loading }
.distinctUntilChanged()
.filter { !it }
.onEach { showNoMoreItemsSnackbar() }

View file

@ -182,6 +182,7 @@ fun MediaViewerView(
// Pre-load previous and next pages
beyondViewportPageCount = 1,
key = { index -> state.listData[index].pagerKey },
reverseLayout = true,
) { page ->
when (val dataForPage = state.listData[page]) {
is MediaViewerPageData.Failure -> {