Merge pull request #5120 from element-hq/feature/bma/a11y/contextMenuKeyboard

[a11y] Open context menu with the keyboard
This commit is contained in:
Benoit Marty 2025-08-06 14:50:12 +02:00 committed by GitHub
commit 4a6765db20
22 changed files with 133 additions and 62 deletions

View file

@ -1,14 +0,0 @@
/*
* Copyright 2023, 2024 New Vector 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.features.createroom.impl.configureroom
import io.element.android.libraries.matrix.api.user.MatrixUser
data class ConfigureRoomPresenterArgs(
val selectedUsers: List<MatrixUser>,
)

View file

@ -240,14 +240,20 @@ private fun HomeScaffold(
contentPadding = PaddingValues( contentPadding = PaddingValues(
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80, // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80,
// and include provided bottom padding // and include provided bottom padding
bottom = 80.dp + padding.calculateBottomPadding(), // Disable contentPadding due to navigation issue using the keyboard
top = padding.calculateTopPadding() // See https://issuetracker.google.com/issues/436432313
bottom = 80.dp,
// bottom = 80.dp + padding.calculateBottomPadding(),
// top = padding.calculateTopPadding()
), ),
modifier = Modifier modifier = Modifier
.padding( .padding(
PaddingValues( PaddingValues(
start = padding.calculateStartPadding(LocalLayoutDirection.current), start = padding.calculateStartPadding(LocalLayoutDirection.current),
end = padding.calculateEndPadding(LocalLayoutDirection.current), end = padding.calculateEndPadding(LocalLayoutDirection.current),
// Remove these two lines once https://issuetracker.google.com/issues/436432313 has been fixed
bottom = padding.calculateBottomPadding(),
top = padding.calculateTopPadding()
) )
) )
.consumeWindowInsets(padding) .consumeWindowInsets(padding)

View file

@ -46,6 +46,7 @@ import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarType import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
@ -170,14 +171,15 @@ private fun RoomSummaryScaffoldRow(
hideAvatarImage: Boolean = false, hideAvatarImage: Boolean = false,
content: @Composable ColumnScope.() -> Unit content: @Composable ColumnScope.() -> Unit
) { ) {
val clickModifier = Modifier.combinedClickable( val clickModifier = Modifier
onClick = { onClick(room) }, .combinedClickable(
onLongClick = { onLongClick(room) }, onClick = { onClick(room) },
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClick = { onLongClick(room) },
indication = ripple(), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
interactionSource = remember { MutableInteractionSource() } indication = ripple(),
) interactionSource = remember { MutableInteractionSource() }
)
.onKeyboardContextMenuAction { onLongClick(room) }
Row( Row(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()

View file

@ -38,6 +38,7 @@ import io.element.android.features.messages.impl.timeline.model.bubble.BubbleSta
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleStateProvider import io.element.android.features.messages.impl.timeline.model.bubble.BubbleStateProvider
import io.element.android.libraries.core.extensions.to01 import io.element.android.libraries.core.extensions.to01
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toDp import io.element.android.libraries.designsystem.text.toDp
@ -96,12 +97,14 @@ fun MessageEventBubble(
val clickableModifier = if (isTalkbackActive()) { val clickableModifier = if (isTalkbackActive()) {
Modifier Modifier
} else { } else {
Modifier.combinedClickable( Modifier
onClick = onClick, .combinedClickable(
onLongClick = onLongClick, onClick = onClick,
indication = ripple(), onLongClick = onLongClick,
interactionSource = interactionSource indication = ripple(),
) interactionSource = interactionSource
)
.onKeyboardContextMenuAction(onLongClick)
} }
// Ignore state.isHighlighted for now, we need a design decision on it. // Ignore state.isHighlighted for now, we need a design decision on it.

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Surface
@ -46,7 +47,8 @@ fun MessageStateEventContainer(
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
indication = ripple(), indication = ripple(),
interactionSource = interactionSource interactionSource = interactionSource
), )
.onKeyboardContextMenuAction(onLongClick),
color = backgroundColor, color = backgroundColor,
shape = shape, shape = shape,
content = content content = content

View file

@ -43,6 +43,7 @@ import io.element.android.features.messages.impl.timeline.model.AggregatedReacti
import io.element.android.features.messages.impl.timeline.model.AggregatedReactionProvider import io.element.android.features.messages.impl.timeline.model.AggregatedReactionProvider
import io.element.android.features.messages.impl.timeline.model.aTimelineItemReactions import io.element.android.features.messages.impl.timeline.model.aTimelineItemReactions
import io.element.android.libraries.designsystem.icons.CompoundDrawables import io.element.android.libraries.designsystem.icons.CompoundDrawables
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toDp import io.element.android.libraries.designsystem.text.toDp
@ -107,6 +108,7 @@ fun MessagesReactionButton(
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
onLongClick = onLongClick onLongClick = onLongClick
) )
.onKeyboardContextMenuAction(onLongClick)
// Inner border, to highlight when selected // Inner border, to highlight when selected
.border(BorderStroke(1.dp, borderColor), RoundedCornerShape(corner = CornerSize(12.dp))) .border(BorderStroke(1.dp, borderColor), RoundedCornerShape(corner = CornerSize(12.dp)))
.background(buttonColor, RoundedCornerShape(corner = CornerSize(12.dp))) .background(buttonColor, RoundedCornerShape(corner = CornerSize(12.dp)))

View file

@ -34,6 +34,7 @@ import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.features.roomcall.api.RoomCallStateProvider import io.element.android.features.roomcall.api.RoomCallStateProvider
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarType import io.element.android.libraries.designsystem.components.avatar.AvatarType
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toDp import io.element.android.libraries.designsystem.text.toDp
@ -57,6 +58,7 @@ internal fun TimelineItemCallNotifyView(
onLongClick = { onLongClick(event) }, onLongClick = { onLongClick(event) },
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
) )
.onKeyboardContextMenuAction { onLongClick(event) }
.padding(12.dp), .padding(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,

View file

@ -37,6 +37,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.modifiers.subtleColorStops import io.element.android.libraries.designsystem.modifiers.subtleColorStops
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -148,11 +149,13 @@ internal fun TimelineItemRow(
// Custom clickable that applies over the whole item for accessibility // Custom clickable that applies over the whole item for accessibility
.then( .then(
if (isTalkbackActive()) { if (isTalkbackActive()) {
Modifier.combinedClickable( Modifier
onClick = { onContentClick(timelineItem) }, .combinedClickable(
onLongClick = { onLongClick(timelineItem) }, onClick = { onContentClick(timelineItem) },
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClick = { onLongClick(timelineItem) },
) onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
)
.onKeyboardContextMenuAction { onLongClick(timelineItem) }
} else { } else {
Modifier Modifier
} }

View file

@ -48,6 +48,7 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI
import io.element.android.features.messages.impl.timeline.protection.ProtectedView import io.element.android.features.messages.impl.timeline.protection.ProtectedView
import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent
import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
@ -91,10 +92,12 @@ fun TimelineItemImageView(
.then(if (isLoaded) Modifier.background(Color.White) else Modifier) .then(if (isLoaded) Modifier.background(Color.White) else Modifier)
.then( .then(
if (!isTalkbackActive() && onContentClick != null) { if (!isTalkbackActive() && onContentClick != null) {
Modifier.combinedClickable( Modifier
onClick = onContentClick, .combinedClickable(
onLongClick = onLongClick onClick = onContentClick,
) onLongClick = onLongClick,
)
.onKeyboardContextMenuAction(onLongClick)
} else { } else {
Modifier Modifier
} }

View file

@ -31,6 +31,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.protection.ProtectedView import io.element.android.features.messages.impl.timeline.protection.ProtectedView
import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent
import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.ui.media.MediaRequestData import io.element.android.libraries.matrix.ui.media.MediaRequestData
@ -74,6 +75,7 @@ fun TimelineItemStickerView(
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
) )
.onKeyboardContextMenuAction(onLongClick)
} else { } else {
Modifier Modifier
} }

View file

@ -54,6 +54,7 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI
import io.element.android.features.messages.impl.timeline.protection.ProtectedView import io.element.android.features.messages.impl.timeline.protection.ProtectedView
import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent import io.element.android.features.messages.impl.timeline.protection.coerceRatioWhenHidingContent
import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.modifiers.roundedBackground import io.element.android.libraries.designsystem.modifiers.roundedBackground
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -105,10 +106,12 @@ fun TimelineItemVideoView(
.then(if (isLoaded) Modifier.background(Color.White) else Modifier) .then(if (isLoaded) Modifier.background(Color.White) else Modifier)
.then( .then(
if (!isTalkbackActive && onContentClick != null) { if (!isTalkbackActive && onContentClick != null) {
Modifier.combinedClickable( Modifier
onClick = onContentClick, .combinedClickable(
onLongClick = onLongClick onClick = onContentClick,
) onLongClick = onLongClick,
)
.onKeyboardContextMenuAction(onLongClick)
} else { } else {
Modifier Modifier
} }

View file

@ -32,7 +32,6 @@ import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
@ -83,8 +82,6 @@ fun ReactionSummaryView(
state: ReactionSummaryState, state: ReactionSummaryState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val sheetState = rememberModalBottomSheetState()
fun onDismiss() { fun onDismiss() {
state.eventSink(ReactionSummaryEvents.Clear) state.eventSink(ReactionSummaryEvents.Clear)
} }
@ -92,7 +89,6 @@ fun ReactionSummaryView(
if (state.target != null) { if (state.target != null) {
ModalBottomSheet( ModalBottomSheet(
onDismissRequest = ::onDismiss, onDismissRequest = ::onDismiss,
sheetState = sheetState,
modifier = modifier modifier = modifier
) { ) {
ReactionSummaryViewContent(summary = state.target) ReactionSummaryViewContent(summary = state.target)

View file

@ -15,7 +15,6 @@ import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -31,7 +30,6 @@ import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.components.preferences.PreferencePage import io.element.android.libraries.designsystem.components.preferences.PreferencePage
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.sheetStateForPreview
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem import io.element.android.libraries.designsystem.theme.components.ListItem
@ -145,11 +143,7 @@ private fun ChangeOwnRoleBottomSheet(
eventSink: (RolesAndPermissionsEvents) -> Unit, eventSink: (RolesAndPermissionsEvents) -> Unit,
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val sheetState = if (LocalInspectionMode.current) { val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
sheetStateForPreview()
} else {
rememberModalBottomSheetState(skipPartiallyExpanded = true)
}
fun dismiss() { fun dismiss() {
sheetState.hide(coroutineScope) { sheetState.hide(coroutineScope) {
eventSink(RolesAndPermissionsEvents.CancelPendingAction) eventSink(RolesAndPermissionsEvents.CancelPendingAction)

View file

@ -0,0 +1,42 @@
/*
* Copyright 2025 New Vector 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.designsystem.modifiers
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
/**
* Modifier to handle Shift + F10 key events.
* This is typically used to trigger context menus in desktop applications.
*
* @param action The callback to invoke when Shift + F10 is pressed.
*/
fun Modifier.onKeyboardContextMenuAction(
action: (() -> Unit)?,
): Modifier = then(
if (action == null) {
Modifier
} else {
Modifier.onKeyEvent { keyEvent ->
// invoke the callback when the user presses Shift + F10
if (keyEvent.type == KeyEventType.KeyUp &&
keyEvent.isShiftPressed &&
keyEvent.key == Key.F10) {
action()
true
} else {
false
}
}
}
)

View file

@ -23,6 +23,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
@ -54,7 +59,17 @@ fun ModalBottomSheet(
val safeSheetState = if (LocalInspectionMode.current) sheetStateForPreview() else sheetState val safeSheetState = if (LocalInspectionMode.current) sheetStateForPreview() else sheetState
androidx.compose.material3.ModalBottomSheet( androidx.compose.material3.ModalBottomSheet(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
modifier = modifier, modifier = modifier.onKeyEvent { keyEvent ->
// It seems that on some devices, we have to handle the Escape key manually to close the bottom sheet.
// This is not the case using an emulator, but is necessary on some physical devices.
if (keyEvent.type == KeyEventType.KeyUp &&
keyEvent.key == Key.Escape) {
onDismissRequest()
true
} else {
false
}
},
sheetState = safeSheetState, sheetState = safeSheetState,
shape = shape, shape = shape,
containerColor = containerColor, containerColor = containerColor,

View file

@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.core.extensions.withBrackets import io.element.android.libraries.core.extensions.withBrackets
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
@ -84,6 +85,7 @@ private fun FilenameRow(
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
) )
.onKeyboardContextMenuAction(onLongClick)
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp), .padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,

View file

@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.core.extensions.withBrackets import io.element.android.libraries.core.extensions.withBrackets
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
@ -84,6 +85,7 @@ private fun FilenameRow(
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
) )
.onKeyboardContextMenuAction(onLongClick)
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp), .padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,

View file

@ -24,6 +24,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import coil3.compose.AsyncImagePainter import coil3.compose.AsyncImagePainter
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.impl.model.MediaItem
@ -44,7 +45,8 @@ fun ImageItemView(
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
), )
.onKeyboardContextMenuAction(onLongClick),
) { ) {
var isLoaded by remember { mutableStateOf(false) } var isLoaded by remember { mutableStateOf(false) }
AsyncImage( AsyncImage(

View file

@ -33,6 +33,7 @@ import coil3.compose.AsyncImage
import coil3.compose.AsyncImagePainter import coil3.compose.AsyncImagePainter
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -54,7 +55,8 @@ fun VideoItemView(
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
), )
.onKeyboardContextMenuAction(onLongClick),
) { ) {
var isLoaded by remember { mutableStateOf(false) } var isLoaded by remember { mutableStateOf(false) }
AsyncImage( AsyncImage(

View file

@ -38,6 +38,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.components.media.WaveformPlaybackView import io.element.android.libraries.designsystem.components.media.WaveformPlaybackView
import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
@ -105,6 +106,7 @@ private fun VoiceInfoRow(
onLongClick = onLongClick, onLongClick = onLongClick,
onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), onLongClickLabel = stringResource(CommonStrings.action_open_context_menu),
) )
.onKeyboardContextMenuAction(onLongClick)
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp), .padding(start = 12.dp, end = 36.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:eb923fffd20dc775f31b998e23c39acf79013a831a7c292c4cdba5b9142b4094 oid sha256:6fd52151e94328a68ef5b65bdc0e5e0d730bd617ed2b58ad92c350fb409c75d2
size 68227 size 63096

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a9066615bfa2f78b77784302ce0272e3a486c79e267629c50c35ec1221c58046 oid sha256:a67035a18b067b07f52090ee0ca9e3defa34a158e7dcefc55062131ac1599823
size 64443 size 59193