Skip to content

feat: accessibility pass (VoiceOver, dynamic type, contrast, tap targets)#38

Merged
windoze95 merged 1 commit into
mainfrom
fix/flutter-accessibility
Jun 28, 2026
Merged

feat: accessibility pass (VoiceOver, dynamic type, contrast, tap targets)#38
windoze95 merged 1 commit into
mainfrom
fix/flutter-accessibility

Conversation

@windoze95

Copy link
Copy Markdown
Owner

Accessibility pass (roadmap LATER tier, #20). The app previously had effectively zero a11y.

VoiceOver

  • Tooltips (= VoiceOver labels) on all icon-only player controls (back, ±10s, state-aware play/pause, speed); the 360p preview badge is labeled ("Playing preview quality, 360p" — quality auto-upgrades, so there's no control to label).
  • The seek bar (NullFeedProgressBar) now exposes slider semantics (role, "Video position", spoken "M:SS of M:SS", ±5% increase/decrease) so VoiceOver can scrub. This also fixed a latent bug: a valued slider with an increase action must define increased/decreased values or Flutter asserts under a screen reader.
  • Cards collapse to one labeled button node (via excludeSemantics + explicit label, so secondary controls — channel link, actions menu, cancel — stay individually operable rather than merged into one node).

Dynamic type

App root clamps the platform text scaler to 0.8–1.3; horizontal content rows grow with the clamped scale so titles keep room. (Text already scaled; this bounds extremes.)

Contrast (WCAG AA)

textMuted #666666 → #858585: was 3.45:1 / 2.90:1 (fail) on base/cards; now 5.37:1 base, 5.08:1 surface, 4.52:1 cards — all ≥ 4.5:1. Smallest bump that clears AA on the worst real surface.

Tap targets

Inline cancel/stop and actions menus bumped to a 44×44pt minimum; player speed button padded to ~44pt.

Verification

  • dart format clean · flutter analyze --fatal-infos --fatal-warnings — No issues · flutter test92 passed (+6 in accessibility_test.dart: seek-bar slider semantics + merged card labels).

🤖 Generated with Claude Code

https://claude.ai/code/session_01RXMKM1rDWn8wNh93MMUtxY

Player controls (video_player_screen.dart): tooltip/semantics labels on
the icon-only back, skip-back/forward and play/pause controls (play/pause
is state-aware), a label on the 360p preview badge, and a slider role on
the seek bar (NullFeedProgressBar) with a spoken time value plus
increase/decrease actions so VoiceOver can scrub.

Cards: video_card, channel_card and video_list_tile now expose a single
merged label (title + channel + state like "downloaded"/"downloading")
via Semantics(excludeSemantics:), while keeping secondary controls
(channel link, actions menu, download/cancel) as their own operable nodes.

Dynamic type: clamp the platform text scaler to 0.8-1.3 at the app root
and grow the content rows with the text scale so layouts hold up.

Contrast: raise textMuted from #666666 to #858585 to meet WCAG AA
(4.5:1 on cards, 5.4:1 on the base background; was ~2.9:1 on cards).

Tap targets: inline cancel buttons, the actions menus and the speed
button now meet the 44pt minimum.

Adds test/widgets/accessibility_test.dart covering the seek-bar slider
semantics and the card labels.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXMKM1rDWn8wNh93MMUtxY
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@windoze95 windoze95 merged commit 7bdefc1 into main Jun 28, 2026
6 checks passed
@windoze95 windoze95 deleted the fix/flutter-accessibility branch June 28, 2026 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant