Move share and download actions to the bottom sheet
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -36,7 +36,5 @@ interface MediaViewerEntryPoint : FeatureEntryPoint {
|
||||
val mediaSource: MediaSource,
|
||||
val thumbnailSource: MediaSource?,
|
||||
val canShowInfo: Boolean,
|
||||
val canDownload: Boolean,
|
||||
val canShare: Boolean,
|
||||
) : NodeInputs
|
||||
}
|
||||
|
||||
@@ -59,8 +59,6 @@ class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint
|
||||
mediaSource = MediaSource(url = avatarUrl),
|
||||
thumbnailSource = null,
|
||||
canShowInfo = false,
|
||||
canDownload = false,
|
||||
canShare = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 = {},
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -122,8 +122,6 @@ class MediaGalleryRootNode @AssistedInject constructor(
|
||||
mediaSource = navTarget.mediaSource,
|
||||
thumbnailSource = navTarget.thumbnailSource,
|
||||
canShowInfo = true,
|
||||
canDownload = true,
|
||||
canShare = true,
|
||||
)
|
||||
)
|
||||
.callback(callback)
|
||||
|
||||
@@ -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 = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user