Player controls: one model, two skins (Standard, Minimal); conventional layout; controls settings
PlayerControlsModel holds the controls' state and actions once; the Standard skin (our own, no more media_kit controls or private-state reach-ins) and Minimal (the former uosc design, made the app's own and credited) only draw it. One layout spec for both: play first, then previous/next, volume, time; subtitles, audio, settings, chat, fullscreen last; everything else in the settings menu. Settings -> Player -> Controls: time display, size, hide delay, optional buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
959eed38a4
commit
fd8064611a
40 files changed
+3820
-3975
No files matched your search
+124
-103
@@ -311,7 +311,7 @@ through the same dynamic `setProperty` and read back
|
||||
(`:` joined, `;` on Windows). One saved choice in `AppSettings`
|
||||
(`shaderPreset`, `shaderQuality`, `customShaders`): applied on every player
|
||||
creation (join, new media, Reload video) and live when changed from the session (the
|
||||
control bar's shader menu, Ctrl+0..6, both also save it). The Anime4K
|
||||
controls' ⚙ → Upscaling shader menu, Ctrl+0..6, both also save it). The Anime4K
|
||||
v4.0.1 files live in `apps/desktop/assets/shaders/anime4k/` (only the 14
|
||||
the presets use, plus its MIT LICENSE); mpv needs real paths, so
|
||||
`extractAnime4k` copies them once per version to
|
||||
@@ -400,7 +400,7 @@ Skip rules (pure, `media_marks.dart`):
|
||||
decides). Without any opening, without chapters (a chaptered file
|
||||
without an OP chapter has none on purpose) and with media over 20 min,
|
||||
"Skip 1:30" during the first 6 min.
|
||||
- +1:30 (`skipForward`: the pill, the controls' "1:30" button,
|
||||
- +1:30 (`skipForward`: the pill, ⚙ → Skip 1:30,
|
||||
Shift+Right) is a `nudge`, so repeated presses add up.
|
||||
- Chapter steps (PgUp / PgDn, `chapterStepTarget`): forward to the next
|
||||
start; back to the current start, or the previous one within 5 s of it
|
||||
@@ -863,10 +863,11 @@ Client side (`lib/src/jellyfin/session_media.dart`, `progress.dart`,
|
||||
- **Episodes**: with `OwnPlay` on an episode, `adjacentEpisodes` (one
|
||||
`/Shows/{id}/Episodes` call; `episodeBefore` / `episodeAfter`) gives the
|
||||
previous and next episode. The controls show previous / next buttons
|
||||
(also `<` `>`, Shift+P / Shift+N); from `nextPromptStart` (the ending's
|
||||
(also `<` `>`, Shift+P / Shift+N; next is Up next's first item when
|
||||
there is one); from `nextPromptStart` (the ending's
|
||||
start when one is known, see "Skip rules", else the last 2 min of the
|
||||
runtime) a floating "Next episode" pill shows while the controls are up
|
||||
(see "Session controls"). Auto-advance still waits for `finished`. Any
|
||||
(see "Player controls"). Auto-advance still waits for `finished`. Any
|
||||
of them swaps to that episode's ref with the clicker's account. Guests
|
||||
(relay, blocked) see none of it.
|
||||
- **Auto-advance** (Settings, on by default): at `finished` with a known
|
||||
@@ -881,15 +882,15 @@ Client side (`lib/src/jellyfin/session_media.dart`, `progress.dart`,
|
||||
and with it every countdown. Only while Up next is empty and its
|
||||
continuation was not cleared (see "Up next"); a queued item replaces
|
||||
a countdown already running.
|
||||
- **Tracks**: the controls' Audio and Subtitles buttons list
|
||||
`PlaybackController.tracks`. A pick is applied, reported, and saved as a `TrackChoice`
|
||||
- **Tracks**: the controls' Audio and Subtitles buttons (or ⚙ when
|
||||
hidden from the bar) list `PlaybackController.tracks`. A pick is applied, reported, and saved as a `TrackChoice`
|
||||
(language, title, codec, channels, forced/HI: from the Jellyfin streams
|
||||
with `OwnPlay`, else from mpv's track list) per series and as the global
|
||||
fallback in the `track_prefs` Hive box. On the next Jellyfin item it is
|
||||
matched with `matchTrack` against the source's streams (mapped to mpv ids
|
||||
with `mpvTrackId`) or mpv's track list, and selected locally. Nothing goes
|
||||
on the wire.
|
||||
- **Change video**: the player's "Change video" opens the Library tab;
|
||||
- **Change video**: the player's ⚙ → Change video opens the Library tab;
|
||||
Link goes through `mediaForLink`, a Jellyfin pick as a ref, a file
|
||||
through `ServerIsolate.setFile` (host) or the relay (`swapFile`).
|
||||
|
||||
@@ -1015,8 +1016,8 @@ every `state` and feed), the pure rules in `queue_logic.dart`, the UI in
|
||||
"+" adds one. "Clear" hides them for the media playing and keeps its
|
||||
next-episode countdown from starting.
|
||||
- **UI**: `UpNextButton` is one of the player's top-bar controls, before
|
||||
chat (see "Player overlay" under Desktop UI), in the look of the
|
||||
design's buttons (`UpNextLook`); it shows and hides with the controls,
|
||||
the window controls (see "Player overlay" under Desktop UI), in the look
|
||||
of the skin's buttons (`UpNextLook`); it shows and hides with the controls,
|
||||
which an open popover holds up: the first item's picture (`QueueThumb`,
|
||||
the rows' faint box and icon until it arrives), "UP NEXT" over its
|
||||
title, a +n count, ⏭ plays it now; without Up next the continuation
|
||||
@@ -1085,9 +1086,9 @@ Enter picks, Esc or a click outside closes, and being a route it keeps
|
||||
the player's keys off (fullscreen too). `AppSelect` is the value picker
|
||||
on it (the current label and a chevron on a soft rounded surface; every
|
||||
setting that picks one of a few values), `AppMenuButton` the ⋮ action
|
||||
menu. Material's own menus (the standard controls' track, chapter and
|
||||
shader menus, the Jellyfin sort and server switch) get the same surface
|
||||
from `AppMenuStyle.theme`; the uosc controls keep their own flat menus.
|
||||
menu; the player controls' track, chapter and ⚙ menus are on it too.
|
||||
Material's own menus (the shader menu, the Jellyfin sort and server
|
||||
switch) get the same surface from `AppMenuStyle.theme`.
|
||||
Reusing what the app shows (`widgets/copy_open.dart`): one wording
|
||||
(`ReuseText`: Copy link, Copy title, Copy message, Open in browser, Open
|
||||
in Jellyfin) in every right-click menu that offers it, and a toast
|
||||
@@ -1232,7 +1233,8 @@ panel) and chat messages (Copy message, and a link in it).
|
||||
(icon chips under 760 px) over pages of rounded Material cards
|
||||
(`SettingsPanel`), one help line under every setting: profile, party &
|
||||
network (Host card port and password in the connect form, recent
|
||||
servers), player (the shared rows below, custom shader files),
|
||||
servers), player (the shared rows below, the controls' choices, custom
|
||||
shader files),
|
||||
Jellyfin & integrations (linked servers, AnimeFlow's `/me` via
|
||||
`AnimeFlowClient.fromAccounts`, auto-advance), notifications & sounds
|
||||
(what pops up; no switches), updates, shortcuts, about.
|
||||
@@ -1289,7 +1291,7 @@ panel) and chat messages (Copy message, and a link in it).
|
||||
fullscreen). The app's shortcuts map Tab / Shift+Tab to nothing, so focus
|
||||
never lands on a button Space would press. Something coming up while the player
|
||||
is closed opens it: full right after joining or after putting it up
|
||||
here, else mini. Both control designs show `NowPlayingTitle` top left
|
||||
here, else mini. Both control skins show `NowPlayingTitle` top left
|
||||
(`now_playing_title.dart`: 2:3 cover, title, episode line from
|
||||
`coordinator.nowPlaying`, art through `artBytes`; it fades through when
|
||||
the media changes); the mini shows title and episode without the cover.
|
||||
@@ -1313,28 +1315,29 @@ panel) and chat messages (Copy message, and a link in it).
|
||||
once (the pill is hidden while playing); avatars carry a red error mark
|
||||
and the members card says "can't play this: ...". 34 px avatars, a main line
|
||||
and a muted detail line. The pill glass, colour only for problems; it fades through
|
||||
between kinds. The mini shows its short line in its hover bar. ⚙ in both
|
||||
control designs opens the player settings card (`controls/
|
||||
between kinds. The mini shows its short line in its hover bar. ⚙ →
|
||||
Player settings (both skins) opens the player settings card (`controls/
|
||||
player_settings.dart`, `showPopover`, on `AppGlass`): player design, progress line
|
||||
when hidden, upscaling shader, hardware decoding (set live on mpv's
|
||||
`hwdec`), subtitle and audio track. The rows (`playerSettingRows`) are
|
||||
the same widgets Settings → Player shows; all apply live. The progress
|
||||
line (2 px, `AppSettings.progressLine`) is the collapsed uosc timeline;
|
||||
for the standard design `ControlsHoverProbe` mirrors media_kit's
|
||||
visibility rule (up on mount and mouse movement, down 3 s later or on
|
||||
exit), as media_kit does not expose it. Fullscreen adds the
|
||||
the same widgets Settings → Player shows; all apply live. Settings →
|
||||
Player also has the controls' own choices (`controlsSettingRows`, see
|
||||
"Player controls"). The progress line (`AppSettings.progressLine`) is
|
||||
what the bottom controls leave while hidden: Standard a 2 px line,
|
||||
Minimal its collapsed timeline. Fullscreen adds the
|
||||
`WindowButtons` to the top bar while the controls are up (restore
|
||||
leaves fullscreen).
|
||||
- **Player overlay** (full player, both designs; `session_player.dart`):
|
||||
- **Player overlay** (full player, both skins; `session_player.dart`):
|
||||
everything over the picture has a fixed place on one grid (16 px from
|
||||
the sides, the bars' inset), so nothing floats on its own. The top
|
||||
bar (part of the controls): now-playing title left; right the Up next
|
||||
button (`UpNextButton`), chat, back-to-library or exit fullscreen,
|
||||
then the window buttons in fullscreen, all in that design's button
|
||||
button (`UpNextButton`), back-to-library or exit fullscreen,
|
||||
then the window buttons in fullscreen, all in that skin's button
|
||||
look. Under it at the right, in fullscreen while paused, the party's
|
||||
avatars; with the controls down and unread chat, the unread chip top
|
||||
right. The action area: one band just above the bottom controls
|
||||
(`_actionArea`; their height per design, 16 px gap), sliding down to
|
||||
(`_actionArea`; their height per skin and size, `controlsBottomHeight`,
|
||||
16 px gap), sliding down to
|
||||
16 px from the bottom while they are hidden (`AnimatedPositioned`,
|
||||
the shell's `ease` / `easeTime`); in it the status pill centred
|
||||
(moved left only as far as it must to clear the right end, never
|
||||
@@ -1349,17 +1352,15 @@ panel) and chat messages (Copy message, and a link in it).
|
||||
tall like the status pill without avatars). The mouse on any
|
||||
floating element counts as the mouse on the controls: a
|
||||
`ControlsHold` (`controls/controls_probe.dart`) held by
|
||||
`ControlsHoldRegion`s (and by the open Up next popover or its preview) keeps either
|
||||
design's controls up (`UoscControls.holdBy`; `ControlsHoverProbe.hold`,
|
||||
which re-wakes media_kit's controls through their private hover
|
||||
handler, the same guarded dynamic call as `keepVideoControlsAwake`),
|
||||
and lets them hide on their usual countdown once released.
|
||||
`ControlsHoldRegion`s (and by the open Up next popover or its preview) keeps the
|
||||
controls up (`ControlsFrame.holdBy`), and lets them hide on their
|
||||
usual countdown once released.
|
||||
- **Chat** (`chat_panel.dart`): a 340 px panel sliding in at the right
|
||||
(strip button or Tab): chat with avatars; the "Activity" chip (off by
|
||||
default, `showActivity`, kept for the app's run only) adds the other
|
||||
feed lines between them. Opening focuses the field; Tab or Esc in it
|
||||
close the panel and focus goes back where it was. Unread chat badges
|
||||
the strip's and both player designs' chat buttons; in fullscreen with
|
||||
the strip's and the player controls' chat buttons; in fullscreen with
|
||||
the controls down and the video not playing a glass chip
|
||||
(`PlayerGlass`) top right shows it (while it plays nothing sits on the
|
||||
picture).
|
||||
@@ -1429,78 +1430,98 @@ Jellyfin on the desktop (`lib/src/jellyfin/`, over the core client):
|
||||
video" opens the library on the series of the episode playing, its
|
||||
season selected and the episode highlighted.
|
||||
|
||||
Session controls (the Standard player design): media_kit's
|
||||
`MaterialDesktopVideoControls` with our bars (`shell/session_player.dart`, pieces in
|
||||
`screens/session/player_controls.dart`); its own double-click and keys are
|
||||
off (its double-click pushes a fullscreen route with a second `Video`), the
|
||||
picture's double-click is a raw pointer observer (`DoubleClickListener`).
|
||||
The top bar holds the now-playing title, Up next, Change video, chat and back-to-library
|
||||
(fullscreen: exit, then the window buttons); the bottom bar ends with the
|
||||
shader button, ⚙ and fullscreen. Its seek bar is off; ours
|
||||
(`ChapterSeekBar`: chapter diamonds, hover time with the chapter title)
|
||||
sits in the bottom bar, which is taller by the bar's height (the top bar
|
||||
keeps its row at the top). A drag sends no hover events, so the bar keeps
|
||||
the controls up through a guarded dynamic `onHover()` on media_kit's
|
||||
private controls state (`keepVideoControlsAwake`). Pills (Skip OP / ED /
|
||||
1:30, Next episode) and cards live outside the auto-hiding controls, in
|
||||
the action area ("Player overlay"). The
|
||||
cards stay up; a pill (`PillGate`) shows only while the controls are up
|
||||
(`ControlsHoverProbe` for this design, `UoscControls.shown` for uosc) or
|
||||
the mouse is on it (which holds the controls up too), and Skip OP / Skip 1:30 also for 5 s when an offer of
|
||||
a new kind appears (Skip ED and Next episode never without the controls).
|
||||
Volume (`controls/volume.dart`, both
|
||||
designs): mpv's `volume-max` is pinned to `PlaybackController.maxVolume`
|
||||
(150) per player; `VolumeBar` runs 0..150 with a tick at 100 and the part
|
||||
above in amber; the wheel and ↑ / ↓ step 5 % (`volumeStep`), clamped.
|
||||
The wheel works anywhere on the full player (`VolumeWheel` around the
|
||||
player's stack): `WheelSteps` makes a mouse notch one step and adds up
|
||||
small smooth-scroll deltas, ignores mostly-horizontal scrolls, and claims
|
||||
the event through `pointerSignalResolver`, so anything under the mouse
|
||||
that scrolls (lists, menus, popovers in their own routes) or the volume
|
||||
buttons themselves take it first. A wheel or key step flashes the
|
||||
design's readout for 1 s (`VolumeFlash`): uosc's vertical volume slider
|
||||
at the right edge (`controls/uosc/volume_flash.dart`, after uosc's
|
||||
`Volume.lua`), else a pill under the top bar (`VolumeReadout`).
|
||||
|
||||
The uosc player design (`controls/uosc/`, after mpv's uosc theme;
|
||||
"Player design" = `AppSettings.mpvControls`, default Standard): the `Video`'s
|
||||
controls builder wraps both sets in `SessionControlsSwitch`, which follows
|
||||
the setting live. `UoscControls` is our
|
||||
own frame (no media_kit controls state): mouse movement shows it, 3 s
|
||||
without any hides it and the cursor; `hold` keeps it up during a timeline
|
||||
drag and while a menu route is open, double-click toggles fullscreen.
|
||||
`UoscTimeline` ports uosc's `Timeline.lua` (style `line`, uosc's defaults
|
||||
at scale 1, `UoscTimelineSpec`) across the full width at the bottom: a
|
||||
40 px band (plus a 1 px top border) of black at 0.9; the position is a
|
||||
2 px white line, no filled part, and times map around it
|
||||
(`UoscTimelineGeometry`, uosc's `t2x` / `get_time_at_x`); the uncached
|
||||
part (from `buffered`, or the position when that is behind, to the end)
|
||||
carries uosc's stripe texture (white then black "/" stripes, 0.2 / 0.4
|
||||
strong); chapter diamonds sit on the top edge (white 0.8, 1 px black
|
||||
border, doubled and clickable to jump while the mouse is within twice
|
||||
their radius); elapsed time left and the time remaining ("-01:47:30")
|
||||
right in 20 px outlined text, inverted where it crosses the line; while
|
||||
less than 60 s is buffered ahead (and the cache does not reach the end)
|
||||
a small "12s" rides right of the line. Hover: a faint 1 px line and a
|
||||
black tooltip with the time (the chapter title, bold, above it). A press
|
||||
seeks, every drag move seeks, and after release the line stays at the
|
||||
target until the position catches up (at most 2 s). Hidden, it animates
|
||||
down (100 ms) to uosc's progress line: 2 px with a 20 px position
|
||||
marker, chapters as small diamonds (faded out when the progress line
|
||||
setting is off). We know only the end of mpv's cache, so a dropped back
|
||||
buffer is not hatched; uosc's pause while dragging, keyframe seeks for
|
||||
fast drags, thumbnails and the fullscreen scale (1.3) are left out. Above it a row of flat buttons: menu (≡:
|
||||
change video, chat & activity, reload, mark everyone ready, fullscreen,
|
||||
leave),
|
||||
subtitles and audio with track counts, a shader badge ("A HQ", opening the
|
||||
shared `showShaderMenu`), ready, mark everyone ready, reload; 1:30,
|
||||
chapters, previous / next episode, change video, volume, ⚙, fullscreen; the
|
||||
now-playing title top left (`UoscControls.topLeft`, with a top gradient), Up next, chat
|
||||
and back-to-library (fullscreen: exit) top right, centred on the title. Menus (`showUoscMenu`: a popup route above the button, the
|
||||
current row highlighted) list tracks and chapters with start times. All
|
||||
actions are the coordinator's (seeks through `player.seek`, the user path;
|
||||
`selectTrack`, `skipForward`, `seekTo`); keys and the floating pills are
|
||||
the same in both sets.
|
||||
Player controls (`lib/src/controls/`): one controls model, two skins.
|
||||
- **Model** (`model/`): `PlayerControlsModel` (built by `SessionPlayer`,
|
||||
wired to the coordinator once) holds what the controls show, as
|
||||
signals (`play`: `PlayState` playing / waiting (you are ready, the
|
||||
others not) / paused / finished, from `state.transport` and your ready
|
||||
flag; position, duration, buffered, chapters, current chapter, tracks,
|
||||
volume, skip offer, render mode; the shell's fullscreen, chat open and
|
||||
unread count) and what they do (`togglePlay` = ready, as Space;
|
||||
`seek` through `player.seek`, the user path; `nudge`, `skipForward`,
|
||||
`skip`, `stepChapter`, `pickChapter`; `next` = Up next's first item,
|
||||
else the next episode, `previous`; volume set / step (flashes) / mute;
|
||||
`pickTrack`, `pickShader`; time display; fullscreen, chat, change
|
||||
video, collapse, leave, reload, mark everyone ready, link). The
|
||||
player keys call the same actions. `ControlsSnapshot` (computed) is
|
||||
what the layout depends on.
|
||||
- **Layout spec** (`model/controls_layout.dart`, pure): `ControlsLayout`
|
||||
is the bar's order, left cluster play / pause, previous / next episode,
|
||||
previous / next chapter, volume, time; right cluster subtitles, audio,
|
||||
⚙, chat, fullscreen. `barControls` drops what does not apply (no
|
||||
episode, no chapters) or what the user hid (`OptionalControl`:
|
||||
chapter buttons, subtitles, audio, chat); the rest keep their order, so
|
||||
play is always first and fullscreen last. `menuActions` is the ⚙ menu
|
||||
(`ControlAction`, fixed order): chapters, the hidden track lists,
|
||||
Skip 1:30, upscaling shader, the hidden chat, change video, copy link
|
||||
(when `currentLink` has one), reload, mark everyone ready (not solo),
|
||||
mark a problem, player settings, leave. Icons, tooltips (with keys) and
|
||||
the clock text (`clockText`) are defined there too, once.
|
||||
- **Shared pieces**: `ControlsFrame` (`frame.dart`): when the controls
|
||||
are up (mouse movement shows them, `controlsHideSecs` without any or the
|
||||
mouse leaving hides them and the cursor), holds (`hold` during a seek
|
||||
drag, `holdDuring` / `holdWhile` around menus and popovers, `holdBy`
|
||||
the session's `ControlsHold`), and the double-click on the picture
|
||||
(`DoubleClickListener`, not on the bars) that toggles fullscreen; it
|
||||
reports `shown` for the overlay. `control_menus.dart`: the track and
|
||||
chapter lists and the ⚙ menu on `showAppMenu` (anchored on the button,
|
||||
holding the controls), and `runControlAction`. `volume.dart`:
|
||||
`VolumeControl` (the skin's speaker button, a `VolumeBar` sliding out
|
||||
on hover, the wheel on it stepping), `VolumeReadout`. `SessionControls`
|
||||
(`session_controls.dart`) puts the skin the settings pick into one
|
||||
frame, live, and gives the overlay the bars' heights.
|
||||
- **Standard skin** (`standard/`): Material-style. A top gradient with the
|
||||
top bar (72 px); at the bottom a gradient with `ChapterSeekBar` (played
|
||||
and buffered track in the theme's primary, a diamond at each chapter
|
||||
start, hover tip with the time and the chapter title, a press holds the
|
||||
frame and every drag move seeks) over a 56 px row of round white icon
|
||||
buttons in the layout's order (badges for track counts and unread
|
||||
chat, the clock as a text button). Hidden, a 2 px progress line.
|
||||
- **Minimal skin** (`minimal/`, inspired by uosc, github.com/tomasklaen/uosc,
|
||||
LGPL-2.1; the drawing and values are our own): the buttons sit in two
|
||||
glass capsules (`MinimalCapsule`, the pills' tint and hairline;
|
||||
`MinimalButton` rounded squares, the play button a filled accent
|
||||
circle) above `MinimalTimeline`, a 36 px band across the bottom: the
|
||||
played part tinted in the theme's primary, the position a white line,
|
||||
the part not downloaded yet (from `buffered`, or the position when
|
||||
that is behind, to the end) in thin stripes, chapter starts as dots on
|
||||
the top edge with a dark cut through the band (a press within reach of
|
||||
a dot jumps to it), elapsed time left and the total or the time left
|
||||
right (the bar's clock lives here; a press on it switches), "12s" by
|
||||
the position while under a minute is buffered ahead (and the cache does
|
||||
not reach the end). Hover: a faint line and a glass tip with the time
|
||||
(the chapter title above it). A press seeks, every drag move seeks,
|
||||
after release the line stays at the target until the position catches
|
||||
up (at most 2 s). Hidden, it shrinks (120 ms) to a 3 px progress line.
|
||||
We know only the end of mpv's cache, so a dropped back buffer is not
|
||||
shown.
|
||||
- **Settings** (`AppSettings`, `model/controls_prefs.dart`, all live):
|
||||
`controlsSkin` (`ControlsSkin` standard / minimal; a stored
|
||||
`mpvControls: true` from before becomes minimal), `timeDisplay`,
|
||||
`controlsSize` (normal / large: the bottom bar ×1.25),
|
||||
`controlsHideSecs` (2 / 3 / 5), `hiddenControls`, `progressLine`.
|
||||
The player settings card has the skin and the progress line; Settings →
|
||||
Player → Controls has the rest.
|
||||
- Pills (Skip OP / ED / 1:30, Next episode) and cards live outside the
|
||||
controls, in the action area ("Player overlay"). The cards stay up; a
|
||||
pill (`PillGate`) shows only while the controls are up (the frame's
|
||||
`shown`) or the mouse is on it (which holds the controls up too), and
|
||||
Skip OP / Skip 1:30 also for 5 s when an offer of a new kind appears
|
||||
(Skip ED and Next episode never without the controls).
|
||||
- Volume: mpv's `volume-max` is pinned to `PlaybackController.maxVolume`
|
||||
(150) per player; `VolumeBar` runs 0..150 with a tick at 100 and the
|
||||
part above in amber; the wheel and ↑ / ↓ step 5 % (`volumeStep`),
|
||||
clamped. The wheel works anywhere on the full player (`VolumeWheel`
|
||||
around the player's stack): `WheelSteps` makes a mouse notch one step
|
||||
and adds up small smooth-scroll deltas, ignores mostly-horizontal
|
||||
scrolls, and claims the event through `pointerSignalResolver`, so
|
||||
anything under the mouse that scrolls (lists, menus, popovers in their
|
||||
own routes) or the volume control itself take it first. A wheel or key
|
||||
step flashes `VolumeReadout` (a glass pill under the top bar) for 1 s
|
||||
(`VolumeFlash`).
|
||||
- The `Video` gets the controls as its controls builder (with
|
||||
`StartBanner` under them); media_kit's own controls are not used, so
|
||||
its keys, double-click route and seek bar are out of the picture.
|
||||
|
||||
Window chrome is frameless (`window_manager`): the party strip is the drag
|
||||
area and holds the min/max/close buttons (`widgets/window_buttons.dart`);
|
||||
|
||||
Reference in new issue
Block a user