Commit Graph

89 Commits

Author SHA1 Message Date
Arkadiusz Fal
31151df169 Fix macOS player window blink when playing a new video
The separate player window's show() restore branch reset alphaValue to 0
and faded back in even when the window was already on screen, so every
Play Now while playing made the window flash. Only run the fade when the
window was actually hidden (PiP restore); otherwise just bring it forward.
2026-06-03 22:27:38 +02:00
Arkadiusz Fal
96fef3663f Add glass background theme setting for macOS control bar
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:).
2026-06-02 19:38:46 +02:00
Arkadiusz Fal
eea13a6290 Stop macOS player shortcuts from swallowing typing in other windows
The player's keyDown monitor only checked that some window was key, so
plain-key shortcuts (m, space, f, arrows) fired while typing into the
Settings window's text fields. Guard on the window actually hosting the
player controls and pass events through while a text field is editing.
2026-06-01 20:32:10 +02:00
Arkadiusz Fal
05bbd449f8 Drive macOS player control bars from presets
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.
2026-05-31 16:55:39 +02:00
Arkadiusz Fal
5950dbb22a Honor Lock Controls on macOS player
The macOS controls stack (MacOSPlayerControlsView + MacOSControlBar)
never read playerState.isControlsLocked, so locking via the settings
sheet had no effect: buttons, the scrubber, the volume slider, and the
AppKit keyboard shortcuts all kept working.

When locked, dim and disable transport, volume, the progress bar,
queue, the more menu, PiP, the pin/floating toggle, and the title-tap
details button; ignore playback keyboard shortcuts (space/arrows/mute)
while keeping F/Esc for fullscreen. Settings and Close stay enabled so
the user can reopen Settings to unlock.
2026-05-30 22:22:18 +02:00
Arkadiusz Fal
2f2e436fe2 Split macOS player mode into window toggle + floating control
Replace the three-way macOS Player Mode picker (Separate Window /
Floating Window / Inline) with a single 'Play in a separate window'
toggle in Playback settings, and move the always-on-top choice to a
pin button in the player's top bar (window mode only).

Floating was really a transient window property (NSWindow.level), not
a peer of the window/inline structural choice — so it belongs on a live
control, not in Settings. The pin state persists across sessions.

- Replace MacPlayerMode enum with macPlayerSeparateWindow /
  macPlayerFloating bool settings
- Branch runtime presentation and window level off the two bools
- Add pin.fill/pin toggle to MacOSPlayerControlsView top bar
- Update localization; drop obsolete playerMode strings and enum tests
2026-05-30 12:42:18 +02:00
Arkadiusz Fal
64ca1c10d9 Snap macOS player window to final size on open
The expanded player window opened at a seeded 16:9 size and was then
resized with an animated setFrame once the real aspect ratio / video
change landed. Because the video and controls are laid out from the
window's live size, they visibly grew/repositioned as the window
animated.

Force the first resize after each open to snap (no animation) so the
player appears at its final fixed layout, and seed the initial window
size and aspect constraint from the real video aspect ratio when it is
already known (e.g. expanding from the mini bar) to avoid even a jump.
Later resizes (switching to a different-aspect video while the window
stays open) still animate.
2026-05-29 18:36:39 +02:00
Arkadiusz Fal
32f526e05b Add macOS player top bar with title, avatar, and close
Show a top row in the macOS player controls (like tvOS) with the channel
avatar, video title, author name, and a close button whenever controls are
visible.

- Offset the top row below the traffic lights in the floating window by
  measuring the window buttons against the top bar (no effect in fullscreen,
  the inline sheet, or the side panel where there is no overlap).
- Tapping the avatar/title/author toggles the floating details panel, mirroring
  the iOS title/author control.
- Hide the controls immediately when the details panel opens instead of waiting
  for the auto-hide timer.
2026-05-29 08:17:14 +02:00
Arkadiusz Fal
ef213307dc Lock macOS inline player sheet resize to the video aspect ratio
In floating/window mode, interactive resize is aspect-locked via the
window's contentAspectRatio, so no black bars appear. The inline sheet
had no such lock, allowing free resize with pan bars on the sides.

Make applyAspectRatioConstraint static so the sheet path can reuse the
exact same lock the standalone window uses, and apply it to the sheet's
backing NSWindow from SheetWindowResizer whenever the video ratio is
known. Like the standalone window, the resize lock always follows the
real video ratio (independent of the playerSheetAutoResize size setting).
2026-05-27 23:21:07 +02:00
Arkadiusz Fal
5f49f2d022 Fix macOS black video after re-parenting the shared player view
The player video surface is a single shared MPVOGLView that is re-parented
between the mini-bar container (main window) and the expanded-player sheet
(a separate sheet window). When presenting the sheet, the new container
attaches the shared view before the old mini-bar container tears down, so
the old container's viewWillMove(toSuperview: nil) was ripping the shared
view out of its new home via removeFromSuperview() — leaving it with no
window and a black surface. Symmetric, so it also blanked the mini-bar
preview after collapsing.

Only detach the shared view if it still belongs to the container
(superview === self). Also force a repaint on window reattach so a paused
frame redraws, and extend the onAppear resumeRendering to macOS.
2026-05-25 19:46:35 +02:00
Arkadiusz Fal
fe4e3c531a Use rounded font for macOS player time labels
Switch the current-time and duration labels in the macOS transport
control bar from a monospaced design to a rounded design with
.monospacedDigit(), keeping stable digit widths while matching the
softer Liquid Glass look.
2026-05-25 18:02:34 +02:00
Arkadiusz Fal
54488aea0f Keep macOS player transport buttons visible but disabled when unavailable
The play-next and Picture-in-Picture buttons were folded into the view
condition (hasNext / isPiPPossible), so they popped in and out of the
control bar and shifted the surrounding layout. Always render them (when
their callback is wired) and gate availability with .disabled() instead,
mirroring the existing play-previous button.
2026-05-24 21:05:29 +02:00
Arkadiusz Fal
9568149c21 Use native text Close button for sheet toolbars on macOS
Sheet dismiss buttons rendered as an iOS-style circular glass "X" on
macOS 26, which looks foreign on the desktop. Add a shared
sheetCloseToolbarItem helper that renders a native text "Close" button
on macOS while keeping the compact icon-only xmark on iOS/tvOS, and
replace the ~14 duplicated inline close buttons across sheets with it.
2026-05-24 12:34:53 +02:00
Arkadiusz Fal
c245a0e2a0 Resize macOS player sheet to match video aspect ratio
In sheet (inline) mode the expanded player kept a fixed size and never
reacted to the video's aspect ratio, unlike window/floating mode. Drive
the sheet's backing NSWindow size from the video aspect ratio, reusing
the same sizing math as the standalone window.

- Extract shared sizing into ExpandedPlayerWindowManager.fittedPlayerSize
  and add fittedSheetSize for the sheet path.
- Add SheetWindowResizer (NSViewRepresentable) + .sheetWindowSize modifier
  that resizes the hosting sheet window, since .presentationSizing(.fitted)
  only fits once at presentation.
- Let the sheet content fill the window and paint the window background
  black so animated resizes stay gap-free with no white bars.
2026-05-23 13:17:28 +02:00
Arkadiusz Fal
86f9ef56b3 Dismiss expanded player window when closing video from the mini bar
The capsule close button (and context-menu close) only stopped playback and
cleared the queue, leaving the separate macOS player window open on a black
frame. Route both through a shared closeVideo() that also sets
isPlayerExpanded = false, mirroring PlaybackCommands.closeVideo, so the
player window is dismissed.
2026-05-23 11:39:46 +02:00
Arkadiusz Fal
84c17382ce Redesign macOS now-playing bar as centered Liquid Glass capsule
- Replace the full-width material overlay bar with a compact, centered
  capsule (Apple Music style) via a macOS-specific macOSCapsuleLayout
- Extend glassBackground() to use real Liquid Glass on macOS 26 with a
  material fallback on macOS 15-25 (mirrors the PlayerOverlayButton pattern)
- Remove the duplicate close button (close now comes only from the
  configurable button set)
- Keep the capsule visible in the main window while the separate player
  window is open (window mode), still hidden in sheet mode
2026-05-22 23:43:51 +02:00
Arkadiusz Fal
a480b73e7c Open macOS player window immediately with loading feedback
On macOS the expanded player window built ExpandedPlayerSheet directly in
a fresh NSHostingController on every open. AppKit doesn't composite the
window until that heavy view finishes its first layout pass, so the click
felt like it waited for data to load before anything appeared.

Host a lightweight two-phase root (black + spinner) that composites
immediately, then defer building ExpandedPlayerSheet by one runloop so the
window shows at once and fades in with visible loading — matching iOS.

Because assigning contentViewController resizes the window to the hosting
controller's fitting size (tiny for the placeholder), force the content
size back to the seeded 16:9 initialSize so the window opens full-sized
during the loading phase too.
2026-05-22 23:13:08 +02:00
Arkadiusz Fal
93f9a382b0 Refine macOS player controls: add queue, more, previous; drop seek/fullscreen buttons
Add Queue (list.bullet), More (VideoContextMenuView ellipsis), and Play
Previous buttons to the macOS control bar. Play Previous is shown always and
disabled when the queue has no previous item. Remove the skip-back/forward 10s
buttons and the fullscreen button from the bar (arrow-key seek and F-key
fullscreen shortcuts are retained).

Queue reuses the existing cross-platform queue sheet; More reuses the shared
VideoContextMenuView (already !os(tvOS)), styled borderless to match the flat
bar buttons.
2026-05-21 21:36:09 +02:00
Arkadiusz Fal
64171a9cfb Add explicit sizing to sheets on macOS
Give player, download, source, and login sheets minimum frame dimensions on macOS so they open at a usable size instead of collapsing.
2026-05-21 18:19:19 +02:00
Arkadiusz Fal
6dfa63c263 Remove Enable DASH setting; make DASH a last-resort format
Drop the dashEnabled toggle and its plumbing. Stream auto-selection now
keeps DASH as a candidate but ranks it strictly below progressive and
HLS formats, so DASH is only chosen when it is the only format available
(including live-stream fallback after HLS). The manual quality selector
hides DASH entirely on iOS/tvOS/macOS. Reconciles BackendSwitcher, which
previously treated HLS/DASH equally, to use the same DASH-last ranking.
2026-05-20 07:14:31 +02:00
Arkadiusz Fal
c168fbae02 Add tvOS A/V sync diagnostics on its own settings page
Surface audio-delay (±10/±100 ms) and video-sync-mode controls behind an
"A/V Sync" navigation row in Advanced settings rather than inline, keeping the
Advanced page uncluttered. Audio delay applies live to the running MPV
instance; sync mode takes effect on next playback.
2026-05-14 09:43:25 +02:00
Arkadiusz Fal
92d0b3215b Resume MPV rendering when expanded player view re-appears
On iPad, expanding the player after collapsing left the MPV display link
paused, showing only a static frame. MiniPlayerView pauses rendering when
its video preview hides during expand, and PlayerService.playerSheetDidAppear
is gated behind background playback so it can't reliably resume.

Call resumeRendering() from MPVVideoView.onAppear so the expanded view
always restarts the display link.
2026-05-10 17:23:56 +02:00
Arkadiusz Fal
a6b95e9dad Dismiss tvOS player panels when playback fails
Settings, queue, and details panels stayed open over the failure overlay
and error details sheet, obscuring them. Close any open right-side panel
on entry to the failed state.
2026-05-10 15:31:39 +02:00
Arkadiusz Fal
c52f035729 Increase tvOS queue row spacing for focus halo breathing room 2026-05-10 15:28:12 +02:00
Arkadiusz Fal
aa5e78a244 Silence Sendable warnings in TVRemoteHoldSeekOverlay
Annotate makeCoordinator/makeUIView/updateUIView as @MainActor so reading
the @MainActor-typed onTick closure stays within MainActor isolation and
no longer triggers a Sendable conversion warning.
2026-05-10 15:28:12 +02:00
Arkadiusz Fal
dac81e1ee8 Convert tvOS settings and queue overlays to half-screen panels
The Settings (quality/audio/subtitles) and Queue panels now slide in
from the right and occupy the right half of the screen, matching the
info/comments details panel introduced in 92cc8b79f. Video stays
visible on the left so the user retains visual context while browsing.

Both panels supply their own ultraThinMaterial backdrop and use a
custom title bar (replacing NavigationStack's auto-title on tvOS) so
the title styling and symmetric padding match across panels and
across pushed destination screens. The Menu button now pops the
quality panel's pushed Video/Audio/Subtitles detail screens before
dismissing the panel itself.

Removes the background Button from the focus tree while either panel
is open so D-pad left/right inside a row no longer escapes focus
into the player and triggers a seek. Initial focus is steered into
the first row programmatically since tvOS doesn't auto-focus inline
overlays the way it does for fullScreenCover.

Doubles the queue thumbnail size on tvOS (160x90) for readability at
the half-screen panel width.
2026-05-10 15:28:12 +02:00
Arkadiusz Fal
4935fbdb83 Remove tvOS close button from MPV debug stats overlay
Menu remote already dismisses the overlay via TVPlayerView's exit
command handler, so the in-overlay close button is redundant.
2026-05-10 15:28:11 +02:00
Arkadiusz Fal
06ae5ac053 Round iOS player seek bar and show scrubber only while dragging
Clip the progress bar with a Capsule for neater edges, and reveal the
scrubber handle only during a drag with a spring zoom animation.
2026-05-09 16:54:45 +02:00
Arkadiusz Fal
aabf5313fa Expose Background Playback toggle on tvOS, default off
Surfaces the existing iOS/macOS Background Playback setting in the tvOS
Playback settings, defaulting to off so audio stops when the user leaves
the app via the TV button. Pauses playback on .background/.inactive when
the toggle is off, regardless of audio route — the user's setting wins
over AirPlay/HomePod handoff. Also auto-shows the tvOS player controls
when returning to foreground so the paused state is immediately visible
and actionable.
2026-05-09 14:50:38 +02:00
Arkadiusz Fal
8a3f76bb1d Constrain tvOS details panel to right half of screen
Full-screen glass overlay was excessive on 4K displays and fully hid
the video. Wrap the panel in a GeometryReader sized to half the parent
width, slide it in from the trailing edge, and tighten internal
horizontal/top padding now that the content lives in a narrower column.
2026-05-09 14:35:00 +02:00
Arkadiusz Fal
9e13bffa8c Live-seek tvOS scrubber and auto-commit on idle
Throttle SELECT-based scrubbing to seek the underlying frame ~every
150ms instead of waiting 1s after pan-end, so the visible frame keeps
up with the scrub handle. Hide the redundant storyboard panel during
live scrub (the frame itself is now the preview) but keep the chapter
capsule visible. Storyboard panel still shown for D-pad arrow-seek
where the frame doesn't move until commit.

Auto-commit scrub mode after 3s of inactivity, matching
AVPlayerViewController behavior — playback resumes via the existing
scrub-pause wiring instead of staying paused indefinitely.
2026-05-09 11:24:46 +02:00
Arkadiusz Fal
80838db9cc Pause tvOS playback on seek bar scrub mode entry 2026-05-09 11:11:39 +02:00
Arkadiusz Fal
b6c3f0e71b Keep tvOS player controls visible on pause via on-screen button
Route the on-screen play/pause button through handlePlayPause() so it
follows the same visibility and auto-hide timer logic as the Siri Remote
hardware button: timer stops when paused (controls stay pinned) and
restarts on resume.
2026-05-09 11:00:04 +02:00
Arkadiusz Fal
10bd7d09af Use black icons on focused tvOS player control buttons for legibility 2026-05-08 19:03:35 +02:00
Arkadiusz Fal
c8e716be94 Match tvOS play button background to prev/next transport buttons 2026-05-08 18:52:23 +02:00
Arkadiusz Fal
9b85ae2b13 Lock macOS player window resize to video aspect ratio 2026-05-08 18:32:43 +02:00
Arkadiusz Fal
c2758b0d0c Use light glass background for tvOS player control buttons 2026-05-07 18:36:47 +02:00
Arkadiusz Fal
c8bb13e229 Show playback failure overlay on tvOS
Previously a failed video left the user staring at a black screen / thumbnail
with no indication anything went wrong — playbackState went to .failed but
TVPlayerView never read it. Add a focusable glass overlay (Details / Retry /
Play Next or Close) gated on isFailed and a parallel one for retry-exhausted
state, with the regular controls and background tap-target disabled while
either is visible so focus stays inside the overlay. Hide the Copy/Share
toolbar items in ErrorDetailsSheet on tvOS where they aren't useful.
2026-05-07 18:29:48 +02:00
Arkadiusz Fal
158d518e3a Trim comments and hoist settings read in stream filtering
Drop comments restating what the code shows; hoist allowSoftwareDecodedFormats
out of the recommendedVideoStreams filter closure so the bridge property is
read once per render instead of once per stream.
2026-05-07 18:03:34 +02:00
Arkadiusz Fal
16477641ab Add Allow Software-Decoded Formats playback setting
Lets the auto stream selector pick formats whose codec isn't hardware
decoded on the current device. Defaults off; when on, 4K VP9/AV1 can be
auto-selected on Apple TV models without those decoders. Software-decoded
streams also move into the Recommended section so the selection stays
visible without enabling advanced stream details.
2026-05-07 18:00:14 +02:00
Arkadiusz Fal
51108738aa Add press-and-hold continuous seek on tvOS d-pad
The Siri Remote's left/right d-pad only delivered a single discrete
seek per click — holding the button did nothing. A window-level custom
UIGestureRecognizer now tracks the actual press duration and drives a
repeating seek tick (10s → 20s → 30s acceleration) until release,
routing through the existing accumulating-seek paths so the scrubber
preview, debounced commit, and on-screen feedback all keep working.
2026-05-07 06:18:40 +02:00
Arkadiusz Fal
73e3d8164b Keep macOS play pause control visible 2026-04-24 01:14:13 +02:00
Arkadiusz Fal
5a839da1bd Resolve URL shorteners and prompt for ambiguous description links
Tapping bit.ly/tinyurl/t.co/etc. in a description or comment previously
opened Safari even when the destination was a playable YouTube URL.
Added an opt-in "Resolve Short Links" toggle under YouTube Enhancements
(off by default) that follows the redirect on tap: if the target is a
YouTube/PeerTube/direct-media URL, open it in-app; otherwise prompt the
user before falling back to yt-dlp extraction or the browser.

Also added a confirmation dialog for non-shortener links that only
matched the loose .externalVideo yt-dlp fallback, so arbitrary web
pages in descriptions no longer silently kick off extraction.

Prompts live on NavigationCoordinator and are dual-hosted by YatteeApp
and ExpandedPlayerSheet so they remain visible whether or not the
expanded player is covering the main view.
2026-04-23 07:29:57 +02:00
Arkadiusz Fal
b54c32edad Route YouTube links tapped in descriptions through in-app playback
Description links to YouTube videos, channels, playlists, and external
video URLs now open in Yattee instead of Safari. When a video is
already playing, tapping a video link surfaces the existing
QueueActionSheet (Play Now / Play Next / Add to Queue) — the sheet is
hosted both at the app root and inside ExpandedPlayerSheet so it
appears above whichever layer is on screen.
2026-04-22 19:00:43 +02:00
Arkadiusz Fal
b0f9bb2229 Restrict swipe actions to iOS 2026-04-20 21:13:08 +02:00
Arkadiusz Fal
1ae73789a4 Smooth player details panel drag on iOS 2026-04-20 01:18:06 +02:00
Arkadiusz Fal
823b8ae686 Pad comment focus area and remove dividers on tvOS 2026-04-18 20:38:02 +02:00
Arkadiusz Fal
d1010507d9 Remove blue tint from tvOS comment replies indicators 2026-04-18 20:38:02 +02:00
Arkadiusz Fal
8f00fe012f Add tvOS setting to close video with Menu button
When enabled, the Siri remote Menu button stops playback and clears the
queue instead of only collapsing the player, and the explicit top-bar
close (X) button is hidden.
2026-04-18 20:38:02 +02:00
Arkadiusz Fal
096df34f64 Redesign tvOS player controls with centered transport cluster
- Move Close to a top-right circular icon; bottom row reorganizes into
  left (Settings/Info/Comments), center transport (Previous/PlayPause/Next),
  and right (Queue) clusters with equal side frames so transport stays
  geometrically centered.
- Introduce a circular icon-only `TVTransportButtonStyle` (primary variant
  for Play/Pause) mirroring the new Close button look.
- Always render Previous/Next so Play/Pause position is fixed; dim and
  disable when unavailable.
- Share `isTransportDisabled` on `PlayerState` and reuse it on iOS and
  tvOS; apply it (plus symbol replace transition) to the tvOS Play/Pause
  button.
2026-04-18 20:38:02 +02:00