mirror of
https://github.com/yattee/yattee.git
synced 2026-07-19 22:02:10 +00:00
Show macOS player controls immediately while video is loading
The controls overlay was gated on the player backend existing, but the backend is created only after the video details fetch completes, so the loading phase showed just the thumbnail and spinner with no controls. Drop the backend gate (MPV is the only backend type) and resolve the PiP backend dynamically in the toggle callback. Also make ended/failed states hide controls directly in shouldShowControls instead of relying on catching the state transition, and reset the manual visibility override when a new load starts so controls reappear for the next video.
This commit is contained in:
@@ -796,7 +796,7 @@ extension ExpandedPlayerSheet {
|
||||
closeVideo()
|
||||
},
|
||||
onTogglePiP: {
|
||||
if let mpvBackend = backend as? MPVBackend {
|
||||
if let mpvBackend = playerService.currentBackend as? MPVBackend {
|
||||
mpvBackend.togglePiP()
|
||||
}
|
||||
},
|
||||
@@ -873,9 +873,9 @@ extension ExpandedPlayerSheet {
|
||||
.offset(y: controlsVerticalOffset)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
if let backend = playerService?.currentBackend,
|
||||
backend.backendType == .mpv,
|
||||
let playerState,
|
||||
// No backend gate: the backend is created only after the video
|
||||
// details fetch, and controls should be visible while loading.
|
||||
if let playerState,
|
||||
let playerService,
|
||||
playerState.pipState != .active && !playerState.showDebugOverlay {
|
||||
MacOSPlayerControlsView(
|
||||
@@ -897,7 +897,7 @@ extension ExpandedPlayerSheet {
|
||||
closeVideo()
|
||||
},
|
||||
onTogglePiP: {
|
||||
if let mpvBackend = backend as? MPVBackend {
|
||||
if let mpvBackend = playerService.currentBackend as? MPVBackend {
|
||||
mpvBackend.togglePiP()
|
||||
}
|
||||
},
|
||||
@@ -1142,9 +1142,9 @@ extension ExpandedPlayerSheet {
|
||||
.frame(width: controlsWidth, height: controlsHeight)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
if let backend = playerService?.currentBackend,
|
||||
backend.backendType == .mpv,
|
||||
let playerState,
|
||||
// No backend gate: the backend is created only after the video
|
||||
// details fetch, and controls should be visible while loading.
|
||||
if let playerState,
|
||||
let playerService,
|
||||
playerState.pipState != .active && !playerState.showDebugOverlay {
|
||||
MacOSPlayerControlsView(
|
||||
@@ -1166,7 +1166,7 @@ extension ExpandedPlayerSheet {
|
||||
closeVideo()
|
||||
},
|
||||
onTogglePiP: {
|
||||
if let mpvBackend = backend as? MPVBackend {
|
||||
if let mpvBackend = playerService.currentBackend as? MPVBackend {
|
||||
mpvBackend.togglePiP()
|
||||
}
|
||||
},
|
||||
@@ -1447,7 +1447,7 @@ extension ExpandedPlayerSheet {
|
||||
closeVideo()
|
||||
},
|
||||
onTogglePiP: {
|
||||
if let mpvBackend = backend as? MPVBackend {
|
||||
if let mpvBackend = playerService.currentBackend as? MPVBackend {
|
||||
mpvBackend.togglePiP()
|
||||
}
|
||||
},
|
||||
@@ -1551,9 +1551,9 @@ extension ExpandedPlayerSheet {
|
||||
}
|
||||
}
|
||||
#elseif os(macOS)
|
||||
if let backend = playerService?.currentBackend,
|
||||
backend.backendType == .mpv,
|
||||
let playerState,
|
||||
// No backend gate: the backend is created only after the video
|
||||
// details fetch, and controls should be visible while loading.
|
||||
if let playerState,
|
||||
let playerService,
|
||||
playerState.pipState != .active && !playerState.showDebugOverlay {
|
||||
MacOSPlayerControlsView(
|
||||
@@ -1585,7 +1585,7 @@ extension ExpandedPlayerSheet {
|
||||
closeVideo()
|
||||
},
|
||||
onTogglePiP: {
|
||||
if let mpvBackend = backend as? MPVBackend {
|
||||
if let mpvBackend = playerService.currentBackend as? MPVBackend {
|
||||
mpvBackend.togglePiP()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -89,6 +89,11 @@ struct MacOSPlayerControlsView: View {
|
||||
|
||||
/// Controls visibility - show when hovering, interacting, or paused
|
||||
private var shouldShowControls: Bool {
|
||||
// Ended/failed overlays take over the surface; controls stay hidden
|
||||
// regardless of hover or manual toggles.
|
||||
if playerState.playbackState == .ended || playerState.isFailed {
|
||||
return false
|
||||
}
|
||||
if let showControls {
|
||||
return showControls
|
||||
}
|
||||
@@ -96,11 +101,9 @@ struct MacOSPlayerControlsView: View {
|
||||
if isHovering || isInteracting {
|
||||
return true
|
||||
}
|
||||
// Show when paused, loading, or failed
|
||||
// Show when paused or loading
|
||||
return playerState.playbackState == .paused ||
|
||||
playerState.playbackState == .loading ||
|
||||
playerState.playbackState == .ended ||
|
||||
playerState.isFailed
|
||||
playerState.playbackState == .loading
|
||||
}
|
||||
|
||||
/// Yattee Server URL used by `ChannelAvatarView` for avatar fallback.
|
||||
@@ -295,14 +298,13 @@ struct MacOSPlayerControlsView: View {
|
||||
if newState == .playing && shouldShowControls {
|
||||
startHideTimer()
|
||||
}
|
||||
// Hide controls when video ends (ended overlay takes over)
|
||||
if newState == .ended {
|
||||
showControls = false
|
||||
cancelHideTimer()
|
||||
// A new load resets any manual show/hide override (e.g. hidden
|
||||
// after ended/failed) so controls are visible while loading.
|
||||
if newState == .loading {
|
||||
showControls = nil
|
||||
}
|
||||
// Hide controls when video fails
|
||||
if case .failed = newState {
|
||||
showControls = false
|
||||
// Ended/failed hide via shouldShowControls; just stop the timer.
|
||||
if newState == .ended || playerState.isFailed {
|
||||
cancelHideTimer()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user