Skip to content

Commit 26ffb1e

Browse files
authored
Merge pull request #4071 from element-hq/feature/bma/galleryUiTweak
Media gallery UI update
2 parents d854ea6 + e5a0576 commit 26ffb1e

File tree

81 files changed

+438
-293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+438
-293
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,6 @@ class MessagesFlowNode @AssistedInject constructor(
251251
mediaSource = navTarget.mediaSource,
252252
thumbnailSource = navTarget.thumbnailSource,
253253
canShowInfo = true,
254-
canDownload = true,
255-
canShare = true,
256254
)
257255
val callback = object : MediaViewerEntryPoint.Callback {
258256
override fun onDone() {

libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ enum class FeatureFlags(
158158
key = "feature.media_gallery",
159159
title = "Allow user to open the media gallery",
160160
description = null,
161-
defaultValue = { buildMeta -> buildMeta.buildType != BuildType.RELEASE },
161+
defaultValue = { true },
162162
isFinished = false,
163163
),
164164
EventCache(

libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,5 @@ interface MediaViewerEntryPoint : FeatureEntryPoint {
3636
val mediaSource: MediaSource,
3737
val thumbnailSource: MediaSource?,
3838
val canShowInfo: Boolean,
39-
val canDownload: Boolean,
40-
val canShare: Boolean,
4139
) : NodeInputs
4240
}

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/DefaultMediaViewerEntryPoint.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint
5959
mediaSource = MediaSource(url = avatarUrl),
6060
thumbnailSource = null,
6161
canShowInfo = false,
62-
canDownload = false,
63-
canShare = false,
6462
)
6563
)
6664
}

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheet.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ import io.element.android.libraries.ui.strings.CommonStrings
4848
fun MediaDetailsBottomSheet(
4949
state: MediaBottomSheetState.MediaDetailsBottomSheetState,
5050
onViewInTimeline: (EventId) -> Unit,
51+
onShare: (EventId) -> Unit,
52+
onDownload: (EventId) -> Unit,
5153
onDelete: (EventId) -> Unit,
5254
onDismiss: () -> Unit,
5355
modifier: Modifier = Modifier,
@@ -92,6 +94,22 @@ fun MediaDetailsBottomSheet(
9294
onViewInTimeline(state.eventId)
9395
}
9496
)
97+
ListItem(
98+
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.ShareAndroid())),
99+
headlineContent = { Text(stringResource(CommonStrings.action_share)) },
100+
style = ListItemStyle.Primary,
101+
onClick = {
102+
onShare(state.eventId)
103+
}
104+
)
105+
ListItem(
106+
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Download())),
107+
headlineContent = { Text(stringResource(CommonStrings.action_save)) },
108+
style = ListItemStyle.Primary,
109+
onClick = {
110+
onDownload(state.eventId)
111+
}
112+
)
95113
if (state.canDelete) {
96114
HorizontalDivider()
97115
ListItem(
@@ -196,6 +214,8 @@ internal fun MediaDetailsBottomSheetPreview() = ElementPreview {
196214
MediaDetailsBottomSheet(
197215
state = aMediaDetailsBottomSheetState(),
198216
onViewInTimeline = {},
217+
onShare = {},
218+
onDownload = {},
199219
onDelete = {},
200220
onDismiss = {},
201221
)

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/Preview.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
1212

1313
fun aMediaDetailsBottomSheetState(
1414
dateSentFull: String = "December 6, 2024 at 12:59",
15+
canDelete: Boolean = true,
1516
): MediaBottomSheetState.MediaDetailsBottomSheetState {
1617
return MediaBottomSheetState.MediaDetailsBottomSheetState(
1718
eventId = EventId("\$eventId"),
18-
canDelete = true,
19+
canDelete = canDelete,
1920
mediaInfo = anImageMediaInfo(
2021
senderName = "Alice",
2122
dateSentFull = dateSentFull,

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryEvents.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
1515
sealed interface MediaGalleryEvents {
1616
data class ChangeMode(val mode: MediaGalleryMode) : MediaGalleryEvents
1717
data class LoadMore(val direction: Timeline.PaginationDirection) : MediaGalleryEvents
18-
data class Share(val mediaItem: MediaItem.Event) : MediaGalleryEvents
19-
data class SaveOnDisk(val mediaItem: MediaItem.Event) : MediaGalleryEvents
18+
data class Share(val eventId: EventId?) : MediaGalleryEvents
19+
data class SaveOnDisk(val eventId: EventId?) : MediaGalleryEvents
2020
data class OpenInfo(val mediaItem: MediaItem.Event) : MediaGalleryEvents
2121
data class ViewInTimeline(val eventId: EventId) : MediaGalleryEvents
2222

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,16 @@ class MediaGalleryPresenter @AssistedInject constructor(
117117
timeline.dataOrNull()?.paginate(event.direction)
118118
}
119119
is MediaGalleryEvents.Delete -> coroutineScope.delete(timeline, event.eventId)
120-
is MediaGalleryEvents.SaveOnDisk -> coroutineScope.saveOnDisk(event.mediaItem)
121-
is MediaGalleryEvents.Share -> coroutineScope.share(event.mediaItem)
120+
is MediaGalleryEvents.SaveOnDisk -> coroutineScope.launch {
121+
mediaItems.dataOrNull().find(event.eventId)?.let {
122+
saveOnDisk(it)
123+
}
124+
}
125+
is MediaGalleryEvents.Share -> coroutineScope.launch {
126+
mediaItems.dataOrNull().find(event.eventId)?.let {
127+
share(it)
128+
}
129+
}
122130
is MediaGalleryEvents.ViewInTimeline -> {
123131
mediaBottomSheetState = MediaBottomSheetState.Hidden
124132
navigator.onViewInTimelineClick(event.eventId)
@@ -221,7 +229,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
221229
}
222230
}
223231

224-
private fun CoroutineScope.saveOnDisk(mediaItem: MediaItem.Event) = launch {
232+
private suspend fun saveOnDisk(mediaItem: MediaItem.Event) {
225233
downloadMedia(mediaItem)
226234
.mapCatching { localMedia ->
227235
localMediaActions.saveOnDisk(localMedia)
@@ -236,7 +244,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
236244
}
237245
}
238246

239-
private fun CoroutineScope.share(mediaItem: MediaItem.Event) = launch {
247+
private suspend fun share(mediaItem: MediaItem.Event) {
240248
downloadMedia(mediaItem)
241249
.mapCatching { localMedia ->
242250
localMediaActions.share(localMedia)
@@ -255,3 +263,11 @@ class MediaGalleryPresenter @AssistedInject constructor(
255263
}
256264
}
257265
}
266+
267+
private fun List<MediaItem>?.find(eventId: EventId?): MediaItem.Event? {
268+
if (this == null || eventId == null) {
269+
return null
270+
}
271+
return filterIsInstance<MediaItem.Event>()
272+
.firstOrNull { it.eventId() == eventId }
273+
}

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryView.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import io.element.android.compound.theme.ElementTheme
4141
import io.element.android.compound.tokens.generated.CompoundIcons
4242
import io.element.android.libraries.architecture.AsyncData
4343
import io.element.android.libraries.architecture.Presenter
44+
import io.element.android.libraries.designsystem.background.OnboardingBackground
4445
import io.element.android.libraries.designsystem.components.BigIcon
4546
import io.element.android.libraries.designsystem.components.PageTitle
4647
import io.element.android.libraries.designsystem.components.async.AsyncFailure
@@ -106,7 +107,8 @@ fun MediaGalleryView(
106107
modifier = Modifier
107108
.padding(paddingValues)
108109
.consumeWindowInsets(paddingValues)
109-
.fillMaxSize()
110+
.fillMaxSize(),
111+
verticalArrangement = Arrangement.spacedBy(2.dp),
110112
) {
111113
SingleChoiceSegmentedButtonRow(
112114
modifier = Modifier
@@ -151,6 +153,12 @@ fun MediaGalleryView(
151153
onViewInTimeline = { eventId ->
152154
state.eventSink(MediaGalleryEvents.ViewInTimeline(eventId))
153155
},
156+
onShare = { eventId ->
157+
state.eventSink(MediaGalleryEvents.Share(eventId))
158+
},
159+
onDownload = { eventId ->
160+
state.eventSink(MediaGalleryEvents.SaveOnDisk(eventId))
161+
},
154162
onDelete = { eventId ->
155163
state.eventSink(
156164
MediaGalleryEvents.ConfirmDelete(
@@ -274,21 +282,27 @@ private fun MediaGalleryFilesList(
274282
modifier = Modifier.animateItem(),
275283
file = item,
276284
onClick = { onItemClick(item) },
285+
onLongClick = {
286+
eventSink(MediaGalleryEvents.OpenInfo(item))
287+
},
277288
)
278289
is MediaItem.Audio -> AudioItemView(
279290
modifier = Modifier.animateItem(),
280291
audio = item,
281292
onClick = { onItemClick(item) },
293+
onLongClick = {
294+
eventSink(MediaGalleryEvents.OpenInfo(item))
295+
},
282296
)
283297
is MediaItem.Voice -> {
284298
val presenter: Presenter<VoiceMessageState> = presenterFactories.rememberPresenter(item)
285299
VoiceItemView(
286300
modifier = Modifier.animateItem(),
287301
state = presenter.present(),
288302
voice = item,
289-
onShareClick = { eventSink(MediaGalleryEvents.Share(item)) },
290-
onDownloadClick = { eventSink(MediaGalleryEvents.SaveOnDisk(item)) },
291-
onInfoClick = { eventSink(MediaGalleryEvents.OpenInfo(item)) },
303+
onLongClick = {
304+
eventSink(MediaGalleryEvents.OpenInfo(item))
305+
},
292306
)
293307
}
294308
is MediaItem.DateSeparator -> DateItemView(
@@ -426,6 +440,7 @@ private fun EmptyContent(
426440
Box(
427441
modifier = Modifier.fillMaxSize(),
428442
) {
443+
OnboardingBackground()
429444
PageTitle(
430445
modifier = Modifier
431446
.fillMaxWidth()

libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/root/MediaGalleryRootNode.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@ class MediaGalleryRootNode @AssistedInject constructor(
122122
mediaSource = navTarget.mediaSource,
123123
thumbnailSource = navTarget.thumbnailSource,
124124
canShowInfo = true,
125-
canDownload = true,
126-
canShare = true,
127125
)
128126
)
129127
.callback(callback)

0 commit comments

Comments
 (0)