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
This commit is contained in:
Arkadiusz Fal
2026-07-03 21:57:55 +02:00
parent 944be5a722
commit ecb6a9dd7a
5 changed files with 167 additions and 290 deletions

View File

@@ -24,6 +24,9 @@ struct MacOSPlayerControlsView: View {
let onSeekBackward: (TimeInterval) async -> Void
var onToggleFullscreen: (() -> Void)? = nil
var isFullscreen: Bool = false
/// Collapses the expanded player (Esc in the inline overlay presentation).
/// When nil, Esc outside fullscreen passes through to the responder chain.
var onCollapse: (() -> Void)? = nil
var onClose: (() -> Void)? = nil
var onTogglePiP: (() -> Void)? = nil
var onPlayNext: (() async -> Void)? = nil
@@ -70,7 +73,7 @@ struct MacOSPlayerControlsView: View {
/// Extra top inset for the top bar so its content drops below the window's
/// traffic-light buttons in the separate/floating window presentation, while
/// keeping the avatar/title aligned to the leading edge.
/// Stays 0 when there is no overlap (inline sheet, side panel, fullscreen).
/// Stays 0 when there is no overlap (inline overlay, side panel, fullscreen).
@State private var trafficLightInset: CGFloat = 0
// MARK: - Control Bar Drag State
@@ -125,7 +128,7 @@ struct MacOSPlayerControlsView: View {
}
/// Whether the hosting window is in native fullscreen. The `isFullscreen`
/// parameter covers the sheet-overlay flow, but its key-window half isn't
/// parameter covers the inline overlay flow, but its key-window half isn't
/// reactive check the tracked host window directly as well.
private var isInNativeFullscreen: Bool {
isFullscreen || hostWindow?.styleMask.contains(.fullScreen) == true
@@ -627,6 +630,12 @@ struct MacOSPlayerControlsView: View {
onToggleFullscreen?()
return nil
}
if let onCollapse {
// Inline overlay presentation: Esc collapses to the mini bar
// (the sheet's default Esc-dismiss is gone with the sheet).
onCollapse()
return nil
}
return event // Pass through if not fullscreen
default: