diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt
index 942e924820..f67338ef21 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt
@@ -33,6 +33,8 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.tokens.generated.CompoundIcons
@@ -112,10 +114,12 @@ private fun RoomListSearchContent(
title = {
// The stateSaver will keep the selection state when returning to this UI
val focusRequester = remember { FocusRequester() }
+ val searchLabel = stringResource(CommonStrings.action_search)
FilledTextField(
modifier = Modifier
.fillMaxWidth()
- .focusRequester(focusRequester),
+ .focusRequester(focusRequester)
+ .semantics { contentDescription = searchLabel },
state = state.query,
lineLimits = TextFieldLineLimits.SingleLine,
colors = TextFieldDefaults.colors(
@@ -132,7 +136,7 @@ private fun RoomListSearchContent(
IconButton(onClick = { state.eventSink(RoomListSearchEvent.ClearQuery) }) {
Icon(
imageVector = CompoundIcons.Close(),
- contentDescription = stringResource(CommonStrings.action_cancel)
+ contentDescription = stringResource(CommonStrings.a11y_clear_search_field)
)
}
}
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
index 037d9ea45d..3ccf32d422 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/TimelineItemReadReceiptView.kt
@@ -25,9 +25,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
-import androidx.compose.ui.semantics.hideFromAccessibility
+import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
@@ -57,18 +58,12 @@ fun TimelineItemReadReceiptView(
modifier: Modifier = Modifier,
) {
if (state.receipts.isNotEmpty()) {
- ReadReceiptsRow(
- modifier = modifier.clearAndSetSemantics {
- hideFromAccessibility()
- }
- ) {
+ ReadReceiptsRow(modifier = modifier) {
ReadReceiptsAvatars(
receipts = state.receipts,
modifier = Modifier
.clip(RoundedCornerShape(4.dp))
- .clickable {
- onReadReceiptsClick()
- }
+ .clickable(onClick = onReadReceiptsClick)
.padding(2.dp)
)
}
@@ -140,6 +135,7 @@ private fun ReadReceiptsAvatars(
.clearAndSetSemantics {
testTag = TestTags.messageReadReceipts.value
contentDescription = receiptDescription
+ role = Role.Button
},
horizontalArrangement = Arrangement.spacedBy(4.dp - avatarStrokeSize),
verticalAlignment = Alignment.CenterVertically,
diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt
index 319aebe33e..f7564aec31 100644
--- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt
+++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/DefaultLocalMediaRenderer.kt
@@ -40,6 +40,7 @@ class DefaultLocalMediaRenderer(
localMediaViewState = localMediaViewState,
textFileViewer = textFileViewer,
audioFocus = audioFocus,
+ forPreview = true,
onClick = {},
onOpenWith = null,
)
diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt
index c19b1a24c0..01b44f1246 100644
--- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt
+++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/LocalMediaView.kt
@@ -33,6 +33,7 @@ fun LocalMediaView(
onClick: () -> Unit,
onOpenWith: (() -> Unit)?,
textFileViewer: TextFileViewer,
+ forPreview: Boolean,
modifier: Modifier = Modifier,
isDisplayed: Boolean = true,
isUserSelected: Boolean = false,
@@ -45,6 +46,7 @@ fun LocalMediaView(
localMediaViewState = localMediaViewState,
localMedia = localMedia,
modifier = modifier,
+ forPreview = forPreview,
onClick = onClick,
)
mimeType.isMimeTypeVideo() -> MediaVideoView(
@@ -54,6 +56,7 @@ fun LocalMediaView(
localMedia = localMedia,
autoplay = isUserSelected,
audioFocus = audioFocus,
+ forPreview = forPreview,
modifier = modifier,
)
mimeType == MimeTypes.PlainText -> TextFileView(
diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt
index 4c73dd215d..c935b17b85 100644
--- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt
+++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/image/MediaImageView.kt
@@ -30,6 +30,7 @@ import me.saket.telephoto.zoomable.rememberZoomableImageState
fun MediaImageView(
localMediaViewState: LocalMediaViewState,
localMedia: LocalMedia?,
+ forPreview: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
@@ -42,11 +43,16 @@ fun MediaImageView(
} else {
val zoomableImageState = rememberZoomableImageState(localMediaViewState.zoomableState)
localMediaViewState.isReady = zoomableImageState.isImageDisplayed
+ val imageDescription = if (forPreview) {
+ stringResource(CommonStrings.a11y_photo_preview)
+ } else {
+ stringResource(CommonStrings.common_image)
+ }
ZoomableAsyncImage(
modifier = modifier,
state = zoomableImageState,
model = localMedia?.uri,
- contentDescription = stringResource(id = CommonStrings.common_image),
+ contentDescription = imageDescription,
contentScale = ContentScale.Fit,
onClick = { onClick() }
)
@@ -60,6 +66,7 @@ internal fun MediaImageViewPreview() = ElementPreview {
modifier = Modifier.fillMaxSize(),
localMediaViewState = rememberLocalMediaViewState(),
localMedia = null,
+ forPreview = false,
onClick = {},
)
}
diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt
index 21279a598e..d6484cd5a4 100644
--- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt
+++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/local/video/MediaVideoView.kt
@@ -30,6 +30,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
import androidx.media3.common.MediaItem
@@ -60,6 +61,7 @@ import io.element.android.libraries.mediaviewer.impl.local.player.rememberExoPla
import io.element.android.libraries.mediaviewer.impl.local.player.seekToEnsurePlaying
import io.element.android.libraries.mediaviewer.impl.local.player.togglePlay
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
+import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.libraries.ui.utils.a11y.isTalkbackActive
import kotlinx.coroutines.delay
import me.saket.telephoto.zoomable.zoomable
@@ -75,6 +77,7 @@ fun MediaVideoView(
localMedia: LocalMedia?,
autoplay: Boolean,
audioFocus: AudioFocus?,
+ forPreview: Boolean,
modifier: Modifier = Modifier,
) {
val exoPlayer = rememberExoPlayer(forAudioOnly = false)
@@ -86,6 +89,7 @@ fun MediaVideoView(
localMedia = localMedia,
autoplay = autoplay,
audioFocus = audioFocus,
+ forPreview = forPreview,
modifier = modifier,
)
}
@@ -100,6 +104,7 @@ private fun ExoPlayerMediaVideoView(
localMedia: LocalMedia?,
autoplay: Boolean,
audioFocus: AudioFocus?,
+ forPreview: Boolean,
modifier: Modifier = Modifier,
) {
var mediaPlayerControllerState: MediaPlayerControllerState by remember {
@@ -218,6 +223,11 @@ private fun ExoPlayerMediaVideoView(
text = "A Video Player will render here",
)
} else {
+ val videoDescription = if (forPreview) {
+ stringResource(CommonStrings.a11y_video_preview)
+ } else {
+ stringResource(CommonStrings.common_video)
+ }
AndroidView(
modifier = Modifier
.fillMaxSize()
@@ -236,6 +246,7 @@ private fun ExoPlayerMediaVideoView(
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
useController = false
+ contentDescription = videoDescription
}
},
onRelease = { playerView ->
@@ -355,5 +366,6 @@ internal fun MediaVideoViewPreview() = ElementPreview {
localMedia = null,
audioFocus = null,
autoplay = false,
+ forPreview = false,
)
}
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 c4d442338a..c981132b48 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
@@ -396,6 +396,7 @@ private fun MediaViewerPage(
onOpenWith = onOpenWith,
isUserSelected = isUserSelected,
audioFocus = audioFocus,
+ forPreview = false,
)
if (showThumbnail) {
ThumbnailView(
diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt
index bd6944d603..064ef03106 100644
--- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt
+++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt
@@ -93,6 +93,7 @@ fun MarkdownTextInput(
setText(text)
setHint(placeholder)
setHintTextColor(ColorStateList.valueOf(placeholderColor.toArgb()))
+ contentDescription = placeholder
inputType = InputType.TYPE_CLASS_TEXT or
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or
InputType.TYPE_TEXT_FLAG_MULTI_LINE or
@@ -129,6 +130,7 @@ fun MarkdownTextInput(
}
},
update = { editText ->
+ editText.contentDescription = placeholder
editText.applyStyleInCompose(richTextEditorStyle)
val text = state.text.value()
mentionSpanUpdater.updateMentionSpans(text)
diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index f477af40d8..4885c38ef3 100644
--- a/libraries/ui-strings/src/main/res/values/localazy.xml
+++ b/libraries/ui-strings/src/main/res/values/localazy.xml
@@ -4,6 +4,7 @@
"Add reaction: %1$s"
"Address"
"Avatar"
+ "Clear search field"
"Minimise message text field"
"Decrease votes allowed per person"
"Increase votes allowed per person"