dreamio/docs/native-player-ux-audit.md

124 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Native Player UX Baseline Audit
Date: 2026-05-26 21:49 EDT
Issue: `dreamio-ee1`
## Scope
This audit covers the current VLC-backed native playback experience before Liquid Glass and broader UX changes. The primary implementation is `Dreamio/NativePlayerViewController.swift`, backed by `Dreamio/NativePlaybackBackend.swift` and `Dreamio/VLCNativePlaybackBackend.swift`.
## Current Experience Summary
Dreamio presents native playback as a full-screen black video surface with a compact bottom control tray, a top-right close button, a loading spinner, and a simple centered failure label. Controls are built directly in UIKit and are intentionally lightweight.
Current user-facing controls:
- Top-right close button.
- Bottom compact blur-backed tray capped at 430 points wide.
- Elapsed time, scrubber, and remaining time row.
- Audio menu button.
- 15-second jump back.
- Play/pause.
- 15-second jump forward.
- Captions menu button with subtitle delay controls.
- Tap anywhere on the playback surface to reveal or hide controls.
- Auto-hide while playing after 3 seconds.
## Existing Strengths
- **Minimal interruption:** The player is full-screen and hides chrome while playback is active.
- **Compact controls:** Recent work reduced the overlay footprint so video content stays dominant.
- **Core playback affordances exist:** Play/pause, seeking, jump controls, elapsed/remaining time, audio tracks, captions, and subtitle delay are present.
- **Backend-aware disabling:** Seek and jump controls disable when VLC reports a non-seekable stream.
- **Track menus are cached:** Audio and captions menus avoid unnecessary rebuilds through signature values.
- **Subtitle handoff exists:** The native player can receive subtitle candidates from the Stremio Web bridge and attach them through the backend.
- **Safe-area aware:** Close and controls are anchored to safe-area guides.
## Current UX Gaps
### Visual Treatment
- The control surface uses `UIBlurEffect(style: .systemUltraThinMaterialDark)` plus manual tint/border styling, not iOS 26 Liquid Glass.
- Buttons are individual translucent wells rather than an intentional grouped glass system.
- There is no bottom readability scrim; bright video frames could reduce time label and icon contrast.
- Loading and failure states are plain compared with the rest of the player chrome.
### Touch Targets and Hierarchy
- Secondary controls are 36×36 points, below Apples recommended 44×44 point minimum target.
- The play/pause button is only 42×42 points, so the primary action is not dominant enough.
- Audio and captions have the same visual weight as transport controls even when unavailable or secondary.
- Disabled captions do not currently mirror the explicit alpha treatment used by audio.
### Scrubbing
- The scrubber has a compact thumb and row, but no preview/target time bubble.
- During scrubbing, the elapsed label updates, but the user does not get a larger focused scrubbing affordance.
- There is no haptic feedback on scrub begin/end or jump actions.
### Gestures
- Single tap toggles controls, but no richer playback gestures exist.
- There is no double-tap left/right jump behavior.
- There is no center tap play/pause behavior separate from chrome visibility.
- Gesture conflict handling will need care because `tap.cancelsTouchesInView = false` currently allows control touches to pass through.
### Auto-Hide
- Controls hide after 3 seconds while playing, which can feel short for subtitle/audio menu interactions or careful scrubbing.
- The auto-hide timer only checks `backend.isPlaying`; future changes should explicitly protect menu presentation, scrubbing, loading, paused, and failure states.
### Loading and Failure
- Startup loading is only a white `UIActivityIndicatorView` over black.
- Failure is a plain text label with no retry, close action, or debug affordance.
- The 20-second startup timeout is useful, but the user receives little guidance after it fires.
### Accessibility
- Buttons have accessibility labels, but no accessibility hints.
- The scrubber has no dynamic accessibility value describing elapsed and remaining time.
- Jump actions are not exposed as custom accessibility actions on the player surface.
- Motion preferences are not checked before animations.
- Dynamic Type behavior for the compact controls has not been explicitly protected.
### Device Adaptation
- The bottom tray is capped at 430 points, which is good for phones but underuses iPad/large landscape space.
- Button sizing and row spacing are fixed; orientation-specific density has not been tuned.
- The supported orientations allow all but upside down, so landscape crowding should be part of validation.
## Implementation Constraints
- `NativePlaybackBackend` currently exposes no thumbnail/preview frames, so scrub previews should begin as a time bubble rather than video thumbnails.
- The backend exposes seekability, duration, position, audio tracks, subtitle tracks, and subtitle delay, which is enough for richer controls without backend changes.
- The app must preserve compatibility with builds where MobileVLCKit is unavailable through the existing fallback backend behavior.
- Liquid Glass APIs should be gated with iOS availability checks and keep the current blur/material implementation as fallback.
- Multiple glass controls should be grouped with container effects where possible to avoid expensive standalone glass rendering.
## Recommended Next Implementation Slice
Start with a low-risk visual and ergonomics pass:
1. Add iOS 26 Liquid Glass availability-gated styling for the main controls tray and interactive buttons, preserving the current blur fallback.
2. Increase button targets to at least 44×44 points and make play/pause 5458 points.
3. Add a subtle bottom gradient scrim behind controls for contrast.
4. Extend auto-hide timing from 3 seconds to about 4.5 seconds and prevent hiding while scrubbing.
5. Add missing accessibility hints and scrubber accessibility value.
Defer until the second implementation slice:
- Scrubber target time bubble.
- Double-tap jump gestures.
- Center tap play/pause behavior.
- Glass-backed loading and failure cards with retry.
- iPad-specific wider layout.
## Validation Targets for Future Changes
- Build the workspace with Xcode command-line tools.
- Test seekable and non-seekable streams.
- Test streams with one audio track, multiple audio tracks, no captions, embedded captions, and external captions.
- Verify controls remain usable in portrait and landscape.
- Verify VoiceOver labels, hints, and scrubber values.
- Verify older iOS fallback styling still works when Liquid Glass is unavailable.