The corner layout's below-video host is the portrait info panel, not a
page host: it can render only Info, plus Comments as the panel's pill on
iOS. The page editor still offered "Below Video" for every page, so
assigning Related there was accepted, stored, listed as such, and then
silently rendered in the side column.
- The Layout section gains a "Below Video" picker in corner mode:
Nothing / Info / Info and Comments (macOS offers the first two). It
writes the info/comments regions; the per-page Location section and
its strings are gone.
- PanelSettings.normalizedPages clamps regions to what the host can
render (only info/comments below, comments only together with info),
so older presets self-correct. effectiveRegion(for:) resolves the
platform-specific placement and is used by both the pages list labels
and CornerPlayerLayout, replacing its own region checks.
- The layout schematic drops the below-video block for "Nothing"; the
corner-mode footer explains the constraint.
- Tests cover the picker round-trip and the clamping.
On iPad both orientations show the video next to a panel, the corner
layout hosts the portrait panel in landscape, and Split View windows make
"portrait" mean "narrow", so the portrait/landscape visibility split never
matched what the user saw. PillVisibility now treats any mode except Never
as visible on iPad, and the pill editor shows a Show pill toggle there
(writes Both/Never, reads synced orientation modes as on). iPhone keeps
the four-way picker.
ExpandedPlayerSheet's bottomPillsOverlay was unreferenced; the floating
panel renders its own pill row.
Pages list
- Info is pinned first and always enabled in every layout: normalized
pages force it to the front and enabled (older presets self-correct),
disabling it is a no-op, and any move that would displace it snaps
back. The iOS/macOS list renders it outside the reorderable ForEach
(no drag handle, nothing drops above it) and the editors hide its
enabled toggle; tvOS also hides its move buttons. The "at least one
page must stay enabled" guard and its strings are gone since Info
always counts.
- iPhone never renders queue or comments as pages, so its Sections list
hides them (PanelSettings.hiddenSettingsPageTypes). Reordering goes
through moveVisiblePages, which keeps hidden entries in their stored
slots. Comments get their own group on the Details Panel screen
(pill mode + avatars) and the overlay hosts pass the avatars flag.
Default visibility
- "When Player Opens" is now configured per orientation
(portraitDefaultVisibility / landscapeDefaultVisibility). The legacy
single value is still decoded and seeds both until set individually;
presets that never set it default to portrait Visible, landscape
Hidden. macOS shows one picker (no portrait layout).
- "Remember Last" no longer leaks across orientations: separate
remembered flags, written by the portrait toggles and by the wide and
corner layouts respectively, with the old shared flag read once as a
fallback. The corner layout seeded from the portrait resolution
before; it now uses landscape.
Section options (iOS inline-sections hosts)
- Chapters and Related editors gain "Expanded by Default" (on by
default). The Info editor gains a Description group with "Expanded by
Default" (off) and a "Collapsed Lines" stepper (1–10, default 3).
Applied when the panel appears and on each video change.
- Expanding a collapsed section scrolls its header to the top of the
panel: PanelPageScrollView can hand its scroll proxy to page content
and each inline section is wrapped in one anchored container.
- The portrait panel's bottom fade sized its touch blocker from a stale
"expanded comments pill" answer that ignored collapse on scroll, so a
collapsed section header (the last item) sat under it and could not
be tapped. The predicate now tracks the pill's actual collapse state.
iPhone landscape now uses the floating panel only, always on the right;
the pin and side-toggle buttons on the grabber are gone and the pinned
setting resolves to false on phone.
iPad and macOS default to the pinned side-by-side layout, keep the pin
button to switch to floating, and pick the panel side in the preset's
panel settings instead of an on-screen arrow. The pinned state persists
as a layout preference: closing the player or the hidden default
visibility no longer resets it.
Removes PanelAlignmentButton, the global floatingDetailsPanelSide setting
and its key, FloatingPanelSide.opposite, and the legacy
wideLayoutPanelAlignment preset field.
iPhone has no page switcher: the portrait panel already rendered one info
page with chapters and related videos as collapsible inline sections. The
landscape floating panel now renders the same panel (no page bar, comments
stay on the pill/overlay), and the settings screen calls the list
"Sections" there, with the page bar labels toggle hidden.
The inline sections were hardcoded to chapters then related and ignored
the configured order, enablement, and thumbnail toggles. The info page now
receives the enabled section pages from PanelSettings.inlineSections(in:)
and renders them in list order with their own settings.
The quality selector sheet already covers quality, audio, subtitles and
rate, so the embedded tracks page duplicated it. Drop the page type, its
per-page settings, the editor toggles, and the visibleSections plumbing
in QualitySelectorView.
The pill mode now lives on CommentsPageSettings and is edited in the
comments page editor instead of a standalone settings section. The
legacy value on PlayerPillSettings is kept for decoding old presets
and migrated by effectivePanelSettings. Comments are loaded when
either the comments page is enabled or the pill is not disabled.
The corner layout now always renders the info page as a portrait-style
panel below the video (collapsible description, drag to hide/expand),
while the side column holds tabs for the remaining pages. Key pieces:
- Below-video panel reuses PortraitDetailsPanel (no comments pill,
square corners, chapters/related stay in the side column tabs)
- Drag down hides the panel with the video recentering in lockstep;
swipe up on the video reveals it following the finger
- Fullscreen button toggles the panels in corner layout (controls hide
first so their resize never plays visibly); status bar and home
indicator hide only while the panels are hidden
- Panel visibility and column width are seeded at init from a warmed
PlayerControlsLayout cache, so the first frame resolves corner mode
without flashing the default layout or animating the panels in
- Dismiss pan is blocked inside the below-video panel frame
(cornerBelowPanelFrame in NavigationCoordinator)
- Resize grabber slimmed to match the panel drag handle look
Phase 5 of the player panels redesign:
- Per-page element toggles now rendered and editable for every page:
comments (author avatars), related (thumbnails), chapters (thumbnails),
queue (previously played section), tracks (video/audio/subtitles/speed
sections)
- Page bar labels toggle (icons-only bar shows the selected page's name)
- Layout mode schematic diagram in the details panel settings
- NEW badge machinery for future page types (versionAdded on PanelPageType)
- Typed per-page settings accessors on PanelPageConfiguration and VM update
helpers for each page kind
- Unit tests for per-page settings round-trip and accessor fallbacks
The standalone quality selector sheet is unaffected: section gating defaults
to everything visible and only the embedded tracks page passes preset
settings through.
Preset-selected two-region layout: video in the top-left, a resizable
side column, and an optional region below the video. Pages are assigned
to regions per preset (Location picker in the page editor); the layout
falls back to the stacked widescreen layout below 900pt width, so Split
View and narrow windows degrade automatically.
- CornerPlayerLayout hosts the shared playerAreaForWidescreen builder,
so the MPV hosting path is identical to the stacked layout
- Layout resolver in ExpandedPlayerSheet picks corner per layout pass;
NavigationCoordinator.isCornerLayoutActive feeds the macOS window
manager, which drops the aspect-ratio lock and auto-fit while corner
is active (and restores them on exit, incl. fullscreen replay and
window re-mounts)
- Side column width persisted via new cornerPanelColumnWidth setting
(280-560pt, video column kept >= 480pt)
- Settings: layout mode picker (iPad/macOS) with automatic-fallback
footer, per-page region picker when corner is on, region shown in
the pages list
Phase 2 of the player panels redesign:
- New "Details Panel" screen in Player Controls settings: page
reorder/enable list with per-page editor (info element toggles),
and a default panel visibility picker (hidden/visible/remember).
- PlayerControlsSettingsViewModel gains panelSettings bindings with
the usual debounced-save flow; the last enabled page cannot be
disabled.
- Built-in presets bumped to v9 with explicit default panelSettings.
- The preset's default visibility now drives the wide-layout panel
on player open and on entering landscape, replacing the hard
hidden resets; "remember" restores the new detailsPanelLastVisible
setting recorded on user toggles. Applied once per expanded player
session (flag on NavigationCoordinator survives re-mounts).
- WideScreenPlayerLayout picks up external visibility writes so the
async-loaded default reaches the mounted layout.
- Unit tests for PanelSettings Codable compatibility (round-trip,
old JSON, unknown page types/discriminators/enum values); removed
stale PlayerInfoTab tests left from Phase 1.
Phase 1 of the player panels redesign:
- New PanelSettings model (pages, regions, layout mode, default
visibility) stored as an optional field on PlayerControlsLayout with
an effectivePanelSettings accessor; lenient Codable so future page
types and settings payloads never corrupt saved presets.
- New Views/Player/Panels content engine: PlayerPanelContentView
renders a page bar plus the selected page (info, comments, related,
chapters, queue, tracks), with runtime hiding of empty pages.
- PortraitDetailsPanel and FloatingDetailsPanel now host the shared
content instead of their duplicated info bodies; drag machinery,
pills, and fades are untouched.
- Comments list extracted into CommentsListContent shared by the
overlay and the comments page; comments pill routes to the comments
page (expanding the portrait panel) when the page is enabled, and
falls back to the overlay when it is not.
- Tracks page embeds QualitySelectorView via a new isEmbedded mode.
- Deleted the unused video info bodies in ExpandedPlayerSheet+VideoInfo
and the dead PlayerInfoTab model.
Phase 0 of the panels redesign, extraction only, no behavior changes:
- Unify comments loading on PlayerState: loadComments/loadMoreComments
become the single loader, used by both the player sheet preload and
the comments overlay (which previously had its own duplicate copy).
- Extract PanelResizeGrabber from FloatingDetailsPanel into the new
Views/Player/Panels/ directory.
- Extract the shared queue list from QueueManagementSheet into
QueueListView plus QueuePlaybackActions, reused by the tvOS panel.
- Remove the no-op wideLayoutPanelAlignment accessor from the settings
view model; the player reads the panel side from SettingsManager, so
the preset field was dead. The Codable field stays so old presets
decode.
Persistent per-platform mode that plays only the audio track to save
bandwidth and speed up loads. When enabled, stream selection picks the
best audio-only stream (preferred language, codec, bitrate) and never
fetches the video URL; toggling mid-video reloads at the current
position using the quality-switch path (live vid=no toggling is avoided
due to A/V desync).
- Toggle row in the player quality/settings sheet on iOS, macOS and
tvOS, next to lock controls
- New audioMode control button type (red when active) for player
controls and mini player layouts
- Picking a video quality explicitly turns the mode off; audio track
picks keep it on and now work while audio-only is playing
- Stream URL refresh preserves audio-only playback instead of
resurrecting video
- Queue preloads and history entries resolved before a toggle are
discarded so selection re-runs with the current mode
- tvOS player shows the video thumbnail instead of a black screen
during audio-only playback
- PiP button hidden for audio-only streams
Playback menu seek items now follow the durations from the active player
controls preset instead of hardcoded 10s/30s labels. AppEnvironment caches
the active preset's center settings (refreshed on preset change
notifications) so menu commands can read them synchronously.
Add secondary seek durations (default 30s) to CenterSectionSettings,
configurable on macOS in Seek Durations settings, used by Shift+arrows in
the player and Cmd+Shift+arrows in the Playback menu.
Also let Cmd-based key equivalents pass through the player keyboard
monitor so menu shortcuts (e.g. Cmd+Option+arrow previous/next video)
work while the player window has focus, and unify macOS built-in preset
primary seek at 10s to match iOS/tvOS (built-in presets version 8).
Rename the macOS "Control Bar Buttons" settings entry to "Control Bar"
and add an Auto/Light/Dark glass background picker on that page. The
choice is stored per-preset as GlobalLayoutSettings.controlBarTheme and
forces the bar's glass color scheme via glassBackground(colorScheme:).
Render the macOS control bar button row and top bar from the active
preset's sections via a new MacOSControlsSectionRenderer, replacing the
hardcoded QuickTime-style rows in MacOSControlBar. Add a keepOnTop
button type and macOS-specific button availability lists, and adapt the
player controls settings editors (preset editor, section editor, button
configuration) for macOS.
Also apply the preset font style to the control bar time labels, and
update the built-in macOS Default preset order (queue before transport,
fullscreen at the end), bumping builtInPresetsVersion to 7.