Rename sub classes of MediaBottomSheetState and improve preview of MediaDeleteConfirmationBottomSheet

This commit is contained in:
Benoit Marty 2026-04-22 14:42:56 +02:00
parent c9b48d32b0
commit 7bbdecc7a8
17 changed files with 103 additions and 89 deletions

View file

@ -15,16 +15,16 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
sealed interface MediaBottomSheetState {
data object Hidden : MediaBottomSheetState
data class MediaDeleteConfirmationState(
val eventId: EventId,
val mediaInfo: MediaInfo,
val thumbnailSource: MediaSource?,
) : MediaBottomSheetState
data class MediaDetailsBottomSheetState(
data class Details(
val eventId: EventId?,
val canDelete: Boolean,
val mediaInfo: MediaInfo,
val thumbnailSource: MediaSource?,
) : MediaBottomSheetState
data class DeleteConfirmation(
val eventId: EventId,
val mediaInfo: MediaInfo,
val thumbnailSource: MediaSource?,
) : MediaBottomSheetState
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.details
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
open class MediaBottomSheetStateDeleteConfirmationProvider : PreviewParameterProvider<MediaBottomSheetState.DeleteConfirmation> {
override val values: Sequence<MediaBottomSheetState.DeleteConfirmation>
get() = sequenceOf(
aMediaBottomSheetStateDeleteConfirmation(),
aMediaBottomSheetStateDeleteConfirmation(
thumbnailSource = MediaSource("url_thumbnail")
),
)
}
fun aMediaBottomSheetStateDeleteConfirmation(
mediaInfo: MediaInfo = anImageMediaInfo(
senderName = "Alice",
),
thumbnailSource: MediaSource? = null,
) = MediaBottomSheetState.DeleteConfirmation(
eventId = EventId("\$eventId"),
mediaInfo = mediaInfo,
thumbnailSource = thumbnailSource,
)

View file

@ -13,31 +13,28 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
open class MediaDetailsBottomSheetStateProvider : PreviewParameterProvider<MediaBottomSheetState.MediaDetailsBottomSheetState> {
override val values: Sequence<MediaBottomSheetState.MediaDetailsBottomSheetState>
open class MediaBottomSheetStateDetailsProvider : PreviewParameterProvider<MediaBottomSheetState.Details> {
override val values: Sequence<MediaBottomSheetState.Details>
get() = sequenceOf(
aMediaDetailsBottomSheetState(),
aMediaDetailsBottomSheetState(
aMediaBottomSheetStateDetails(),
aMediaBottomSheetStateDetails(
canDelete = false,
),
aMediaDetailsBottomSheetState(
aMediaBottomSheetStateDetails(
mediaInfo = anApkMediaInfo(),
),
)
}
fun aMediaDetailsBottomSheetState(
dateSentFull: String = "December 6, 2024 at 12:59",
fun aMediaBottomSheetStateDetails(
canDelete: Boolean = true,
mediaInfo: MediaInfo = anImageMediaInfo(
senderName = "Alice",
dateSentFull = dateSentFull,
dateSentFull = "December 6, 2024 at 12:59",
),
): MediaBottomSheetState.MediaDetailsBottomSheetState {
return MediaBottomSheetState.MediaDetailsBottomSheetState(
eventId = EventId("\$eventId"),
canDelete = canDelete,
mediaInfo = mediaInfo,
thumbnailSource = null,
)
}
) = MediaBottomSheetState.Details(
eventId = EventId("\$eventId"),
canDelete = canDelete,
mediaInfo = mediaInfo,
thumbnailSource = null,
)

View file

@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import io.element.android.compound.theme.ElementTheme
@ -49,7 +50,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediaDeleteConfirmationBottomSheet(
state: MediaBottomSheetState.MediaDeleteConfirmationState,
state: MediaBottomSheetState.DeleteConfirmation,
onDelete: (EventId) -> Unit,
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
@ -105,7 +106,7 @@ fun MediaDeleteConfirmationBottomSheet(
@Composable
private fun MediaRow(
state: MediaBottomSheetState.MediaDeleteConfirmationState,
state: MediaBottomSheetState.DeleteConfirmation,
modifier: Modifier = Modifier,
) {
Row(
@ -160,9 +161,11 @@ private fun MediaRow(
@PreviewsDayNight
@Composable
internal fun MediaDeleteConfirmationBottomSheetPreview() = ElementPreview {
internal fun MediaDeleteConfirmationBottomSheetPreview(
@PreviewParameter(provider = MediaBottomSheetStateDeleteConfirmationProvider::class) state: MediaBottomSheetState.DeleteConfirmation,
) = ElementPreview {
MediaDeleteConfirmationBottomSheet(
state = aMediaDeleteConfirmationState(),
state = state,
onDelete = {},
onDismiss = {},
)

View file

@ -54,7 +54,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediaDetailsBottomSheet(
state: MediaBottomSheetState.MediaDetailsBottomSheetState,
state: MediaBottomSheetState.Details,
onViewInTimeline: (EventId) -> Unit,
onShare: (EventId) -> Unit,
onForward: (EventId) -> Unit,
@ -250,7 +250,7 @@ private fun SectionText(
@PreviewsDayNight
@Composable
internal fun MediaDetailsBottomSheetPreview(
@PreviewParameter(MediaDetailsBottomSheetStateProvider::class) state: MediaBottomSheetState.MediaDetailsBottomSheetState,
@PreviewParameter(MediaBottomSheetStateDetailsProvider::class) state: MediaBottomSheetState.Details,
) = ElementPreview {
MediaDetailsBottomSheet(
state = state,

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.details
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
fun aMediaDeleteConfirmationState(): MediaBottomSheetState.MediaDeleteConfirmationState {
return MediaBottomSheetState.MediaDeleteConfirmationState(
eventId = EventId("\$eventId"),
mediaInfo = anImageMediaInfo(
senderName = "Alice",
),
thumbnailSource = null,
)
}

View file

@ -126,7 +126,7 @@ class MediaGalleryPresenter(
navigator.onViewInTimelineClick(event.eventId)
}
is MediaGalleryEvent.OpenInfo -> coroutineScope.launch {
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
mediaBottomSheetState = MediaBottomSheetState.Details(
eventId = event.mediaItem.eventId(),
canDelete = when (event.mediaItem.mediaInfo().senderId) {
null -> false
@ -144,7 +144,7 @@ class MediaGalleryPresenter(
)
}
is MediaGalleryEvent.ConfirmDelete -> {
mediaBottomSheetState = MediaBottomSheetState.MediaDeleteConfirmationState(
mediaBottomSheetState = MediaBottomSheetState.DeleteConfirmation(
eventId = event.eventId,
mediaInfo = event.mediaInfo,
thumbnailSource = event.thumbnailSource,

View file

@ -13,7 +13,7 @@ import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.media.WaveFormSamples
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.details.aMediaBottomSheetStateDetails
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
@ -79,7 +79,7 @@ open class MediaGalleryStateProvider : PreviewParameterProvider<MediaGalleryStat
)
),
),
aMediaGalleryState(mediaBottomSheetState = aMediaDetailsBottomSheetState()),
aMediaGalleryState(mediaBottomSheetState = aMediaBottomSheetStateDetails()),
aMediaGalleryState(
groupedMediaItems = AsyncData.Failure(Exception("Failed to load media")),
),

View file

@ -158,7 +158,7 @@ fun MediaGalleryView(
}
when (val bottomSheetState = state.mediaBottomSheetState) {
MediaBottomSheetState.Hidden -> Unit
is MediaBottomSheetState.MediaDetailsBottomSheetState -> {
is MediaBottomSheetState.Details -> {
MediaDetailsBottomSheet(
state = bottomSheetState,
onViewInTimeline = { eventId ->
@ -190,7 +190,7 @@ fun MediaGalleryView(
},
)
}
is MediaBottomSheetState.MediaDeleteConfirmationState -> {
is MediaBottomSheetState.DeleteConfirmation -> {
MediaDeleteConfirmationBottomSheet(
state = bottomSheetState,
onDelete = {

View file

@ -131,7 +131,7 @@ class MediaViewerPresenter(
)
}
is MediaViewerEvent.OpenInfo -> coroutineScope.launch {
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
mediaBottomSheetState = MediaBottomSheetState.Details(
eventId = event.data.eventId,
canDelete = when (event.data.mediaInfo.senderId) {
null -> false
@ -143,7 +143,7 @@ class MediaViewerPresenter(
)
}
is MediaViewerEvent.ConfirmDelete -> {
mediaBottomSheetState = MediaBottomSheetState.MediaDeleteConfirmationState(
mediaBottomSheetState = MediaBottomSheetState.DeleteConfirmation(
eventId = event.eventId,
mediaInfo = event.data.mediaInfo,
thumbnailSource = event.data.thumbnailSource ?: event.data.mediaSource,

View file

@ -25,8 +25,8 @@ import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
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.aMediaDeleteConfirmationState
import io.element.android.libraries.mediaviewer.impl.details.aMediaDetailsBottomSheetState
import io.element.android.libraries.mediaviewer.impl.details.aMediaBottomSheetStateDeleteConfirmation
import io.element.android.libraries.mediaviewer.impl.details.aMediaBottomSheetStateDetails
import kotlinx.collections.immutable.toImmutableList
private const val LONG_CAPTION = "This is a very long caption that should be scrollable in the media viewer. " +
@ -141,10 +141,10 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState>
)
},
aMediaViewerState(
mediaBottomSheetState = aMediaDetailsBottomSheetState(),
mediaBottomSheetState = aMediaBottomSheetStateDetails(),
),
aMediaViewerState(
mediaBottomSheetState = aMediaDeleteConfirmationState(),
mediaBottomSheetState = aMediaBottomSheetStateDeleteConfirmation(),
),
anAudioMediaInfo(
waveForm = WaveFormSamples.realisticWaveForm,

View file

@ -253,7 +253,7 @@ fun MediaViewerView(
when (val bottomSheetState = state.mediaBottomSheetState) {
MediaBottomSheetState.Hidden -> Unit
is MediaBottomSheetState.MediaDetailsBottomSheetState -> {
is MediaBottomSheetState.Details -> {
MediaDetailsBottomSheet(
state = bottomSheetState,
onViewInTimeline = {
@ -292,7 +292,7 @@ fun MediaViewerView(
},
)
}
is MediaBottomSheetState.MediaDeleteConfirmationState -> {
is MediaBottomSheetState.DeleteConfirmation -> {
MediaDeleteConfirmationBottomSheet(
state = bottomSheetState,
onDelete = {