mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(player): keyboard focus, contrast and ARIA for controls and settings (#1769)
* fix(player): keyboard focus, contrast and ARIA for controls and settings
Dock and settings-panel icon buttons draw a 2px --pc-text ring on
:focus-visible, and Material's theme-coloured focus layer is off, so
keyboard focus shows on video in the light theme too. A focused selected
subtitle swatch now differs from one that is only selected.
Settings headings read --pc-text-secondary on denser glass
(--pc-glass-bg-dense, 0.86): 4.5:1 or more over mid-grey and white
frames. They wrap (overflow-wrap: anywhere, hyphens: auto), so long
German and Russian headings stay inside the sheet's heading column.
The settings panel is now radio groups only (SettingsRadioGroupDirective
over a CDK FocusKeyManager): one Tab stop per group on the checked option,
arrows, Home and End move focus without applying, and Space/Enter checks.
The dialog and its groups are named by real h2/h3/h4 headings, the
load-file action sits outside the subtitle radio group, the subtitle and
speed chips carry their value in their name ("Subtitles: English"), and
tune has aria-haspopup="dialog".
Adds a web E2E for the keyboard path in both themes with an axe check on
the open panel, and de/ru sheet heading wrapping; axe-core is a new dev
dependency for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(player): arrows check settings radios; subtitle chip reads On
Review follow-up:
- Arrow keys, Home and End now check the settings radio they reach, as a
native radio group does (the directive clicks it, so the template's
handler applies the choice); an option the engine already reports as
checked is not applied again.
- With subtitles on but no track marked selected yet (the engine can
report the switch before the track list), the subtitle chip reads and
announces "On" (new SUBTITLES_ON key, 19 locales) instead of "Off".
- The swatch row has 4px padding on every side, so the outer focus ring
is not clipped at the scroll edge of the panel body.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(player): re-apply a settings radio while a switch is pending
The arrow-key check skipped any option the engine still reported as
checked. Arrowing from audio track A to B and back to A before the engine
confirmed B therefore sent no command for A, and playback ended on B with
focus on A. An arrow move always lands on an option other than the last
one applied, so it now applies unconditionally.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5d50995c30
commit
adb4889b0f
37 files changed
+1450
-257
No files matched your search
@@ -91,7 +91,9 @@ themes and fullscreen; frame-copy and built-in shared controls keep their
|
||||
light-on-dark overlay palette — the fixed `--pc-*` token set of the shared
|
||||
dock (accent blue, cyan, violet, the `--pc-live` / `--pc-danger` reds and a
|
||||
light text ramp), never the app theme. The overlay styles in
|
||||
`player-controls/` never read a `--mat-sys-*` token.
|
||||
`player-controls/` never read a `--mat-sys-*` token, and their keyboard focus
|
||||
is a 2px `--pc-text` outline rather than Material's theme-coloured focus layer
|
||||
(`player-controls-keyboard.e2e.ts` checks it in both themes).
|
||||
|
||||
EPG timeline, list, empty states and programme details use the library-local
|
||||
`libs/ui/epg/src/lib/_epg-theme.scss` palette, based on app surfaces, separators,
|
||||
|
||||
@@ -297,7 +297,8 @@ It owns only transient presentation behavior:
|
||||
- `ControlsSettings` — the settings panel's groups, on/modified state and
|
||||
open/close transitions (`controls-settings-groups.ts` holds the pure
|
||||
group-availability rule);
|
||||
- `app-player-settings-panel` — the panel / bottom sheet presentation;
|
||||
- `app-player-settings-panel` — the panel / bottom sheet presentation,
|
||||
whose radio groups use `settings-radio-group.directive.ts`;
|
||||
- `ControlsUpNext` and `app-player-up-next-card` — the "Up next" card's
|
||||
gate and presentation; and
|
||||
- `controls-view-model.ts` — derived display state.
|
||||
@@ -346,7 +347,11 @@ app's `--app-selection-color` is a different blue that would fight the video.
|
||||
measured below 3:1 against the lighter fills.
|
||||
- **Icon buttons** are 40px with a 12px radius (32px / 9px compact) through
|
||||
Material's `--mat-icon-button-*` tokens; their hover is a flat
|
||||
`rgba(255,255,255,.1)` layer.
|
||||
`rgba(255,255,255,.1)` layer. Keyboard focus draws a 2px `--pc-text`
|
||||
outline (`:focus-visible`), and Material's focus state layer is switched
|
||||
off: its colour comes from the app theme, and the light theme's dark layer
|
||||
left no visible focus on video. The settings panel's icon buttons use the
|
||||
same ring, inset by 2px because the panel body clips at its edge.
|
||||
|
||||
### Timeline segments
|
||||
|
||||
@@ -458,7 +463,10 @@ the panel the moment the last group disappears.
|
||||
|
||||
- **Roomy wide dock** (≥ 960px): two **value chips** precede `tune` — subtitles
|
||||
(`closed_caption` + the selected track's label, or "Off") and speed
|
||||
(`speed` + `1.25×`). Audio and aspect ratio have no chip: they are
|
||||
(`speed` + `1.25×`). A chip's accessible name and tooltip carry its
|
||||
value (`SUBTITLES_TOOLTIP` "Subtitles: English", `SPEED_TOOLTIP`
|
||||
"Speed: 1.25×"); `tune` has `aria-haspopup="dialog"` and
|
||||
`aria-expanded`. Audio and aspect ratio have no chip: they are
|
||||
panel-only. A chip click opens the panel **focused on its group**
|
||||
(`settingsFocus`; the group scrolls into view and wears a brief ring);
|
||||
right-click or long-press on the subtitle chip toggles subtitles without
|
||||
@@ -476,12 +484,34 @@ the panel the moment the last group disappears.
|
||||
picture and recording stay in the compact dock — the mock shows only
|
||||
`tune` + fullscreen there, but those two are engine features a viewer
|
||||
needs without opening anything.
|
||||
- **Inside**: list groups (audio, subtitles, quality) use `menuitemradio`
|
||||
rows with a check mark and a cyan selection; segmented groups (speed,
|
||||
aspect) use `radio` items with a violet selection, and a selected default
|
||||
(`1×`, the first aspect preset) stays neutral. The subtitle group carries
|
||||
the load-file action and the delay / size / color sections that the
|
||||
popover used to hold (same `player-controls-load-subtitle`,
|
||||
- **Inside**: every choice is a `radio` in a `radiogroup`
|
||||
(`SettingsRadioGroupDirective` / `SettingsRadioDirective`). List groups
|
||||
(audio, subtitles, quality) are rows with a check mark and a cyan
|
||||
selection; segmented groups (speed, aspect, subtitle size) have a violet
|
||||
selection, and a selected default (`1×`, the first aspect preset) stays
|
||||
neutral. Each group is one Tab stop — the checked option as the engine
|
||||
reports it, else the first — and arrows, Home and End move focus with a
|
||||
CDK `FocusKeyManager` (wrapping; the horizontal arrows follow `direction`)
|
||||
and check the option they reach, as a native radio group does: the
|
||||
directive clicks it, so the template's handler applies the choice, even
|
||||
onto an option the engine still reports as checked: returning to it must
|
||||
cancel a switch that is still pending. Focus
|
||||
changes also write the roving `tabindex` immediately, because a quick
|
||||
Shift+Tab, Tab can arrive before change detection updates the bindings. The dialog is named by its `h2` title (`aria-labelledby`), each
|
||||
radio group by its `h3` group heading or `h4` subheading, and the delay
|
||||
buttons form a labelled `group`. Headings read `--pc-text-secondary` on
|
||||
`--pc-glass-bg-dense` (`rgba(12,16,23,.86)`), 4.5:1 or more even over a
|
||||
white frame. They wrap with `overflow-wrap: anywhere` and `hyphens: auto`,
|
||||
so one long word (German "Wiedergabegeschwindigkeit") breaks inside the
|
||||
sheet's 84px heading column. Hyphenation needs a `lang` on `<html>`.
|
||||
With subtitles on but no track marked selected yet (the engine can report
|
||||
the switch before the track list), the subtitle chip reads "On"
|
||||
(`SUBTITLES_ON`), never "Off".
|
||||
Every focused option shows the `--pc-text` ring; a selected swatch has a
|
||||
white border with a dark inner gap, and focus adds an outer ring. The
|
||||
subtitle group carries the load-file action (a plain button outside the
|
||||
radio group) and the delay / size / color sections that the popover used
|
||||
to hold (same `player-controls-load-subtitle`,
|
||||
`player-controls-subtitle-delay`, `player-controls-subtitle-style` test
|
||||
ids). The panel is a `role="dialog"` with `tabindex="-1"`: opened from
|
||||
the keyboard (the opener is `:focus-visible`) it takes focus, a pointer
|
||||
@@ -1639,6 +1669,7 @@ libs/ui/playback/src/lib/player-controls/
|
||||
├── player-settings-panel.component.ts
|
||||
├── player-settings-panel.component.html
|
||||
├── player-settings-panel.component.scss
|
||||
├── settings-radio-group.directive.ts
|
||||
├── controls-fullscreen.ts
|
||||
├── controls-menu-selection.ts
|
||||
├── controls-menu-state.ts
|
||||
|
||||
Reference in new issue
Block a user