diff --git a/Yattee/Views/Player/ExpandedPlayerSheet.swift b/Yattee/Views/Player/ExpandedPlayerSheet.swift index 2e7edc93..0f5e12bd 100644 --- a/Yattee/Views/Player/ExpandedPlayerSheet.swift +++ b/Yattee/Views/Player/ExpandedPlayerSheet.swift @@ -875,9 +875,11 @@ private struct PlayerMacOSEventHandlersModifier: ViewModifier { var playerState: PlayerState? { appEnvironment?.playerService.state } - /// Corner layout resizes the window freely: no aspect lock, no auto-fit. + /// Corner layout with its panels visible resizes the window freely: no + /// aspect lock, no auto-fit. With the panels hidden only the video is + /// left, so the window follows the ratio lock like the stacked layout. private var isCornerLayoutActive: Bool { - appEnvironment?.navigationCoordinator.isCornerLayoutActive == true + appEnvironment?.isCornerPanelLayoutActive == true } func body(content: Content) -> some View { @@ -895,7 +897,7 @@ private struct PlayerMacOSEventHandlersModifier: ViewModifier { .onChange(of: playerState?.currentVideo?.id) { oldValue, newValue in handleVideoChangeForResize(oldValue: oldValue, newValue: newValue) } - .onChange(of: appEnvironment?.navigationCoordinator.isCornerLayoutActive) { _, isCorner in + .onChange(of: appEnvironment?.isCornerPanelLayoutActive) { _, isCorner in handleCornerLayoutChange(isCorner: isCorner == true) } .onAppear { @@ -903,9 +905,10 @@ private struct PlayerMacOSEventHandlersModifier: ViewModifier { } } - /// Entering corner mode drops the window's aspect-ratio constraint so it - /// resizes freely; leaving it restores the lock (and auto-fit, when on) - /// exactly as the aspect-change handler would have applied it. + /// Entering corner mode with panels shown drops the window's aspect-ratio + /// constraint so it resizes freely; leaving it (stacked layout, or corner + /// panels hidden) restores the lock (and auto-fit, when on) exactly as the + /// aspect-change handler would have applied it. private func handleCornerLayoutChange(isCorner: Bool) { if isCorner { ExpandedPlayerWindowManager.shared.unlockAspectRatio() diff --git a/Yattee/Views/Player/ExpandedPlayerWindowManager.swift b/Yattee/Views/Player/ExpandedPlayerWindowManager.swift index fc615b89..d5d8244d 100644 --- a/Yattee/Views/Player/ExpandedPlayerWindowManager.swift +++ b/Yattee/Views/Player/ExpandedPlayerWindowManager.swift @@ -176,9 +176,10 @@ final class ExpandedPlayerWindowManager: NSObject { // Lock manual resize to the video aspect ratio. Seeded with the real ratio // when known (else 16:9); updated as soon as the real ratio is known. - // Corner layout (already active on a window re-mount, e.g. switching - // from the inline overlay) keeps the window unconstrained. - if appEnvironment.navigationCoordinator.isCornerLayoutActive != true { + // Corner layout with its panels visible (already active on a window + // re-mount, e.g. switching from the inline overlay) keeps the window + // unconstrained. + if !appEnvironment.isCornerPanelLayoutActive { Self.applyAspectRatioConstraint(seedAspect, to: window) } @@ -599,8 +600,17 @@ final class ExpandedPlayerWindowManager: NSObject { func unlockAspectRatio() { guard let window = playerWindow else { return } pendingFullScreenAspectRatio = nil - window.contentAspectRatio = .zero - LoggingService.shared.debug("unlockAspectRatio (corner layout)", category: .player) + // `aspectRatio` and `resizeIncrements` are mutually exclusive: setting + // one resets the other. Assigning a zero aspect ratio does NOT clear the + // lock — it leaves AppKit's aspect handler active with a degenerate 0:0 + // ratio, which makes interactive resize a no-op (the window can't be + // resized at all). Resetting the increments to 1×1 is the supported way + // to return to free resizing. + window.contentResizeIncrements = NSSize(width: 1, height: 1) + LoggingService.shared.debug( + "unlockAspectRatio (corner layout) aspect=\(window.contentAspectRatio) increments=\(window.contentResizeIncrements)", + category: .player + ) } // MARK: - Private Helpers @@ -828,8 +838,8 @@ extension ExpandedPlayerWindowManager: NSWindowDelegate { // exactly what the aspect-change handler would have done windowed. if let ratio = pendingFullScreenAspectRatio { pendingFullScreenAspectRatio = nil - // Corner layout keeps the window unconstrained. - guard appEnvironment?.navigationCoordinator.isCornerLayoutActive != true else { return } + // Corner layout with visible panels keeps the window unconstrained. + guard appEnvironment?.isCornerPanelLayoutActive != true else { return } Self.applyAspectRatioConstraint(ratio, to: window) if appEnvironment?.settingsManager.playerSheetAutoResize == true { resizeToFitAspectRatio(ratio, animated: false) @@ -839,6 +849,19 @@ extension ExpandedPlayerWindowManager: NSWindowDelegate { } } +// MARK: - Free-Resize Gate + +extension AppEnvironment { + /// Whether the player window should resize freely instead of following + /// the video aspect ratio: the corner layout is resolved AND its panel + /// regions are shown, so the window frames video plus panels. Hiding the + /// panels in corner mode leaves only the video, which follows the ratio + /// lock (and auto-fit) exactly like the stacked layout. + var isCornerPanelLayoutActive: Bool { + navigationCoordinator.isCornerLayoutActive && settingsManager.landscapeDetailsPanelVisible + } +} + // MARK: - Two-Phase Window Root /// Root view hosted in the expanded player window.