Repository: HedvigInsurance/android
Pull request #2508: Feature/a11y bottom navigation focus
Author: login: panasetskaya
Created: 2025-04-02T09:40:54Z | Merged: 2025-04-07T06:49:13Z

nav bar/rail and home screen a11y

- [x] keys translated
```
TALKBACK_CLAIM_STATUS_CARD
TALKBACK_UNKNOWN
TALKBACK_CLAIM_STATUS
```


Diff:
diff --git a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/NavigationBar.kt b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/NavigationBar.kt
index bb44667477..cc506de07e 100644
--- a/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/NavigationBar.kt
+++ b/app/design-system/design-system-hedvig/src/main/kotlin/com/hedvig/android/design/system/hedvig/NavigationBar.kt
@@ -36,6 +36,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.layout.onPlaced
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.selected
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.traversalIndex
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.tooling.preview.PreviewFontScale
@@ -83,6 +88,7 @@ fun NavigationBar(
         .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)),
     ) {
       for (destination in destinations) {
+        val name = stringResource(destination.titleTextId())
         val selected = getIsCurrentlySelected(destination)
         NavigationItem(
           icon = if (selected) {
@@ -90,7 +96,7 @@ fun NavigationBar(
           } else {
             destination.unselectedIcon()
           },
-          text = stringResource(destination.titleTextId()),
+          text = name,
           withNotification = destination in destinationsWithNotifications,
           selected = selected,
           onClick = { onNavigateToDestination(destination) },
@@ -100,7 +106,11 @@ fun NavigationBar(
             top = NavigationBarTokens.ItemTopPadding,
             bottom = NavigationBarTokens.ItemBottomPadding,
           ),
-          modifier = Modifier.weight(1f),
+          modifier = Modifier.weight(1f)
+            .semantics {
+              role = Role.Tab
+              this.selected = selected
+            },
         )
       }
     }
@@ -165,6 +175,10 @@ fun NavigationRail(
             top = NavigationRailTokens.ItemTopPadding,
             bottom = NavigationRailTokens.ItemBottomPadding,
           ),
+          modifier = Modifier.semantics {
+            role = Role.Tab
+            this.selected = selected
+          },
         )
       }
     }
@@ -181,7 +195,9 @@ private fun NavigationContainer(modifier: Modifier = Modifier, content: @Composa
   CompositionLocalProvider(LocalDensity provides fontCappedDensity) {
     Surface(
       color = HedvigTheme.colorScheme.backgroundPrimary,
-      modifier = modifier,
+      modifier = modifier.semantics{
+        this.traversalIndex = 0f
+      },
     ) {
       content()
     }
diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt
index d2535cf89a..7fa6655dfa 100644
--- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt
+++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt
@@ -46,6 +46,8 @@ import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.hideFromAccessibility
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.text.font.FontFamily
 import androidx.compose.ui.text.style.LineBreak
 import androidx.compose.ui.text.style.TextAlign
@@ -397,7 +399,10 @@ private fun HomeScreenSuccess(
             modifier = Modifier
               .padding(horizontal = 24.dp)
               .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal))
-              .testTag("welcome_message"),
+              .testTag("welcome_message")
+              .semantics {
+                hideFromAccessibility()
+              },
           )
         },
         claimStatusCards = {
diff --git a/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/ClaimStatusCard.kt b/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/ClaimStatusCard.kt
index dd87b07e8f..3d859997f4 100644
--- a/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/ClaimStatusCard.kt
+++ b/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/ClaimStatusCard.kt
@@ -10,6 +10,8 @@ import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import com.hedvig.android.design.system.hedvig.ButtonDefaults.ButtonSize.Medium
@@ -45,9 +47,13 @@ fun ClaimStatusCard(
   onClick: (claimId: String) -> Unit,
   modifier: Modifier = Modifier,
 ) {
+  val description = stringResource(R.string.TALKBACK_CLAIM_STATUS_CARD)
   HedvigCard(
     onClick = { onClick(uiState.id) },
-    modifier = modifier,
+    modifier = modifier
+      .semantics {
+        contentDescription = description
+      },
   ) {
     Column {
       ClaimStatusCardContent(uiState, withInfoIcon = true, Modifier.padding(16.dp))
diff --git a/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt b/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt
index 5993d165b5..a071dd8271 100644
--- a/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt
+++ b/app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt
@@ -14,6 +14,9 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.hideFromAccessibility
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import com.hedvig.android.design.system.hedvig.HedvigPreview
@@ -32,15 +35,22 @@ import hedvig.resources.R
 
 @Composable
 internal fun ClaimProgressRow(claimProgressItemsUiState: List<ClaimProgressSegment>, modifier: Modifier = Modifier) {
+  val currentStatus =
+    claimProgressItemsUiState.lastOrNull { it.type == ACTIVE }?.text ?: stringResource(R.string.TALKBACK_UNKNOWN)
+  val description = stringResource(R.string.TALKBACK_CLAIM_STATUS, currentStatus)
   Row(
-    modifier = modifier,
+    modifier = modifier.semantics {
+      contentDescription = description
+    },
     horizontalArrangement = Arrangement.spacedBy(6.dp),
   ) {
     for (claimProgressSegment in claimProgressItemsUiState) {
       ClaimProgress(
         segmentText = claimProgressSegment.text,
         type = claimProgressSegment.type,
-        modifier = Modifier.weight(1f),
+        modifier = Modifier.weight(1f).semantics {
+          hideFromAccessibility()
+        },
       )
     }
   }


Reviews:
user: login: StylianosGakis
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-02T11:41:29Z
user: login: panasetskaya
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T12:05:12Z

Review comments:
diff_hunk: @@ -45,9 +47,13 @@ fun ClaimStatusCard(
   onClick: (claimId: String) -> Unit,
   modifier: Modifier = Modifier,
 ) {
+  val description = stringResource(R.string.TALKBACK_CLAIM_STATUS_CARD)
path: app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/ClaimStatusCard.kt
user: login: StylianosGakis
body: Could this be "Information about your claim" perhaps?
created_at: 2025-04-02T11:39:57Z
author_association: MEMBER
diff_hunk: @@ -32,15 +35,22 @@ import hedvig.resources.R
 
 @Composable
 internal fun ClaimProgressRow(claimProgressItemsUiState: List<ClaimProgressSegment>, modifier: Modifier = Modifier) {
+  val currentStatus =
path: app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt
user: login: StylianosGakis
body: Just saying "Unknown" might be a bit confusing here. Should we give a more descriptive description, or otherwise no description at all?
created_at: 2025-04-02T11:41:25Z
author_association: MEMBER
diff_hunk: @@ -32,15 +35,22 @@ import hedvig.resources.R
 
 @Composable
 internal fun ClaimProgressRow(claimProgressItemsUiState: List<ClaimProgressSegment>, modifier: Modifier = Modifier) {
+  val currentStatus =
path: app/ui/claim-status/src/main/kotlin/com/hedvig/android/ui/claimstatus/internal/ClaimProgressRow.kt
user: login: panasetskaya
body: well it would be "Claim status: unknown" actually, and I think it rarely happens actually (it's usually at least "submitted")
created_at: 2025-04-02T12:05:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: notion-workspace[bot]
created_at: 2025-04-02T11:10:04Z
body: <a href="https://www.notion.so/Traversal-order-Insurance-card-Perhaps-merge-all-into-one-big-explanation-or-at-least-start-from--1b9c3f71cb0a80b2ab75f58ccf9130b1?pvs=8&n=github_linkback">Traversal order: Insurance card. Perhaps merge all into one big explanation, or at least start from title and then go to labels</a>
author_association: NONE
user: login: notion-workspace[bot]
created_at: 2025-04-02T11:10:21Z
body: <a href="https://www.notion.so/Bottom-nav-Make-items-not-be-announced-as-double-tap-to-activate-when-already-active-Perhaps-there-1b9c3f71cb0a80a5be10edee53d38418?pvs=8&n=github_linkback">Bottom nav: Make items not be announced as double tap to activate when already active. Perhaps there is a way to make them “toggleable” or something like that, but which are not able to be toggled off. Look into other apps how they announce these.</a>
author_association: NONE
user: login: notion-workspace[bot]
created_at: 2025-04-02T11:11:13Z
body: <a href="https://www.notion.so/Traversal-order-After-login-ensure-that-the-home-screen-ordering-makes-sense-And-that-we-focus-on-1b9c3f71cb0a8017939bfb20a7541311?pvs=8&n=github_linkback">Traversal order: After login, ensure that the home screen ordering makes sense. And that we focus on the first item in the navigation bar, not sometimes insurance tab.</a>
author_association: NONE