fix: expand window outward for playback queue

This commit is contained in:
2026-10-18 00:37:21 +02:00
parent ce903e2367
commit 1d33f5d572
3 changed files with 31 additions and 4 deletions
+9
View File
@@ -140,6 +140,15 @@ struct SystemPlaybackChecks {
window.isReleasedWhenClosed = false
defer { window.close() }
model.attachWindow(window)
let videoFrame = window.frame
model.showsQueue = true
require(abs(window.frame.width - videoFrame.width - 261) < 0.01 &&
abs(window.frame.height - videoFrame.height) < 0.01,
"opening queue grows window without shrinking video")
model.showsQueue = false
require(abs(window.frame.width - videoFrame.width) < 0.01 &&
abs(window.frame.height - videoFrame.height) < 0.01,
"closing queue restores video-only window size")
model.open(directory.appendingPathComponent("anamorphic.mp4"))
require(model.isBusy && model.perform(.enterCompact) && model.isCompact,
"compact entry is available before native media opening acknowledges")
+2
View File
@@ -57,6 +57,8 @@ Active playback prevents idle system sleep. Local video also keeps the display a
Use the titlebar's **Queue** icon or **View → Show Queue** to show the editable sidebar. **Add to Queue…** and dropping files onto the sidebar append without replacing the queue or interrupting the current item. Drag rows to reorder, remove them with the minus button, and double-click a row to play it. The current item is marked; context menus also offer Play, Remove and Move Up/Down.
In a normal window, showing the queue expands the window outward while preserving the video's size; hiding it removes that extra width. The window shifts left when necessary near the screen's right edge. Fullscreen keeps its fixed bounds.
Playback advances automatically and stops at the end, without wrapping. **Previous Queue Item** and **Next Queue Item** are available in the sidebar and Playback menu and are disabled at their respective ends. Reordering or removing another item does not interrupt playback; removing the current item plays its next neighbor, or stops if there is none. A playback error stays on that item rather than skipping it.
The queue contains local files only and lasts until it is replaced, closed or the app quits; it has no persistence, shuffle, repeat or playlist-file import. Opening a YouTube video or resolved stream clears it. The sidebar is hidden in compact mode; Playback-menu queue navigation remains available. Sidebar appearance, drag/drop interaction and physical-receiver queue transitions still need manual verification.
+20 -4
View File
@@ -32,7 +32,22 @@ final class PlayerModel: ObservableObject {
@Published private(set) var fileIcon: NSImage?
@Published private(set) var commandError: String?
@Published private(set) var queue = PlaybackQueue()
@Published var showsQueue = false
@Published var showsQueue = false {
didSet {
guard showsQueue != oldValue, let window, !isFullScreen,
!isCompact, !compactWindow.isTransitioning else { return }
window.aspectRatio = .zero
var frame = window.frame
frame.size.width += showsQueue ? 261 : -261
if let screen = window.screen?.visibleFrame {
frame.origin.x = max(screen.minX, min(frame.minX, screen.maxX - frame.width))
}
window.setFrame(frame, display: true)
if !showsQueue, state.has_video, state.video_aspect_ratio > 0 {
window.aspectRatio = NSSize(width: state.video_aspect_ratio, height: 1)
}
}
}
private var queuePlaybackRevision: UInt64?
private var queueCompletionHandled = false
private var queueCastDevice: CastDevice?
@@ -968,14 +983,15 @@ final class PlayerModel: ObservableObject {
return
}
let screen = (window.screen ?? NSScreen.main)?.visibleFrame ?? window.frame
let width = min(window.frame.width, screen.width, screen.height * aspect)
let size = NSSize(width: width, height: width / aspect)
let sidebarWidth: CGFloat = showsQueue ? 261 : 0
let width = min(window.frame.width - sidebarWidth, screen.width - sidebarWidth, screen.height * aspect)
let size = NSSize(width: width + sidebarWidth, height: width / aspect)
// ponytail: extreme ratios retain letterboxing; compact controls if exact fitting is needed.
guard size.width >= window.minSize.width, size.height >= window.minSize.height else {
window.aspectRatio = .zero
return
}
window.aspectRatio = NSSize(width: aspect, height: 1)
window.aspectRatio = showsQueue ? .zero : NSSize(width: aspect, height: 1)
let frame = NSRect(
x: min(max(window.frame.midX - size.width / 2, screen.minX), screen.maxX - size.width),
y: min(max(window.frame.midY - size.height / 2, screen.minY), screen.maxY - size.height),