Move share and download actions to the bottom sheet

This commit is contained in:
Benoit Marty
2024-12-19 16:20:41 +01:00
parent 194b1a8c56
commit f8b2f24962
17 changed files with 127 additions and 178 deletions

View File

@@ -251,8 +251,6 @@ class MessagesFlowNode @AssistedInject constructor(
mediaSource = navTarget.mediaSource,
thumbnailSource = navTarget.thumbnailSource,
canShowInfo = true,
canDownload = true,
canShare = true,
)
val callback = object : MediaViewerEntryPoint.Callback {
override fun onDone() {

View File

@@ -36,7 +36,5 @@ interface MediaViewerEntryPoint : FeatureEntryPoint {
val mediaSource: MediaSource,
val thumbnailSource: MediaSource?,
val canShowInfo: Boolean,
val canDownload: Boolean,
val canShare: Boolean,
) : NodeInputs
}

View File

@@ -59,8 +59,6 @@ class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint
mediaSource = MediaSource(url = avatarUrl),
thumbnailSource = null,
canShowInfo = false,
canDownload = false,
canShare = false,
)
)
}

View File

@@ -48,6 +48,8 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun MediaDetailsBottomSheet(
state: MediaBottomSheetState.MediaDetailsBottomSheetState,
onViewInTimeline: (EventId) -> Unit,
onShare: (EventId) -> Unit,
onDownload: (EventId) -> Unit,
onDelete: (EventId) -> Unit,
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
@@ -92,6 +94,22 @@ fun MediaDetailsBottomSheet(
onViewInTimeline(state.eventId)
}
)
ListItem(
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.ShareAndroid())),
headlineContent = { Text(stringResource(CommonStrings.action_share)) },
style = ListItemStyle.Primary,
onClick = {
onShare(state.eventId)
}
)
ListItem(
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Download())),
headlineContent = { Text(stringResource(CommonStrings.action_save)) },
style = ListItemStyle.Primary,
onClick = {
onDownload(state.eventId)
}
)
if (state.canDelete) {
HorizontalDivider()
ListItem(
@@ -196,6 +214,8 @@ internal fun MediaDetailsBottomSheetPreview() = ElementPreview {
MediaDetailsBottomSheet(
state = aMediaDetailsBottomSheetState(),
onViewInTimeline = {},
onShare = {},
onDownload = {},
onDelete = {},
onDismiss = {},
)

View File

@@ -15,8 +15,8 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
sealed interface MediaGalleryEvents {
data class ChangeMode(val mode: MediaGalleryMode) : MediaGalleryEvents
data class LoadMore(val direction: Timeline.PaginationDirection) : MediaGalleryEvents
data class Share(val mediaItem: MediaItem.Event) : MediaGalleryEvents
data class SaveOnDisk(val mediaItem: MediaItem.Event) : MediaGalleryEvents
data class Share(val eventId: EventId?) : MediaGalleryEvents
data class SaveOnDisk(val eventId: EventId?) : MediaGalleryEvents
data class OpenInfo(val mediaItem: MediaItem.Event) : MediaGalleryEvents
data class ViewInTimeline(val eventId: EventId) : MediaGalleryEvents

View File

@@ -117,8 +117,16 @@ class MediaGalleryPresenter @AssistedInject constructor(
timeline.dataOrNull()?.paginate(event.direction)
}
is MediaGalleryEvents.Delete -> coroutineScope.delete(timeline, event.eventId)
is MediaGalleryEvents.SaveOnDisk -> coroutineScope.saveOnDisk(event.mediaItem)
is MediaGalleryEvents.Share -> coroutineScope.share(event.mediaItem)
is MediaGalleryEvents.SaveOnDisk -> coroutineScope.launch {
mediaItems.dataOrNull().find(event.eventId)?.let {
saveOnDisk(it)
}
}
is MediaGalleryEvents.Share -> coroutineScope.launch {
mediaItems.dataOrNull().find(event.eventId)?.let {
share(it)
}
}
is MediaGalleryEvents.ViewInTimeline -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
navigator.onViewInTimelineClick(event.eventId)
@@ -221,7 +229,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
}
}
private fun CoroutineScope.saveOnDisk(mediaItem: MediaItem.Event) = launch {
private suspend fun saveOnDisk(mediaItem: MediaItem.Event) {
downloadMedia(mediaItem)
.mapCatching { localMedia ->
localMediaActions.saveOnDisk(localMedia)
@@ -236,7 +244,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
}
}
private fun CoroutineScope.share(mediaItem: MediaItem.Event) = launch {
private suspend fun share(mediaItem: MediaItem.Event) {
downloadMedia(mediaItem)
.mapCatching { localMedia ->
localMediaActions.share(localMedia)
@@ -255,3 +263,11 @@ class MediaGalleryPresenter @AssistedInject constructor(
}
}
}
private fun List<MediaItem>?.find(eventId: EventId?): MediaItem.Event? {
if (this == null || eventId == null) {
return null
}
return filterIsInstance<MediaItem.Event>()
.firstOrNull { it.eventId() == eventId }
}

View File

@@ -153,6 +153,12 @@ fun MediaGalleryView(
onViewInTimeline = { eventId ->
state.eventSink(MediaGalleryEvents.ViewInTimeline(eventId))
},
onShare = { eventId ->
state.eventSink(MediaGalleryEvents.Share(eventId))
},
onDownload = { eventId ->
state.eventSink(MediaGalleryEvents.SaveOnDisk(eventId))
},
onDelete = { eventId ->
state.eventSink(
MediaGalleryEvents.ConfirmDelete(
@@ -276,11 +282,17 @@ private fun MediaGalleryFilesList(
modifier = Modifier.animateItem(),
file = item,
onClick = { onItemClick(item) },
onLongClick = {
eventSink(MediaGalleryEvents.OpenInfo(item))
},
)
is MediaItem.Audio -> AudioItemView(
modifier = Modifier.animateItem(),
audio = item,
onClick = { onItemClick(item) },
onLongClick = {
eventSink(MediaGalleryEvents.OpenInfo(item))
},
)
is MediaItem.Voice -> {
val presenter: Presenter<VoiceMessageState> = presenterFactories.rememberPresenter(item)
@@ -288,9 +300,9 @@ private fun MediaGalleryFilesList(
modifier = Modifier.animateItem(),
state = presenter.present(),
voice = item,
onShareClick = { eventSink(MediaGalleryEvents.Share(item)) },
onDownloadClick = { eventSink(MediaGalleryEvents.SaveOnDisk(item)) },
onInfoClick = { eventSink(MediaGalleryEvents.OpenInfo(item)) },
onLongClick = {
eventSink(MediaGalleryEvents.OpenInfo(item))
},
)
}
is MediaItem.DateSeparator -> DateItemView(

View File

@@ -122,8 +122,6 @@ class MediaGalleryRootNode @AssistedInject constructor(
mediaSource = navTarget.mediaSource,
thumbnailSource = navTarget.thumbnailSource,
canShowInfo = true,
canDownload = true,
canShare = true,
)
)
.callback(callback)

View File

@@ -7,8 +7,9 @@
package io.element.android.libraries.mediaviewer.impl.gallery.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -41,6 +42,7 @@ import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem
fun AudioItemView(
audio: MediaItem.Audio,
onClick: () -> Unit,
onLongClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
@@ -52,6 +54,7 @@ fun AudioItemView(
FilenameRow(
audio = audio,
onClick = onClick,
onLongClick = onLongClick,
)
val caption = audio.mediaInfo.caption
if (caption != null) {
@@ -63,10 +66,12 @@ fun AudioItemView(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun FilenameRow(
audio: MediaItem.Audio,
onClick: () -> Unit,
onLongClick: () -> Unit,
) {
Row(
modifier = Modifier
@@ -75,7 +80,7 @@ private fun FilenameRow(
color = ElementTheme.colors.bgSubtleSecondary,
shape = RoundedCornerShape(12.dp),
)
.clickable { onClick() }
.combinedClickable(onClick = onClick, onLongClick = onLongClick)
.fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -119,5 +124,6 @@ internal fun AudioItemViewPreview(
AudioItemView(
audio = audio,
onClick = {},
onLongClick = {},
)
}

View File

@@ -7,8 +7,9 @@
package io.element.android.libraries.mediaviewer.impl.gallery.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -40,6 +41,7 @@ import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem
fun FileItemView(
file: MediaItem.File,
onClick: () -> Unit,
onLongClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
@@ -51,6 +53,7 @@ fun FileItemView(
FilenameRow(
file = file,
onClick = onClick,
onLongClick = onLongClick,
)
val caption = file.mediaInfo.caption
if (caption != null) {
@@ -62,10 +65,12 @@ fun FileItemView(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun FilenameRow(
file: MediaItem.File,
onClick: () -> Unit,
onLongClick: () -> Unit,
) {
Row(
modifier = Modifier
@@ -74,7 +79,7 @@ private fun FilenameRow(
color = ElementTheme.colors.bgSubtleSecondary,
shape = RoundedCornerShape(12.dp),
)
.clickable { onClick() }
.combinedClickable(onClick = onClick, onLongClick = onLongClick)
.fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -118,5 +123,6 @@ internal fun FileItemViewPreview(
FileItemView(
file = file,
onClick = {},
onLongClick = {},
)
}

View File

@@ -7,9 +7,10 @@
package io.element.android.libraries.mediaviewer.impl.gallery.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -58,9 +59,7 @@ import kotlinx.coroutines.delay
fun VoiceItemView(
state: VoiceMessageState,
voice: MediaItem.Voice,
onShareClick: () -> Unit,
onDownloadClick: () -> Unit,
onInfoClick: () -> Unit,
onLongClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
@@ -72,6 +71,7 @@ fun VoiceItemView(
VoiceInfoRow(
state = state,
voice = voice,
onLongClick = onLongClick,
)
val caption = voice.mediaInfo.caption
if (caption != null) {
@@ -79,19 +79,16 @@ fun VoiceItemView(
} else {
Spacer(modifier = Modifier.height(16.dp))
}
ActionIconsRow(
onShareClick = onShareClick,
onDownloadClick = onDownloadClick,
onInfoClick = onInfoClick,
)
HorizontalDivider()
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun VoiceInfoRow(
state: VoiceMessageState,
voice: MediaItem.Voice,
onLongClick: () -> Unit,
) {
fun playPause() {
state.eventSink(VoiceMessageEvents.PlayPause)
@@ -104,6 +101,7 @@ private fun VoiceInfoRow(
color = ElementTheme.colors.bgSubtleSecondary,
shape = RoundedCornerShape(12.dp),
)
.combinedClickable(onClick = {}, onLongClick = onLongClick)
.fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -257,43 +255,6 @@ private fun CustomIconButton(
)
}
@Composable
private fun ActionIconsRow(
onShareClick: () -> Unit,
onDownloadClick: () -> Unit,
onInfoClick: () -> Unit,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
IconButton(
onClick = onShareClick,
) {
Icon(
imageVector = CompoundIcons.ShareAndroid(),
contentDescription = null,
)
}
IconButton(
onClick = onDownloadClick,
) {
Icon(
imageVector = CompoundIcons.Download(),
contentDescription = null,
)
}
IconButton(
onClick = onInfoClick,
) {
Icon(
imageVector = CompoundIcons.Info(),
contentDescription = null,
)
}
}
}
@PreviewsDayNight
@Composable
internal fun VoiceItemViewPreview(
@@ -302,9 +263,7 @@ internal fun VoiceItemViewPreview(
VoiceItemView(
state = aVoiceMessageState(),
voice = voice,
onShareClick = {},
onDownloadClick = {},
onInfoClick = {},
onLongClick = {},
)
}
@@ -316,8 +275,6 @@ internal fun VoiceItemViewPlayPreview(
VoiceItemView(
state = state,
voice = aMediaItemVoice(),
onShareClick = {},
onDownloadClick = {},
onInfoClick = {},
onLongClick = {},
)
}

View File

@@ -83,9 +83,18 @@ class MediaViewerPresenter @AssistedInject constructor(
when (mediaViewerEvents) {
MediaViewerEvents.RetryLoading -> loadMediaTrigger++
MediaViewerEvents.ClearLoadingError -> localMedia.value = AsyncData.Uninitialized
MediaViewerEvents.SaveOnDisk -> coroutineScope.saveOnDisk(localMedia.value)
MediaViewerEvents.Share -> coroutineScope.share(localMedia.value)
MediaViewerEvents.OpenWith -> coroutineScope.open(localMedia.value)
MediaViewerEvents.SaveOnDisk -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
coroutineScope.saveOnDisk(localMedia.value)
}
MediaViewerEvents.Share -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
coroutineScope.share(localMedia.value)
}
MediaViewerEvents.OpenWith -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
coroutineScope.open(localMedia.value)
}
is MediaViewerEvents.Delete -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
coroutineScope.delete(mediaViewerEvents.eventId)
@@ -126,8 +135,6 @@ class MediaViewerPresenter @AssistedInject constructor(
downloadedMedia = localMedia.value,
snackbarMessage = snackbarMessage,
canShowInfo = inputs.canShowInfo,
canDownload = inputs.canDownload,
canShare = inputs.canShare,
mediaBottomSheetState = mediaBottomSheetState,
eventSink = ::handleEvents
)

View File

@@ -22,8 +22,6 @@ data class MediaViewerState(
val downloadedMedia: AsyncData<LocalMedia>,
val snackbarMessage: SnackbarMessage?,
val canShowInfo: Boolean,
val canDownload: Boolean,
val canShare: Boolean,
val mediaBottomSheetState: MediaBottomSheetState,
val eventSink: (MediaViewerEvents) -> Unit,
)

View File

@@ -91,8 +91,6 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState>
),
mediaInfo = it,
canShowInfo = false,
canDownload = false,
canShare = false,
)
},
aMediaViewerState(
@@ -118,8 +116,6 @@ fun aMediaViewerState(
downloadedMedia: AsyncData<LocalMedia> = AsyncData.Uninitialized,
mediaInfo: MediaInfo = anImageMediaInfo(),
canShowInfo: Boolean = true,
canDownload: Boolean = true,
canShare: Boolean = true,
mediaBottomSheetState: MediaBottomSheetState = MediaBottomSheetState.Hidden,
eventSink: (MediaViewerEvents) -> Unit = {},
) = MediaViewerState(
@@ -129,8 +125,6 @@ fun aMediaViewerState(
downloadedMedia = downloadedMedia,
snackbarMessage = null,
canShowInfo = canShowInfo,
canDownload = canDownload,
canShare = canShare,
mediaBottomSheetState = mediaBottomSheetState,
eventSink = eventSink,
)

View File

@@ -119,8 +119,6 @@ fun MediaViewerView(
) {
MediaViewerTopBar(
actionsEnabled = state.downloadedMedia is AsyncData.Success,
canDownload = state.canDownload,
canShare = state.canShare,
mimeType = state.mediaInfo.mimeType,
senderName = state.mediaInfo.senderName,
dateSent = state.mediaInfo.dateSent,
@@ -148,6 +146,12 @@ fun MediaViewerView(
onViewInTimeline = {
state.eventSink(MediaViewerEvents.ViewInTimeline(it))
},
onShare = {
state.eventSink(MediaViewerEvents.Share)
},
onDownload = {
state.eventSink(MediaViewerEvents.SaveOnDisk)
},
onDelete = { eventId ->
state.eventSink(MediaViewerEvents.ConfirmDelete(eventId))
},
@@ -313,8 +317,6 @@ private fun rememberShowProgress(downloadedMedia: AsyncData<LocalMedia>): Boolea
@Composable
private fun MediaViewerTopBar(
actionsEnabled: Boolean,
canDownload: Boolean,
canShare: Boolean,
mimeType: String,
senderName: String?,
dateSent: String?,
@@ -348,19 +350,6 @@ private fun MediaViewerTopBar(
),
navigationIcon = { BackButton(onClick = onBackClick) },
actions = {
if (canShare) {
IconButton(
enabled = actionsEnabled,
onClick = {
eventSink(MediaViewerEvents.Share)
},
) {
Icon(
imageVector = CompoundIcons.ShareAndroid(),
contentDescription = stringResource(id = CommonStrings.action_share)
)
}
}
IconButton(
enabled = actionsEnabled,
onClick = {
@@ -378,19 +367,6 @@ private fun MediaViewerTopBar(
)
}
}
if (canDownload) {
IconButton(
enabled = actionsEnabled,
onClick = {
eventSink(MediaViewerEvents.SaveOnDisk)
},
) {
Icon(
imageVector = CompoundIcons.Download(),
contentDescription = stringResource(id = CommonStrings.action_save),
)
}
}
if (canShowInfo) {
IconButton(
onClick = onInfoClick,

View File

@@ -66,8 +66,6 @@ class MediaViewerPresenterTest {
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@@ -86,48 +84,6 @@ class MediaViewerPresenterTest {
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isFalse()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@Test
fun `present - initial state cannot share`() = runTest {
val presenter = createMediaViewerPresenter(
canShare = false,
room = FakeMatrixRoom(
canRedactOwnResult = { Result.success(true) },
)
)
presenter.test {
skipItems(2)
val initialState = awaitItem()
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@Test
fun `present - initial state cannot download`() = runTest {
val presenter = createMediaViewerPresenter(
canDownload = false,
room = FakeMatrixRoom(
canRedactOwnResult = { Result.success(true) },
)
)
presenter.test {
skipItems(2)
val initialState = awaitItem()
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isFalse()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@@ -146,8 +102,6 @@ class MediaViewerPresenterTest {
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@@ -167,8 +121,6 @@ class MediaViewerPresenterTest {
assertThat(initialState.downloadedMedia).isInstanceOf(AsyncData.Success::class.java)
assertThat(initialState.snackbarMessage).isNull()
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@@ -350,8 +302,6 @@ class MediaViewerPresenterTest {
localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(),
snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
canShowInfo: Boolean = true,
canShare: Boolean = true,
canDownload: Boolean = true,
mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(),
room: MatrixRoom = FakeMatrixRoom(
liveTimeline = FakeTimeline(),
@@ -364,8 +314,6 @@ class MediaViewerPresenterTest {
mediaSource = aMediaSource(),
thumbnailSource = null,
canShowInfo = canShowInfo,
canShare = canShare,
canDownload = canDownload,
),
localMediaFactory = localMediaFactory,
mediaLoader = matrixMediaLoader,

View File

@@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.architecture.AsyncData
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.aMediaDetailsBottomSheetState
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.EventsRecorder
@@ -54,16 +55,6 @@ class MediaViewerViewTest {
testMenuAction(CommonStrings.action_open_with, MediaViewerEvents.OpenWith)
}
@Test
fun `clicking on save emit expected Event`() {
testMenuAction(CommonStrings.action_save, MediaViewerEvents.SaveOnDisk)
}
@Test
fun `clicking on share emit expected Event`() {
testMenuAction(CommonStrings.action_share, MediaViewerEvents.Share)
}
private fun testMenuAction(contentDescriptionRes: Int, expectedEvent: MediaViewerEvents) {
val eventsRecorder = EventsRecorder<MediaViewerEvents>()
rule.setMediaViewerView(
@@ -80,6 +71,32 @@ class MediaViewerViewTest {
eventsRecorder.assertSingle(expectedEvent)
}
@Test
fun `clicking on save emit expected Event`() {
testBottomSheetAction(CommonStrings.action_save, MediaViewerEvents.SaveOnDisk)
}
@Test
fun `clicking on share emit expected Event`() {
testBottomSheetAction(CommonStrings.action_share, MediaViewerEvents.Share)
}
private fun testBottomSheetAction(contentDescriptionRes: Int, expectedEvent: MediaViewerEvents) {
val eventsRecorder = EventsRecorder<MediaViewerEvents>()
rule.setMediaViewerView(
aMediaViewerState(
downloadedMedia = AsyncData.Success(
LocalMedia(Uri.EMPTY, anImageMediaInfo())
),
mediaInfo = anImageMediaInfo(),
mediaBottomSheetState = aMediaDetailsBottomSheetState(),
eventSink = eventsRecorder
),
)
rule.clickOn(contentDescriptionRes)
eventsRecorder.assertSingle(expectedEvent)
}
@Test
fun `clicking on image hides the overlay`() {
val eventsRecorder = EventsRecorder<MediaViewerEvents>(expectEvents = false)