diff --git a/Yattee/Views/Player/macOS/MacOSControlBar.swift b/Yattee/Views/Player/macOS/MacOSControlBar.swift index 53e26653..2a9f49e2 100644 --- a/Yattee/Views/Player/macOS/MacOSControlBar.swift +++ b/Yattee/Views/Player/macOS/MacOSControlBar.swift @@ -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) } } } diff --git a/Yattee/Views/Player/macOS/MacOSPlayerControlsView.swift b/Yattee/Views/Player/macOS/MacOSPlayerControlsView.swift index eed02ca3..a86ca666 100644 --- a/Yattee/Views/Player/macOS/MacOSPlayerControlsView.swift +++ b/Yattee/Views/Player/macOS/MacOSPlayerControlsView.swift @@ -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