@@ -28,6 +28,9 @@ import androidx.compose.runtime.setValue
2828import androidx.compose.ui.Alignment
2929import androidx.compose.ui.Modifier
3030import androidx.compose.ui.res.stringResource
31+ import androidx.compose.ui.semantics.contentDescription
32+ import androidx.compose.ui.semantics.semantics
33+ import androidx.compose.ui.semantics.stateDescription
3134import androidx.compose.ui.text.style.TextAlign
3235import androidx.compose.ui.tooling.preview.PreviewParameter
3336import androidx.compose.ui.unit.dp
@@ -100,36 +103,54 @@ fun MediaPlayerControllerView(
100103 contentColor = ElementTheme .colors.iconOnSolidPrimary,
101104 )
102105 }
106+ val a11yPause = stringResource(CommonStrings .a11y_pause)
107+ val a11yPlay = stringResource(CommonStrings .a11y_play)
103108 IconButton (
104109 modifier = Modifier
105- .size(36 .dp),
110+ .size(36 .dp)
111+ .semantics {
112+ stateDescription = if (state.isPlaying) a11yPause else a11yPlay
113+ },
106114 onClick = onTogglePlay,
107115 colors = colors,
108116 ) {
109117 if (state.isPlaying) {
110118 Icon (
111119 imageVector = CompoundIcons .PauseSolid (),
112- contentDescription = stringResource( CommonStrings .a11y_pause)
120+ contentDescription = null ,
113121 )
114122 } else {
115123 Icon (
116124 imageVector = CompoundIcons .PlaySolid (),
117- contentDescription = stringResource( CommonStrings .a11y_play)
125+ contentDescription = null ,
118126 )
119127 }
120128 }
129+ val position = state.displayProgressInMillis.toHumanReadableDuration()
130+ val a11yPosition = stringResource(CommonStrings .a11y_position, position)
121131 Text (
122132 modifier = Modifier
123133 .widthIn(min = 48 .dp)
124- .padding(horizontal = 8 .dp),
125- text = state.displayProgressInMillis.toHumanReadableDuration(),
134+ .padding(horizontal = 8 .dp)
135+ .semantics {
136+ contentDescription = a11yPosition
137+ },
138+ text = position,
126139 textAlign = TextAlign .Center ,
127140 color = ElementTheme .colors.textPrimary,
128141 style = ElementTheme .typography.fontBodyXsMedium,
129142 )
130143 var lastSelectedValue by remember { mutableFloatStateOf(- 1f ) }
131144 Slider (
132- modifier = Modifier .weight(1f ),
145+ modifier = Modifier
146+ .weight(1f )
147+ .semantics {
148+ // Speak out a progress percent instead of milliseconds
149+ stateDescription = buildString {
150+ append((state.progressAsFloat * 100 ).toInt())
151+ append(" %" )
152+ }
153+ },
133154 valueRange = 0f .. state.durationInMillis.toFloat(),
134155 value = lastSelectedValue.takeIf { it >= 0 }
135156 ? : state.seekingToMillis?.toFloat()
@@ -146,30 +167,40 @@ fun MediaPlayerControllerView(
146167 val formattedDuration = remember(state.durationInMillis) {
147168 state.durationInMillis.toHumanReadableDuration()
148169 }
170+ val a11yDuration = stringResource(CommonStrings .a11y_duration, formattedDuration)
149171 Text (
150172 modifier = Modifier
151173 .widthIn(min = 48 .dp)
152- .padding(horizontal = 8 .dp),
174+ .padding(horizontal = 8 .dp)
175+ .semantics {
176+ contentDescription = a11yDuration
177+ },
153178 text = formattedDuration,
154179 textAlign = TextAlign .Center ,
155180 color = ElementTheme .colors.textPrimary,
156181 style = ElementTheme .typography.fontBodyXsMedium,
157182 )
158183 if (state.canMute) {
184+ val a11yUnmute = stringResource(CommonStrings .common_unmute)
185+ val a11yMute = stringResource(CommonStrings .common_mute)
159186 IconButton (
160187 onClick = onToggleMute,
188+ modifier = Modifier
189+ .semantics {
190+ stateDescription = if (state.isMuted) a11yUnmute else a11yMute
191+ },
161192 ) {
162193 if (state.isMuted) {
163194 Icon (
164195 imageVector = CompoundIcons .VolumeOffSolid (),
165196 tint = ElementTheme .colors.iconPrimary,
166- contentDescription = stringResource( CommonStrings .common_unmute)
197+ contentDescription = null ,
167198 )
168199 } else {
169200 Icon (
170201 imageVector = CompoundIcons .VolumeOnSolid (),
171202 tint = ElementTheme .colors.iconPrimary,
172- contentDescription = stringResource( CommonStrings .common_mute)
203+ contentDescription = null ,
173204 )
174205 }
175206 }
0 commit comments