From f5737e9d2b2fb9e202c68533c22fb5ef588eddef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 15:44:02 +0200 Subject: [PATCH 01/16] a11y: add alternative text to the info icon. Closes #6379 --- .../io/element/android/libraries/textcomposer/TextComposer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 4860a53ae7..3993b3d64c 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -679,7 +679,7 @@ private fun TextInputBox( .align(Alignment.CenterEnd), imageVector = CompoundIcons.InfoSolid(), tint = ElementTheme.colors.iconCriticalPrimary, - contentDescription = null, + contentDescription = stringResource(CommonStrings.a11y_info), ) if (showBottomSheet) { CaptionWarningBottomSheet( From b815aaabc9b550192a80fad97f432dcecb954121 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 15:54:07 +0200 Subject: [PATCH 02/16] a11y: let section header be implemented as a heading. Closes #6386 --- .../designsystem/theme/components/ListSectionHeader.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSectionHeader.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSectionHeader.kt index 403ed6da97..3a86d72e7d 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSectionHeader.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ListSectionHeader.kt @@ -17,6 +17,8 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.heading +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme @@ -48,6 +50,9 @@ fun ListSectionHeader( verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( + modifier = Modifier.semantics { + heading() + }, text = title, style = ElementTheme.typography.fontBodyLgMedium, color = ElementTheme.colors.textPrimary, From 0a99b28963ed247da62b2bbd0b54081b48ca8771 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 16:10:19 +0200 Subject: [PATCH 03/16] a11y: let banner title be implemented as a heading. Closes #6384 --- .../libraries/designsystem/components/Announcement.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Announcement.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Announcement.kt index dcd3f8fa21..037c37e3a8 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Announcement.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/Announcement.kt @@ -24,6 +24,8 @@ import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.heading +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons @@ -148,7 +150,11 @@ private fun TitleAndDescription( text = title, style = ElementTheme.typography.fontBodyLgMedium, color = titleColor, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .semantics { + heading() + }, ) if (trailingContent != null) { Spacer(Modifier.width(12.dp)) From 0c333235f808113c9a37d6d1aacb3b97a0874ff4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 16:16:15 +0200 Subject: [PATCH 04/16] a11y: set role = button for "learn more" texts. Closes #6405 --- .../choosemode/ChooseSelfVerificationModeView.kt | 9 ++++++++- .../impl/outgoing/OutgoingVerificationView.kt | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt index 0ca25c9455..1bfa10daf2 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt @@ -19,6 +19,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme @@ -90,7 +93,11 @@ fun ChooseSelfVerificationModeView( Text( modifier = Modifier .clickable(onClick = onLearnMore) - .padding(vertical = 4.dp, horizontal = 16.dp), + .padding(vertical = 4.dp, horizontal = 16.dp) + .semantics { + // Note: there is no Role.Link, so we use Role.Button for better accessibility support + role = Role.Button + }, text = stringResource(CommonStrings.action_learn_more), style = ElementTheme.typography.fontBodyLgMedium ) diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationView.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationView.kt index 2dd2850174..1c199f8826 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationView.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/OutgoingVerificationView.kt @@ -24,8 +24,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.focused +import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -227,7 +229,11 @@ private fun ContentInitial( Text( modifier = Modifier .clickable { onLearnMoreClick() } - .padding(vertical = 4.dp, horizontal = 16.dp), + .padding(vertical = 4.dp, horizontal = 16.dp) + .semantics { + // Note: there is no Role.Link, so we use Role.Button for better accessibility support + role = Role.Button + }, text = stringResource(CommonStrings.action_learn_more), style = ElementTheme.typography.fontBodyLgMedium ) From 9912d763d41719f57fab36d05d5891b170ba01b6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 16:41:32 +0200 Subject: [PATCH 05/16] a11y: use different content description when the red dot is displayed Closes #6395 --- .../features/home/impl/components/HomeTopBar.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt index ff0fc00496..5c3075fc75 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt @@ -237,6 +237,7 @@ private fun SpaceFilterButton( else -> Unit } } + val isSelected = spaceFiltersState is SpaceFiltersState.Selected IconButton( onClick = ::onClick, @@ -320,7 +321,15 @@ private fun AccountIcon( Avatar( avatarData = avatarData, avatarType = AvatarType.User, - contentDescription = if (isCurrentAccount) stringResource(CommonStrings.common_settings) else null, + contentDescription = if (isCurrentAccount) { + if (showAvatarIndicator) { + stringResource(CommonStrings.a11y_settings_with_required_action) + } else { + stringResource(CommonStrings.common_settings) + } + } else { + null + }, ) if (showAvatarIndicator) { RedIndicatorAtom( From 70583fc3fce11779dc532104cc509e80158bc976 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 17:25:15 +0200 Subject: [PATCH 06/16] Remove unused content parameter. --- .../io/element/android/libraries/architecture/BaseFlowNode.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt index ce89e8a9d9..da849b753e 100644 --- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt @@ -11,7 +11,6 @@ package io.element.android.libraries.architecture import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier @@ -88,11 +87,9 @@ inline fun BaseFlowNode.OverlayView( @Composable inline fun BaseFlowNode.BackstackWithOverlayBox( modifier: Modifier = Modifier, - content: @Composable BoxScope.() -> Unit = {}, ) { Box(modifier = modifier) { BackstackView() OverlayView() - content() } } From 4e46f12a120f987bcf8c3899aec18d496824e3d2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 17:45:53 +0200 Subject: [PATCH 07/16] Remove useless Box --- .../impl/viewer/MediaViewerView.kt | 78 +++++++++---------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index abea2f66d2..7149592a26 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -204,48 +204,42 @@ fun MediaViewerView( } // Top bar AnimatedVisibility(visible = showOverlay, enter = fadeIn(), exit = fadeOut()) { - Box( - modifier = Modifier - .fillMaxSize() - .navigationBarsPadding() - ) { - when (currentData) { - is MediaViewerPageData.MediaViewerData -> { - MediaViewerTopBar( - data = currentData, - canShowInfo = state.canShowInfo, - onBackClick = onBackClick, - onShareClick = { - state.eventSink(MediaViewerEvent.Share(currentData)) - }, - onSaveClick = { - state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) - }, - onInfoClick = { - state.eventSink(MediaViewerEvent.OpenInfo(currentData)) - }, - ) - } - else -> { - TopAppBar( - title = { - if (currentData is MediaViewerPageData.Loading) { - Text( - modifier = Modifier.semantics { - heading() - }, - text = stringResource(id = CommonStrings.common_loading_more), - style = ElementTheme.typography.fontBodyMdMedium, - color = ElementTheme.colors.textPrimary, - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = bgCanvasWithTransparency, - ), - navigationIcon = { BackButton(onClick = onBackClick) }, - ) - } + when (currentData) { + is MediaViewerPageData.MediaViewerData -> { + MediaViewerTopBar( + data = currentData, + canShowInfo = state.canShowInfo, + onBackClick = onBackClick, + onShareClick = { + state.eventSink(MediaViewerEvent.Share(currentData)) + }, + onSaveClick = { + state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) + }, + onInfoClick = { + state.eventSink(MediaViewerEvent.OpenInfo(currentData)) + }, + ) + } + else -> { + TopAppBar( + title = { + if (currentData is MediaViewerPageData.Loading) { + Text( + modifier = Modifier.semantics { + heading() + }, + text = stringResource(id = CommonStrings.common_loading_more), + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = bgCanvasWithTransparency, + ), + navigationIcon = { BackButton(onClick = onBackClick) }, + ) } } } From dcd0a98c0c73c2d23a0be25ec5763d5f84b73893 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Apr 2026 17:49:31 +0200 Subject: [PATCH 08/16] Declare Top bar first and use zIndex. --- .../impl/viewer/MediaViewerView.kt | 88 ++++++++++--------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 7149592a26..f22f326986 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -59,6 +59,7 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import coil3.compose.AsyncImage import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons @@ -130,6 +131,52 @@ fun MediaViewerView( state.eventSink(MediaViewerEvent.OnNavigateTo(page)) } } + // Top bar + AnimatedVisibility( + modifier = Modifier.zIndex(1f), + visible = showOverlay, + enter = fadeIn(), + exit = fadeOut(), + ) { + when (currentData) { + is MediaViewerPageData.MediaViewerData -> { + MediaViewerTopBar( + data = currentData, + canShowInfo = state.canShowInfo, + onBackClick = onBackClick, + onShareClick = { + state.eventSink(MediaViewerEvent.Share(currentData)) + }, + onSaveClick = { + state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) + }, + onInfoClick = { + state.eventSink(MediaViewerEvent.OpenInfo(currentData)) + }, + ) + } + else -> { + TopAppBar( + title = { + if (currentData is MediaViewerPageData.Loading) { + Text( + modifier = Modifier.semantics { + heading() + }, + text = stringResource(id = CommonStrings.common_loading_more), + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = bgCanvasWithTransparency, + ), + navigationIcon = { BackButton(onClick = onBackClick) }, + ) + } + } + } HorizontalPager( state = pagerState, modifier = Modifier, @@ -202,47 +249,6 @@ fun MediaViewerView( } } } - // Top bar - AnimatedVisibility(visible = showOverlay, enter = fadeIn(), exit = fadeOut()) { - when (currentData) { - is MediaViewerPageData.MediaViewerData -> { - MediaViewerTopBar( - data = currentData, - canShowInfo = state.canShowInfo, - onBackClick = onBackClick, - onShareClick = { - state.eventSink(MediaViewerEvent.Share(currentData)) - }, - onSaveClick = { - state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) - }, - onInfoClick = { - state.eventSink(MediaViewerEvent.OpenInfo(currentData)) - }, - ) - } - else -> { - TopAppBar( - title = { - if (currentData is MediaViewerPageData.Loading) { - Text( - modifier = Modifier.semantics { - heading() - }, - text = stringResource(id = CommonStrings.common_loading_more), - style = ElementTheme.typography.fontBodyMdMedium, - color = ElementTheme.colors.textPrimary, - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = bgCanvasWithTransparency, - ), - navigationIcon = { BackButton(onClick = onBackClick) }, - ) - } - } - } } when (val bottomSheetState = state.mediaBottomSheetState) { From 5e963fc743b3a279db90006cb63ec2fe853f2176 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 10:08:37 +0200 Subject: [PATCH 09/16] a11y: do not use Overlay if screen reader is active, or external keyboard is connected. Related to #6399 --- .../messages/impl/MessagesFlowNode.kt | 29 +++++++++-- .../features/messages/impl/MessagesNode.kt | 9 ++-- .../pinned/list/PinnedMessagesListNode.kt | 9 +++- .../impl/threads/ThreadedMessagesNode.kt | 9 ++-- .../ui/utils/a11y/hasExternalKeyboard.kt | 49 +++++++++++++++++++ 5 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt 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 36e94ec456..4079a540f6 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 @@ -143,6 +143,7 @@ class MessagesFlowNode( val mediaInfo: MediaInfo, val mediaSource: MediaSource, val thumbnailSource: MediaSource?, + val canUseOverlay: Boolean, ) : NavTarget @Parcelize @@ -227,10 +228,11 @@ class MessagesFlowNode( callback.navigateToRoomDetails() } - override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean { + override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean { return processEventClick( timelineMode = timelineMode, event = event, + canUseOverlay = canUseOverlay, ) } @@ -320,7 +322,11 @@ class MessagesFlowNode( ) val callback = object : MediaViewerEntryPoint.Callback { override fun onDone() { - overlay.hide() + if (navTarget.canUseOverlay) { + overlay.hide() + } else { + backstack.pop() + } } override fun viewInTimeline(eventId: EventId) { @@ -414,10 +420,11 @@ class MessagesFlowNode( } NavTarget.PinnedMessagesList -> { val callback = object : PinnedMessagesListNode.Callback { - override fun handleEventClick(event: TimelineItem.Event) { + override fun handleEventClick(event: TimelineItem.Event, canUseOverlay: Boolean) { processEventClick( timelineMode = Timeline.Mode.PinnedEvents, event = event, + canUseOverlay = canUseOverlay, ) } @@ -456,10 +463,11 @@ class MessagesFlowNode( focusedEventId = navTarget.focusedEventId, ) val callback = object : ThreadedMessagesNode.Callback { - override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean { + override fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean { return processEventClick( timelineMode = timelineMode, event = event, + canUseOverlay = canUseOverlay, ) } @@ -547,6 +555,7 @@ class MessagesFlowNode( private fun processEventClick( timelineMode: Timeline.Mode, event: TimelineItem.Event, + canUseOverlay: Boolean, ): Boolean { val navTarget = when (event.content) { is TimelineItemImageContent -> { @@ -556,6 +565,7 @@ class MessagesFlowNode( content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, + canUseOverlay = canUseOverlay, ) } is TimelineItemVideoContent -> { @@ -565,6 +575,7 @@ class MessagesFlowNode( content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, + canUseOverlay = canUseOverlay, ) } is TimelineItemFileContent -> { @@ -574,6 +585,7 @@ class MessagesFlowNode( content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, + canUseOverlay = canUseOverlay, ) } is TimelineItemAudioContent -> { @@ -583,6 +595,7 @@ class MessagesFlowNode( content = event.content, mediaSource = event.content.mediaSource, thumbnailSource = null, + canUseOverlay = canUseOverlay, ) } is TimelineItemLocationContent -> { @@ -603,7 +616,11 @@ class MessagesFlowNode( } return when (navTarget) { is NavTarget.MediaViewer -> { - overlay.show(navTarget) + if (canUseOverlay) { + overlay.show(navTarget) + } else { + backstack.push(navTarget) + } true } is NavTarget.LocationViewer -> { @@ -620,6 +637,7 @@ class MessagesFlowNode( content: TimelineItemEventContentWithAttachment, mediaSource: MediaSource, thumbnailSource: MediaSource?, + canUseOverlay: Boolean, ): NavTarget { return NavTarget.MediaViewer( mode = mode, @@ -647,6 +665,7 @@ class MessagesFlowNode( ), mediaSource = mediaSource, thumbnailSource = thumbnailSource, + canUseOverlay = canUseOverlay, ) } 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 a2cf4a3da0..f8c54d284e 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 @@ -68,6 +68,8 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard +import io.element.android.libraries.ui.utils.time.isTalkbackActive import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.finishLongRunningTransaction @@ -115,7 +117,7 @@ class MessagesNode( ) interface Callback : Plugin { - fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean + fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -247,6 +249,7 @@ class MessagesNode( override fun View(modifier: Modifier) { val activity = requireNotNull(LocalActivity.current) val isDark = ElementTheme.isLightTheme.not() + val canUseOverlay = !isTalkbackActive() && !hasExternalKeyboard() CompositionLocalProvider( LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories, ) { @@ -268,11 +271,11 @@ class MessagesNode( onRoomDetailsClick = callback::navigateToRoomDetails, onEventContentClick = { isLive, event -> if (isLive) { - callback.handleEventClick(timelineController.mainTimelineMode(), event) + callback.handleEventClick(timelineController.mainTimelineMode(), event, canUseOverlay) } else { val detachedTimelineMode = timelineController.detachedTimelineMode() if (detachedTimelineMode != null) { - callback.handleEventClick(detachedTimelineMode, event) + callback.handleEventClick(detachedTimelineMode, event, canUseOverlay) } else { false } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt index cddc1831db..9800f0296a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt @@ -38,6 +38,8 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.ui.strings.CommonStrings +import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard +import io.element.android.libraries.ui.utils.time.isTalkbackActive @ContributesNode(RoomScope::class) @AssistedInject @@ -50,7 +52,7 @@ class PinnedMessagesListNode( private val permalinkParser: PermalinkParser, ) : Node(buildContext, plugins = plugins), PinnedMessagesListNavigator { interface Callback : Plugin { - fun handleEventClick(event: TimelineItem.Event) + fun handleEventClick(event: TimelineItem.Event, canUseOverlay: Boolean) fun navigateToRoomMemberDetails(userId: UserId) fun viewInTimeline(eventId: EventId) fun handlePermalinkClick(data: PermalinkData.RoomLink) @@ -103,6 +105,7 @@ class PinnedMessagesListNode( @Composable override fun View(modifier: Modifier) { + val canUseOverlay = !isTalkbackActive() && !hasExternalKeyboard() CompositionLocalProvider( LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories, ) { @@ -113,7 +116,9 @@ class PinnedMessagesListNode( PinnedMessagesListView( state = state, onBackClick = ::navigateUp, - onEventClick = callback::handleEventClick, + onEventClick = { + callback.handleEventClick(it, canUseOverlay) + }, onUserDataClick = { callback.navigateToRoomMemberDetails(it.userId) }, onLinkClick = { link -> onLinkClick(context, link.url) }, onLinkLongClick = { 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 0949237862..c51c24c168 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 @@ -68,6 +68,8 @@ import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.mediaplayer.api.MediaPlayer +import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard +import io.element.android.libraries.ui.utils.time.isTalkbackActive import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.collections.immutable.ImmutableList @@ -124,7 +126,7 @@ class ThreadedMessagesNode( } interface Callback : Plugin { - fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event): Boolean + fun handleEventClick(timelineMode: Timeline.Mode, event: TimelineItem.Event, canUseOverlay: Boolean): Boolean fun navigateToPreviewAttachments(attachments: ImmutableList, inReplyToEventId: EventId?) fun navigateToRoomMemberDetails(userId: UserId) fun handlePermalinkClick(data: PermalinkData) @@ -252,6 +254,7 @@ class ThreadedMessagesNode( override fun View(modifier: Modifier) { val activity = requireNotNull(LocalActivity.current) val isDark = ElementTheme.isLightTheme.not() + val canUseOverlay = !isTalkbackActive() && !hasExternalKeyboard() CompositionLocalProvider( LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories, ) { @@ -271,11 +274,11 @@ class ThreadedMessagesNode( onEventContentClick = { isLive, event -> timelineController?.let { controller -> if (isLive) { - callback.handleEventClick(controller.mainTimelineMode(), event) + callback.handleEventClick(controller.mainTimelineMode(), event, canUseOverlay) } else { val detachedTimelineMode = controller.detachedTimelineMode() if (detachedTimelineMode != null) { - callback.handleEventClick(detachedTimelineMode, event) + callback.handleEventClick(detachedTimelineMode, event, canUseOverlay) } else { false } diff --git a/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt new file mode 100644 index 0000000000..ed35cfbc3e --- /dev/null +++ b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2026 Element Creations 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.ui.utils.a11y + +import android.app.Activity +import android.app.Application +import android.content.res.Configuration +import android.os.Build +import android.os.Bundle +import androidx.activity.compose.LocalActivity +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +@Composable +fun hasExternalKeyboard(): Boolean { + val activity = requireNotNull(LocalActivity.current) + var hasExternalKeyboard by remember { mutableStateOf(activity.resources.configuration.keyboard != Configuration.KEYBOARD_NOKEYS) } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + DisposableEffect(Unit) { + val callback = object : Application.ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} + override fun onActivityStarted(activity: Activity) {} + override fun onActivityResumed(activity: Activity) { + // We do not have access to onActivityConfigurationChanged, so update the value when tha Activity is resumed + hasExternalKeyboard = activity.resources.configuration.keyboard != Configuration.KEYBOARD_NOKEYS + } + + override fun onActivityPaused(activity: Activity) {} + override fun onActivityStopped(activity: Activity) {} + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} + override fun onActivityDestroyed(activity: Activity) {} + } + activity.registerActivityLifecycleCallbacks(callback) + onDispose { + activity.unregisterActivityLifecycleCallbacks(callback) + } + } + } + return hasExternalKeyboard +} From 97cada743278217b137c960d9b25241564c5a6b1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 10:09:50 +0200 Subject: [PATCH 10/16] Move isTalkbackActive to a11y package. --- .../io/element/android/features/messages/impl/MessagesNode.kt | 2 +- .../messages/impl/pinned/list/PinnedMessagesListNode.kt | 2 +- .../features/messages/impl/threads/ThreadedMessagesNode.kt | 2 +- .../android/features/messages/impl/timeline/TimelineView.kt | 2 +- .../messages/impl/timeline/components/MessageEventBubble.kt | 2 +- .../messages/impl/timeline/components/TimelineItemEventRow.kt | 2 +- .../impl/timeline/components/TimelineItemGroupedEventsRow.kt | 2 +- .../messages/impl/timeline/components/TimelineItemRow.kt | 2 +- .../impl/timeline/components/event/TimelineItemImageView.kt | 2 +- .../impl/timeline/components/event/TimelineItemVideoView.kt | 2 +- .../impl/timeline/components/event/TimelineItemVoiceView.kt | 2 +- .../libraries/ui/utils/{time => a11y}/IsTalkbackEnabled.kt | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) rename libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/{time => a11y}/IsTalkbackEnabled.kt (96%) 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 f8c54d284e..308cda506e 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 @@ -69,7 +69,7 @@ import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugIn import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadMessagesUi import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.finishLongRunningTransaction diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt index 9800f0296a..a618117950 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListNode.kt @@ -39,7 +39,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive @ContributesNode(RoomScope::class) @AssistedInject 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 c51c24c168..0c58316b5e 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 @@ -69,7 +69,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.mediaplayer.api.MediaPlayer import io.element.android.libraries.ui.utils.a11y.hasExternalKeyboard -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.collections.immutable.ImmutableList diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index 2105cf9df7..41a828abb4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -77,7 +77,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt index aa5aaa2075..80bd342d01 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessageEventBubble.kt @@ -47,8 +47,8 @@ import io.element.android.libraries.designsystem.theme.messageFromMeBackground import io.element.android.libraries.designsystem.theme.messageFromOtherBackground import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.libraries.ui.utils.graphics.drawInLayer -import io.element.android.libraries.ui.utils.time.isTalkbackActive private val BUBBLE_RADIUS = 12.dp private val avatarRadius = AvatarSize.TimelineSender.dp / 2 diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 976fa3c17e..f15d4d39a5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -120,7 +120,7 @@ import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonPlurals import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link import kotlinx.coroutines.launch import kotlin.math.abs diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index 8316911843..df2b9d8691 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -34,7 +34,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link @Composable diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt index e75df2f89f..842b7a08f5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt @@ -47,7 +47,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.link.Link import kotlin.time.DurationUnit diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemImageView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemImageView.kt index a8cbb89e96..bef06bcd73 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemImageView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemImageView.kt @@ -54,7 +54,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.compose.EditorStyledText import io.element.android.wysiwyg.link.Link diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVideoView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVideoView.kt index f5e760736e..8d1ef18f39 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVideoView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVideoView.kt @@ -64,7 +64,7 @@ import io.element.android.libraries.matrix.ui.media.MAX_THUMBNAIL_WIDTH import io.element.android.libraries.matrix.ui.media.MediaRequestData import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.wysiwyg.compose.EditorStyledText import io.element.android.wysiwyg.link.Link diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt index 5dbd0c478f..86e3f1c849 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemVoiceView.kt @@ -52,7 +52,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.libraries.ui.utils.time.isTalkbackActive +import io.element.android.libraries.ui.utils.a11y.isTalkbackActive import io.element.android.libraries.voiceplayer.api.VoiceMessageEvent import io.element.android.libraries.voiceplayer.api.VoiceMessageState import io.element.android.libraries.voiceplayer.api.VoiceMessageStateProvider diff --git a/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/time/IsTalkbackEnabled.kt b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/IsTalkbackEnabled.kt similarity index 96% rename from libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/time/IsTalkbackEnabled.kt rename to libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/IsTalkbackEnabled.kt index 60ac1887c6..938a774355 100644 --- a/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/time/IsTalkbackEnabled.kt +++ b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/IsTalkbackEnabled.kt @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.ui.utils.time +package io.element.android.libraries.ui.utils.a11y import android.view.accessibility.AccessibilityManager import androidx.compose.runtime.Composable From 562e36b5eae3cae43344ea88c1d93c3bb9c21015 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 10:41:36 +0200 Subject: [PATCH 11/16] Improve how the ThumbnailView is added to the composition --- .../impl/viewer/MediaViewerView.kt | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index f22f326986..f767fdbde1 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -373,11 +373,12 @@ private fun MediaViewerPage( isUserSelected = isUserSelected, audioFocus = audioFocus, ) - ThumbnailView( - mediaInfo = data.mediaInfo, - thumbnailSource = data.thumbnailSource, - isVisible = showThumbnail, - ) + if (showThumbnail) { + ThumbnailView( + mediaInfo = data.mediaInfo, + thumbnailSource = data.thumbnailSource, + ) + } if (showError) { ErrorView( errorMessage = stringResource(id = CommonStrings.error_unknown), @@ -603,7 +604,6 @@ private val maxCaptionHeightLandscape = 128.dp @Composable private fun ThumbnailView( thumbnailSource: MediaSource?, - isVisible: Boolean, mediaInfo: MediaInfo, modifier: Modifier = Modifier, ) { @@ -611,21 +611,19 @@ private fun ThumbnailView( modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { - if (isVisible) { - val mediaRequestData = MediaRequestData( - source = thumbnailSource, - kind = MediaRequestData.Kind.File(mediaInfo.filename, mediaInfo.mimeType) - ) - val alpha = if (LocalInspectionMode.current) 0.1f else 1f - AsyncImage( - modifier = Modifier - .fillMaxSize() - .alpha(alpha), - model = mediaRequestData, - contentScale = ContentScale.Fit, - contentDescription = null, - ) - } + val mediaRequestData = MediaRequestData( + source = thumbnailSource, + kind = MediaRequestData.Kind.File(mediaInfo.filename, mediaInfo.mimeType) + ) + val alpha = if (LocalInspectionMode.current) 0.1f else 1f + AsyncImage( + modifier = Modifier + .fillMaxSize() + .alpha(alpha), + model = mediaRequestData, + contentScale = ContentScale.Fit, + contentDescription = null, + ) } } From 8188ef1463701911daf441f8b498441abe87ede7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 11:31:32 +0200 Subject: [PATCH 12/16] Improve MediaViewerBottomBar usage. --- .../impl/viewer/MediaViewerView.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index f767fdbde1..c3c8aa8907 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -233,17 +233,17 @@ fun MediaViewerView( isUserSelected = (state.listData[page] as? MediaViewerPageData.MediaViewerData)?.eventId == state.initiallySelectedEventId, ) // Bottom bar - AnimatedVisibility(visible = showOverlay, enter = fadeIn(), exit = fadeOut()) { - Box( - modifier = Modifier.fillMaxSize() - ) { - MediaViewerBottomBar( - modifier = Modifier.align(Alignment.BottomCenter), - showDivider = dataForPage.mediaInfo.mimeType.isMimeTypeVideo(), - caption = dataForPage.mediaInfo.caption, - onHeightChange = { bottomPaddingInPixels = it }, - ) - } + AnimatedVisibility( + visible = showOverlay, + enter = fadeIn(), + exit = fadeOut(), + modifier = Modifier.align(Alignment.BottomCenter), + ) { + MediaViewerBottomBar( + showDivider = dataForPage.mediaInfo.mimeType.isMimeTypeVideo(), + caption = dataForPage.mediaInfo.caption, + onHeightChange = { bottomPaddingInPixels = it }, + ) } } } From b1890de26aa36097ea01eaeb1a1d819c2a5e0608 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 11:46:57 +0200 Subject: [PATCH 13/16] MediaViewerView: move TopBar to Scaffold topbar --- .../impl/viewer/MediaViewerView.kt | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index c3c8aa8907..5b10fbfe96 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -121,6 +121,52 @@ fun MediaViewerView( Scaffold( modifier, containerColor = Color.Transparent, + topBar = { + AnimatedVisibility( + visible = showOverlay, + enter = fadeIn(), + exit = fadeOut(), + ) { + when (currentData) { + is MediaViewerPageData.MediaViewerData -> { + MediaViewerTopBar( + data = currentData, + canShowInfo = state.canShowInfo, + onBackClick = onBackClick, + onShareClick = { + state.eventSink(MediaViewerEvent.Share(currentData)) + }, + onSaveClick = { + state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) + }, + onInfoClick = { + state.eventSink(MediaViewerEvent.OpenInfo(currentData)) + }, + ) + } + else -> { + TopAppBar( + title = { + if (currentData is MediaViewerPageData.Loading) { + Text( + modifier = Modifier.semantics { + heading() + }, + text = stringResource(id = CommonStrings.common_loading_more), + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = bgCanvasWithTransparency, + ), + navigationIcon = { BackButton(onClick = onBackClick) }, + ) + } + } + } + }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) { val pagerState = rememberPagerState(state.currentIndex, 0f) { @@ -131,52 +177,6 @@ fun MediaViewerView( state.eventSink(MediaViewerEvent.OnNavigateTo(page)) } } - // Top bar - AnimatedVisibility( - modifier = Modifier.zIndex(1f), - visible = showOverlay, - enter = fadeIn(), - exit = fadeOut(), - ) { - when (currentData) { - is MediaViewerPageData.MediaViewerData -> { - MediaViewerTopBar( - data = currentData, - canShowInfo = state.canShowInfo, - onBackClick = onBackClick, - onShareClick = { - state.eventSink(MediaViewerEvent.Share(currentData)) - }, - onSaveClick = { - state.eventSink(MediaViewerEvent.SaveOnDisk(currentData)) - }, - onInfoClick = { - state.eventSink(MediaViewerEvent.OpenInfo(currentData)) - }, - ) - } - else -> { - TopAppBar( - title = { - if (currentData is MediaViewerPageData.Loading) { - Text( - modifier = Modifier.semantics { - heading() - }, - text = stringResource(id = CommonStrings.common_loading_more), - style = ElementTheme.typography.fontBodyMdMedium, - color = ElementTheme.colors.textPrimary, - ) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = bgCanvasWithTransparency, - ), - navigationIcon = { BackButton(onClick = onBackClick) }, - ) - } - } - } HorizontalPager( state = pagerState, modifier = Modifier, From d6f8c13c3f1c9b0480c28778c0dccd86ef6ce0a0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Apr 2026 12:08:19 +0200 Subject: [PATCH 14/16] MediaPlayerControllerView: Use IconButton instead of Box and remove the clipping. --- .../local/player/MediaPlayerControllerView.kt | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/MediaPlayerControllerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/MediaPlayerControllerView.kt index b83c598c10..b06b97f491 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/MediaPlayerControllerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/player/MediaPlayerControllerView.kt @@ -12,13 +12,12 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.IconButtonDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -28,7 +27,6 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter @@ -91,33 +89,31 @@ fun MediaPlayerControllerView( .widthIn(max = 480.dp), verticalAlignment = Alignment.CenterVertically, ) { - val bgColor = if (state.isPlaying) { - ElementTheme.colors.bgCanvasDefault + val colors = if (state.isPlaying) { + IconButtonDefaults.iconButtonColors( + containerColor = ElementTheme.colors.bgCanvasDefault, + contentColor = ElementTheme.colors.iconPrimary, + ) } else { - ElementTheme.colors.textPrimary + IconButtonDefaults.iconButtonColors( + containerColor = ElementTheme.colors.iconPrimary, + contentColor = ElementTheme.colors.iconOnSolidPrimary, + ) } - Box( + IconButton( modifier = Modifier - .size(36.dp) - .background( - color = bgColor, - shape = CircleShape, - ) - .clip(CircleShape) - .clickable { onTogglePlay() } - .padding(8.dp), - contentAlignment = Alignment.Center, + .size(36.dp), + onClick = onTogglePlay, + colors = colors, ) { if (state.isPlaying) { Icon( imageVector = CompoundIcons.PauseSolid(), - tint = ElementTheme.colors.iconPrimary, contentDescription = stringResource(CommonStrings.a11y_pause) ) } else { Icon( imageVector = CompoundIcons.PlaySolid(), - tint = ElementTheme.colors.iconOnSolidPrimary, contentDescription = stringResource(CommonStrings.a11y_play) ) } From 0b04dec85c88d76c412e1f53b4a9c3033e05ff88 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 30 Apr 2026 10:44:04 +0000 Subject: [PATCH 15/16] Update screenshots --- .../images/features.roomdetails.impl_RoomDetailsA11y_en.png | 4 ++-- ...s.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png | 4 ++-- ...s.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en.png | 4 ++-- ...mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png | 4 ++-- ...mediaviewer.impl.local.audio_MediaAudioView_Night_1_en.png | 4 ++-- ...r.impl.local.player_MediaPlayerControllerView_Day_0_en.png | 4 ++-- ...r.impl.local.player_MediaPlayerControllerView_Day_1_en.png | 4 ++-- ...r.impl.local.player_MediaPlayerControllerView_Day_2_en.png | 4 ++-- ...impl.local.player_MediaPlayerControllerView_Night_0_en.png | 4 ++-- ...impl.local.player_MediaPlayerControllerView_Night_1_en.png | 4 ++-- ...impl.local.player_MediaPlayerControllerView_Night_2_en.png | 4 ++-- ...s.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png | 4 ++-- ...mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png | 4 ++-- ...mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en.png | 4 ++-- ....mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png | 4 ++-- ....mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png | 4 ++-- ....mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png | 4 ++-- ...ibraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png | 4 ++-- ...libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png | 4 ++-- 21 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png index 8d8186f2d3..5f0cdd8eca 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2119838c9649710465dc1b8610550ce101f3016a1a6511c3f6dadc715fb75862 -size 82975 +oid sha256:33d583fac967f383a3d3535c4ac38aaccdcbf4a1d48323ff375a239dbce81838 +size 83494 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png index 8ca8df6e8e..3c218ccbbc 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c7dea18de5eabe820fe8670cd09d7b68160a97f31e4f1c474c790d829854ef7 -size 25291 +oid sha256:b918ce7162d95c873f0029a657ee07fca2e34926e4c3cdb39eaeb10123a08721 +size 25340 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en.png index e7f7345c31..37ecdb10ac 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98b39ded83aac1bb5befba6749c08a328b6855bcbd491c1a2f669c848ce72c31 -size 22982 +oid sha256:478c8ee2d55bb2a9f99b8d83c6e0eb0b316237ff1a60a6a735b5eb06f7ca083e +size 23029 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png index 086f166d79..e6925f9f5b 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f7aa184c28a4281a30a443b208bf3f64d9a0f85ad135ef50c999d40362c67d4 -size 24670 +oid sha256:d62cf7beeba92ee47193a871becad07f50d27e6f6fa0b85f6c620c3f1b04b6ce +size 24697 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en.png index 86ab39550c..e62cdf3ec4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.audio_MediaAudioView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e13b61fcb56fbd64064bc35628957cb68507efb7fdc25280d6dbf1e6477addc -size 22637 +oid sha256:d684c9ed8b2c38cdf7017194ca656ca8da161ab0a40ef3270c6e3988d8e7f144 +size 22664 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en.png index 67fbefb086..ad12fe8923 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbd0574dba895e157ff5b69ab23f3b389d280538810b457d2860ae5d77331705 -size 8256 +oid sha256:2b55fce1bf0d6b764aaed8eed0fbc1416c5aa1c5b6160775a641dfa10addb227 +size 8231 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en.png index 6b140844b0..db6b026090 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e87c0990dcaf2511a2a0573a04bf14c6a9a7d24e0291fed18aa3a9ea28da572 -size 7543 +oid sha256:4ca666990cb421602e21be0dbf4ec075e8d3e94f9835464923bd31d2414d9d57 +size 7594 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_2_en.png index de0bd78c7d..e40d0af8b2 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ed14962b63afa972c68a53d2366b9f00906bab2f3436220bb28643fcb1d56cb -size 7668 +oid sha256:01726f688e5149a460cb1004dff0c7700302a3fe7179829603625dd369b20e78 +size 7659 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en.png index bded2caa96..65f3240329 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a50093fb47b3b17a2ccd1aeb2a10fb6b5d368add8f7d458e50f0cc8643128b7c -size 8053 +oid sha256:8c30a496415f6c00f5ce3a01c775c78994992efd68b2548ecbb5b5ffac054cc1 +size 8041 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en.png index 7030c0a8c4..039388acdc 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a45336123e1eec5ea4b21c6932c1c11d6024685f736454e585a0fb6e6a85ccb2 -size 7701 +oid sha256:10f58df934f372a3b8c68c8e0c4ef61e5bfef242d65daa8f34f4999249bf9e8d +size 7799 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_2_en.png index 41449d52b8..f9f1b8195d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.player_MediaPlayerControllerView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:174f9f97fbce115d36fc5124d3301bd148444acdf24bdc933b5a3fb0754c883d -size 7545 +oid sha256:6d452b48ef65df5257eb708553d667bee46b9d83b1c29a07119c54e342cf1bc2 +size 7527 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png index 9b62306041..12f6ba7c36 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed8342b56d749db4d862aaa82d5d312089494965c2879adf18e8fd0c94f8525f -size 13476 +oid sha256:f10ca2d461e4078e46455e007eca2d1e9c9a20dbb6bc24c681fa5164e5f50efd +size 13531 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png index 72bd9cfb6c..6273b591af 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.local.video_MediaVideoView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04a62974dd81e0786127501b8778f9d302db38a27c984d1b403884942d43accd -size 13209 +oid sha256:da386980ce6a45e102727715b5d50f219e39dcb40a513abdfaab9fa725b8ea41 +size 13260 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en.png index d2231ed54c..9ca317cf9d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:041669475888f2f0c3b2d34502ae72098547340d8c2422ea2a674d38eb6a6241 -size 207620 +oid sha256:d265f0c3fe5bc7f5a6e6d6cfa022ba16ca770b65eeb9a742ba250ff55c4b066a +size 207625 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png index 8a6ebb2746..d404456119 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c56b22d79924d1f463f01428d5be1c69c8068b94a953160fae59a9f6faa112ad -size 206047 +oid sha256:f6870b9c1a5aad4257aa4bd7b13d0be5bea281778061d71c711495aadfaafdb8 +size 206057 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png index bbea97e0b3..77e9dad534 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e72ef42ad838837ce2427af5677931f5db68f876eccc297894c7a2cdd437cffa -size 210729 +oid sha256:094c1de97c33431390f3ff71d73019d9af9a62ed57ba98c94e53f1f9680851fa +size 210728 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png index 67bec8b0d3..c3caba08ff 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerViewLandscape_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58a323c4f06745a877ea546870fbe69ec927aea50584001b3871cad833fca1d4 -size 211343 +oid sha256:2a17d0f4bc47305b9c8a3866f70cdddb16fcb5ba10c8007c8739a329025e846a +size 211342 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png index d5b81bb469..4734e4e6db 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_13_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55671428c52d37c3f63f8b3410817d4e893e2f4327b31b227bc7b7d9ff84b884 -size 134680 +oid sha256:b593f6827598052cbde0e580dcd43b92fb098f6755779b95a60bb691d9ad5003 +size 134711 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png index 26dcbe4099..c44162b0ff 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7bee65567cced59131d471b5c3795347a2ef52cf64ff74b47f1c983a0b4a36f -size 130718 +oid sha256:c0249f33aca3e50713c87a3826e71985991f0996998132c42a374c6169800023 +size 130728 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png index f2ff11333d..932ddfb632 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3cea16c42488306fe29fd22362a0d37c1eeb0fbb1db48f26ad7ff18f6b196ae -size 137605 +oid sha256:43ab4873fc5fc812bf18af50cbe620c83b273ee70305b5ea06a7aeabdf8dbc93 +size 137637 diff --git a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png index 62de7a4953..924e24ba8a 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.mediaviewer.impl.viewer_MediaViewerView_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58655e1846dbe73c287073ac909ee6c881a0ad800e8852653116fdbfd043b9a0 -size 137881 +oid sha256:33048dafab286cf0e5c84040c034d93a42d69c234edd53132d918a4a1c135ece +size 137908 From b8995e4356a85fdc1bb7438366fb7995b368c1d9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 30 Apr 2026 14:09:07 +0200 Subject: [PATCH 16/16] Fix quality issues --- .../android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt | 1 - .../a11y/{hasExternalKeyboard.kt => HasExternalKeyboard.kt} | 0 2 files changed, 1 deletion(-) rename libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/{hasExternalKeyboard.kt => HasExternalKeyboard.kt} (100%) diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt index 5b10fbfe96..738d940453 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerView.kt @@ -59,7 +59,6 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import coil3.compose.AsyncImage import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons diff --git a/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt b/libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/HasExternalKeyboard.kt similarity index 100% rename from libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/hasExternalKeyboard.kt rename to libraries/ui-utils/src/main/kotlin/io/element/android/libraries/ui/utils/a11y/HasExternalKeyboard.kt