// // ServicesMALiveActivityManager.swift // Mobile Music Assistant // import ActivityKit import Foundation import MobileMAShared import OSLog private let logger = Logger(subsystem: "com.musicassistant.mobile", category: "LiveActivity") /// Manages the Now Playing Live Activity lifecycle. @Observable final class MALiveActivityManager { private var currentActivity: Activity? init() { // End any orphaned activities left over from previous sessions or format changes. Task { for orphan in Activity.activities { await orphan.end(dismissalPolicy: .immediate) } } } // MARK: - Public Interface /// Start or update the Live Activity with current playback state. func update(trackTitle: String, artistName: String, artworkData: Data?, isPlaying: Bool, playerName: String) { let state = MusicActivityAttributes.ContentState( trackTitle: trackTitle, artistName: artistName, artworkData: artworkData, isPlaying: isPlaying, playerName: playerName ) if let activity = currentActivity { Task { await activity.update(ActivityContent(state: state, staleDate: nil)) logger.debug("Updated live activity: \(trackTitle)") } } else { start(state: state) } } /// End the Live Activity immediately. func end() { guard let activity = currentActivity else { return } currentActivity = nil Task { await activity.end(dismissalPolicy: .immediate) logger.debug("Ended live activity") } } // MARK: - Private private func start(state: MusicActivityAttributes.ContentState) { guard ActivityAuthorizationInfo().areActivitiesEnabled else { logger.info("Live Activities not enabled on this device") return } do { let activity = try Activity.request( attributes: MusicActivityAttributes(), content: ActivityContent(state: state, staleDate: nil) ) currentActivity = activity logger.info("Started live activity: \(state.trackTitle)") } catch { logger.error("Failed to start live activity: \(error.localizedDescription)") } } }