From 80de66b3ad2f06a19121fe7e14e17ba49b4c1268 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Sun, 5 Oct 2025 23:48:38 +0530 Subject: [PATCH] Working but NowPlaying slider not working --- .../Notch/MinimalisticMusicPlayerView.swift | 2 +- .../components/Notch/NotchHomeView.swift | 4 - DynamicIsland/managers/MusicManager.swift | 106 +++++++----------- 3 files changed, 43 insertions(+), 69 deletions(-) diff --git a/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift b/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift index ca52fe1..7cec2a4 100644 --- a/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift +++ b/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift @@ -135,7 +135,7 @@ struct MinimalisticMusicPlayerView: View { // Update slider value based on playback if musicManager.isPlaying { - let timeSinceLastUpdate = date.timeIntervalSince(musicManager.lastUpdated) + let timeSinceLastUpdate = date.timeIntervalSince(musicManager.timestampDate) let estimatedElapsed = musicManager.elapsedTime + (timeSinceLastUpdate * musicManager.playbackRate) return min(estimatedElapsed, musicManager.songDuration) } diff --git a/DynamicIsland/components/Notch/NotchHomeView.swift b/DynamicIsland/components/Notch/NotchHomeView.swift index f284cea..6291f67 100644 --- a/DynamicIsland/components/Notch/NotchHomeView.swift +++ b/DynamicIsland/components/Notch/NotchHomeView.swift @@ -156,8 +156,6 @@ struct MusicControlsView: View { color: musicManager.avgColor, dragging: $dragging, currentDate: timeline.date, - lastUpdated: musicManager.lastUpdated, - ignoreLastUpdated: musicManager.ignoreLastUpdated, timestampDate: musicManager.timestampDate, elapsedTime: musicManager.elapsedTime, playbackRate: musicManager.playbackRate, @@ -285,8 +283,6 @@ struct MusicSliderView: View { var color: NSColor @Binding var dragging: Bool let currentDate: Date - let lastUpdated: Date - let ignoreLastUpdated: Bool let timestampDate: Date let elapsedTime: Double let playbackRate: Double diff --git a/DynamicIsland/managers/MusicManager.swift b/DynamicIsland/managers/MusicManager.swift index 16bb793..48b04e6 100644 --- a/DynamicIsland/managers/MusicManager.swift +++ b/DynamicIsland/managers/MusicManager.swift @@ -34,8 +34,6 @@ class MusicManager: ObservableObject { @Published var albumArt: NSImage = defaultImage @Published var isPlaying = false @Published var album: String = "Self Love" - @Published var lastUpdated: Date = .distantPast - @Published var ignoreLastUpdated = true @Published var isPlayerIdle: Bool = true @Published var animations: DynamicIslandAnimations = .init() @Published var avgColor: NSColor = .white @@ -48,9 +46,15 @@ class MusicManager: ObservableObject { @Published var repeatMode: RepeatMode = .off @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @Published var usingAppIconForArtwork: Bool = false - + private var artworkData: Data? = nil + // Store last values at the time artwork was changed + private var lastArtworkTitle: String = "I'm Handsome" + private var lastArtworkArtist: String = "Me" + private var lastArtworkAlbum: String = "Self Love" + private var lastArtworkBundleIdentifier: String? = nil + @Published var isFlipping: Bool = false private var flipWorkItem: DispatchWorkItem? @@ -82,12 +86,16 @@ class MusicManager: ObservableObject { } deinit { + destroy() + } + + public func destroy() { debounceIdleTask?.cancel() cancellables.removeAll() controllerCancellables.removeAll() flipWorkItem?.cancel() transitionWorkItem?.cancel() - + // Release active controller activeController = nil } @@ -106,35 +114,22 @@ class MusicManager: ObservableObject { case .nowPlaying: // Only create NowPlayingController if not deprecated on this macOS version if !self.isNowPlayingDeprecated { - ignoreLastUpdated = false - if let controller = NowPlayingController() { - // Check if the controller can actually work - if controller.isWorking { - newController = controller - } else { - print("⚠️ NowPlayingController created but resources unavailable, falling back to default") - return nil - } - } else { - return nil - } + newController = NowPlayingController() } else { return nil } case .appleMusic: - ignoreLastUpdated = true newController = AppleMusicController() case .spotify: - ignoreLastUpdated = true newController = SpotifyController() case .youtubeMusic: - ignoreLastUpdated = true newController = YouTubeMusicController() } // Set up state observation for the new controller if let controller = newController { controller.playbackStatePublisher + .receive(on: DispatchQueue.main) .sink { [weak self] state in guard let self = self, self.activeController === controller else { return } @@ -164,19 +159,8 @@ class MusicManager: ObservableObject { } private func setActiveController(_ controller: any MediaControllerProtocol) { - // Transition animation when changing controllers - transitionWorkItem?.cancel() - let workItem = DispatchWorkItem { [weak self] in - self?.isTransitioning = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - self?.isTransitioning = false - } - } - transitionWorkItem = workItem - DispatchQueue.main.async(execute: workItem) - - // Set new active controller - activeController = controller + // Set the active controller + self.activeController = controller // Get current state from active controller if let state = Mirror(reflecting: controller).children.first(where: { $0.label == "playbackState" })?.value as? PlaybackState { @@ -192,7 +176,6 @@ class MusicManager: ObservableObject { // Check for playback state changes (playing/paused) if state.isPlaying != self.isPlaying { - self.lastUpdated = Date() withAnimation(.smooth) { self.isPlaying = state.isPlaying self.updateIdleState(state: state.isPlaying) @@ -218,7 +201,7 @@ class MusicManager: ObservableObject { if artworkChanged, let artwork = state.artwork { self.updateArtwork(artwork) - } else if hasContentChange && state.artwork == nil { + } else if state.artwork == nil { // Try to use app icon if no artwork but track changed if let appIconImage = AppIconAsNSImage(for: state.bundleIdentifier) { self.usingAppIconForArtwork = true @@ -227,6 +210,14 @@ class MusicManager: ObservableObject { } self.artworkData = state.artwork + if artworkChanged || state.artwork == nil { + // Update last artwork change values + self.lastArtworkTitle = state.title + self.lastArtworkArtist = state.artist + self.lastArtworkAlbum = state.album + self.lastArtworkBundleIdentifier = state.bundleIdentifier + } + // Only update sneak peek if there's actual content and something changed if !state.title.isEmpty && !state.artist.isEmpty && state.isPlaying { self.updateSneakPeek() @@ -236,16 +227,18 @@ class MusicManager: ObservableObject { let timeChanged = state.currentTime != self.elapsedTime let durationChanged = state.duration != self.songDuration let playbackRateChanged = state.playbackRate != self.playbackRate + let shuffleChanged = state.isShuffled != self.isShuffled + let repeatModeChanged = state.repeatMode != self.repeatMode - if titleChanged { + if state.title != self.songTitle { self.songTitle = state.title } - if artistChanged { + if state.artist != self.artistName { self.artistName = state.artist } - if albumChanged { + if state.album != self.album { self.album = state.album } @@ -261,30 +254,19 @@ class MusicManager: ObservableObject { self.playbackRate = state.playbackRate } + if shuffleChanged { + self.isShuffled = state.isShuffled + } + if state.bundleIdentifier != self.bundleIdentifier { self.bundleIdentifier = state.bundleIdentifier } - // Update shuffle and repeat state from controller - if state.isShuffled != self.isShuffled { - self.isShuffled = state.isShuffled - } - - if state.repeatMode != self.repeatMode { + if repeatModeChanged { self.repeatMode = state.repeatMode } - // Update timestamp - use current time if state doesn't provide recent timestamp - let stateTimestamp = state.lastUpdated - let now = Date() - - // If the state timestamp is very recent (within 1 second), use it - // Otherwise, use current time for better real-time calculation - if abs(stateTimestamp.timeIntervalSince(now)) < 1.0 { - self.timestampDate = stateTimestamp - } else { - self.timestampDate = now - } + self.timestampDate = state.lastUpdated } // Execute the batch update on the main thread @@ -312,9 +294,9 @@ class MusicManager: ObservableObject { guard let self = self else { return } if let artworkImage = NSImage(data: artworkData) { - DispatchQueue.main.async { - self.usingAppIconForArtwork = false - self.updateAlbumArt(newAlbumArt: artworkImage) + DispatchQueue.main.async { [weak self] in + self?.usingAppIconForArtwork = false + self?.updateAlbumArt(newAlbumArt: artworkImage) } } } @@ -327,14 +309,10 @@ class MusicManager: ObservableObject { } else { debounceIdleTask?.cancel() debounceIdleTask = Task { [weak self] in + guard let self = self else { return } try? await Task.sleep(for: .seconds(Defaults[.waitInterval])) - guard let self = self, !Task.isCancelled else { return } - await MainActor.run { - if self.lastUpdated.timeIntervalSinceNow < -Defaults[.waitInterval] { - withAnimation { - self.isPlayerIdle = !self.isPlaying - } - } + withAnimation { + self.isPlayerIdle = !self.isPlaying } } }