Commit Graph

366 Commits

Author SHA1 Message Date
Arkadiusz Fal
aa6e7fbce9 Stop tracking resume progress for live streams
With "Partially Watched Videos" set to Ask, opening a live stream showed
the resume sheet with a playback timestamp. A live position is relative
to the live edge, not a fixed timeline, so it is meaningless as a
playhead.

Live views are still recorded in history, but carry no resume position:

- WatchEntry gains a persisted isLive flag plus recordLiveWatch(), which
  stores no position and clears state a drifting HLS duration may have
  left behind. progress is always 0 and toVideo() propagates the flag so
  history rows render the LIVE badge.
- from(video:) clamps duration, keeping Piped's -1 live sentinel out of
  storage.
- DataManager routes live saves through recordLiveWatch() and clears the
  flag on the non-live path (before updateProgress, so the auto-finish
  check is not suppressed by the hard-0 live progress), letting an entry
  heal once the stream becomes a VOD.
- PlayerService skips completion saves, always starts at the live edge,
  and drops any startTime passed for a live video.
- The resume prompt, the "Continue at" button label, thumbnail progress
  bars, "X remaining", Continue Watching and tvOS Top Shelf all exclude
  live entries.
- CloudKit syncs isLive with the rest of the watch state: the conflict
  resolver carries it with watchedSeconds/isFinished and the sync engine
  applies it when merging into an existing entry. It is read leniently,
  so the schema version stays at 2 and older clients keep parsing these
  records.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
8faf20c9e9 Add loading external subtitle files for media-source playback
Adds a "Load subtitle from file…" row to the Subtitles section on iOS
(document picker) and macOS (open panel), available when playing files
from local folder, SMB, or WebDAV sources. The picked file is copied
into the per-video temp subtitle directory, registered as a selectable
Caption (displayed by filename), and activated through the existing
loadCaption flow. The Subtitles tab and captions control button now
also appear for media-source files without any subtitles.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
6a0fe2fbbf Show and label WebDAV/SMB video streams in the quality selector
Media-source streams from WebDAV/SMB were invisible in the Video list:
the filter required remote URLs to carry a resolution, which
MediaFile.toStream never sets. Include non-adaptive remote streams
without resolution (only media sources produce those), extend the
mpv-track display enrichment to the currently playing stream regardless
of URL scheme, and classify metadata-less streams as recommended — a
nil codec previously counted as software-decoded, hiding the row behind
advanced mode with a spurious warning. The warning now uses the
enriched codec.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
9e546e29ee Label local-file video quality from mpv track info instead of Unknown
Streams built for local folder files carry no resolution/codec/fps
metadata (unknowable before demux), so the quality selector labeled
them "Unknown". Use the video track mpv reports (demux-w/h/fps, codec)
to fill those fields into a display-only copy of the stream — the
Video row and summary now show e.g. "720p · 30fps" with a codec badge.
Selection and tap handling keep using the original stream.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
67ed8c322b Add embedded audio/subtitle track selection for multi-track files
Files with multiple embedded tracks (e.g. MKV from media sources or
downloads) previously exposed none of them: mpv's track-list was never
read, aid was never set, and sid was only ever no/auto. The quality
selector showed no Audio or Subtitles tab for such files.

MPVClient now observes track-list/aid/sid and delivers a coalesced,
leniently decoded [MPVTrack] snapshot; selection state is derived from
the reported "selected" flags. Embedded tracks are switched live via
aid/sid (no reload), surfaced in the existing Audio/Subtitles sections
alongside external captions on iOS, tvOS and macOS. External sub-add/
audio-add tracks are filtered out to avoid double-listing. User picks
are sticky across same-video reloads (quality switch, audio mode,
retries) and preferred audio/subtitle languages auto-select a matching
embedded track once per load, with external captions taking precedence.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
150ebf42a4 Fix #955: make subtitle appearance settings adjustable on tvOS
Text color, border color, background color, border size, and bottom
margin were rendered as static rows on tvOS (ColorPicker and Slider are
unavailable there), so the focus engine skipped over them and they could
never be changed.

Replace them with menu pickers following the existing font size pattern:
- Text/border/background color: 9 preset colors with a swatch in the
  row label; stored values snap to the nearest preset
- Background opacity: 25-100% steps (iOS parity, where ColorPicker
  supports opacity for the background)
- Border size: 0.0-5.0 in 0.5 steps
- Bottom margin: 0-50% in 5% steps

Verified on tvOS simulator: rows are focusable, selections persist and
are rendered by MPV during playback.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
cd01c08b5a Fix #960: scope subscription counts, import/export to active account
When an Invidious/Piped account is active, several views read the local
SwiftData subscription store instead of the account, so counts
contradicted each other (Home tile said 10 while the Channels list
showed the server's 2):

- Home Channels tile now uses the provider's count via new
  SubscriptionService.cachedSubscriptionCount (fetched once in the
  background when the server cache isn't populated yet)
- Export footer and export content use the active account's list;
  export runs async with a spinner and surfaces fetch errors as a toast
- CSV/OPML import routes through SubscriptionService.importSubscriptions,
  subscribing on the server for server accounts instead of silently
  writing to the invisible local store
- ChannelView subscribe-state is corrected via the provider after the
  optimistic local-store read; unused *Sync write helpers removed
- Server-account subscribe/unsubscribe/import now post
  subscriptionsDidChange so other views refresh
- New "Delete Local Subscription Data" section in Subscriptions
  settings (visible with a server account) clears the local store and
  queues CloudKit deletions so iCloud doesn't restore it
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
76a709a921 Keep macOS player fullscreen when queue advances to different-aspect video
Aspect-driven window sizing (contentAspectRatio + setFrame) ran even while
the separate player window was in native fullscreen, making AppKit fit and
center the content inside the fullscreen space with black bars around it.

Defer the aspect lock and auto-resize while fullscreen by parking the ratio,
then replay it in windowDidExitFullScreen so the window is ratio-locked (and
auto-fitted when that setting is on) once back in windowed mode.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
40f043b769 Fix startup crash in sideloaded builds without iCloud entitlements
Sideloading tools re-sign the app with a team that cannot register the
iCloud.stream.yattee.app container, and CKContainer(identifier:) fatally
traps when the entitlement is missing. Detect availability by parsing
the embedded provisioning profile, skip creating any CloudKit objects
when the entitlement is absent, and show an explanation in iCloud
settings instead of the sync toggle.
2026-08-03 23:34:06 +02:00
Arkadiusz Fal
2ff248e262 Harden player view detach and time-update gate heal from #957
Guard the deinit detach by superview so a container whose render view
was stolen by a newer, not-yet-windowed container cannot rip the shared
view out of it. Narrow the loading-gate heal to .ready only: the old
video still playing during the details/streams fetch can emit .playing,
which would open the gate to stale time updates and break the
stale-error suppression in play()'s catch.
2026-07-23 23:06:48 +02:00
Arkadiusz Fal
6994b9353a Show missing-credentials indicator for remote server sources
After reinstalling the app and importing sources from iCloud, remote
server instances with Keychain-only credentials showed no indication
that login is needed, unlike WebDAV/SMB sources.

- Show the orange key icon for Yattee Server instances without stored
  basic auth credentials (auth is always required for this type)
- Persist usesBasicAuth/usesAccountLogin flags on Instance (synced via
  iCloud) so missing Invidious/Piped/PeerTube credentials are detectable
  too; maintained on credential save/delete, login/logout, and legacy
  migration
- Centralize the check in AppEnvironment.needsCredentials(for:) used by
  SourcesListView, MediaSourcesView, and SourceRow
- Backfill the flags at launch from credentials currently in the
  Keychain so existing setups publish them without a re-login
2026-07-23 22:57:24 +02:00
Ramon
0db7b73d25 Fix black video, freezes, autoplay and clock on Apple TV HD (A8)
Fixes four bugs behind yattee#956 on Apple TV HD (AppleTV5,3, A8,
tvOS 26.5), where video played audio only with a permanently black
picture, never autoplayed, the clock stayed at 0:00, and navigating
during/after playback could freeze the whole app.

1. A8 GL driver deadlock (device-specific). glTexImage2D uploading
   float32 data into a float16 texture hangs in libGLImage's
   glgProcessPixelsWithProcessor (a dispatch_group_wait that never
   returns), permanently wedging mpv_render_context_render. mpv 0.37
   (commit 703f1588) turned on dithering (dither-depth=auto) and
   LUT-based scalers by default; on the A8 (no GL_EXT_texture_norm16)
   both upload float weights via that fatal conversion, and per-frame
   CPU plane uploads (videotoolbox-copy / software decode) hit the same
   path. Yattee 1.x shipped mpv 0.36 with these off, which is why the
   device worked there. Worked around on AppleTV5,3 only: dither-depth=no,
   hwdec=videotoolbox (zero-copy via IOSurface), and bilinear scalers.
   Confirmed by two on-device lldb backtraces.

2. Swift cooperative-pool starvation (all platforms). MPVClient's event
   loop ran as Task.detached and blocked a cooperative-pool thread for
   the client's entire lifetime. With two clients alive (active +
   pre-warmed) on a 2-core A8, both pool threads were held and every
   await in the app starved: the load pipeline froze at its first
   Task.sleep, killing autoplay, Now Playing and progress saving. Moved
   the event loop to a dedicated Thread; EAGLContext creation now bridges
   through GCD instead of Task.detached.

3. Leaked time-update gate (all platforms). PlayerService dropped all
   time updates while loadingVideoID was set; when a load task died
   mid-flight the flag leaked and the clock stayed at 0:00 during
   playback. Heal the gate on the ready/playing transition and leak-proof
   play() with a defer; log the previously silent load cancellation.

4. Orphaned player view (all platforms). Detach the shared render view in
   MPVContainerView.deinit when no successor container exists, and skip
   framebuffer recreation while the view is windowless, to stop a 100% CPU
   SwiftUI trait-update loop when opening a settings detail during playback.
2026-07-22 14:30:00 +02:00
Arkadiusz Fal
f275499c7b Fix macOS legacy import sheet missing grouped form style 2026-07-19 19:35:26 +02:00
Arkadiusz Fal
283c2cb9cb Fix tvOS legacy import rows acting as a single Remove button
On tvOS a Form row is one focusable unit, so the legacy account/source
cards - header, credential fields, and both buttons stacked in a single
row - focused as a whole and every click fired the first button (Remove),
making credentials and Import unreachable.

- Split the tvOS rows into individually focusable rows (info header,
  fields, Import, Remove), keeping the card layout on iOS/macOS
- Wrap the tvOS entry points in TVSidebarDetailContainer and drop the
  tvOS navigationTitle that rendered as a ghost behind the form
- Present the review screen from the first-launch alert as a
  fullScreenCover on tvOS: sheets render as a small transparent card
  that cannot fit the sidebar layout (Menu button dismisses the cover)
- Dim disabled TVSettingsButtonStyle buttons
- Widen the row icon frame for tvOS glyph sizes and skip the caption
  when it would repeat the host shown as the title
2026-07-19 19:23:36 +02:00
Arkadiusz Fal
a673968f1e Fix build error with confirmationDialog on CI Xcode
Replace the item-based confirmationDialog overload, which is unavailable
in the Xcode 26.5 SDK used on CI, with the isPresented/presenting
variant.
2026-07-18 17:54:49 +02:00
Arkadiusz Fal
4ec9b936a6 Fix background playback setting behavior across platforms
Hide the toggle on macOS, where apps are never suspended and playback
always continues regardless of the setting. Pause playback on iOS when
backgrounding with the setting disabled — the audio background mode
previously kept mpv playing, making the off state a no-op.

Move the continue-playing policy into PlayerService and make the
backend's background render pause unconditional (PiP-gated only):
it is a GPU optimization that should not depend on the setting.
Also ungate the player sheet visibility handlers, which manage
foreground mini player rendering unrelated to background playback.
2026-07-18 16:28:19 +02:00
Arkadiusz Fal
bc7b00dfb3 Restore last player window frame when auto-resize is off
With auto-resize disabled the separate player window opened at a
computed 16:9 default and was never corrected, so non-16:9 videos sat
letterboxed until a manual resize. Persist the window frame via
NSWindow frame autosave and restore it on open when auto-resize is
off, so the window reopens exactly as the user last left it.
2026-07-18 16:21:12 +02:00
Arkadiusz Fal
e905932cfa Use toolbar search placement on iPad channel view
The navigationBarDrawer search field on iPad added a resting scroll
position above the banner on iOS 27, letting the view scroll past the
banner top with the mirrored banner filling the gap. iPhone keeps the
drawer placement since its header reserves space for the search bar.
2026-07-18 12:54:47 +02:00
Arkadiusz Fal
74442f2764 Force soft top scroll edge effect for banner and video info views
iOS 27 changes the default scroll edge effect style to hard, which
draws a sharp cutoff line over the channel banner and video info
gradient extending under the toolbar.
2026-07-18 10:40:31 +02:00
Arkadiusz Fal
3a8f91f88c Reset player aspect ratio to 16:9 for audio-only playback
Audio-only streams never report a video size, so the aspect ratio of
the last played video stuck to the player area indefinitely once audio
mode was enabled. Reset it in play() when the selected stream is
audio-only, and let the macOS player window fall back to 16:9 instead
of keeping the previous lock.
2026-07-17 18:43:10 +02:00
Arkadiusz Fal
6514cb426e Keep macOS channel search bar pinned right during search
The content type picker in the center .principal toolbar slot is what
constrains the .searchable field to the trailing edge. Dropping the
picker when a search was submitted let the toolbar reflow and the search
field re-center. Keep the picker in place and disable it while searching
instead.
2026-07-16 21:35:47 +02:00
Arkadiusz Fal
e7886d9707 Raise player settings sheet detent so audio mode toggle is visible
Rest the quality/settings sheet at a 0.6 fraction instead of .medium on
iOS so the general section (playback speed / audio mode / lock) at the
bottom of the scroll view is reachable without dragging up to .large.
2026-07-16 20:12:41 +02:00
Arkadiusz Fal
06087220ef Add audio-only music mode
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
2026-07-13 19:06:01 +02:00
Arkadiusz Fal
66f7602d08 Exit fullscreen before dismissing macOS player window
Ordering out a window in native fullscreen skips the exit transition and
strands its black fullscreen space on screen. Route all dismissal paths
(stop/collapse, PiP hide, window close) through exitFullScreenIfNeeded,
which leaves fullscreen first and defers hiding until the transition
completes, with a timeout fallback if AppKit refuses the exit.
2026-07-12 21:01:15 +02:00
Arkadiusz Fal
ab5163e29f Add toolbar scrim on channel view for pre-macOS 26 2026-07-12 19:09:28 +02:00
Arkadiusz Fal
aa81fdac7d Move channel tab picker to toolbar on macOS
Replace the centered avatar/name toolbar title with the
About/Videos/Shorts/Streams/Playlists segmented picker. The channel
avatar and name move to the leading edge next to the view options
button, in their own glass capsule (sharedBackgroundVisibility(.hidden)
+ glassEffect on macOS 26). Add spacing between the channel banner and
the content below now that the inline picker is gone.
2026-07-11 22:26:48 +02:00
Arkadiusz Fal
cc50c88d75 Fix Clear All Recents button stretching full width on macOS 2026-07-11 20:25:10 +02:00
Arkadiusz Fal
8b50c2ee14 Default Channels grid to 5 columns on macOS and tvOS 2026-07-10 21:07:31 +02:00
Arkadiusz Fal
31bbbd317f Fix truncated section footers in Remote Control sheet on macOS 2026-07-10 19:26:20 +02:00
Arkadiusz Fal
e6aa95b656 Handle live videos in mini player bar
Live streams have no meaningful duration, so the mini player's bottom
progress line collapsed to nothing (or showed a misleading partial fill
on DVR streams). Hide the line for live playback and show a red dot +
LIVE indicator next to the author name instead, matching the expanded
player controls. Applies to both the macOS capsule and iOS overlay
layouts.
2026-07-09 23:52:43 +02:00
Arkadiusz Fal
ffcb73fe33 Strengthen top bar scrim gradient on macOS player controls 2026-07-08 23:43:02 +02:00
Arkadiusz Fal
9918a68d73 Fix tvOS ao value shown in MPV options settings
The read-only defaults list grouped tvOS with iOS as ao=audiounit, but
MPVClient actually sets ao=avfoundation,audiounit on tvOS (avfoundation
first because audiounit can't open 32-channel HDMI Atmos routes).
Display-only fix; no playback behavior change.
2026-07-08 07:59:11 +02:00
Arkadiusz Fal
afa73e6bcb Prefer avfoundation AO on macOS 27 to avoid mpv hotplug listener crash
On macOS 27 beta, mpv's coreaudio AO fails to initialize (channel layout
set rejected with paramErr -50). The existing ao=coreaudio,avfoundation
fallback restored audio, but exposed an mpv bug: init() registers a HAL
hotplug listener (AudioObjectAddPropertyListener on the system object,
with the raw ao pointer as user data) before the step that fails, and
the coreaudio_error path never unregisters it. mpv then frees the ao
and falls back to avfoundation, leaving a dangling listener per
playback start. The next audio device change (AirPods connect,
sleep/wake device republish) invokes the listener with the freed
pointer and crashes with a use-after-free SIGSEGV on the
HALC_ProxyNotification Call Listener Queue (observed in build 262;
faulting address was reused "texture_" shader string memory).

Gate the AO order by OS version: on macOS 27+ use
avfoundation,coreaudio so the failing coreaudio init never runs; older
macOS keeps the native coreaudio first with avfoundation as fallback.
Update the read-only defaults mirror in MPV options settings to match.
2026-07-07 23:51:34 +02:00
Arkadiusz Fal
9e2b0fa095 Extend opaque background to settings and other pushed pages on macOS
The NavigationStack-level background wasn't enough: macOS draws its own
translucent material behind pushed navigation pages, and Form/List
containers draw a translucent scroll background on top of anything
placed behind them, so several pages kept the wallpaper-tinted look.

Bake the opaque background into SettingsFormContainer (covers all pages
built on it, pushed or not) and add opaqueSettingsFormBackground(),
which hides the container's scroll background before applying the
opaque one, to every macOS-reachable Form/List settings page: player
controls and its sub-editors, sidebar settings, edit source, legacy
data import, subscription/playlist import, customize home and its
shortcut style page, and the log viewer. Contributors, translators and
the remote control device page get the plain opaque background.

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
2026-07-07 22:16:09 +02:00
Arkadiusz Fal
8d4f472348 Unify macOS content view backgrounds with opaque window background
Views without an explicit background sat on the translucent window
material, which picks up a wallpaper tint (bluish in dark mode) and
clashed with views drawing windowBackgroundColor, making the video
info header gradient fade visibly mismatch. Add opaqueWindowBackground()
and apply it centrally in NavigationDestinationHandlerModifier to both
stack roots and pushed destinations, plus VideoInfoView for
presentations outside navigation stacks.

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
2026-07-06 09:36:49 +02:00
Arkadiusz Fal
48378d7ca8 Add download row context menu for pause, resume and cancel
Download row actions were wired only as swipe actions, and
SwipeActionModifier has #if !os(iOS) overloads that return the view
unmodified, so macOS had no way to pause, resume or cancel a download.
The video context menu could not cover it either, since the .downloads
context deliberately hides the built-in cancel item.

Give active download rows their own context menu with pause when queued
or downloading, resume when paused, retry when failed, and a destructive
cancel. Right-click on macOS, long-press on iOS.

Completed rows had a related bug: the delete item called an onDelete
callback that DownloadsView never passed, so it rendered but did nothing
on macOS. Drop the callback and delete via the download manager directly,
which is what already made the same menu work in HomeView.

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
2026-07-06 08:19:56 +02:00
Arkadiusz Fal
b632f11b2f Add separate light/dark mode accent colors
Adds an option in Appearance settings to use different accent colors
in light and dark mode, with a toggle to keep a single shared color
(the default, preserving existing behavior).

- New synced settings keys: accentColorDark, customAccentColorDark,
  useSeparateDarkAccentColor; dark values fall back to the light
  selection until explicitly set, so no migration is needed
- resolvedAccentColor returns a dynamic platform color (UIColor trait
  provider / NSColor appearance provider) when the toggle is on, so
  the root tint and all direct readers adapt to light/dark
  automatically without consumer changes
- Accent Color section shows two stacked preset+custom grids with
  Light/Dark headers when enabled, extracted into AccentColorGrid;
  CustomAccentColorButton now takes bindings so the macOS color panel
  edits whichever target was last opened
- New DarkAccentColorTests covering sync contract, default-off state,
  fallbacks, and toggle-off resolution

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
2026-07-05 21:06:26 +02:00
Arkadiusz Fal
b47888fe04 Add custom accent color with system color picker
Add a Custom swatch to the appearance settings accent color grid,
backed by a hex value stored in settings (synced via iCloud like the
rest). iOS uses the native ColorPicker wheel; macOS uses a circular
swatch that opens NSColorPanel, since the SwiftUI color well looks out
of place among the circles. All accent consumers now read the resolved
color through SettingsManager.resolvedAccentColor.

The indigo preset is retired from the grid but kept in the enum, so
users who selected it keep their color until they pick another one.

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
2026-07-04 23:57:59 +02:00
Arkadiusz Fal
f5b86effd3 Fix layout jump when subscriptions sidebar appears after load on macOS
Load local-account subscriptions synchronously on appear so the channels
sidebar is present in the first layout pass, and reserve the sidebar
column with a spinner while async loads are in flight (gated by a
persisted flag so users without enough channels never see a phantom
column).
2026-07-04 17:04:09 +02:00
Arkadiusz Fal
ecb6a9dd7a Replace macOS inline player sheet with full-window overlay
When "Play in a separate window" is disabled, the expanded player was a
native sheet attached to the main window. AppKit refuses fullscreen with
an attached sheet, so pressing F swapped the sheet for an in-window
overlay before fullscreening — a visible two-step transition.

Present the inline player as the full-window overlay from the start, so
fullscreen is just the window's native toggle. This removes the whole
sheet-swap machinery (toggleSheetFullScreen with its detach timing,
SheetWindowResizer, sheet sizing helpers).

- beginInlineOverlay/endInlineOverlay hide/restore the main window
  toolbar and mirror the window's fullscreen state into the renamed
  isMacInlinePlayerFullScreen flag via NSWindow notifications, so exits
  through Esc/green button/Mission Control stay in sync
- Collapsing exits fullscreen only if it was entered for the video
- Esc in the windowed overlay collapses to the mini bar via a new
  onCollapse callback (replacing the sheet's default Esc-dismiss)
- ContentView registers its hosting window (MainContentWindowReader) so
  the overlay targets the right window even when the setting is toggled
  while the Settings window has focus
2026-07-03 21:57:55 +02:00
Arkadiusz Fal
944be5a722 Fix duplicate log actions in macOS settings toolbar
The Filter/Export/Clear buttons appeared twice on macOS: inline next
to the search bar and again inside the ellipsis toolbar menu. Show
them once as plain toolbar buttons on macOS; keep the menu on iOS/tvOS.
2026-07-03 19:18:25 +02:00
Arkadiusz Fal
fdd6075a49 Fix unclickable error/replay overlays in macOS 15 player window
On macOS 15 Sequoia the error overlay buttons (Retry / Play Next /
error details) and the ended-state replay buttons did nothing when
clicked, while working fine on macOS 26. Layered event logging showed
the click reached SwiftUI but always landed on MacOSPlayerControlsView,
which covers the whole video surface above those overlays: on Sequoia a
view with .onContinuousHover participates in click hit-testing across
its full frame, so even with its inner layers hit-disabled the controls
view formed an invisible wall. Drop the whole controls view out of
hit-testing while the ended/failed overlays own the surface.

Also keep the traffic-light buttons visible on the ended/failed
overlays: they used to fade out with the controls and nothing could
bring them back, leaving the error screen with no way to close the
window.
2026-07-02 18:34:43 +02:00
Arkadiusz Fal
30b2f67752 Auto-hide macOS player controls on mouse idle and hide pointer in fullscreen
The hide timer was gated on the pointer leaving the player view, which
never happens in fullscreen, so controls shown when pressing F stayed up
forever. Switch to idle-based hiding: mouse movement shows controls and
resets the 3s timer; controls fade after inactivity even while the
pointer rests over the video, unless it's on one of the control bars.
Entering fullscreen rebaselines hover tracking so the resize-driven
hover re-emission doesn't count as movement.

Also hide the mouse pointer (setHiddenUntilMouseMoves) when controls
hide in fullscreen, restoring it on exit or any mouse move.
2026-07-02 07:30:42 +02:00
Arkadiusz Fal
b642813716 Fall back to avfoundation AO when coreaudio fails on macOS
macOS 27 beta's AUHAL rejects mpv's channel-layout property with paramErr
(-50), so the coreaudio AO fails to initialize and playback is silent.
Change the macOS ao option from "coreaudio" to "coreaudio,avfoundation"
so mpv self-heals: older macOS keeps using coreaudio unchanged, while the
beta drops to avfoundation (AVSampleBufferAudioRenderer) instead of playing
no sound.
2026-07-01 06:40:16 +02:00
Arkadiusz Fal
403b83badc Show queue mode label and split bottom bar on macOS
On macOS the queue sheet's mode selector now shows both icon and text
and shares a single bottom toolbar bar with the Close button, pinned to
opposite edges.
2026-06-29 23:42:30 +02:00
Arkadiusz Fal
daf5fe1ad1 Fix full-width Speed menu on macOS Sequoia
The borderlessButton menu stretches to fill the available width on
macOS 15, so pin it to its intrinsic size with .fixedSize().
2026-06-29 21:04:41 +02:00
Arkadiusz Fal
f730542903 Right-align toast dismiss button on macOS 2026-06-28 09:57:25 +02:00
Arkadiusz Fal
b230d56379 Fix oversized ellipsis menu buttons on macOS Sequoia
The default SwiftUI Menu style on macOS 15 renders as a bordered
pull-down button that stretches to fill available width, while
macOS 26 hugs the label. Apply .menuStyle(.borderlessButton) and
.fixedSize() to the video context menu and playlist header menu.
2026-06-28 08:01:46 +02:00
Arkadiusz Fal
b72fd2d3f0 Fade traffic lights with controls in macOS player window
In the separate player window the traffic-light buttons stayed visible
while the controls overlay was hidden. Animate the standard window
buttons' alpha in sync with controls visibility, QuickTime-style.

Applies only to the dedicated player window (inline sheet and overlay
fullscreen presentations keep their parent window's chrome). Buttons
are handed back at full alpha when entering native fullscreen, when the
controls unmount (PiP, debug overlay), and when the view re-parents to
another window.
2026-06-27 21:30:52 +02:00
Arkadiusz Fal
46735b07aa Show macOS player controls on hover after auto-hide
When the pointer left the player window during playback, the auto-hide
timer set the manual showControls override to false. The override takes
precedence over hover state, so re-entering the window kept controls
hidden until a click toggled them back.

Clear a stale hide override on mouse activity so hovering reveals the
controls again, except while the details panel is open, which keeps
controls hidden on purpose.
2026-06-27 17:58:00 +02:00