diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index da7f3d8d5b..cbab26fe54 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -159,6 +159,7 @@ class MessagesFlowNode( @Parcelize data class GalleryViewer( + val fromPinnedMessages: Boolean, val eventId: EventId?, val galleryInfo: GalleryInfo, val canUseOverlay: Boolean, @@ -265,11 +266,13 @@ class MessagesFlowNode( } override fun handleGalleryItemClick( + timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean, ): Boolean { return processGalleryEventClick( + timelineMode = timelineMode, event = event, canUseOverlay = canUseOverlay, galleryItemIndex = galleryItemIndex, @@ -405,6 +408,7 @@ class MessagesFlowNode( eventId = navTarget.eventId, galleryInfo = navTarget.galleryInfo, galleryItems = navTarget.galleryItems, + fromPinnedMessages = navTarget.fromPinnedMessages, ) val callback = object : MediaViewerEntryPoint.Callback { override fun onDone() { @@ -520,6 +524,7 @@ class MessagesFlowNode( canUseOverlay: Boolean, ) { processGalleryEventClick( + timelineMode = Timeline.Mode.PinnedEvents, event = event, galleryItemIndex = galleryItemIndex, canUseOverlay = canUseOverlay, @@ -574,11 +579,13 @@ class MessagesFlowNode( } override fun handleGalleryItemClick( + timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean, ): Boolean { return processGalleryEventClick( + timelineMode = timelineMode, event = event, canUseOverlay = canUseOverlay, galleryItemIndex = galleryItemIndex, @@ -792,6 +799,7 @@ class MessagesFlowNode( } private fun processGalleryEventClick( + timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean, @@ -827,6 +835,7 @@ class MessagesFlowNode( galleryInfo = galleryInfo, canUseOverlay = canUseOverlay, galleryItems = galleryItems, + fromPinnedMessages = timelineMode is Timeline.Mode.PinnedEvents ) } is TimelineItemAttachmentsContent -> { @@ -859,6 +868,7 @@ class MessagesFlowNode( galleryInfo = galleryInfo, canUseOverlay = canUseOverlay, galleryItems = galleryItems, + fromPinnedMessages = timelineMode is Timeline.Mode.PinnedEvents ) } else -> null diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 1eb3a82e1a..a7e8846047 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -119,7 +119,7 @@ class MessagesNode( interface Callback : Plugin { fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean - fun handleGalleryItemClick(event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean + fun handleGalleryItemClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -290,8 +290,17 @@ class MessagesNode( } } }, - onGalleryEventItemClick = { event, index -> - callback.handleGalleryItemClick(event, index, canUseOverlay) + onGalleryEventItemClick = { isLive, event, index -> + if (isLive) { + callback.handleGalleryItemClick(timelineController.mainTimelineMode(), event, index, canUseOverlay) + } else { + val detachedTimelineMode = timelineController.detachedTimelineMode() + if (detachedTimelineMode != null) { + callback.handleGalleryItemClick(detachedTimelineMode, event, index, canUseOverlay) + } else { + false + } + } }, onUserDataClick = callback::navigateToRoomMemberDetails, onLinkClick = { url, customTab -> diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 1e9471fa4b..0be003d8d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -136,7 +136,7 @@ fun MessagesView( onBackClick: () -> Unit, onRoomDetailsClick: () -> Unit, onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean, - onGalleryEventItemClick: (event: TimelineItem.Event, index: Int) -> Boolean, + onGalleryEventItemClick: (isLive: Boolean, event: TimelineItem.Event, index: Int) -> Boolean, onUserDataClick: (UserId) -> Unit, onLinkClick: (String, Boolean) -> Unit, onSendLocationClick: () -> Unit, @@ -260,7 +260,11 @@ fun MessagesView( state = state, onContentClick = ::onContentClick, onGalleryItemClick = { event, index -> - val hideKeyboard = onGalleryEventItemClick(event, index) + val hideKeyboard = onGalleryEventItemClick( + state.timelineState.isLive, + event, + index, + ) if (hideKeyboard) { localView.hideKeyboard() } @@ -646,6 +650,7 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, @@ -655,7 +660,6 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) forceJumpToBottomVisibility = true, knockRequestsBannerView = {}, onThreadsListClick = {}, - onGalleryEventItemClick = { _, _ -> false }, ) } @@ -702,6 +706,7 @@ internal fun MessagesViewA11yPreview() = ElementPreview { onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, @@ -709,7 +714,6 @@ internal fun MessagesViewA11yPreview() = ElementPreview { onJoinCallClick = {}, onViewAllPinnedMessagesClick = {}, onThreadsListClick = {}, - onGalleryEventItemClick = { _, _ -> false }, forceJumpToBottomVisibility = true, knockRequestsBannerView = {}, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt index 2bad9a64d9..d7dd95eb95 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt @@ -35,6 +35,7 @@ internal fun MessagesViewWithIdentityChangePreview( onBackClick = {}, onRoomDetailsClick = {}, onEventContentClick = { _, _ -> false }, + onGalleryEventItemClick = { _, _, _ -> false }, onUserDataClick = {}, onLinkClick = { _, _ -> }, onSendLocationClick = {}, @@ -43,6 +44,5 @@ internal fun MessagesViewWithIdentityChangePreview( onViewAllPinnedMessagesClick = {}, knockRequestsBannerView = {}, onThreadsListClick = {}, - onGalleryEventItemClick = { _, _ -> false }, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt index 4d52773691..c3e06b880b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt @@ -126,7 +126,7 @@ class ThreadedMessagesNode( interface Callback : Plugin { fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean - fun handleGalleryItemClick(event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean + fun handleGalleryItemClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, galleryItemIndex: Int, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -290,8 +290,19 @@ class ThreadedMessagesNode( } } == true }, - onGalleryEventItemClick = { event, index -> - callback.handleGalleryItemClick(event, index, canUseOverlay) + onGalleryEventItemClick = { isLive, event, index -> + timelineController?.let { controller -> + if (isLive) { + callback.handleGalleryItemClick(controller.mainTimelineMode(), event, index, canUseOverlay) + } else { + val detachedTimelineMode = controller.detachedTimelineMode() + if (detachedTimelineMode != null) { + callback.handleGalleryItemClick(detachedTimelineMode, event, index, canUseOverlay) + } else { + false + } + } + } == true }, onUserDataClick = callback::navigateToRoomMemberDetails, onLinkClick = { url, customTab -> diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt index 7930175d53..f6de6cf839 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/MediaViewerEntryPoint.kt @@ -48,6 +48,7 @@ interface MediaViewerEntryPoint : FeatureEntryPoint { val eventId: EventId?, val galleryInfo: GalleryInfo, val galleryItems: List, + val fromPinnedMessages: Boolean, ) : Params data class Avatar( @@ -59,7 +60,7 @@ interface MediaViewerEntryPoint : FeatureEntryPoint { sealed interface MediaViewerMode : Parcelable { @Parcelize - data object EventGallery : MediaViewerMode + data class EventGallery(val fromPinnedMessages: Boolean) : MediaViewerMode @Parcelize data class TimelineImagesAndVideos(val timelineMode: Timeline.Mode) : MediaViewerMode diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt index 7806ac2d95..7cbeafa0b2 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerDataSource.kt @@ -64,7 +64,7 @@ class MediaViewerDataSource( private val galleryMode = when (mode) { is MediaViewerMode.TimelineImagesAndVideos -> MediaGalleryMode.Images is MediaViewerMode.TimelineFilesAndAudios -> MediaGalleryMode.Files - MediaViewerMode.EventGallery -> MediaGalleryMode.Images + is MediaViewerMode.EventGallery -> MediaGalleryMode.Images } // Map of sourceUrl to local media state diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt index f169c6a3f1..2298981543 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerNode.kt @@ -131,7 +131,7 @@ class MediaViewerNode( is MediaViewerEntryPoint.Params.Avatar -> MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(Timeline.Mode.Media) is MediaViewerEntryPoint.Params.EventGallery -> - MediaViewerEntryPoint.MediaViewerMode.EventGallery + MediaViewerEntryPoint.MediaViewerMode.EventGallery(fromPinnedMessages = inputs.fromPinnedMessages) is MediaViewerEntryPoint.Params.RoomMedia -> inputs.mode }, @@ -169,6 +169,6 @@ internal fun MediaViewerEntryPoint.MediaViewerMode.getTimelineMode(): Timeline.M return when (this) { is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> timelineMode is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> timelineMode - MediaViewerEntryPoint.MediaViewerMode.EventGallery -> null + is MediaViewerEntryPoint.MediaViewerMode.EventGallery -> null } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt index 1890142b8d..da181a80d3 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt @@ -151,8 +151,11 @@ class MediaViewerPresenter( mediaBottomSheetState = MediaBottomSheetState.Hidden navigator.onForwardClick( eventId = event.eventId, - // TODO We can have a pinned gallery - fromPinnedEvents = inputs.mode()?.getTimelineMode() == Timeline.Mode.PinnedEvents, + fromPinnedEvents = when (inputs) { + is MediaViewerEntryPoint.Params.RoomMedia -> inputs.mode == Timeline.Mode.PinnedEvents + is MediaViewerEntryPoint.Params.EventGallery -> inputs.fromPinnedMessages + is MediaViewerEntryPoint.Params.Avatar -> false + }, ) } is MediaViewerEvent.OpenInfo -> coroutineScope.launch { @@ -241,7 +244,7 @@ class MediaViewerPresenter( is MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos -> R.string.screen_media_details_no_more_media_to_show is MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios -> R.string.screen_media_details_no_more_files_to_show // Should not happen - MediaViewerEntryPoint.MediaViewerMode.EventGallery -> R.string.screen_media_details_no_more_media_to_show + is MediaViewerEntryPoint.MediaViewerMode.EventGallery -> R.string.screen_media_details_no_more_media_to_show } val message = SnackbarMessage(messageResId) snackbarDispatcher.post(message) @@ -319,9 +322,3 @@ private fun MediaViewerEntryPoint.Params.mediaSource() = when (this) { is MediaViewerEntryPoint.Params.EventGallery -> null is MediaViewerEntryPoint.Params.RoomMedia -> mediaSource } - -private fun MediaViewerEntryPoint.Params.mode() = when (this) { - is MediaViewerEntryPoint.Params.Avatar -> null - is MediaViewerEntryPoint.Params.EventGallery -> null - is MediaViewerEntryPoint.Params.RoomMedia -> mode -}