media viewer : use collectAsState in the DataSource

This commit is contained in:
ganfra 2025-01-21 09:57:22 +01:00 committed by Benoit Marty
parent 40ef05b6e6
commit 13defbbcc0
2 changed files with 38 additions and 31 deletions

View file

@ -7,10 +7,13 @@
package io.element.android.libraries.mediaviewer.impl.viewer package io.element.android.libraries.mediaviewer.impl.viewer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.MediaFile
import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.Timeline
@ -56,33 +59,27 @@ class MediaViewerDataSource(
localMediaStates.clear() localMediaStates.clear()
} }
fun initialPageIndex(eventId: EventId?): Int { @Composable
if (eventId == null) { fun collectAsState(): State<PersistentList<MediaViewerPageData>> {
return 0 return remember { dataFlow() }.collectAsState(initialData())
}
val mediaItems =
galleryDataSource.getLastData().dataOrNull()?.getItems(galleryMode).orEmpty()
val pageList = buildMediaViewerPageList(mediaItems)
return pageList.indexOfFirst { data ->
when (data) {
is MediaViewerPageData.MediaViewerData -> data.eventId == eventId
else -> false
}
}
.takeIf { it != -1 }
?: 0
} }
fun dataFlow(): Flow<PersistentList<MediaViewerPageData>> { private fun dataFlow(): Flow<PersistentList<MediaViewerPageData>> {
return galleryDataSource.groupedMediaItemsFlow() return galleryDataSource.groupedMediaItemsFlow()
.map { .map { groupedItems ->
val groupedItems = it.dataOrNull()?.getItems(galleryMode).orEmpty() val mediaItems = groupedItems.dataOrNull()?.getItems(galleryMode).orEmpty()
withContext(dispatcher) { withContext(dispatcher) {
buildMediaViewerPageList(groupedItems) buildMediaViewerPageList(mediaItems)
} }
} }
} }
private fun initialData(): PersistentList<MediaViewerPageData> {
val initialMediaItems =
galleryDataSource.getLastData().dataOrNull()?.getItems(galleryMode).orEmpty()
return buildMediaViewerPageList(initialMediaItems)
}
private fun buildMediaViewerPageList(groupedItems: List<MediaItem>) = buildList { private fun buildMediaViewerPageList(groupedItems: List<MediaItem>) = buildList {
groupedItems.forEach { mediaItem -> groupedItems.forEach { mediaItem ->
when (mediaItem) { when (mediaItem) {
@ -112,6 +109,14 @@ class MediaViewerDataSource(
} }
}.toPersistentList() }.toPersistentList()
fun clearLoadingError(data: MediaViewerPageData.MediaViewerData) {
localMediaStates[data.mediaSource.url]?.value = AsyncData.Uninitialized
}
suspend fun loadMore(direction: Timeline.PaginationDirection) {
galleryDataSource.loadMore(direction)
}
suspend fun loadMedia(data: MediaViewerPageData.MediaViewerData) { suspend fun loadMedia(data: MediaViewerPageData.MediaViewerData) {
Timber.d("loadMedia for ${data.eventId}") Timber.d("loadMedia for ${data.eventId}")
val localMediaState = localMediaStates.getOrPut(data.mediaSource.url) { val localMediaState = localMediaStates.getOrPut(data.mediaSource.url) {
@ -141,11 +146,5 @@ class MediaViewerDataSource(
} }
} }
fun clearLoadingError(data: MediaViewerPageData.MediaViewerData) {
localMediaStates[data.mediaSource.url]?.value = AsyncData.Uninitialized
}
suspend fun loadMore(direction: Timeline.PaginationDirection) {
galleryDataSource.loadMore(direction)
}
} }

View file

@ -10,7 +10,6 @@ package io.element.android.libraries.mediaviewer.impl.viewer
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -35,8 +34,6 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState 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.local.LocalMediaActions
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import io.element.android.libraries.androidutils.R as UtilsR import io.element.android.libraries.androidutils.R as UtilsR
@ -61,8 +58,8 @@ class MediaViewerPresenter @AssistedInject constructor(
@Composable @Composable
override fun present(): MediaViewerState { override fun present(): MediaViewerState {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val data: ImmutableList<MediaViewerPageData> by dataSource.dataFlow().collectAsState(persistentListOf()) val data by dataSource.collectAsState()
var currentIndex by remember { mutableIntStateOf(dataSource.initialPageIndex(inputs.eventId)) } var currentIndex by remember { mutableIntStateOf(searchIndex(data, inputs.eventId)) }
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState() val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) } var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
@ -202,4 +199,15 @@ class MediaViewerPresenter @AssistedInject constructor(
CommonStrings.error_unknown CommonStrings.error_unknown
} }
} }
private fun searchIndex(data: List<MediaViewerPageData>, eventId: EventId?): Int {
if (eventId == null) {
return 0
}
return data.indexOfFirst {
(it as? MediaViewerPageData.MediaViewerData)?.eventId == eventId
}
.takeIf { it != -1 }
?: 0
}
} }