mirror of
https://github.com/yattee/yattee.git
synced 2026-07-20 14:22:02 +00:00
Honor Lock Controls on macOS player
The macOS controls stack (MacOSPlayerControlsView + MacOSControlBar) never read playerState.isControlsLocked, so locking via the settings sheet had no effect: buttons, the scrubber, the volume slider, and the AppKit keyboard shortcuts all kept working. When locked, dim and disable transport, volume, the progress bar, queue, the more menu, PiP, the pin/floating toggle, and the title-tap details button; ignore playback keyboard shortcuts (space/arrows/mute) while keeping F/Esc for fullscreen. Settings and Close stay enabled so the user can reopen Settings to unlock.
This commit is contained in:
@@ -58,6 +58,11 @@ struct MacOSControlBar: View {
|
||||
playerState.isTransportDisabled
|
||||
}
|
||||
|
||||
/// Whether the controls are locked (playback buttons/gestures disabled except Settings).
|
||||
private var isLocked: Bool {
|
||||
playerState.isControlsLocked
|
||||
}
|
||||
|
||||
private var playPauseIcon: String {
|
||||
switch playerState.playbackState {
|
||||
case .playing:
|
||||
@@ -133,11 +138,15 @@ struct MacOSControlBar: View {
|
||||
HStack(spacing: 0) {
|
||||
// Left: Volume controls
|
||||
volumeControls
|
||||
.disabled(isLocked)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
|
||||
Spacer()
|
||||
|
||||
// Center: Transport controls
|
||||
transportControls
|
||||
.disabled(isLocked)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
|
||||
Spacer()
|
||||
|
||||
@@ -264,6 +273,7 @@ struct MacOSControlBar: View {
|
||||
.gesture(
|
||||
DragGesture(minimumDistance: 0)
|
||||
.onChanged { value in
|
||||
guard !isLocked else { return }
|
||||
if !isDragging {
|
||||
isDragging = true
|
||||
onInteractionStarted?()
|
||||
@@ -272,6 +282,7 @@ struct MacOSControlBar: View {
|
||||
dragProgress = progress
|
||||
}
|
||||
.onEnded { value in
|
||||
guard !isLocked else { return }
|
||||
isDragging = false
|
||||
let progress = max(0, min(1, value.location.x / geometry.size.width))
|
||||
let seekTime = progress * playerState.duration
|
||||
@@ -288,8 +299,10 @@ struct MacOSControlBar: View {
|
||||
isHoveringProgress = false
|
||||
}
|
||||
}
|
||||
.allowsHitTesting(!isLocked)
|
||||
}
|
||||
.frame(height: 20)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
}
|
||||
|
||||
private func seekPreviewPosition(
|
||||
@@ -338,6 +351,8 @@ struct MacOSControlBar: View {
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
.disabled(isLocked)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
}
|
||||
|
||||
// More (context menu)
|
||||
@@ -351,6 +366,8 @@ struct MacOSControlBar: View {
|
||||
)
|
||||
.menuStyle(.borderlessButton)
|
||||
.fixedSize()
|
||||
.disabled(isLocked)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
}
|
||||
|
||||
// Settings
|
||||
@@ -377,7 +394,8 @@ struct MacOSControlBar: View {
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(MacOSControlButtonStyle())
|
||||
.disabled(!playerState.isPiPPossible)
|
||||
.disabled(isLocked || !playerState.isPiPPossible)
|
||||
.opacity(isLocked ? 0.5 : 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ struct MacOSPlayerControlsView: View {
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(onTitleTap == nil)
|
||||
.disabled(onTitleTap == nil || playerState.isControlsLocked)
|
||||
.opacity(playerState.isControlsLocked ? 0.5 : 1.0)
|
||||
.help(Text("player.controls.info"))
|
||||
}
|
||||
|
||||
@@ -129,6 +130,8 @@ struct MacOSPlayerControlsView: View {
|
||||
.buttonStyle(.plain)
|
||||
.help(Text("player.controls.keepOnTop"))
|
||||
.accessibilityLabel(Text("player.controls.keepOnTop"))
|
||||
.disabled(playerState.isControlsLocked)
|
||||
.opacity(playerState.isControlsLocked ? 0.5 : 1.0)
|
||||
}
|
||||
|
||||
if onClose != nil {
|
||||
@@ -273,6 +276,24 @@ struct MacOSPlayerControlsView: View {
|
||||
// Only handle events when the player window is key (active)
|
||||
guard NSApp.keyWindow != nil else { return event }
|
||||
|
||||
// When controls are locked, ignore playback keys (space/arrows/mute) and
|
||||
// only keep fullscreen (F) and exit-fullscreen (Esc) working.
|
||||
if playerState.isControlsLocked {
|
||||
switch event.keyCode {
|
||||
case 3: // F
|
||||
onToggleFullscreen?()
|
||||
return nil
|
||||
case 53: // Escape
|
||||
if isFullscreen {
|
||||
onToggleFullscreen?()
|
||||
return nil
|
||||
}
|
||||
return event
|
||||
default:
|
||||
return event // Pass through space/arrows/M while locked
|
||||
}
|
||||
}
|
||||
|
||||
// Handle keyboard shortcuts
|
||||
switch event.keyCode {
|
||||
case 49: // Space
|
||||
|
||||
Reference in New Issue
Block a user