Lagging as Hell

This commit is contained in:
Hariharan Mudaliar 2025-11-21 10:39:26 +05:30
commit 8fb0731ebb
2 changed files with 68 additions and 37 deletions

View file

@ -72,8 +72,8 @@ struct ContentView: View {
@State private var gestureProgress: CGFloat = .zero @State private var gestureProgress: CGFloat = .zero
@State private var isMusicControlWindowVisible = false @State private var isMusicControlWindowVisible = false
@State private var pendingMusicControlSync: DispatchWorkItem? @State private var pendingMusicControlTask: Task<Void, Never>?
@State private var musicControlHideWorkItem: DispatchWorkItem? @State private var musicControlHideTask: Task<Void, Never>?
@State private var musicControlVisibilityDeadline: Date? @State private var musicControlVisibilityDeadline: Date?
@State private var haptics: Bool = false @State private var haptics: Bool = false
@ -1005,7 +1005,9 @@ struct ContentView: View {
if isPlaying { if isPlaying {
clearMusicControlVisibilityDeadline() clearMusicControlVisibilityDeadline()
scheduleMusicControlWindowSync(forceRefresh: true) if vm.notchState == .closed {
scheduleMusicControlWindowSync(forceRefresh: false)
}
} else { } else {
extendMusicControlVisibilityAfterPause() extendMusicControlVisibilityAfterPause()
} }
@ -1027,7 +1029,9 @@ struct ContentView: View {
let deadline = Date().addingTimeInterval(musicControlPauseGrace) let deadline = Date().addingTimeInterval(musicControlPauseGrace)
musicControlVisibilityDeadline = deadline musicControlVisibilityDeadline = deadline
scheduleMusicControlVisibilityCheck(deadline: deadline) scheduleMusicControlVisibilityCheck(deadline: deadline)
scheduleMusicControlWindowSync(forceRefresh: true) if vm.notchState == .closed {
scheduleMusicControlWindowSync(forceRefresh: false)
}
} }
private func clearMusicControlVisibilityDeadline() { private func clearMusicControlVisibilityDeadline() {
@ -1038,24 +1042,31 @@ struct ContentView: View {
private func scheduleMusicControlVisibilityCheck(deadline: Date) { private func scheduleMusicControlVisibilityCheck(deadline: Date) {
cancelMusicControlVisibilityTimer() cancelMusicControlVisibilityTimer()
let workItem = DispatchWorkItem { let interval = max(0, deadline.timeIntervalSinceNow)
musicControlHideWorkItem = nil
musicControlHideTask = Task { @MainActor [interval] in
defer { musicControlHideTask = nil }
if interval > 0 {
let nanoseconds = UInt64(interval * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanoseconds)
}
guard !Task.isCancelled else { return }
if let currentDeadline = musicControlVisibilityDeadline, currentDeadline <= Date() { if let currentDeadline = musicControlVisibilityDeadline, currentDeadline <= Date() {
musicControlVisibilityDeadline = nil musicControlVisibilityDeadline = nil
} }
scheduleMusicControlWindowSync(forceRefresh: true) if vm.notchState == .closed {
scheduleMusicControlWindowSync(forceRefresh: false)
}
} }
musicControlHideWorkItem = workItem
let interval = max(0, deadline.timeIntervalSinceNow)
DispatchQueue.main.asyncAfter(deadline: .now() + interval, execute: workItem)
} }
private func cancelMusicControlVisibilityTimer() { private func cancelMusicControlVisibilityTimer() {
musicControlHideWorkItem?.cancel() musicControlHideTask?.cancel()
musicControlHideWorkItem = nil musicControlHideTask = nil
} }
private func musicControlVisibilityIsActive() -> Bool { private func musicControlVisibilityIsActive() -> Bool {
@ -1089,8 +1100,16 @@ struct ContentView: View {
} }
let syncDelay = max(0, delay) let syncDelay = max(0, delay)
let workItem = DispatchWorkItem { [forceRefresh] in
pendingMusicControlSync = nil pendingMusicControlTask = Task { @MainActor [forceRefresh, syncDelay] in
defer { pendingMusicControlTask = nil }
if syncDelay > 0 {
let nanoseconds = UInt64(syncDelay * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanoseconds)
}
guard !Task.isCancelled else { return }
if shouldShowMusicControlWindow() { if shouldShowMusicControlWindow() {
syncMusicControlWindow(forceRefresh: forceRefresh) syncMusicControlWindow(forceRefresh: forceRefresh)
@ -1098,15 +1117,12 @@ struct ContentView: View {
hideMusicControlWindow() hideMusicControlWindow()
} }
} }
pendingMusicControlSync = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + syncDelay, execute: workItem)
#endif #endif
} }
private func cancelMusicControlWindowSync() { private func cancelMusicControlWindowSync() {
pendingMusicControlSync?.cancel() pendingMusicControlTask?.cancel()
pendingMusicControlSync = nil pendingMusicControlTask = nil
} }
#if os(macOS) #if os(macOS)

View file

@ -33,6 +33,7 @@ class MusicManager: ObservableObject {
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
private var controllerCancellables = Set<AnyCancellable>() private var controllerCancellables = Set<AnyCancellable>()
private var debounceIdleTask: Task<Void, Never>? private var debounceIdleTask: Task<Void, Never>?
@MainActor private var pendingOptimisticPlayState: Bool?
// Helper to check if macOS has removed support for NowPlayingController // Helper to check if macOS has removed support for NowPlayingController
public private(set) var isNowPlayingDeprecated: Bool = false public private(set) var isNowPlayingDeprecated: Bool = false
@ -193,20 +194,38 @@ class MusicManager: ObservableObject {
forceUpdate() forceUpdate()
} }
@MainActor
private func applyPlayState(_ state: Bool, animation: Animation?) {
if let animation {
var transaction = Transaction()
transaction.animation = animation
withTransaction(transaction) {
self.isPlaying = state
}
} else {
self.isPlaying = state
}
self.updateIdleState(state: state)
}
// MARK: - Update Methods // MARK: - Update Methods
@MainActor @MainActor
private func updateFromPlaybackState(_ state: PlaybackState) { private func updateFromPlaybackState(_ state: PlaybackState) {
// Check for playback state changes (playing/paused) // Check for playback state changes (playing/paused)
if state.isPlaying != self.isPlaying { let eventIsPlaying = state.isPlaying
NSLog("Playback state changed: \(state.isPlaying ? "Playing" : "Paused")") let expectedState = pendingOptimisticPlayState
withAnimation(.smooth) { pendingOptimisticPlayState = nil
self.isPlaying = state.isPlaying
self.updateIdleState(state: state.isPlaying)
}
if state.isPlaying && !state.title.isEmpty && !state.artist.isEmpty { if eventIsPlaying != self.isPlaying {
self.updateSneakPeek() let animation: Animation? = (expectedState == eventIsPlaying) ? .smooth(duration: 0.18) : .smooth
} applyPlayState(eventIsPlaying, animation: animation)
} else {
self.updateIdleState(state: eventIsPlaying)
}
if eventIsPlaying && !state.title.isEmpty && !state.artist.isEmpty {
self.updateSneakPeek()
} }
// Check for changes in track metadata using last artwork change values // Check for changes in track metadata using last artwork change values
@ -486,20 +505,16 @@ class MusicManager: ObservableObject {
} }
func togglePlay() { func togglePlay() {
let controller = activeController guard let controller = activeController else { return }
Task { Task {
await MainActor.run { await MainActor.run {
let newState = !isPlaying let newState = !isPlaying
withAnimation(.smooth(duration: 0.18)) { pendingOptimisticPlayState = newState
isPlaying = newState applyPlayState(newState, animation: .smooth(duration: 0.18))
if newState {
isPlayerIdle = false
}
}
} }
await controller?.togglePlay() await controller.togglePlay()
} }
} }