diff --git a/.jules/palette.md b/.jules/palette.md index a021571..1ee937b 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -4,3 +4,6 @@ ## 2024-05-18 - Redundant Icon Content Descriptions **Learning:** Adding `contentDescription` to icons that are directly adjacent to `Text` components containing the same wording is an anti-pattern. Screen readers will announce the information twice (e.g., "Liked, Liked"), creating a noisy experience. Icons in this context should remain decorative (`contentDescription = null`). **Action:** Verify if text alternatives exist near visual elements before assigning a `contentDescription` to avoid duplicate screen reader announcements. +## $(date +%Y-%m-%d) - Dynamic Content Descriptions +**Learning:** State-dependent buttons (like Mute/Unmute or Lock/Unlock) need dynamic `contentDescription`s to accurately reflect the action they perform when toggled, rather than statically describing the button's purpose. Screen readers use this context to clarify the action to the user. +**Action:** When working with toggleable state buttons, update `contentDescription` to be dynamic (e.g., `if (isMuted) "Unmute" else "Mute"`) instead of using a static string. diff --git a/app/src/main/java/com/example/reddittube/ui/main/VideoPage.kt b/app/src/main/java/com/example/reddittube/ui/main/VideoPage.kt index ef24e33..d6a2c2c 100644 --- a/app/src/main/java/com/example/reddittube/ui/main/VideoPage.kt +++ b/app/src/main/java/com/example/reddittube/ui/main/VideoPage.kt @@ -69,6 +69,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.CustomAccessibilityAction +import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -729,7 +730,7 @@ Box( .clip(CircleShape) .background(Color.Black.copy(alpha = 0.65f)) .border(1.dp, GlassBorder, CircleShape) - .clickable { + .clickable(role = Role.Button) { hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) if (exoPlayer.playbackState == Player.STATE_ENDED) { exoPlayer.seekTo(0) @@ -786,7 +787,7 @@ Box( .size(40.dp) .clip(CircleShape) .background(Color.Black.copy(alpha = 0.55f)) - .clickable { onBack?.invoke() }, + .clickable(role = Role.Button) { onBack?.invoke() }, contentAlignment = Alignment.Center ) { Icon(Icons.Default.ArrowBack, contentDescription = "Back", tint = Color.White, modifier = Modifier.size(22.dp)) @@ -868,7 +869,7 @@ Box( color = BrandRed, fontSize = 16.sp, fontWeight = FontWeight.Bold, - modifier = Modifier.clickable { onSubredditClick(post.subreddit) } + modifier = Modifier.clickable(role = Role.Button) { onSubredditClick(post.subreddit) } ) Spacer(modifier = Modifier.width(6.dp)) val isSubbed = subscribedSet.contains(post.subreddit.lowercase()) @@ -877,7 +878,7 @@ Box( .size(32.dp) .clip(CircleShape) .background(BrandRed.copy(alpha = if (isSubbed) 0.2f else 0.15f)) - .clickable { + .clickable(role = Role.Button) { hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) onSubscribeToggle(post.subreddit.lowercase()) }, @@ -988,7 +989,7 @@ Box( ) { Icon( if (isRotationLocked) Icons.Default.Lock else Icons.Default.LockOpen, - contentDescription = "Rotation", + contentDescription = if (isRotationLocked) "Unlock rotation" else "Lock rotation", tint = if (isRotationLocked) BrandRed else Color.White, modifier = Modifier.size(14.dp) ) @@ -1001,7 +1002,7 @@ Box( ) { Icon( if (isMuted) Icons.AutoMirrored.Filled.VolumeOff else Icons.AutoMirrored.Filled.VolumeUp, - contentDescription = "Mute", + contentDescription = if (isMuted) "Unmute" else "Mute", tint = if (isMuted) BrandRed else Color.White, modifier = Modifier.size(14.dp) ) @@ -1017,7 +1018,7 @@ Box( ) { Icon( Icons.Default.SkipNext, - contentDescription = "Auto-next", + contentDescription = if (autoNextEnabled) "Disable auto-next" else "Enable auto-next", tint = if (autoNextEnabled) Color.White else TextMuted, modifier = Modifier.size(14.dp) ) @@ -1034,7 +1035,7 @@ Box( ) { Icon( Icons.Default.Repeat, - contentDescription = "Loop video", + contentDescription = if (isLoopEnabled) "Disable loop" else "Enable loop", tint = if (isLoopEnabled) Color.White else TextMuted, modifier = Modifier.size(14.dp) ) diff --git a/app/src/main/java/com/example/reddittube/ui/main/components/MinimalButton.kt b/app/src/main/java/com/example/reddittube/ui/main/components/MinimalButton.kt index 056265a..8879150 100644 --- a/app/src/main/java/com/example/reddittube/ui/main/components/MinimalButton.kt +++ b/app/src/main/java/com/example/reddittube/ui/main/components/MinimalButton.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp