fix: scope control fades to preserve responsive window animation

This commit is contained in:
2026-10-18 18:43:05 +02:00
parent 29a70678a4
commit c2261ad2f0
5 changed files with 87 additions and 30 deletions
+25 -19
View File
@@ -935,9 +935,7 @@ final class PlayerModel: ObservableObject {
guard shouldHideControls else { return }
hideDeadline = nil
keyboardNavigation = false
withAnimation(NSWorkspace.shared.accessibilityDisplayShouldReduceMotion ? nil : .easeIn(duration: 0.25)) {
controlsVisible = false
}
controlsVisible = false
NSCursor.setHiddenUntilMouseMoves(hideCursor && pointerInsideWindow && windowActive && !isCompact)
}
@@ -956,11 +954,7 @@ final class PlayerModel: ObservableObject {
hideControls(hideCursor: false)
return
}
if !controlsVisible {
withAnimation(NSWorkspace.shared.accessibilityDisplayShouldReduceMotion ? nil : .easeOut(duration: 0.25)) {
controlsVisible = true
}
}
if !controlsVisible { controlsVisible = true }
guard shouldHideControls else { return }
hideDeadline = ContinuousClock.now.advanced(by: .milliseconds(2500))
}
@@ -2009,9 +2003,7 @@ private struct PlayerContent: View {
private func toggleYouTubeInput() {
if showsYouTubeInput { youTubeInputFocused = false }
withAnimation(reduceMotion ? nil : .easeInOut(duration: 0.22)) {
showsYouTubeInput.toggle()
}
showsYouTubeInput.toggle()
if showsYouTubeInput { youTubeInputFocused = true }
}
@@ -2024,6 +2016,10 @@ private struct PlayerContent: View {
? nil : .easeInOut(duration: CompactWindowController.transitionDuration)
}
private var controlsVisibilityAnimation: Animation? {
reduceMotion ? nil : (model.controlsVisible ? .easeOut(duration: 0.25) : .easeIn(duration: 0.25))
}
private var bufferedStatus: String? {
model.bufferedRange.map {
let behind = max(0, model.state.position - $0.lowerBound)
@@ -2092,7 +2088,9 @@ private struct PlayerContent: View {
.frame(height: 32)
.foregroundStyle(Color(SunsetPalette.text))
.onHover(perform: model.setTitleHovered)
.opacity(model.controlsVisible ? 1 : 0)
.animation(controlsVisibilityAnimation) { content in
content.opacity(model.controlsVisible ? 1 : 0)
}
.allowsHitTesting(model.controlsVisible)
.accessibilityHidden(!model.controlsVisible)
}
@@ -2188,7 +2186,9 @@ private struct PlayerContent: View {
.foregroundStyle(Color(SunsetPalette.text))
.background(PlayerGlass(cornerRadius: 10).clipShape(RoundedRectangle(cornerRadius: 10)))
.onHover(perform: model.setControlsHovered)
.opacity(model.controlsVisible ? 1 : 0)
.animation(controlsVisibilityAnimation) { content in
content.opacity(model.controlsVisible ? 1 : 0)
}
.allowsHitTesting(model.controlsVisible)
.accessibilityHidden(!model.controlsVisible)
}
@@ -2413,9 +2413,11 @@ private struct PlayerContent: View {
.clipShape(RoundedRectangle(cornerRadius: 12)).allowsHitTesting(false))
.frame(maxWidth: geometry.size.width * 0.8)
.padding(.horizontal, 8)
.padding(.bottom, model.controlsVisible
? (model.isCompact ? compactControlHeight + 20 : 110)
: (model.isCompact ? 12 : 24))
.animation(controlsVisibilityAnimation) { content in
content.padding(.bottom, model.controlsVisible
? (model.isCompact ? compactControlHeight + 20 : 110)
: (model.isCompact ? 12 : 24))
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.allowsHitTesting(false)
}
@@ -2520,7 +2522,7 @@ private struct PlayerContent: View {
.overlay(RoundedRectangle(cornerRadius: 8)
.strokeBorder(Color(SunsetPalette.outline), lineWidth: 0.5)
.allowsHitTesting(false))
.transition(.opacity)
.transition(.opacity.animation(reduceMotion ? nil : .easeInOut(duration: 0.22)))
.disabled(!model.canOpen)
}
Text("Drop a media file or YouTube link here")
@@ -2578,7 +2580,9 @@ private struct PlayerContent: View {
.padding(8)
.foregroundStyle(Color(SunsetPalette.text))
.onHover(perform: model.setTitleHovered)
.opacity(model.controlsVisible ? 1 : 0)
.animation(controlsVisibilityAnimation) { content in
content.opacity(model.controlsVisible ? 1 : 0)
}
.allowsHitTesting(model.controlsVisible)
.accessibilityHidden(!model.controlsVisible)
compactControls
@@ -2607,7 +2611,9 @@ private struct PlayerContent: View {
height: controlHeight * min(1, (geometry.size.width - 32) / 440))
.onGeometryChange(for: CGSize.self) { $0.size } action: { controlSize = $0 }
.position(controllerPosition(in: geometry.size))
.opacity(model.controlsVisible ? 1 : 0)
.animation(controlsVisibilityAnimation) { content in
content.opacity(model.controlsVisible ? 1 : 0)
}
.animation(compactChromeAnimation) { content in
content.opacity(model.isCompact ? 0 : 1)
}