|
|
@@ -7,7 +7,6 @@ import UIKit
|
|
|
|
|
|
@available(iOS 16.2, *) private struct ActiveActivity {
|
|
|
let activity: Activity<LiveActivityAttributes>
|
|
|
- let startDate: Date
|
|
|
|
|
|
/// Determines if the current activity needs to be recreated.
|
|
|
///
|
|
|
@@ -23,10 +22,21 @@ import UIKit
|
|
|
@unknown default:
|
|
|
return true
|
|
|
}
|
|
|
- return -startDate.timeIntervalSinceNow > TimeInterval(60 * 60)
|
|
|
+ return -activity.attributes.startDate.timeIntervalSinceNow > TimeInterval(60 * 60)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+final class LiveActivityData: ObservableObject {
|
|
|
+ /// Determination data used to update live activity state.
|
|
|
+ @Published var determination: DeterminationData?
|
|
|
+ /// Array of glucose readings fetched from persistent storage.
|
|
|
+ @Published var glucoseFromPersistence: [GlucoseData]?
|
|
|
+ /// The current override data (if any).
|
|
|
+ @Published var override: OverrideData?
|
|
|
+ /// The widget items displayed within the live activity.
|
|
|
+ @Published var widgetItems: [LiveActivityAttributes.LiveActivityItem]?
|
|
|
+}
|
|
|
+
|
|
|
/// A service managing live activity updates and state management.
|
|
|
///
|
|
|
/// This class handles the creation, update, and termination of live activities based on various data sources
|
|
|
@@ -51,18 +61,10 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
settingsManager.settings
|
|
|
}
|
|
|
|
|
|
- /// Determination data used to update live activity state.
|
|
|
- var determination: DeterminationData?
|
|
|
/// The current active live activity.
|
|
|
private var currentActivity: ActiveActivity?
|
|
|
- /// The most recent glucose reading.
|
|
|
- private var latestGlucose: GlucoseData?
|
|
|
- /// Array of glucose readings fetched from persistent storage.
|
|
|
- var glucoseFromPersistence: [GlucoseData]?
|
|
|
- /// The current override data (if any).
|
|
|
- var override: OverrideData?
|
|
|
- /// The widget items displayed within the live activity.
|
|
|
- var widgetItems: [LiveActivityAttributes.LiveActivityItem]?
|
|
|
+
|
|
|
+ private var data = LiveActivityData()
|
|
|
|
|
|
/// A Core Data task context.
|
|
|
let context = CoreDataStack.shared.newTaskContext()
|
|
|
@@ -85,11 +87,16 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
systemEnabled = activityAuthorizationInfo.areActivitiesEnabled
|
|
|
injectServices(resolver)
|
|
|
setupNotifications()
|
|
|
- registerSubscribers()
|
|
|
registerHandler()
|
|
|
monitorForLiveActivityAuthorizationChanges()
|
|
|
- setupGlucoseArray()
|
|
|
broadcaster.register(SettingsObserver.self, observer: self)
|
|
|
+ data.objectWillChange.sink { [weak self] in
|
|
|
+ Task { @MainActor in
|
|
|
+ // by the time this runs, the object change is done, so we see the new data here
|
|
|
+ await self?.pushCurrentContent()
|
|
|
+ }
|
|
|
+ }.store(in: &subscriptions)
|
|
|
+ loadInitialData()
|
|
|
}
|
|
|
|
|
|
/// Sets up application notifications that trigger live activity updates when the app state changes.
|
|
|
@@ -98,18 +105,18 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
notificationCenter
|
|
|
.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self] _ in
|
|
|
Task { @MainActor in
|
|
|
- self?.forceActivityUpdate()
|
|
|
+ await self?.pushCurrentContent()
|
|
|
}
|
|
|
}
|
|
|
notificationCenter
|
|
|
.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in
|
|
|
Task { @MainActor in
|
|
|
- self?.forceActivityUpdate()
|
|
|
+ await self?.pushCurrentContent()
|
|
|
}
|
|
|
}
|
|
|
notificationCenter.addObserver(
|
|
|
self,
|
|
|
- selector: #selector(handleLiveActivityOrderChange),
|
|
|
+ selector: #selector(loadWidgetItems),
|
|
|
name: .liveActivityOrderDidChange,
|
|
|
object: nil
|
|
|
)
|
|
|
@@ -120,143 +127,75 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
/// This method triggers an update to the live activity content state based on the new settings.
|
|
|
/// - Parameter _: The updated `TrioSettings`.
|
|
|
func settingsDidChange(_: TrioSettings) {
|
|
|
- Task {
|
|
|
- await updateContentState(determination)
|
|
|
+ Task { @MainActor in
|
|
|
+ await self.pushCurrentContent()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Registers handlers for Core Data changes related to overrides, glucose readings, and determinations.
|
|
|
private func registerHandler() {
|
|
|
coreDataPublisher?.filteredByEntityName("OverrideStored").sink { [weak self] _ in
|
|
|
- guard let self = self else { return }
|
|
|
- self.overridesDidUpdate()
|
|
|
+ Task { await self?.loadOverrides() }
|
|
|
}.store(in: &subscriptions)
|
|
|
|
|
|
coreDataPublisher?.filteredByEntityName("GlucoseStored").sink { [weak self] _ in
|
|
|
- guard let self = self else { return }
|
|
|
- self.setupGlucoseArray()
|
|
|
+ Task { await self?.loadGlucose() }
|
|
|
}.store(in: &subscriptions)
|
|
|
|
|
|
coreDataPublisher?.filteredByEntityName("OrefDetermination")
|
|
|
.debounce(for: .seconds(2), scheduler: DispatchQueue.global(qos: .utility))
|
|
|
.sink { [weak self] _ in
|
|
|
- guard let self = self else { return }
|
|
|
- self.cobOrIobDidUpdate()
|
|
|
+ Task { await self?.loadDetermination() }
|
|
|
}.store(in: &subscriptions)
|
|
|
}
|
|
|
|
|
|
- /// Registers subscribers for updates from the glucose storage.
|
|
|
- private func registerSubscribers() {
|
|
|
- glucoseStorage.updatePublisher
|
|
|
- .receive(on: queue)
|
|
|
- .sink { [weak self] _ in
|
|
|
- guard let self = self else { return }
|
|
|
- self.setupGlucoseArray()
|
|
|
- }
|
|
|
- .store(in: &subscriptions)
|
|
|
- }
|
|
|
-
|
|
|
/// Fetches and maps new determination data and updates the live activity content state.
|
|
|
- private func cobOrIobDidUpdate() {
|
|
|
- Task { @MainActor in
|
|
|
- do {
|
|
|
- self.determination = try await fetchAndMapDetermination()
|
|
|
- if let determination = determination {
|
|
|
- await self.updateContentState(determination)
|
|
|
- }
|
|
|
- } catch {
|
|
|
- debug(
|
|
|
- .default,
|
|
|
- "\(DebuggingIdentifiers.failed) failed to fetch and map determination: \(error)"
|
|
|
- )
|
|
|
- }
|
|
|
+ private func loadDetermination() async {
|
|
|
+ do {
|
|
|
+ data.determination = try await fetchAndMapDetermination()
|
|
|
+ } catch {
|
|
|
+ debug(
|
|
|
+ .default,
|
|
|
+ "[LiveActivityManager] \(DebuggingIdentifiers.failed) failed to fetch and map determination: \(error)"
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Fetches and maps override data and updates the live activity content state.
|
|
|
- private func overridesDidUpdate() {
|
|
|
- Task { @MainActor in
|
|
|
- do {
|
|
|
- self.override = try await fetchAndMapOverride()
|
|
|
- if let determination = determination {
|
|
|
- await self.updateContentState(determination)
|
|
|
- }
|
|
|
- } catch {
|
|
|
- debug(.default, "\(DebuggingIdentifiers.failed) failed to fetch and map override: \(error)")
|
|
|
- }
|
|
|
+ private func loadOverrides() async {
|
|
|
+ do {
|
|
|
+ data.override = try await fetchAndMapOverride()
|
|
|
+ } catch {
|
|
|
+ debug(.default, "[LiveActivityManager] \(DebuggingIdentifiers.failed) failed to fetch and map override: \(error)")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Handles changes to the live activity order.
|
|
|
///
|
|
|
/// Loads widget items from user defaults and triggers an update to the live activity order.
|
|
|
- @objc private func handleLiveActivityOrderChange() {
|
|
|
- Task {
|
|
|
- self.widgetItems = UserDefaults.standard.loadLiveActivityOrderFromUserDefaults() ?? LiveActivityAttributes
|
|
|
- .LiveActivityItem.defaultItems
|
|
|
- await self.updateLiveActivityOrder()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Updates the live activity content state based on new determination or override data.
|
|
|
- ///
|
|
|
- /// - Parameter update: An object representing new `DeterminationData` or `OverrideData`.
|
|
|
- @MainActor private func updateContentState<T>(_ update: T) async {
|
|
|
- guard let latestGlucose = latestGlucose else {
|
|
|
- return
|
|
|
- }
|
|
|
- var content: LiveActivityAttributes.ContentState?
|
|
|
-
|
|
|
- widgetItems = UserDefaults.standard.loadLiveActivityOrderFromUserDefaults() ?? LiveActivityAttributes
|
|
|
+ @objc private func loadWidgetItems() {
|
|
|
+ data.widgetItems = UserDefaults.standard.loadLiveActivityOrderFromUserDefaults() ?? LiveActivityAttributes
|
|
|
.LiveActivityItem.defaultItems
|
|
|
+ }
|
|
|
|
|
|
- if let determination = update as? DeterminationData {
|
|
|
- content = LiveActivityAttributes.ContentState(
|
|
|
- new: latestGlucose,
|
|
|
- prev: latestGlucose,
|
|
|
- units: settings.units,
|
|
|
- chart: glucoseFromPersistence ?? [],
|
|
|
- settings: settings,
|
|
|
- determination: determination,
|
|
|
- override: override,
|
|
|
- widgetItems: widgetItems
|
|
|
- )
|
|
|
- } else if let override = update as? OverrideData {
|
|
|
- content = LiveActivityAttributes.ContentState(
|
|
|
- new: latestGlucose,
|
|
|
- prev: latestGlucose,
|
|
|
- units: settings.units,
|
|
|
- chart: glucoseFromPersistence ?? [],
|
|
|
- settings: settings,
|
|
|
- determination: determination,
|
|
|
- override: override,
|
|
|
- widgetItems: widgetItems
|
|
|
+ /// Sets up the array of glucose data from persistent storage and triggers an update to the live activity.
|
|
|
+ private func loadGlucose() async {
|
|
|
+ do {
|
|
|
+ data.glucoseFromPersistence = try await fetchAndMapGlucose()
|
|
|
+ } catch {
|
|
|
+ debug(
|
|
|
+ .default,
|
|
|
+ "[LiveActivityManager] \(DebuggingIdentifiers.failed) failed to fetch glucose with error: \(error)"
|
|
|
)
|
|
|
}
|
|
|
-
|
|
|
- if let content = content {
|
|
|
- await pushUpdate(content)
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- /// Triggers an update of the live activity order.
|
|
|
- ///
|
|
|
- /// This method refreshes the activity's content state to reflect any changes in the widget order.
|
|
|
- @MainActor private func updateLiveActivityOrder() async {
|
|
|
+ private func loadInitialData() {
|
|
|
Task {
|
|
|
- await updateContentState(determination)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Sets up the array of glucose data from persistent storage and triggers an update to the live activity.
|
|
|
- private func setupGlucoseArray() {
|
|
|
- Task { @MainActor in
|
|
|
- do {
|
|
|
- self.glucoseFromPersistence = try await fetchAndMapGlucose()
|
|
|
- glucoseDidUpdate(glucoseFromPersistence ?? [])
|
|
|
- } catch {
|
|
|
- debug(.default, "\(DebuggingIdentifiers.failed) failed to fetch glucose with error: \(error)")
|
|
|
- }
|
|
|
+ await self.loadGlucose()
|
|
|
+ await self.loadOverrides()
|
|
|
+ await self.loadDetermination()
|
|
|
+ self.loadWidgetItems()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -273,22 +212,6 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Forces an update to the live activity.
|
|
|
- ///
|
|
|
- /// If live activities are enabled and the current activity requires recreation, this method triggers a new glucose update.
|
|
|
- /// Otherwise, it ends the current live activity.
|
|
|
- @MainActor private func forceActivityUpdate() {
|
|
|
- if settings.useLiveActivity {
|
|
|
- if currentActivity?.needsRecreation() ?? true {
|
|
|
- glucoseDidUpdate(glucoseFromPersistence ?? [])
|
|
|
- }
|
|
|
- } else {
|
|
|
- Task {
|
|
|
- await self.endActivity()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/// Pushes an update to the live activity with the specified content state.
|
|
|
///
|
|
|
/// If an existing activity requires recreation or is outdated, this method ends it and starts a new one.
|
|
|
@@ -296,6 +219,23 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
///
|
|
|
/// - Parameter state: The new content state to push to the live activity.
|
|
|
@MainActor private func pushUpdate(_ state: LiveActivityAttributes.ContentState) async {
|
|
|
+ if !settings.useLiveActivity || !systemEnabled {
|
|
|
+ await endActivity()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if currentActivity == nil {
|
|
|
+ // try to restore an existing activity
|
|
|
+ currentActivity = Activity<LiveActivityAttributes>.activities
|
|
|
+ .max { $0.attributes.startDate < $1.attributes.startDate }.map {
|
|
|
+ ActiveActivity(activity: $0)
|
|
|
+ }
|
|
|
+
|
|
|
+ if let currentActivity {
|
|
|
+ debug(.default, "[LiveActivityManager] Restored live activity: \(currentActivity.activity.id)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// End all unknown activities except the current one
|
|
|
for unknownActivity in Activity<LiveActivityAttributes>.activities
|
|
|
.filter({ self.currentActivity?.activity.id != $0.id })
|
|
|
@@ -303,22 +243,14 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
await unknownActivity.end(nil, dismissalPolicy: .immediate)
|
|
|
}
|
|
|
|
|
|
- // Defensive: capture the current activity at function start
|
|
|
- let activityAtStart = currentActivity
|
|
|
-
|
|
|
- if let currentActivity = activityAtStart {
|
|
|
+ if let currentActivity {
|
|
|
if currentActivity.needsRecreation(), UIApplication.shared.applicationState == .active {
|
|
|
debug(.default, "[LiveActivityManager] Ending current activity for recreation: \(currentActivity.activity.id)")
|
|
|
await endActivity()
|
|
|
// After endActivity(), currentActivity is guaranteed to be nil
|
|
|
// No recursive task, but explicitly restart
|
|
|
- if self.currentActivity == nil {
|
|
|
- debug(.default, "[LiveActivityManager] Re-pushing update after recreation.")
|
|
|
- await pushUpdate(state)
|
|
|
- } else {
|
|
|
- debug(.default, "[LiveActivityManager] Warning: currentActivity was not nil after endActivity!")
|
|
|
- }
|
|
|
- return
|
|
|
+ debug(.default, "[LiveActivityManager] Re-pushing update after recreation.")
|
|
|
+ await pushUpdate(state)
|
|
|
} else {
|
|
|
let content = ActivityContent(
|
|
|
state: state,
|
|
|
@@ -345,7 +277,7 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
date: Date.now,
|
|
|
highGlucose: settings.high,
|
|
|
lowGlucose: settings.low,
|
|
|
- target: determination?.target ?? 100 as Decimal,
|
|
|
+ target: data.determination?.target ?? 100 as Decimal,
|
|
|
glucoseColorScheme: settings.glucoseColorScheme.rawValue,
|
|
|
detailedViewState: nil,
|
|
|
isInitialState: true
|
|
|
@@ -358,7 +290,7 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
content: expired,
|
|
|
pushType: nil
|
|
|
)
|
|
|
- currentActivity = ActiveActivity(activity: activity, startDate: Date.now)
|
|
|
+ currentActivity = ActiveActivity(activity: activity)
|
|
|
debug(.default, "[LiveActivityManager] Created new activity: \(activity.id)")
|
|
|
|
|
|
// Update the newly created activity with actual data
|
|
|
@@ -367,11 +299,11 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
staleDate: Date.now.addingTimeInterval(5 * 60)
|
|
|
)
|
|
|
await activity.update(updateContent)
|
|
|
- debug(.default, "[LiveActivityManager] Updated new activity with actual data")
|
|
|
+ debug(.default, "[LiveActivityManager] Set initial content for new activity: \(activity.id)")
|
|
|
} catch {
|
|
|
debug(
|
|
|
.default,
|
|
|
- "\(#file): Error creating new activity: \(error)"
|
|
|
+ "[LiveActivityManager]: Error creating new activity: \(error)"
|
|
|
)
|
|
|
// Reset currentActivity on error to allow retry on next update
|
|
|
currentActivity = nil
|
|
|
@@ -381,25 +313,20 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
|
|
|
/// Ends the current live activity and ensures that all unknown activities are terminated.
|
|
|
private func endActivity() async {
|
|
|
- debug(.default, "Ending all live activities...")
|
|
|
+ debug(.default, "[LiveActivityManager] Ending all live activities...")
|
|
|
|
|
|
if let currentActivity {
|
|
|
- debug(.default, "Ending current activity: \(currentActivity.activity.id)")
|
|
|
+ debug(.default, "[LiveActivityManager] Ending current activity: \(currentActivity.activity.id)")
|
|
|
await currentActivity.activity.end(nil, dismissalPolicy: .immediate)
|
|
|
self.currentActivity = nil
|
|
|
}
|
|
|
|
|
|
- for activity in Activity<LiveActivityAttributes>.activities {
|
|
|
- debug(.default, "Ending lingering activity: \(activity.id)")
|
|
|
- await activity.end(nil, dismissalPolicy: .immediate)
|
|
|
- }
|
|
|
-
|
|
|
for unknownActivity in Activity<LiveActivityAttributes>.activities {
|
|
|
- debug(.default, "Ending unknown activity: \(unknownActivity.id)")
|
|
|
+ debug(.default, "[LiveActivityManager] Ending unknown activity: \(unknownActivity.id)")
|
|
|
await unknownActivity.end(nil, dismissalPolicy: .immediate)
|
|
|
}
|
|
|
|
|
|
- debug(.default, "All live activities ended.")
|
|
|
+ debug(.default, "[LiveActivityManager] All live activities ended.")
|
|
|
}
|
|
|
|
|
|
/// Restarts the live activity from a Live Activity Intent.
|
|
|
@@ -407,91 +334,50 @@ final class LiveActivityManager: Injectable, ObservableObject, SettingsObserver
|
|
|
/// This method mimics xdrip's `restartActivityFromLiveActivityIntent()` behavior by verifying that a valid content state exists,
|
|
|
/// ending the current live activity, and starting a new one using the current state.
|
|
|
@MainActor func restartActivityFromLiveActivityIntent() async {
|
|
|
- guard let latestGlucose = latestGlucose,
|
|
|
- let determination = determination
|
|
|
- else {
|
|
|
- debug(.default, "Cannot restart live activity because required persistent state is not available. Fetching data...")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- guard let contentState = LiveActivityAttributes.ContentState(
|
|
|
- new: latestGlucose,
|
|
|
- prev: latestGlucose,
|
|
|
- units: settings.units,
|
|
|
- chart: glucoseFromPersistence ?? [],
|
|
|
- settings: settings,
|
|
|
- determination: determination,
|
|
|
- override: override,
|
|
|
- widgetItems: widgetItems
|
|
|
- ) else {
|
|
|
- debug(.default, "Cannot restart live activity because content state cannot be created")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
await endActivity()
|
|
|
|
|
|
while (currentActivity != nil && currentActivity!.activity.activityState != .ended) || Activity<LiveActivityAttributes>
|
|
|
.activities.contains(where: { $0.activityState != .ended })
|
|
|
{
|
|
|
- debug(.default, "Waiting for Live Activity to end...")
|
|
|
+ debug(.default, "[LiveActivityManager] Waiting for Live Activity to end...")
|
|
|
try? await Task.sleep(nanoseconds: 200_000_000) // 0.2s sleep
|
|
|
}
|
|
|
|
|
|
// Add additional delay to ensure iOS has fully cleaned up the previous activity
|
|
|
- debug(.default, "Waiting additional time for iOS to clean up...")
|
|
|
+ debug(.default, "[LiveActivityManager] Waiting additional time for iOS to clean up...")
|
|
|
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1s additional delay
|
|
|
|
|
|
- Task { @MainActor in
|
|
|
- await self.pushUpdate(contentState)
|
|
|
- }
|
|
|
- debug(.default, "Restarted Live Activity from LiveActivityIntent (via iOS Shortcut)")
|
|
|
+ await pushCurrentContent()
|
|
|
+
|
|
|
+ debug(.default, "[LiveActivityManager] Restarted Live Activity from LiveActivityIntent (via iOS Shortcut)")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@available(iOS 16.2, *)
|
|
|
extension LiveActivityManager {
|
|
|
- /// Updates the live activity when new glucose data is available.
|
|
|
- ///
|
|
|
- /// This function adjusts the live activity content based on new glucose readings and triggers an update to the live activity.
|
|
|
- /// - Parameter glucose: An array of `GlucoseData` objects.
|
|
|
- @MainActor func glucoseDidUpdate(_ glucose: [GlucoseData]) {
|
|
|
- guard settings.useLiveActivity else {
|
|
|
- if currentActivity != nil {
|
|
|
- Task {
|
|
|
- await self.endActivity()
|
|
|
- }
|
|
|
- }
|
|
|
+ @MainActor func pushCurrentContent() async {
|
|
|
+ guard let glucose = data.glucoseFromPersistence, let bg = glucose.first else {
|
|
|
+ debug(.default, "[LiveActivityManager] pushCurrentContent: no current glucose data available")
|
|
|
return
|
|
|
}
|
|
|
+ let prevGlucose = data.glucoseFromPersistence?.dropFirst().first
|
|
|
|
|
|
- if glucose.count > 1 {
|
|
|
- latestGlucose = glucose.dropFirst().first
|
|
|
- }
|
|
|
- defer {
|
|
|
- self.latestGlucose = glucose.first
|
|
|
- }
|
|
|
-
|
|
|
- guard let bg = glucose.first else {
|
|
|
+ guard let determination = data.determination else {
|
|
|
+ debug(.default, "[LiveActivityManager] pushCurrentContent: no determination available")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- if let determination = determination {
|
|
|
- let content = LiveActivityAttributes.ContentState(
|
|
|
- new: bg,
|
|
|
- prev: latestGlucose,
|
|
|
- units: settings.units,
|
|
|
- chart: glucose,
|
|
|
- settings: settings,
|
|
|
- determination: determination,
|
|
|
- override: override,
|
|
|
- widgetItems: widgetItems
|
|
|
- )
|
|
|
+ let content = LiveActivityAttributes.ContentState(
|
|
|
+ new: bg,
|
|
|
+ prev: prevGlucose,
|
|
|
+ units: settings.units,
|
|
|
+ chart: glucose,
|
|
|
+ settings: settings,
|
|
|
+ determination: determination,
|
|
|
+ override: data.override,
|
|
|
+ widgetItems: data.widgetItems
|
|
|
+ )
|
|
|
|
|
|
- if let content = content {
|
|
|
- Task {
|
|
|
- await self.pushUpdate(content)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ await pushUpdate(content)
|
|
|
}
|
|
|
}
|