mirror of
https://github.com/yattee/yattee.git
synced 2026-07-20 14:22:02 +00:00
Refine macOS player controls: add queue, more, previous; drop seek/fullscreen buttons
Add Queue (list.bullet), More (VideoContextMenuView ellipsis), and Play Previous buttons to the macOS control bar. Play Previous is shown always and disabled when the queue has no previous item. Remove the skip-back/forward 10s buttons and the fullscreen button from the bar (arrow-key seek and F-key fullscreen shortcuts are retained). Queue reuses the existing cross-platform queue sheet; More reuses the shared VideoContextMenuView (already !os(tvOS)), styled borderless to match the flat bar buttons.
This commit is contained in:
@@ -904,6 +904,9 @@ extension ExpandedPlayerSheet {
|
||||
onPlayNext: {
|
||||
await playerService.playNext()
|
||||
},
|
||||
onPlayPrevious: {
|
||||
await playerService.playPrevious()
|
||||
},
|
||||
onVolumeChanged: { [weak appEnvironment] volume in
|
||||
playerService.currentBackend?.volume = volume
|
||||
appEnvironment?.settingsManager.playerVolume = volume
|
||||
@@ -917,6 +920,9 @@ extension ExpandedPlayerSheet {
|
||||
},
|
||||
onShowSettings: { [self] in
|
||||
showingQualitySheet = true
|
||||
},
|
||||
onShowQueue: { [self] in
|
||||
showingQueueSheet = true
|
||||
}
|
||||
)
|
||||
.frame(width: controlsWidth, height: controlsHeight)
|
||||
@@ -1160,6 +1166,9 @@ extension ExpandedPlayerSheet {
|
||||
onPlayNext: {
|
||||
await playerService.playNext()
|
||||
},
|
||||
onPlayPrevious: {
|
||||
await playerService.playPrevious()
|
||||
},
|
||||
onVolumeChanged: { [weak appEnvironment] volume in
|
||||
playerService.currentBackend?.volume = volume
|
||||
appEnvironment?.settingsManager.playerVolume = volume
|
||||
@@ -1173,6 +1182,9 @@ extension ExpandedPlayerSheet {
|
||||
},
|
||||
onShowSettings: { [self] in
|
||||
showingQualitySheet = true
|
||||
},
|
||||
onShowQueue: { [self] in
|
||||
showingQueueSheet = true
|
||||
}
|
||||
)
|
||||
.frame(width: controlsWidth, height: controlsHeight)
|
||||
@@ -1560,6 +1572,9 @@ extension ExpandedPlayerSheet {
|
||||
onPlayNext: {
|
||||
await playerService.playNext()
|
||||
},
|
||||
onPlayPrevious: {
|
||||
await playerService.playPrevious()
|
||||
},
|
||||
onVolumeChanged: { [weak appEnvironment] volume in
|
||||
playerService.currentBackend?.volume = volume
|
||||
appEnvironment?.settingsManager.playerVolume = volume
|
||||
@@ -1573,6 +1588,9 @@ extension ExpandedPlayerSheet {
|
||||
},
|
||||
onShowSettings: { [self] in
|
||||
showingQualitySheet = true
|
||||
},
|
||||
onShowQueue: { [self] in
|
||||
showingQueueSheet = true
|
||||
}
|
||||
)
|
||||
.frame(width: availableWidth, height: availableHeight)
|
||||
|
||||
@@ -23,9 +23,11 @@ struct MacOSControlBar: View {
|
||||
var isFullscreen: Bool = false
|
||||
var onTogglePiP: (() -> Void)? = nil
|
||||
var onPlayNext: (() async -> Void)? = nil
|
||||
var onPlayPrevious: (() async -> Void)? = nil
|
||||
var onVolumeChanged: ((Float) -> Void)? = nil
|
||||
var onMuteToggled: (() -> Void)? = nil
|
||||
var onShowSettings: (() -> Void)? = nil
|
||||
var onShowQueue: (() -> Void)? = nil
|
||||
/// Whether to show chapter markers on the progress bar (default: true)
|
||||
var showChapters: Bool = true
|
||||
/// SponsorBlock segments to display on the progress bar.
|
||||
@@ -47,8 +49,7 @@ struct MacOSControlBar: View {
|
||||
@State private var isHoveringProgress = false
|
||||
@State private var hoverProgress: Double = 0
|
||||
@State private var playNextTapCount = 0
|
||||
@State private var seekBackwardTrigger = 0
|
||||
@State private var seekForwardTrigger = 0
|
||||
@State private var playPreviousTapCount = 0
|
||||
|
||||
// MARK: - Computed Properties
|
||||
|
||||
@@ -149,19 +150,21 @@ struct MacOSControlBar: View {
|
||||
|
||||
private var transportControls: some View {
|
||||
HStack(spacing: 4) {
|
||||
// Skip backward
|
||||
Button {
|
||||
seekBackwardTrigger += 1
|
||||
Task { await onSeekBackward(10) }
|
||||
} label: {
|
||||
Image(systemName: "10.arrow.trianglehead.counterclockwise")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
.symbolEffect(.rotate.byLayer, options: .speed(2).nonRepeating, value: seekBackwardTrigger)
|
||||
// Play previous (disabled when no previous in queue)
|
||||
if let onPlayPrevious {
|
||||
Button {
|
||||
playPreviousTapCount += 1
|
||||
Task { await onPlayPrevious() }
|
||||
} label: {
|
||||
Image(systemName: "backward.fill")
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
.symbolEffect(.bounce.down.byLayer, options: .nonRepeating, value: playPreviousTapCount)
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
.disabled(!playerState.hasPrevious)
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
.disabled(isTransportDisabled)
|
||||
|
||||
// Play/Pause
|
||||
Button {
|
||||
@@ -177,20 +180,6 @@ struct MacOSControlBar: View {
|
||||
.disabled(isTransportDisabled)
|
||||
.opacity(isTransportDisabled ? 0.3 : 1.0)
|
||||
|
||||
// Skip forward
|
||||
Button {
|
||||
seekForwardTrigger += 1
|
||||
Task { await onSeekForward(10) }
|
||||
} label: {
|
||||
Image(systemName: "10.arrow.trianglehead.clockwise")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
.symbolEffect(.rotate.byLayer, options: .speed(2).nonRepeating, value: seekForwardTrigger)
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
.disabled(isTransportDisabled)
|
||||
|
||||
// Play next (if queue has items)
|
||||
if let onPlayNext, playerState.hasNext {
|
||||
Button {
|
||||
@@ -337,6 +326,32 @@ struct MacOSControlBar: View {
|
||||
|
||||
private var trailingActionControls: some View {
|
||||
HStack(spacing: 4) {
|
||||
// Queue
|
||||
if let onShowQueue {
|
||||
Button {
|
||||
onShowQueue()
|
||||
} label: {
|
||||
Image(systemName: "list.bullet")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
}
|
||||
|
||||
// More (context menu)
|
||||
if let video = playerState.currentVideo {
|
||||
VideoContextMenuView(
|
||||
video: video,
|
||||
accentColor: .primary,
|
||||
buttonSize: 28,
|
||||
buttonBackgroundStyle: .none,
|
||||
theme: .dark
|
||||
)
|
||||
.menuStyle(.borderlessButton)
|
||||
.fixedSize()
|
||||
}
|
||||
|
||||
// Settings
|
||||
if let onShowSettings {
|
||||
Button {
|
||||
@@ -362,19 +377,6 @@ struct MacOSControlBar: View {
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
}
|
||||
|
||||
// Fullscreen
|
||||
if let onToggleFullscreen {
|
||||
Button {
|
||||
onToggleFullscreen()
|
||||
} label: {
|
||||
Image(systemName: isFullscreen ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,11 @@ struct MacOSPlayerControlsView: View {
|
||||
var onClose: (() -> Void)? = nil
|
||||
var onTogglePiP: (() -> Void)? = nil
|
||||
var onPlayNext: (() async -> Void)? = nil
|
||||
var onPlayPrevious: (() async -> Void)? = nil
|
||||
var onVolumeChanged: ((Float) -> Void)? = nil
|
||||
var onMuteToggled: (() -> Void)? = nil
|
||||
var onShowSettings: (() -> Void)? = nil
|
||||
var onShowQueue: (() -> Void)? = nil
|
||||
|
||||
// MARK: - State
|
||||
|
||||
@@ -91,9 +93,11 @@ struct MacOSPlayerControlsView: View {
|
||||
isFullscreen: isFullscreen,
|
||||
onTogglePiP: onTogglePiP,
|
||||
onPlayNext: onPlayNext,
|
||||
onPlayPrevious: onPlayPrevious,
|
||||
onVolumeChanged: onVolumeChanged,
|
||||
onMuteToggled: onMuteToggled,
|
||||
onShowSettings: onShowSettings,
|
||||
onShowQueue: onShowQueue,
|
||||
sponsorSegments: playerState.sponsorSegments,
|
||||
onInteractionStarted: {
|
||||
isInteracting = true
|
||||
|
||||
Reference in New Issue
Block a user