Merge pull request #5120 from element-hq/feature/bma/a11y/contextMenuKeyboard
[a11y] Open context menu with the keyboard
This commit is contained in:
commit
4a6765db20
22 changed files with 133 additions and 62 deletions
|
|
@ -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>,
|
|
||||||
)
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue