Conversation
`RuntimeFormatStyle` produces digit patterns like 1:23:45. VoiceOver reads those as a run of separate numbers rather than a length of time, so accessibility values need a spelled out counterpart. Contributes to jellyfin#1738.
The player is presented with a custom presentation controller rather than a system one, so it doesn't inherit the isolation a modal presentation provides and VoiceOver keeps reaching the item view behind it. Mark the outermost presented view as modal while the player is up, and move focus into the player when it appears.
Everything behind the controls is decorative: the video surface itself, the dimming, and the gradient, which alone claims the bottom 55% of the screen. Left visible they are silent elements to swipe past. The same goes for the scrubbing preview and the slow scrubbing indicator. `GestureView` has no label to give, so it reads as an unnamed button that still fires its tap gesture when activated. Every gesture it carries is offered elsewhere through a named control, so hide it and wrap the representable to keep the modifier out of its callers. Hiding a view with `isVisible` only set its opacity, leaving faded controls focusable but invisible.
The playback controls are shown and hidden with a tap gesture, which assistive technologies intercept before it reaches the player. The video has no accessibility element of its own, so once the controls fade there is nothing left to focus and no way to bring them back, which usually leaves no way out of the player either. Fixes jellyfin#1733. Add an element standing in for the video, placed beneath the controls so that exploring by touch finds a control where there is one and the video everywhere else. Activating it toggles the controls. While the controls are hidden the element is a corner target rather than the full screen, since a full screen element traces its focus ring around the whole video for no reason, and focus moves to it because it is the only thing left to reach. Playback moves the position every second, and a value that changes under focus is read out again on every change, so the announced position is held still while the element has focus. Co-authored-by: samglt <191187090+samglt@users.noreply.github.com>
The controls fade after five seconds regardless of what is happening, so they disappear out from under someone still swiping through them. While an assistive technology is running, only let them fade with focus resting on the video, since that is how they are dismissed there. Holding the fade timer is not enough on its own, as button presses and overlay changes poke it back to life, so the fade itself checks too.
The jump buttons carried their interval as their label, so VoiceOver read "15s" without saying which way it jumps. The timestamps were built from raw digit patterns, read as a run of separate numbers rather than a length of time, and neither said what tapping it does. Contributes to jellyfin#1738. The episode title and its season and episode label were two elements in the toolbar, read one after the other. Several gestures report only through a toast, which is purely visual, so announce those as well.
The progress bar is a `ProgressView` driven by a drag gesture rather than a slider, so it carried no value and no way to move it. Assistive technology users could tell how far playback had got only by opening the controls and reading the timestamps, and could not seek at all. Expose it as one adjustable element. Swiping up and down seeks by the same interval as the jump buttons, so the step follows whatever was already chosen there. The scrubbed value moves before the seek is requested, otherwise the position announced is a step behind. The track is ten points tall, so widen its accessibility hit area.
52e01d8 to
6e88cfc
Compare
LePips
left a comment
There was a problem hiding this comment.
Thank you for wanting to contribute accessibility settings. However, I will have to request to remove the subtitle reading. I have been working on some exciting developments that would enable you to contribute that in the future.
|
Hey! If I submit subtitle reading as a separate feature PR, would it be possible to get it into the repo? Right now, there’s no way to consume any content with subtitles using VoiceOver, and even information from forced subtitles gets lost. It feels like a pretty basic accessibility feature to have. Thanks so much! |
6e88cfc to
21ce7af
Compare
|
Removed — the last commit is gone, the PR is back to the player fixes only. Happy to wait for what you're working on and bring the subtitle reading separately once it lands. |
Fixes #1733
Contributes to #1738
Summary
The video player was close to unusable with VoiceOver. Once the playback controls faded there was no element left to focus, no way to bring them back, and usually no way out of the player. VoiceOver also read straight through to the item view behind it, the controls that were on screen didn't say what they were, and the progress bar couldn't be moved at all.
There is one commit per fix.
The player is presented with a custom presentation controller rather than a system one, so it doesn't inherit the isolation a modal presentation provides. The outermost presented view is now marked modal while the player is up.
An accessibility element stands in for the video, placed beneath the controls, and toggles them when activated. This is the approach from #1741, whose
accessibilityToggleOverlayI kept and credited on the commit. While the controls are hidden the element collapses to a corner target rather than tracing a focus ring around the whole screen.The decorative elements are hidden. The dimming, the gradient that covers the bottom 55% of the screen,
GestureView, the scrubbing preview and the slow scrubbing indicator were all silent elements to swipe past.isVisiblenow hides from accessibility as well as setting opacity, so faded controls aren't focusable either.The controls no longer disappear from under someone still reading them. With an assistive technology running they only fade with focus resting on the video, which is how they are dismissed there.
The jump buttons read "15s" without saying which way they jump, and the timestamps were digit patterns like 1:23:45, read as a run of separate numbers. Both are labelled now, and a
spokenRuntimeformat style spells the durations out. Gestures that report only through a toast are announced.The progress bar is a
ProgressViewdriven by a drag gesture, so it carried no value and no way to move it. It is now a single adjustable element that seeks by the same interval as the jump buttons.Testing
--strict) andFindUnusedStringspassNot covered
The tvOS half of #1738. The timestamps in the tvOS player are untouched, and the only change reaching tvOS at all is the shared
isVisiblemodifier.