ZaStoGram_desktop/docs/superpowers/specs/2026-07-01-video-like-media-viewer-design.md
2026-07-01 23:03:49 +03:00

121 lines
5 KiB
Markdown

# Video-Like Media Viewer Controls Design
Date: 2026-07-01
## Goal
Make all video-like viewing feel like one precise video player:
- stories can be paused by tapping the visible story content
- stories can be scrubbed with drag seeking instead of only auto-progress
- video messages open in the full media viewer on single click
- a click on video content inside the media viewer toggles pause/play
- seek behavior uses the existing media viewer playback controls where possible
- paused video keeps precise frame stepping through the existing fps-based path
## Current Behavior
The media viewer already owns normal video playback controls through
`Media::View::PlaybackControls`, including continuous slider drag callbacks.
The same overlay has frame-step support for paused videos through
`OverlayWidget::flushPendingFrameStep()`.
Stories use the media viewer overlay, but story playback is deliberately not
seekable today: `OverlayWidget::restartAtSeekPosition()` sets
`PlaybackOptions::seekable` to false for stories, and playback controls are not
created for story streams. The story progress bar is visual-only and does not
handle mouse drag seeking.
Round video messages are still routed like voice/video messages in the chat
player path. `HistoryView::Gif` has a circular progress/seek interaction for
active round playback, but the user-facing model is still "round message in
chat", not "open as a video".
## Recommended Approach
Use the media viewer as the primary video surface.
### Stories
Story video documents should be seekable in the media viewer. The story progress
bar should become interactive for the active segment: pressing and dragging maps
the pointer to a playback progress value, pauses playback during the drag, and
seeks to the selected position on release. A simple tap on story content toggles
pause/play unless the tap is consumed by an existing story control, caption,
navigation button, reaction, menu, or slider drag.
Story auto-advance should stay tied to real playback completion. Manual seek
must not immediately advance to the next story unless the player actually
reaches the end after the seek.
### Video Messages
Single-clicking a video message in the chat opens the media viewer with
`showInMediaView = true`. The old chat-surface play/pause is no longer the
primary action for video messages. Existing download, spoiler, TTL, transcribe,
and context-menu behavior must keep their current priority before the open
action.
Inside the media viewer, clicking the video content toggles pause/play for
video documents, including video messages. Existing drag, menu, navigation,
caption, and control interactions keep priority over that content-click toggle.
### Precise Seeking
Normal viewer seeking should keep using `PlaybackControls` so drag progress and
release seek use one shared path for regular videos, video messages, and story
videos. While the user drags the progress control, the player should pause and
show the target time. On release it should restart at the exact selected
position and resume only if playback was running before the drag.
Paused frame stepping should reuse the existing fps-based overlay path. The
change does not add a new decoder or frame indexer; it makes the existing
viewer behavior consistently reachable for video-like media.
## Components
- `media/view/media_view_overlay_widget.*`
- allow story streams to be seekable
- allow controls for story video where useful
- route content clicks to pause/play for viewer video
- keep controls/caption/navigation priority unchanged
- `media/stories/media_stories_slider.*`
- add active-segment drag/tap mapping to progress
- call back into the stories delegate for seek progress and seek finish
- `media/stories/media_stories_delegate.h`
- expose story seek progress and seek finish callbacks from the slider to the
overlay
- `history/view/media/history_view_gif.*`
- route single-click video messages to `elementOpenDocument(..., true)`
- preserve existing higher-priority links and controls
## Error Handling
If a story has no seekable video stream, slider interaction should do nothing
and leave the current visual-only behavior intact. If a seek target is outside
the media duration, clamp it to the valid range. If a stream fails or finishes
while the user is dragging, cancel the drag state and keep the viewer stable.
## Testing
No compile/build is part of the default verification for this WSL checkout
unless explicitly requested.
Focused verification should include:
- a source guard that story playback no longer hard-disables seekability
- a source guard that story slider exposes seek callbacks
- a source guard that video-message click routing opens the media viewer
- `git diff --check`
Manual runtime verification, when a build is requested, should cover:
- story tap pauses and resumes
- story progress drag seeks without accidental story advance
- video message single click opens the viewer
- viewer content click toggles pause/play
- viewer progress drag is precise enough for short videos
- paused frame-step keys still move one frame at a time