Skip to content

a11y: Group chat rows and label tapbacks/unread for VoiceOver#2119

Merged
garthvh merged 2 commits into
meshtastic:mainfrom
bruschill:a11y/pr4-messages
Jul 20, 2026
Merged

a11y: Group chat rows and label tapbacks/unread for VoiceOver#2119
garthvh merged 2 commits into
meshtastic:mainfrom
bruschill:a11y/pr4-messages

Conversation

@bruschill

@bruschill bruschill commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

What changed?

Makes the chat surface coherent to VoiceOver: each message bubble reads as one element instead of many fragments, and icon/color-only affordances get spoken labels.

  • UserMessageRow / ChannelMessageRow — a composed messageAccessibilityLabel ("You sent: …" / "Message from : …", timestamp, plus "Encrypted"/"Verified" mirroring the visible security badges) applied to the bubble via .accessibilityElement(children: .combine). The sender caption is folded in with .accessibilityHidden(true); the reply-quote button gets its own label. Delivery status, RetryButton, and reactions stay siblings outside the combined element so they remain independently navigable and context-menu actions (reply/tapback) stay on the Actions rotor.
  • TapbackResponses — each reaction announces "Reaction from ".
  • ChannelList — unread badge labeled "N unread" (hidden when none); mute icon labeled "Muted"; the channel.unreadMessages fetch is hoisted to run once per row (was twice).
  • Messages — Channels / Direct Messages rows combine + announce unread counts.
  • AlertButton — labeled "Alert".
  • 7 files changed, +101 / −3; 9 additive Localizable.xcstrings keys.

Why did it change?

Chat rows exposed sender, text, timestamp, security badges, and reactions as separate, out-of-order VoiceOver fragments, and several affordances (reactions, unread, mute, alert) were unlabeled color/icon-only elements. Grouping the bubble and labeling the affordances makes conversations understandable and actionable with VoiceOver.

How is this tested?

Built the Meshtastic scheme for iOS Simulator (iPhone 17 Pro, Xcode 26) → ** BUILD SUCCEEDED **. SwiftLint clean. Passed a focused Swift/SwiftUI review that traced the view composition to confirm .combine is scoped to the bubble only (reactions/retry/actions remain reachable) and that the "Encrypted"/"Verified" conditions are an exact match to MessageText.cornerBadges. A live VoiceOver pass to confirm the Actions rotor enumerates reply/tapback is recommended before merge.

Screenshots/Videos (when applicable)

N/A — no visual change; affects spoken VoiceOver grouping/labels only.

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/. No doc update is needed (VoiceOver labels only, no UI/flow change) — please apply the skip-docs-check label.
  • I have tested the change to ensure that it works as intended.

Summary by CodeRabbit

  • Accessibility
    • Improved VoiceOver support for channels and direct messages, including unread-count-aware section labels.
    • Message bubbles now announce message text, timestamp, “You sent” vs “Message from …”, plus delivery/read and security indicators as a single combined label.
    • Reply navigation buttons, reaction rows, and alert (bell) buttons now include explicit accessibility labels; sender names are hidden from separate reading.
    • Updated localized accessibility strings for unread counts, muted state, verification status, and sent/received message phrasing.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ce2fe97c-7ce8-43c4-a747-91bb3e4f713d

📥 Commits

Reviewing files that changed from the base of the PR and between 64f7a3a and c9054a5.

📒 Files selected for processing (1)
  • Localizable.xcstrings

📝 Walkthrough

Walkthrough

VoiceOver accessibility labels are added across channel navigation, message rows, reactions, and alert controls. Localized strings describe unread counts, senders, replies, security status, reactions, and muted channels.

Changes

VoiceOver accessibility

Layer / File(s) Summary
Navigation and channel labels
Localizable.xcstrings, Meshtastic/Views/Messages/ChannelList.swift, Meshtastic/Views/Messages/Messages.swift
Channel and sidebar rows announce unread counts, while muted channels expose a localized label.
Message row accessibility
Localizable.xcstrings, Meshtastic/Views/Messages/ChannelMessageRow.swift, Meshtastic/Views/Messages/UserMessageRow.swift
Message bubbles combine text, sender, timestamp, security state, and reply context into VoiceOver labels.
Reaction and alert control labels
Localizable.xcstrings, Meshtastic/Views/Messages/TapbackResponses.swift, Meshtastic/Views/Messages/TextMessageField/AlertButton.swift
Reaction rows and the alert button receive explicit accessibility labels.

Estimated code review effort: 2 (Simple) | ~15 minutes

Poem

I’m a rabbit hopping through the code,
Giving quiet labels a clearer road.
Unread hops and messages sing,
Reactions glow on everything.
VoiceOver ears now know the way—
Accessibility blooms today!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main accessibility change: grouping chat rows and labeling tapbacks and unread counts for VoiceOver.
Description check ✅ Passed The description includes all required template sections and gives clear details for what changed, why, testing, screenshots, and checklist items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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.

@garthvh garthvh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved after detailed review (CodeRabbit confirmed no actionable items). Accessibility grouping/labels verified correct; CI green. Merged current main to resolve the Localizable.xcstrings key conflict (union of both key sets, JSON validated).

@garthvh
garthvh merged commit 5c61d1b into meshtastic:main Jul 20, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-docs-check Use this label to skip the automatic docs audit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants