mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 13:12:53 +00:00
Keep the macOS corner player layout from being squeezed
The separate player window could be resized below what the corner layout needs. Free resize now floors at the corner layout's minimum (its width threshold, the narrowest side column plus a video column wide enough for the control bar, and 600pt tall), and an undersized window grows to it when the corner layout takes over. The video column minimum is 560pt on macOS so the control bar capsule fits. The control bar's fixed 650pt frame also widened the controls stack past a narrower video column, clipping the top bar's avatar and close button; the frame is now capped to the container width.
This commit is contained in:
@@ -71,8 +71,15 @@ struct CornerPlayerLayout<PlayerContent: View>: View {
|
||||
/// matching the panel drag handle look.
|
||||
static var grabberWidth: CGFloat { 12 }
|
||||
static var maxColumnWidthCap: CGFloat { 560 }
|
||||
/// Minimum width kept for the video column.
|
||||
static var minVideoColumnWidth: CGFloat { 480 }
|
||||
/// Minimum width kept for the video column. macOS needs room for the
|
||||
/// floating control bar (up to 500pt wide plus its edge margins).
|
||||
static var minVideoColumnWidth: CGFloat {
|
||||
#if os(macOS)
|
||||
560
|
||||
#else
|
||||
480
|
||||
#endif
|
||||
}
|
||||
/// Maximum fraction of the window height the video area may take when a
|
||||
/// below-video region needs space.
|
||||
static var maxVideoHeightFraction: CGFloat { 0.72 }
|
||||
|
||||
@@ -22,7 +22,8 @@ extension ExpandedPlayerSheet {
|
||||
/// keeps it off tall-phone landscape (iPhone Pro Max is 956×440) while
|
||||
/// the iPhone Duo interior (951×669) and every iPad qualify. The gate is
|
||||
/// size-only — the Duo interior behaves like a small iPad, and the
|
||||
/// exterior display never reaches the width.
|
||||
/// exterior display never reaches the width. On macOS it is not a gate
|
||||
/// but the player window's resize floor while the corner layout is on.
|
||||
static let minHeightForCornerLayout: CGFloat = 600
|
||||
|
||||
/// Tabletop (foldable, hinge partially open): vertical room reserved on
|
||||
|
||||
@@ -789,6 +789,7 @@ final class ExpandedPlayerWindowManager: NSObject {
|
||||
restoreOverlaySizingConstraints(on: window)
|
||||
} else {
|
||||
window.contentResizeIncrements = NSSize(width: 1, height: 1)
|
||||
growToCornerLayoutMinimum(window)
|
||||
}
|
||||
LoggingService.shared.debug(
|
||||
"unlockAspectRatio (corner layout) aspect=\(window.contentAspectRatio) increments=\(window.contentResizeIncrements)",
|
||||
@@ -796,6 +797,45 @@ final class ExpandedPlayerWindowManager: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
/// Smallest window the corner layout fits in: its width threshold (below
|
||||
/// it the layout falls back to stacked), room for the narrowest side
|
||||
/// column next to a video column wide enough for the controls, and
|
||||
/// enough height for the video plus the below-video panel, capped to the
|
||||
/// screen.
|
||||
static func cornerLayoutMinimumSize(for screen: NSScreen?) -> NSSize {
|
||||
let columnsWidth = CornerPlayerLayout<EmptyView>.minColumnWidth
|
||||
+ CornerPlayerLayout<EmptyView>.grabberWidth
|
||||
+ CornerPlayerLayout<EmptyView>.minVideoColumnWidth
|
||||
var size = NSSize(
|
||||
width: max(ExpandedPlayerSheet.minWidthForCornerLayout, columnsWidth),
|
||||
height: ExpandedPlayerSheet.minHeightForCornerLayout
|
||||
)
|
||||
if let visibleFrame = screen?.visibleFrame {
|
||||
size.width = min(size.width, visibleFrame.width)
|
||||
size.height = min(size.height, visibleFrame.height)
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
/// The corner layout resolves from window width only, so it can take over
|
||||
/// a window shorter than it needs; grow the height (keeping the top edge)
|
||||
/// so the floor `windowWillResize(_:to:)` enforces holds from the start.
|
||||
private func growToCornerLayoutMinimum(_ window: NSWindow) {
|
||||
guard !isActivePlayerWindowFullScreen else { return }
|
||||
let screen = window.screen ?? NSScreen.main
|
||||
let minimum = Self.cornerLayoutMinimumSize(for: screen)
|
||||
var frame = window.frame
|
||||
guard frame.width < minimum.width || frame.height < minimum.height else { return }
|
||||
let top = frame.maxY
|
||||
frame.size.width = max(frame.width, minimum.width)
|
||||
frame.size.height = max(frame.height, minimum.height)
|
||||
frame.origin.y = top - frame.height
|
||||
if let screen {
|
||||
frame = constrainToScreen(frame, screen: screen)
|
||||
}
|
||||
window.setFrame(frame, display: true, animate: true)
|
||||
}
|
||||
|
||||
// MARK: - Private Helpers
|
||||
|
||||
private func synchronizeActiveWindowAspectRatio() {
|
||||
@@ -1019,8 +1059,12 @@ extension ExpandedPlayerWindowManager: NSWindowDelegate {
|
||||
// Free resize (corner layout): clamp each axis on its own.
|
||||
// Preserving the proposal's ratio here would widen the window
|
||||
// while the user drags only its bottom edge past the floor.
|
||||
width = max(frameSize.width, 320)
|
||||
height = max(frameSize.height, Self.minHeight)
|
||||
// The floor is the corner layout's own minimum, so a drag
|
||||
// can't squeeze the layout or push it under its width
|
||||
// threshold (which would flip it to stacked mid-drag).
|
||||
let minimum = Self.cornerLayoutMinimumSize(for: window.screen ?? NSScreen.main)
|
||||
width = max(frameSize.width, minimum.width)
|
||||
height = max(frameSize.height, minimum.height)
|
||||
}
|
||||
|
||||
return NSSize(width: width, height: height)
|
||||
|
||||
@@ -330,7 +330,10 @@ struct MacOSPlayerControlsView: View {
|
||||
// AppKit claims drags on the glass capsule as window moves
|
||||
// and the reposition gesture never fires.
|
||||
.background(WindowDragBlockingView())
|
||||
.frame(width: 650)
|
||||
// Never wider than the container: a wider bar frame
|
||||
// widens the whole VStack, and the top bar then
|
||||
// overflows (and is clipped) on both sides.
|
||||
.frame(width: min(650, geometry.size.width))
|
||||
.padding(.bottom, BarDrag.bottomPadding)
|
||||
.offset(barOffset(in: geometry.size))
|
||||
.gesture(barDragGesture(in: geometry.size))
|
||||
|
||||
Reference in New Issue
Block a user