@@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.height
2929import androidx.compose.foundation.layout.heightIn
3030import androidx.compose.foundation.layout.padding
3131import androidx.compose.foundation.layout.size
32+ import androidx.compose.foundation.selection.toggleable
3233import androidx.compose.foundation.shape.RoundedCornerShape
3334import androidx.compose.material3.AlertDialog
3435import androidx.compose.material3.ButtonDefaults
@@ -50,6 +51,11 @@ import androidx.compose.ui.graphics.StrokeCap
5051import androidx.compose.ui.platform.LocalContext
5152import androidx.compose.ui.res.pluralStringResource
5253import androidx.compose.ui.res.stringResource
54+ import androidx.compose.ui.semantics.Role
55+ import androidx.compose.ui.semantics.clearAndSetSemantics
56+ import androidx.compose.ui.semantics.contentDescription
57+ import androidx.compose.ui.semantics.hideFromAccessibility
58+ import androidx.compose.ui.semantics.semantics
5359import androidx.compose.ui.text.style.TextOverflow
5460import androidx.compose.ui.tooling.preview.Preview
5561import androidx.compose.ui.unit.dp
@@ -69,6 +75,7 @@ import io.getstream.chat.android.compose.ui.theme.MessageFailedIconParams
6975import io.getstream.chat.android.compose.ui.theme.MessageStyling
7076import io.getstream.chat.android.compose.ui.theme.MessageStyling.PollStyle
7177import io.getstream.chat.android.compose.ui.theme.StreamTokens
78+ import io.getstream.chat.android.compose.ui.util.applyIf
7279import io.getstream.chat.android.compose.ui.util.isErrorOrFailed
7380import io.getstream.chat.android.compose.ui.util.passiveRipple
7481import io.getstream.chat.android.compose.util.extensions.toSet
@@ -427,23 +434,35 @@ private fun PollOptionItem(
427434 onRemoveVote : () -> Unit ,
428435) {
429436 val typography = ChatTheme .typography
437+ val toggleRole = if (poll.maxVotesAllowed == 1 ) Role .RadioButton else Role .Checkbox
438+ val onToggle: (Boolean ) -> Unit = { enabled ->
439+ val canVote = poll.maxVotesAllowed?.let { checkedCount < it } ? : true
440+ if (enabled && canVote && ! checked) {
441+ onCastVote.invoke()
442+ } else if (! enabled) {
443+ onRemoveVote.invoke()
444+ }
445+ }
430446
431447 Row (
432- modifier = modifier.fillMaxWidth(),
448+ modifier = modifier
449+ .fillMaxWidth()
450+ .applyIf(! poll.closed) {
451+ toggleable(
452+ value = checked,
453+ role = toggleRole,
454+ onValueChange = onToggle,
455+ )
456+ }
457+ .semantics(mergeDescendants = true ) {},
433458 horizontalArrangement = Arrangement .spacedBy(StreamTokens .spacingSm),
434459 verticalAlignment = Alignment .CenterVertically ,
435460 ) {
436461 if (! poll.closed) {
437462 RadioCheck (
463+ modifier = Modifier .semantics { hideFromAccessibility() },
438464 checked = checked,
439- onCheckedChange = { enabled: Boolean ->
440- val canVote = poll.maxVotesAllowed?.let { checkedCount < it } ? : true
441- if (enabled && canVote && ! checked) {
442- onCastVote.invoke()
443- } else if (! enabled) {
444- onRemoveVote.invoke()
445- }
446- },
465+ onCheckedChange = onToggle,
447466 borderColor = style.outlineColor,
448467 )
449468 }
@@ -468,8 +487,15 @@ private fun PollOptionItem(
468487 )
469488 }
470489
490+ val voteCountDescription = pluralStringResource(
491+ R .plurals.stream_compose_poll_vote_counts,
492+ voteCount,
493+ voteCount,
494+ )
471495 Text (
472- modifier = Modifier .align(Alignment .CenterVertically ),
496+ modifier = Modifier
497+ .align(Alignment .CenterVertically )
498+ .semantics { contentDescription = voteCountDescription },
473499 text = voteCount.toString(),
474500 style = typography.metadataDefault,
475501 color = style.textColor,
@@ -488,7 +514,8 @@ private fun PollOptionItem(
488514 modifier = Modifier
489515 .fillMaxWidth()
490516 .height(8 .dp)
491- .clip(RoundedCornerShape (4 .dp)),
517+ .clip(RoundedCornerShape (4 .dp))
518+ .clearAndSetSemantics {},
492519 progress = { progress },
493520 color = style.progressColor,
494521 trackColor = style.trackColor,
0 commit comments