diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt
index 27883e88d5..2a6cfee502 100644
--- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt
+++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt
@@ -176,7 +176,6 @@ private fun RoomListModalBottomSheetContent(
leadingContent = ListItemContent.Icon(
iconSource = IconSource.Vector(
CompoundIcons.ChatProblem(),
- contentDescription = stringResource(CommonStrings.action_report_room),
)
),
style = ListItemStyle.Destructive,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt
index 644cbf2310..d8af3c1736 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineEventTimestampView.kt
@@ -18,8 +18,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.semantics.hideFromAccessibility
-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
@@ -44,15 +42,15 @@ fun TimelineEventTimestampView(
modifier: Modifier = Modifier,
) {
val formattedTime = event.sentTime
- val hasError = event.localSendState is LocalEventSendState.Failed
+ val hasError = event.failedToSend
val hasEncryptionCritical = event.messageShield?.isCritical.orFalse()
val isMessageEdited = event.content.isEdited()
val isMessageRedacted = event.content.isRedacted()
val tint = if (hasError || hasEncryptionCritical && !isMessageRedacted) ElementTheme.colors.textCriticalPrimary else ElementTheme.colors.textSecondary
Row(
modifier = Modifier
- .padding(PaddingValues(start = TimelineEventTimestampViewDefaults.spacing))
- .then(modifier),
+ .padding(PaddingValues(start = TimelineEventTimestampViewDefaults.spacing))
+ .then(modifier),
verticalAlignment = Alignment.CenterVertically,
) {
if (isMessageEdited) {
@@ -76,11 +74,13 @@ fun TimelineEventTimestampView(
contentDescription = stringResource(id = CommonStrings.common_sending_failed),
tint = tint,
modifier = Modifier
- .size(15.dp, 18.dp)
- .clickable(isVerifiedUserSendFailure) {
- eventSink(TimelineEvents.ComputeVerifiedUserSendFailure(event))
- }
- .semantics { hideFromAccessibility() }
+ .size(15.dp, 18.dp)
+ .clickable(
+ enabled = isVerifiedUserSendFailure,
+ onClickLabel = stringResource(CommonStrings.action_open_context_menu),
+ ) {
+ eventSink(TimelineEvents.ComputeVerifiedUserSendFailure(event))
+ }
)
}
@@ -89,13 +89,14 @@ fun TimelineEventTimestampView(
Spacer(modifier = Modifier.width(2.dp))
Icon(
imageVector = shield.toIcon(),
- contentDescription = shield.toText(),
+ contentDescription = stringResource(id = CommonStrings.a11y_encryption_details),
modifier = Modifier
.size(15.dp)
- .clickable {
+ .clickable(
+ onClickLabel = stringResource(CommonStrings.a11y_view_details),
+ ) {
eventSink(TimelineEvents.ShowShieldDialog(shield))
- }
- .semantics { hideFromAccessibility() },
+ },
tint = shield.toIconColor(),
)
Spacer(modifier = Modifier.width(4.dp))
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 9628fb2bb4..59ec63d842 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
@@ -140,7 +140,10 @@ internal fun TimelineItemRow(
timelineItem.safeSenderName
}
// For Polls, allow the answers to be traversed by Talkback
- isTraversalGroup = timelineItem.content is TimelineItemPollContent
+ isTraversalGroup = timelineItem.content is TimelineItemPollContent ||
+ timelineItem.failedToSend ||
+ timelineItem.messageShield != null
+ // TODO Also set to true when the event has link(s)
}
// Custom clickable that applies over the whole item for accessibility
.then(
diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt
index c4a2351990..73969a2860 100644
--- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt
+++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt
@@ -116,7 +116,7 @@ class TimelineViewTest {
eventSink = eventsRecorder,
),
)
- val contentDescription = rule.activity.getString(CommonStrings.event_shield_reason_unverified_identity)
+ val contentDescription = rule.activity.getString(CommonStrings.a11y_encryption_details)
rule.onNodeWithContentDescription(contentDescription).performClick()
eventsRecorder.assertList(
listOf(
diff --git a/features/poll/api/src/main/res/values/localazy.xml b/features/poll/api/src/main/res/values/localazy.xml
index 2d1142194c..ebba470b6a 100644
--- a/features/poll/api/src/main/res/values/localazy.xml
+++ b/features/poll/api/src/main/res/values/localazy.xml
@@ -4,5 +4,6 @@
- "%1$d percent of total votes"
- "%1$d percents of total votes"
+ "Will remove previous selection"
"This is the winning answer"
diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesViewTest.kt
index 4bb0253e6a..6f2179d4d4 100644
--- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesViewTest.kt
+++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesViewTest.kt
@@ -225,7 +225,10 @@ class ChangeRolesViewTest {
)
// Unselect the user from the row list
val contentDescription = rule.activity.getString(CommonStrings.action_remove)
- rule.onNodeWithContentDescription(contentDescription).performClick()
+ rule.onNodeWithContentDescription(
+ label = contentDescription,
+ useUnmergedTree = true,
+ ).performClick()
eventsRecorder.assertList(
listOf(
ChangeRolesEvent.QueryChanged(""),
@@ -248,7 +251,7 @@ class ChangeRolesViewTest {
rule.setChangeRolesContent(
state = state,
)
- // Select the user from the row list
+ // Select the user from the user list
rule.onNodeWithText("Carol").performClick()
eventsRecorder.assertList(
listOf(
@@ -271,8 +274,11 @@ class ChangeRolesViewTest {
rule.setChangeRolesContent(
state = state,
)
- // Select the user from the rom list
- rule.onAllNodesWithText("Bob")[1].performClick()
+ // Unselect the user from the user list
+ rule.onAllNodesWithText(
+ text = "Bob",
+ useUnmergedTree = true,
+ )[1].performClick()
eventsRecorder.assertList(
listOf(
ChangeRolesEvent.QueryChanged(""),
diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/accessibility/ContextExt.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/accessibility/ContextExt.kt
deleted file mode 100644
index 02250297b3..0000000000
--- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/accessibility/ContextExt.kt
+++ /dev/null
@@ -1,29 +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.libraries.androidutils.accessibility
-
-import android.content.Context
-import android.view.accessibility.AccessibilityManager
-import androidx.core.content.getSystemService
-
-/**
- * Whether a screen reader is enabled.
- *
- * Avoid changing UI or app behavior based on the state of accessibility.
- * See [AccessibilityManager.isTouchExplorationEnabled] for more details.
- *
- * @return true if the screen reader is enabled.
- */
-fun Context.isScreenReaderEnabled(): Boolean {
- val accessibilityManager = getSystemService()
- ?: return false
-
- return accessibilityManager.let {
- it.isEnabled && it.isTouchExplorationEnabled
- }
-}
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
index 3b8b6831ca..ad06985ab7 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/EditableAvatarView.kt
@@ -62,6 +62,7 @@ fun EditableAvatarView(
modifier = Modifier
.clickable(
interactionSource = remember { MutableInteractionSource() },
+ onClickLabel = stringResource(CommonStrings.a11y_edit_avatar),
onClick = onAvatarClick,
indication = ripple(bounded = false),
)
diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedUser.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedUser.kt
index 31cc724838..f3c3c634e6 100644
--- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedUser.kt
+++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedUser.kt
@@ -23,6 +23,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -48,9 +51,24 @@ fun SelectedUser(
onUserRemove: (MatrixUser) -> Unit,
modifier: Modifier = Modifier,
) {
+ val actionRemove = stringResource(id = CommonStrings.action_remove)
Box(
modifier = modifier
.width(AvatarSize.SelectedUser.dp)
+ .clearAndSetSemantics {
+ contentDescription = matrixUser.getBestName()
+ if (canRemove) {
+ // Note: this does not set the click effect to the whole Box
+ // when talkback is not enabled
+ onClick(
+ label = actionRemove,
+ action = {
+ onUserRemove(matrixUser)
+ true
+ }
+ )
+ }
+ }
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
@@ -83,6 +101,7 @@ fun SelectedUser(
) {
Icon(
imageVector = CompoundIcons.Close(),
+ // Note: keep the context description for the test
contentDescription = stringResource(id = CommonStrings.action_remove),
tint = ElementTheme.colors.iconOnSolidPrimary,
modifier = Modifier.padding(2.dp)
diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml
index 270e862300..362b2310d4 100644
--- a/libraries/ui-strings/src/main/res/values/localazy.xml
+++ b/libraries/ui-strings/src/main/res/values/localazy.xml
@@ -7,11 +7,16 @@
- "%1$d digit entered"
- "%1$d digits entered"
+ "Edit avatar"
+ "Encryption details"
"Hide password"
"Join call"
"Jump to bottom"
"Mentions only"
"Muted"
+ "New mentions"
+ "New messages"
+ "Ongoing call"
"Other user\'s avatar"
"Page %1$d"
"Pause"
@@ -35,6 +40,7 @@
"Send files"
"Show password"
"Start a call"
+ "Time limited action required"
"User avatar"
"User menu"
"View avatar"