|
|
@@ -2,14 +2,21 @@ import CoreData
|
|
|
import Foundation
|
|
|
import UIKit
|
|
|
|
|
|
+/// Handles intent requests related to temporary presets, such as fetching, enacting, and canceling temp targets.
|
|
|
final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
+ /// Enum representing possible errors related to temporary presets.
|
|
|
enum TempPresetsError: Error {
|
|
|
case noTempTargetFound
|
|
|
case noDurationDefined
|
|
|
}
|
|
|
|
|
|
+ /// Tracks whether the intent execution was successful.
|
|
|
private var intentSuccess: Bool = false
|
|
|
|
|
|
+ /// Fetches and processes all available temporary target presets.
|
|
|
+ ///
|
|
|
+ /// - Returns: An array of `TempPreset` objects.
|
|
|
+ /// - Throws: An error if fetching or processing fails.
|
|
|
func fetchAndProcessTempTargets() async throws -> [TempPreset] {
|
|
|
// Fetch all Temp Target Presets via TempTargetStorage
|
|
|
let allTempTargetPresetsIDs = try await tempTargetsStorage.fetchForTempTargetPresets()
|
|
|
@@ -40,6 +47,10 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Fetches temporary target presets based on the given identifiers.
|
|
|
+ ///
|
|
|
+ /// - Parameter uuid: An array of preset IDs to fetch.
|
|
|
+ /// - Returns: An array of `TempPreset` objects.
|
|
|
func fetchIDs(_ uuid: [TempPreset.ID]) async -> [TempPreset] {
|
|
|
await coredataContext.perform {
|
|
|
let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
|
|
|
@@ -69,6 +80,10 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Fetches the `NSManagedObjectID` for a given `TempPreset`.
|
|
|
+ ///
|
|
|
+ /// - Parameter preset: The `TempPreset` to find.
|
|
|
+ /// - Returns: The `NSManagedObjectID` of the temp target if found, otherwise `nil`.
|
|
|
private func fetchTempTargetID(_ preset: TempPreset) async -> NSManagedObjectID? {
|
|
|
let fetchRequest: NSFetchRequest<TempTargetStored> = TempTargetStored.fetchRequest()
|
|
|
fetchRequest.predicate = NSPredicate(format: "id == %@", preset.id.uuidString)
|
|
|
@@ -86,6 +101,10 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Enacts a temporary target preset by updating Core Data and notifying relevant components.
|
|
|
+ ///
|
|
|
+ /// - Parameter preset: The `TempPreset` to apply.
|
|
|
+ /// - Returns: `true` if successfully enacted, otherwise `false`.
|
|
|
@MainActor func enactTempTarget(_ preset: TempPreset) async -> Bool {
|
|
|
debug(.default, "Enacting Temp Target: \(preset.name)")
|
|
|
intentSuccess = false
|
|
|
@@ -94,7 +113,7 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
|
|
|
backgroundTaskID = startBackgroundTask(withName: "TempTarget Enact")
|
|
|
|
|
|
- // Disable previous overrides if necessary, without starting a background task
|
|
|
+ // Disable previous temp targets if necessary, without starting a background task
|
|
|
await disableAllActiveTempTargets(shouldStartBackgroundTask: false)
|
|
|
|
|
|
do {
|
|
|
@@ -110,34 +129,11 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
|
|
|
if viewContext.hasChanges {
|
|
|
debug(.default, "Saving changes...")
|
|
|
-
|
|
|
try viewContext.save()
|
|
|
|
|
|
- // Update State variables in TempTargetView
|
|
|
+ // Update state variables
|
|
|
Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
|
|
|
|
|
|
- // Await the notification
|
|
|
- debug(.default, "Waiting for notification...")
|
|
|
-
|
|
|
- guard let tempTargetDate = tempTargetObject.date, let tempTarget = tempTargetObject.target,
|
|
|
- let tempTargetDuration = tempTargetObject.duration else { return false }
|
|
|
-
|
|
|
- let tempTargetToStoreAsJSON = TempTarget(
|
|
|
- name: tempTargetObject.name,
|
|
|
- createdAt: tempTargetDate,
|
|
|
- targetTop: tempTarget as Decimal,
|
|
|
- targetBottom: tempTarget as Decimal,
|
|
|
- duration: tempTargetDuration as Decimal,
|
|
|
- enteredBy: TempTarget.local,
|
|
|
- reason: TempTarget.custom,
|
|
|
- isPreset: tempTargetObject.isPreset,
|
|
|
- enabled: tempTargetObject.enabled,
|
|
|
- halfBasalTarget: tempTargetObject.halfBasalTarget as Decimal?
|
|
|
- )
|
|
|
-
|
|
|
- // Save the temp targets to JSON so that they get used by oref
|
|
|
- tempTargetsStorage.saveTempTargetsToStorage([tempTargetToStoreAsJSON])
|
|
|
-
|
|
|
await awaitNotification(.didUpdateTempTargetConfiguration)
|
|
|
|
|
|
debug(.default, "Notification received, continuing...")
|
|
|
@@ -150,9 +146,8 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
|
|
|
return intentSuccess
|
|
|
} catch {
|
|
|
- // Handle error and ensure background task is ended
|
|
|
debugPrint(
|
|
|
- "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to enact Temp Targett with error: \(error.localizedDescription)"
|
|
|
+ "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to enact Temp Target with error: \(error.localizedDescription)"
|
|
|
)
|
|
|
|
|
|
endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Enact")
|
|
|
@@ -162,54 +157,52 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Cancels an active temporary target.
|
|
|
func cancelTempTarget() async {
|
|
|
await disableAllActiveTempTargets(shouldStartBackgroundTask: true)
|
|
|
tempTargetsStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date().addingTimeInterval(-1))])
|
|
|
}
|
|
|
|
|
|
+ /// Disables all active temporary targets.
|
|
|
+ ///
|
|
|
+ /// - Parameter shouldStartBackgroundTask: A flag indicating whether a background task should be started.
|
|
|
@MainActor func disableAllActiveTempTargets(shouldStartBackgroundTask: Bool = true) async {
|
|
|
var backgroundTaskID: UIBackgroundTaskIdentifier?
|
|
|
|
|
|
if shouldStartBackgroundTask {
|
|
|
- // Start background task
|
|
|
backgroundTaskID = .invalid
|
|
|
backgroundTaskID = startBackgroundTask(withName: "TempTarget Cancel")
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
- // Get NSManagedObjectID of all active temp Targets
|
|
|
+ // Fetch active temp targets
|
|
|
let ids = try await tempTargetsStorage.loadLatestTempTargetConfigurations(fetchLimit: 0)
|
|
|
- // Fetch existing OverrideStored objects
|
|
|
let results = try ids.compactMap { id in
|
|
|
try self.viewContext.existingObject(with: id) as? TempTargetStored
|
|
|
}
|
|
|
|
|
|
- // Return early if no results
|
|
|
guard !results.isEmpty else {
|
|
|
debug(.default, "No active temp targets to cancel... returning early")
|
|
|
|
|
|
if var backgroundTaskID = backgroundTaskID {
|
|
|
- debug(.default, "Ending background task for temp target cancel")
|
|
|
endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- // Create TempTargetRunStored entry
|
|
|
- // Use the first temp target to create a new TempTargetRunStored entry
|
|
|
+ // Create a new `TempTargetRunStored` entry
|
|
|
if let canceledTempTarget = results.first {
|
|
|
let newTempTargetRunStored = TempTargetRunStored(context: viewContext)
|
|
|
newTempTargetRunStored.id = UUID()
|
|
|
newTempTargetRunStored.name = canceledTempTarget.name
|
|
|
newTempTargetRunStored.startDate = canceledTempTarget.date ?? .distantPast
|
|
|
newTempTargetRunStored.endDate = Date()
|
|
|
- newTempTargetRunStored
|
|
|
- .target = canceledTempTarget.target ?? 0
|
|
|
+ newTempTargetRunStored.target = canceledTempTarget.target ?? 0
|
|
|
newTempTargetRunStored.tempTarget = canceledTempTarget
|
|
|
newTempTargetRunStored.isUploadedToNS = false
|
|
|
}
|
|
|
|
|
|
- // Disable all override except the one with overrideID
|
|
|
+ // Disable all temp targets
|
|
|
for tempTargetToCancel in results {
|
|
|
tempTargetToCancel.enabled = false
|
|
|
tempTargetToCancel.isUploadedToNS = false
|
|
|
@@ -217,32 +210,16 @@ final class TempPresetsIntentRequest: BaseIntentsRequest {
|
|
|
|
|
|
if viewContext.hasChanges {
|
|
|
try viewContext.save()
|
|
|
-
|
|
|
- // Update State variables in OverrideView
|
|
|
Foundation.NotificationCenter.default.post(name: .willUpdateTempTargetConfiguration, object: nil)
|
|
|
}
|
|
|
|
|
|
- // Await the notification
|
|
|
- // Await the notification
|
|
|
- debug(.default, "Waiting for notification...")
|
|
|
-
|
|
|
await awaitNotification(.didUpdateOverrideConfiguration)
|
|
|
|
|
|
- debug(.default, "Notification received, continuing...")
|
|
|
-
|
|
|
if var backgroundTaskID = backgroundTaskID {
|
|
|
- debug(.default, "Ending background task for temp target cancel")
|
|
|
endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
|
|
|
}
|
|
|
} catch {
|
|
|
- debugPrint(
|
|
|
- "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to disable active Temp Targets with error: \(error.localizedDescription)"
|
|
|
- )
|
|
|
-
|
|
|
- if var backgroundTaskID = backgroundTaskID {
|
|
|
- debug(.default, "Ending background task for temp target cancel")
|
|
|
- endBackgroundTaskSafely(&backgroundTaskID, taskName: "TempTarget Cancel")
|
|
|
- }
|
|
|
+ debugPrint("Failed to disable active Temp Targets with error: \(error.localizedDescription)")
|
|
|
}
|
|
|
}
|
|
|
}
|