Skip to content

Improve poll creation TalkBack accessibility: action verb, toggle rows, error live region, reorder actions#6445

Merged
andremion merged 15 commits into
developfrom
fix/compose-poll-creation-a11y
May 21, 2026
Merged

Improve poll creation TalkBack accessibility: action verb, toggle rows, error live region, reorder actions#6445
andremion merged 15 commits into
developfrom
fix/compose-poll-creation-a11y

Conversation

@andremion
Copy link
Copy Markdown
Contributor

@andremion andremion commented May 19, 2026

AND-1180

Goal

Bring the Compose poll creation screen to a usable TalkBack baseline.

Implementation

  • Create button verb. StreamButton accepts an onClickLabel; the poll header passes "create poll". TalkBack reads the verb instead of the generic hint.
  • Switch rows as a single cell. Multiple votes and Limit votes per person rows are toggleable with merged semantics; inner StreamSwitch is non-interactive and the row owns the 48 dp touch target via defaultMinSize. TalkBack reads label + state.
  • Option error live region. PollOptionErrorRow uses liveRegion = Polite so the duplicate-title error is announced as it mounts.
  • Reorder via custom actions. Drag handle exposes boundary-aware Move up / Move down CustomAccessibilityActions. Drag-settle and a11y action share one move lambda.
  • Option identity in reorder / remove. Reorder / Remove icons announce "Reorder option {name}" / "Remove option {name}", falling back to "option N" when the row is blank.

New strings: stream_compose_poll_create_action, stream_compose_poll_option_move_up, stream_compose_poll_option_move_down. stream_compose_poll_option_reorder and _remove take the option name as %s. Translated in 7 locales.

Public API: additive onClickLabel: String? = null on StreamButton (internal).

Testing

Enable TalkBack on a physical device. Open the Compose sample, start a new channel, tap the attachments picker, select Polls.

  1. Create button verb — Focus Create → "Create, double-tap to create".
  2. Switch rows — Focus Multiple votes / Limit votes per person → one cell with "off" / "on"; double-tap toggles.
  3. Error live region — Type the same title in two options → TalkBack announces the duplicate error as the row mounts.
  4. Reorder actions — With 3+ options, open the drag handle's local context menu (single-finger swipe down → right). First row offers only Move down; last row only Move up; middle rows both. Activate → list reorders.
  5. Option identity — Filled-in row's drag handle / remove icon say "Reorder option Pizza" / "Remove option Pizza"; blank row says "Reorder option 2" / "Remove option 2".

Summary by CodeRabbit

  • New Features

    • Poll option reordering with move up/down actions and per-row move controls.
  • Accessibility

    • Added labeled accessibility actions for poll move operations and polite live-region updates.
    • Buttons now include optional accessibility click labels for screen readers.
  • Localization

    • Added/updated poll-related translations (create, move up/down, remove/reorder with placeholders) across multiple languages.

Review Change Stack

andremion added 5 commits May 19, 2026 10:24
StreamButton's clickable was set with no onClickLabel, so TalkBack
defaulted to the generic "double-tap to activate" hint. Add an
optional `onClickLabel` parameter to StreamButton and pass it through
to clickable. PollCreationHeader's create button now provides
"create poll" as the verb, so TalkBack reads "Create Poll, button.
Double-tap to create poll." instead of the generic hint.
Each switch row in `PollSwitchList` (top-level options and the inner
limit-votes row) wraps a title, description and a `StreamSwitch` —
TalkBack focused each as its own node, so a user had to swipe three
times to learn what one switch controlled. Wrap each row in
`Modifier.toggleable(role = Role.Switch) + semantics(mergeDescendants
= true) {}` so the row becomes a single focus stop announced as
"{title}, {description}, switch, on/off", with the row's onValueChange
firing on tap or double-tap. The inner `StreamSwitch` now takes
`onCheckedChange = null` (the pattern its KDoc already documents),
which makes the visual switch decorative while the parent row owns
the toggle action. Sighted users also gain a larger hit target.
`PollOptionErrorRow` mounts conditionally when an option has an error
(currently only the duplicate-title case). Sighted users see the icon
and message appear inline; TalkBack users had no signal until they
swiped to the row. Add `Modifier.semantics(mergeDescendants = true)
{ liveRegion = LiveRegionMode.Polite }` so TalkBack announces the
existing error message the moment the row enters the tree.
The reorder UX relies on dragging a handle, which isn't a gesture
TalkBack supports natively. Expose two `CustomAccessibilityAction`s
("Move up" / "Move down") on each option's drag handle so TalkBack
users can reorder via the local context menu. Each action is wired to
a shared `move` lambda used by both the gesture's `onSettle` callback
and the new accessibility actions, and the action list is built per
row so the top option doesn't offer Move up and the bottom option
doesn't offer Move down.
@andremion andremion added the pr:improvement Improvement label May 19, 2026
@andremion
Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Walkthrough

Adds accessibility labels and actions to poll UI and StreamButton, centralizes poll item move logic and toggle handling, updates localized poll strings, and regenerates Compose lambda accessors in the public API surface.

Changes

Poll UI and Button Accessibility Enhancements

Layer / File(s) Summary
StreamButton accessibility enhancement
src/main/java/io/getstream/chat/android/compose/ui/components/button/StreamButton.kt
StreamButton signature now accepts onClickLabel: String? = null and passes it to Modifier.clickable.
Poll creation button integration
src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt
DefaultPollOptionsHeaderTrailingContent supplies onClickLabel = stringResource(R.string.stream_compose_poll_create_action) to StreamButton.
Poll option reordering with accessibility actions
src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt
Centralized move(from,to) lambda for reordering, ReorderableColumn uses onSettle = move, rows receive optional move-up/move-down callbacks, PollOptionRow exposes labeled CustomAccessibilityActions on the drag handle, error row liveRegion set to polite, and helpers moveItem, toMoveAction, PollOptionMoves added.
Poll switch accessibility refactor
src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt
PollSwitchHeader and LimitVotesPerPerson wrap row content with Modifier.toggleable(value = enabled, role = Role.Switch, onValueChange = onCheckedChange) and set StreamSwitch.onCheckedChange = null; imports added for toggleable/Role and minimum interactive sizing.
Localization for poll features
src/main/res/values/strings.xml, src/main/res/values-*/strings.xml
Added stream_compose_poll_create_action, stream_compose_poll_option_move_up, stream_compose_poll_option_move_down; updated stream_compose_poll_option_remove and stream_compose_poll_option_reorder to include %s placeholders across languages (en, es, fr, hi, in, it, ja, ko).
Generated API surface updates
api/stream-chat-android-compose.api
Autogenerated getLambda$...(): Function2 accessors were added/removed/renumbered across multiple ComposableSingletons classes (MediaGalleryPreviewScreenKt, AddMembersScreenKt, GroupChannelEditScreenKt, ChannelListHeaderKt, MessageActionsHeaderKt, PollAnswersKt, PollCreationHeaderKt, AudioRecordingContentKt, ChatComponentFactoryKt).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • gpunto

🐰 With polls now dancing, ordered neat,
And switches toggling row-by-row,
Accessibility's complete—
A better UI, hear me crow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main accessibility improvements: TalkBack enhancements including action verb, toggle rows, error live region, and reorder actions for poll creation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description includes all critical sections: Goal (clear purpose), Implementation (detailed feature breakdown), Testing (comprehensive manual TalkBack steps with expected behaviors), and API impact note.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/compose-poll-creation-a11y

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.82 MB 5.82 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.02 MB 11.02 MB 0.00 MB 🟢
stream-chat-android-compose 12.41 MB 12.41 MB 0.00 MB 🟢

@andremion
Copy link
Copy Markdown
Contributor Author

@CodeRabbit full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

✅ Actions performed

Full review triggered.

@andremion andremion marked this pull request as ready for review May 19, 2026 13:56
@andremion andremion requested a review from a team as a code owner May 19, 2026 13:56
@andremion andremion marked this pull request as draft May 20, 2026 08:37
@andremion andremion marked this pull request as ready for review May 20, 2026 13:03
@andremion andremion enabled auto-merge (squash) May 20, 2026 13:03
@andremion andremion disabled auto-merge May 21, 2026 08:27
@andremion andremion enabled auto-merge (squash) May 21, 2026 08:30
Copy link
Copy Markdown
Contributor

@gpunto gpunto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a suggestion

@sonarqubecloud
Copy link
Copy Markdown

@andremion andremion merged commit 97817c2 into develop May 21, 2026
16 checks passed
@andremion andremion deleted the fix/compose-poll-creation-a11y branch May 21, 2026 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants