diff --git a/DynamicIsland/components/LockScreen/LockScreenMusicPanel.swift b/DynamicIsland/components/LockScreen/LockScreenMusicPanel.swift index 61b6cf0..b869389 100644 --- a/DynamicIsland/components/LockScreen/LockScreenMusicPanel.swift +++ b/DynamicIsland/components/LockScreen/LockScreenMusicPanel.swift @@ -390,6 +390,10 @@ struct LockScreenMusicPanel: View { return .accentColor } } + + private var brandAccentColor: Color { + musicManager.brandAccentColor + } // MARK: - Playback Controls @@ -496,7 +500,7 @@ struct LockScreenMusicPanel: View { icon: "shuffle", size: 18, isActive: musicManager.isShuffled, - activeColor: .red + activeColor: brandAccentColor ) { musicManager.toggleShuffle() } @@ -505,7 +509,7 @@ struct LockScreenMusicPanel: View { icon: repeatIcon, size: 18, isActive: musicManager.repeatMode != .off, - activeColor: .red, + activeColor: brandAccentColor, symbolEffect: .replace ) { musicManager.toggleRepeat() @@ -517,7 +521,7 @@ struct LockScreenMusicPanel: View { icon: enableLyrics ? "quote.bubble.fill" : "quote.bubble", size: 18, isActive: enableLyrics, - activeColor: .accentColor, + activeColor: brandAccentColor, symbolEffect: .replace ) { withAnimation(.spring(response: 0.35, dampingFraction: 0.82)) { @@ -547,14 +551,15 @@ struct LockScreenMusicPanel: View { icon: String, size: CGFloat = 18, isActive: Bool = false, - activeColor: Color = .red, + activeColor: Color? = nil, interaction: PanelControlButton.Interaction = .none, symbolEffect: PanelControlButton.SymbolEffectStyle = .replace, action: @escaping () -> Void ) -> some View { + let resolvedActiveColor = activeColor ?? brandAccentColor let frameSize: CGFloat = isExpanded ? 56 : 32 let iconSize: CGFloat = isExpanded ? max(size, 24) : size - let iconColor = isActive ? activeColor : .white.opacity(0.8) + let iconColor = isActive ? resolvedActiveColor : .white.opacity(0.8) let backgroundOpacity: Double = isActive ? 0.22 : 0.0 return PanelControlButton( diff --git a/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift b/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift index 2de1727..6379b1f 100644 --- a/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift +++ b/DynamicIsland/components/Notch/MinimalisticMusicPlayerView.swift @@ -169,6 +169,10 @@ struct MinimalisticMusicPlayerView: View { coordinator.timerLiveActivityEnabled && timerManager.isExternalTimerActive } + private var brandAccentColor: Color { + musicManager.brandAccentColor + } + private var timerCountdownColor: Color { let baseColor: Color if let presetId = timerManager.activePresetId, @@ -683,19 +687,20 @@ private struct MinimalisticReminderDetailsView: View { icon: String, size: CGFloat = 18, isActive: Bool = false, - activeColor: Color = .red, + activeColor: Color? = nil, pressEffect: MinimalisticSquircircleButton.PressEffect = .none, symbolEffect: MinimalisticSquircircleButton.SymbolEffectStyle = .none, trigger: SkipTrigger? = nil, action: @escaping () -> Void ) -> some View { - MinimalisticSquircircleButton( + let resolvedActiveColor = activeColor ?? brandAccentColor + return MinimalisticSquircircleButton( icon: icon, fontSize: size, fontWeight: .medium, frameSize: CGSize(width: 40, height: 40), cornerRadius: 16, - foregroundColor: isActive ? activeColor : .white.opacity(0.85), + foregroundColor: isActive ? resolvedActiveColor : .white.opacity(0.85), pressEffect: pressEffect, symbolEffectStyle: symbolEffect, externalTriggerToken: trigger?.token, @@ -775,7 +780,7 @@ private struct MinimalisticReminderDetailsView: View { controlButton( icon: enableLyrics ? "quote.bubble.fill" : "quote.bubble", isActive: enableLyrics, - activeColor: Color(nsColor: musicManager.avgColor), + activeColor: brandAccentColor, symbolEffect: .replace ) { enableLyrics.toggle() diff --git a/DynamicIsland/managers/MusicManager.swift b/DynamicIsland/managers/MusicManager.swift index c9c3fd9..241ac7c 100644 --- a/DynamicIsland/managers/MusicManager.swift +++ b/DynamicIsland/managers/MusicManager.swift @@ -845,6 +845,45 @@ class MusicManager: ObservableObject { } } +// MARK: - Media Branding + +extension MusicManager { + var brandAccentColor: Color { + Self.brandAccentColor(for: Defaults[.mediaController], bundleIdentifier: bundleIdentifier) + } + + private static func brandAccentColor(for controller: MediaControllerType, bundleIdentifier: String?) -> Color { + switch controller { + case .appleMusic: + return appleMusicPink + case .spotify: + return spotifyGreen + case .nowPlaying: + if let bundleIdentifier, + let bundleColor = brandAccentColor(forBundleIdentifier: bundleIdentifier) { + return bundleColor + } + fallthrough + case .youtubeMusic: + return .accentColor + } + } + + private static func brandAccentColor(forBundleIdentifier bundleIdentifier: String) -> Color? { + switch bundleIdentifier { + case "com.apple.Music": + return appleMusicPink + case "com.spotify.client": + return spotifyGreen + default: + return nil + } + } + + private static let appleMusicPink = Color(red: 0.999, green: 0.171, blue: 0.331) + private static let spotifyGreen = Color(red: 0.0, green: 0.857, blue: 0.302) +} + // MARK: - Album Art Flip Helper private struct AlbumArtFlipModifier: ViewModifier {