mirror of
https://github.com/yattee/yattee.git
synced 2026-07-19 22:02:10 +00:00
Fix unclickable error/replay overlays in macOS 15 player window
On macOS 15 Sequoia the error overlay buttons (Retry / Play Next / error details) and the ended-state replay buttons did nothing when clicked, while working fine on macOS 26. Layered event logging showed the click reached SwiftUI but always landed on MacOSPlayerControlsView, which covers the whole video surface above those overlays: on Sequoia a view with .onContinuousHover participates in click hit-testing across its full frame, so even with its inner layers hit-disabled the controls view formed an invisible wall. Drop the whole controls view out of hit-testing while the ended/failed overlays own the surface. Also keep the traffic-light buttons visible on the ended/failed overlays: they used to fade out with the controls and nothing could bring them back, leaving the error screen with no way to close the window.
This commit is contained in:
@@ -116,6 +116,14 @@ struct MacOSPlayerControlsView: View {
|
||||
playerState.playbackState == .loading
|
||||
}
|
||||
|
||||
/// Traffic-light visibility. Follows the controls, except on the
|
||||
/// ended/failed overlays: those hide the controls entirely (no hover
|
||||
/// brings them back), so the window buttons must stay up or the error /
|
||||
/// replay screen can't be closed.
|
||||
private var shouldShowTrafficLights: Bool {
|
||||
shouldShowControls || playerState.playbackState == .ended || playerState.isFailed
|
||||
}
|
||||
|
||||
/// Whether the hosting window is in native fullscreen. The `isFullscreen`
|
||||
/// parameter covers the sheet-overlay flow, but its key-window half isn't
|
||||
/// reactive — check the tracked host window directly as well.
|
||||
@@ -341,7 +349,6 @@ struct MacOSPlayerControlsView: View {
|
||||
}
|
||||
}
|
||||
.onChange(of: shouldShowControls) { _, visible in
|
||||
setTrafficLightsVisible(visible)
|
||||
// Hidden bars stop hit-testing, so their `onHover(false)` may
|
||||
// never arrive — clear the flags or they'd stay stuck true and
|
||||
// block every future idle-hide.
|
||||
@@ -350,11 +357,14 @@ struct MacOSPlayerControlsView: View {
|
||||
isHoveringBottomBar = false
|
||||
}
|
||||
}
|
||||
.onChange(of: shouldShowTrafficLights) { _, visible in
|
||||
setTrafficLightsVisible(visible)
|
||||
}
|
||||
.onChange(of: hostWindow) { oldWindow, _ in
|
||||
// Restore the old window's chrome when re-parented (sheet <->
|
||||
// floating window), then sync the new window to the current state.
|
||||
if let oldWindow { applyTrafficLightAlpha(1, to: oldWindow, animated: false) }
|
||||
setTrafficLightsVisible(shouldShowControls, animated: false)
|
||||
setTrafficLightsVisible(shouldShowTrafficLights, animated: false)
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: NSWindow.willEnterFullScreenNotification)) { note in
|
||||
// In fullscreen the system owns titlebar visibility (hover at the
|
||||
@@ -365,7 +375,7 @@ struct MacOSPlayerControlsView: View {
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: NSWindow.didExitFullScreenNotification)) { note in
|
||||
if let window = note.object as? NSWindow, window === hostWindow {
|
||||
setTrafficLightsVisible(shouldShowControls, animated: false)
|
||||
setTrafficLightsVisible(shouldShowTrafficLights, animated: false)
|
||||
// Pointer hiding is a fullscreen-only behavior; make sure it's
|
||||
// back even before the next mouse move.
|
||||
NSCursor.setHiddenUntilMouseMoves(false)
|
||||
@@ -410,6 +420,13 @@ struct MacOSPlayerControlsView: View {
|
||||
.onReceive(NotificationCenter.default.publisher(for: .playerControlsPresetsDidChange)) { _ in
|
||||
Task { await loadLayout() }
|
||||
}
|
||||
// The ended/failed overlays own the surface — their replay/retry/next
|
||||
// buttons live in the layer BELOW this view. The inner layers already
|
||||
// opt out of hit-testing in those states, but on macOS 15 the hover
|
||||
// tracking on this view makes its full frame participate in click
|
||||
// hit-testing anyway, silently swallowing every click aimed at those
|
||||
// buttons. Drop the whole view out of hit-testing while they're up.
|
||||
.allowsHitTesting(playerState.playbackState != .ended && !playerState.isFailed)
|
||||
}
|
||||
|
||||
// MARK: - Control Bar Drag
|
||||
|
||||
Reference in New Issue
Block a user