parent
df5bb8c8d4
commit
2eb0232bf7
@ -0,0 +1,133 @@ |
||||
// |
||||
// AppEnvironment.swift |
||||
// LeCountdown |
||||
// |
||||
// Created by Laurent Morvillier on 31/01/2023. |
||||
// |
||||
|
||||
import Foundation |
||||
import ActivityKit |
||||
|
||||
class Conductor : ObservableObject { |
||||
|
||||
static let maestro: Conductor = Conductor() |
||||
|
||||
@UserDefault(Key.dates.rawValue, defaultValue: [:]) static var savedDates: [String : DateInterval] |
||||
|
||||
init() { |
||||
self.notificationDates = Conductor.savedDates |
||||
} |
||||
|
||||
@Published var notificationDates: [String : DateInterval] = [:] { |
||||
didSet { |
||||
Conductor.savedDates = notificationDates |
||||
} |
||||
} |
||||
|
||||
enum Key : String { |
||||
case dates |
||||
} |
||||
|
||||
func startCountdown(_ date: Date, countdown: Countdown) { |
||||
DispatchQueue.main.async { |
||||
let dateInterval = DateInterval(start: Date(), end: date) |
||||
self.notificationDates[countdown.stringId] = dateInterval |
||||
|
||||
self._launchLiveActivity(countdown: countdown, endDate: date) |
||||
} |
||||
} |
||||
|
||||
func notifyUser(countdownId: String, cancel: Bool) { |
||||
// self._playSound(countdownId: countdownId) |
||||
endCountdown(countdownId: countdownId, cancel: cancel) |
||||
} |
||||
|
||||
func endCountdown(countdownId: String, cancel: Bool) { |
||||
DispatchQueue.main.async { |
||||
if !cancel { |
||||
self._recordActivity(countdownId: countdownId) |
||||
} |
||||
self.notificationDates.removeValue(forKey: countdownId) |
||||
|
||||
self._endLiveActivity(countdownId: countdownId) |
||||
} |
||||
} |
||||
|
||||
func cleanup() { |
||||
let now = Date() |
||||
for (key, value) in self.notificationDates { |
||||
if value.end < now { |
||||
self.endCountdown(countdownId: key, cancel: false) |
||||
} |
||||
} |
||||
} |
||||
|
||||
fileprivate func _recordActivity(countdownId: String) { |
||||
let context = PersistenceController.shared.container.viewContext |
||||
if let countdown = context.object(stringId: countdownId) as? Countdown, |
||||
let dateInterval = self.notificationDates[countdownId] { |
||||
do { |
||||
try CoreDataRequests.recordActivity(countdown: countdown, dateInterval: dateInterval) |
||||
} catch { |
||||
print("Could not record activity = \(error)") |
||||
// TODO: show error to user |
||||
} |
||||
} |
||||
} |
||||
|
||||
// MARK: - Live Activity |
||||
|
||||
fileprivate func _launchLiveActivity(countdown: Countdown, endDate: Date) { |
||||
|
||||
if ActivityAuthorizationInfo().areActivitiesEnabled { |
||||
|
||||
let contentState = LaunchWidgetAttributes.ContentState(ended: false) |
||||
let attributes = LaunchWidgetAttributes(id: countdown.stringId, name: countdown.displayName, endDate: endDate) |
||||
let activityContent = ActivityContent(state: contentState, staleDate: endDate.addingTimeInterval(30.0)) |
||||
|
||||
do { |
||||
let liveActivity = try ActivityKit.Activity.request(attributes: attributes, content: activityContent) |
||||
print("Requested a countdown Live Activity \(String(describing: liveActivity.id)).") |
||||
} catch (let error) { |
||||
print("Error requesting countdown Live Activity \(error.localizedDescription).") |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
fileprivate func _liveActivity(countdownId: String) -> ActivityKit.Activity<LaunchWidgetAttributes>? { |
||||
return ActivityKit.Activity<LaunchWidgetAttributes>.activities.first(where: { $0.attributes.id == countdownId } ) |
||||
} |
||||
|
||||
func updateLiveActivities() { |
||||
|
||||
for (countdownId, interval) in self.notificationDates { |
||||
if let activity = self._liveActivity(countdownId: countdownId) { |
||||
|
||||
Task { |
||||
let ended = interval.end < Date() |
||||
let state = LaunchWidgetAttributes.ContentState(ended: ended) |
||||
let content = ActivityContent(state: state, staleDate: interval.end) |
||||
await activity.update(content) |
||||
print("Ending the Live Activity: \(activity.id)") |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
fileprivate func _endLiveActivity(countdownId: String) { |
||||
|
||||
print("Trt to end the Live Activity: \(countdownId)") |
||||
|
||||
if let activity = self._liveActivity(countdownId: countdownId) { |
||||
Task { |
||||
let state = LaunchWidgetAttributes.ContentState(ended: true) |
||||
let content = ActivityContent(state: state, staleDate: Date()) |
||||
await activity.end(content, dismissalPolicy: .immediate) |
||||
print("Ending the Live Activity: \(activity.id)") |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
Binary file not shown.
Loading…
Reference in new issue