Explorar o código

Add carbs shortcuts

Add shortcuts to add carbs with a specific date and fat/protein information.
Pierre L %!s(int64=2) %!d(string=hai) anos
pai
achega
0a47ccf0a6

+ 16 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -305,6 +305,8 @@
 		CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8BCB0C37DEB5EC377B9612 /* BasalProfileEditorRootView.swift */; };
 		CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */; };
 		CD78BB94E43B249D60CC1A1B /* NotificationsConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22963BD06A9C83959D4914E4 /* NotificationsConfigRootView.swift */; };
+		CE1856F52ADC4858007E39C7 /* AddCarbPresetIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1856F42ADC4858007E39C7 /* AddCarbPresetIntent.swift */; };
+		CE1856F72ADC4869007E39C7 /* CarbPresetIntentRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1856F62ADC4869007E39C7 /* CarbPresetIntentRequest.swift */; };
 		CE2FAD38297D69E1001A872C /* ShareClient.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE398D1A297D69A900DF218F /* ShareClient.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */; };
 		CE398D16297C9D1D00DF218F /* dexcomSourceG7.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE398D15297C9D1D00DF218F /* dexcomSourceG7.swift */; };
@@ -820,6 +822,8 @@
 		C377490C77661D75E8C50649 /* ManualTempBasalRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManualTempBasalRootView.swift; sourceTree = "<group>"; };
 		C8D1A7CA8C10C4403D4BBFA7 /* BolusDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusDataFlow.swift; sourceTree = "<group>"; };
 		CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawFetchedProfile.swift; sourceTree = "<group>"; };
+		CE1856F42ADC4858007E39C7 /* AddCarbPresetIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCarbPresetIntent.swift; sourceTree = "<group>"; };
+		CE1856F62ADC4869007E39C7 /* CarbPresetIntentRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbPresetIntentRequest.swift; sourceTree = "<group>"; };
 		CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloodGlucoseExtensions.swift; sourceTree = "<group>"; };
 		CE398D012977349800DF218F /* CryptoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoKit.framework; path = System/Library/Frameworks/CryptoKit.framework; sourceTree = SDKROOT; };
 		CE398D15297C9D1D00DF218F /* dexcomSourceG7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dexcomSourceG7.swift; sourceTree = "<group>"; };
@@ -2058,9 +2062,19 @@
 			path = Bolus;
 			sourceTree = "<group>";
 		};
+		CE1856F32ADC4835007E39C7 /* Carbs */ = {
+			isa = PBXGroup;
+			children = (
+				CE1856F42ADC4858007E39C7 /* AddCarbPresetIntent.swift */,
+				CE1856F62ADC4869007E39C7 /* CarbPresetIntentRequest.swift */,
+			);
+			path = Carbs;
+			sourceTree = "<group>";
+		};
 		CE7CA3422A064973004BE681 /* Shortcuts */ = {
 			isa = PBXGroup;
 			children = (
+				CE1856F32ADC4835007E39C7 /* Carbs */,
 				CE7CA3432A064973004BE681 /* AppShortcuts.swift */,
 				CE7CA3442A064973004BE681 /* BaseIntentsRequest.swift */,
 				CE7CA3452A064973004BE681 /* TempPresets */,
@@ -2590,6 +2604,7 @@
 				388358C825EEF6D200E024B2 /* BasalProfileEntry.swift in Sources */,
 				3811DE0B25C9D32F00A708ED /* BaseView.swift in Sources */,
 				3811DE3225C9D49500A708ED /* HomeDataFlow.swift in Sources */,
+				CE1856F52ADC4858007E39C7 /* AddCarbPresetIntent.swift in Sources */,
 				38569347270B5DFB0002C50D /* CGMType.swift in Sources */,
 				3821ED4C25DD18BA00BC42AD /* Constants.swift in Sources */,
 				384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */,
@@ -2664,6 +2679,7 @@
 				CE7CA3532A064973004BE681 /* tempPresetIntent.swift in Sources */,
 				D6DEC113821A7F1056C4AA1E /* NightscoutConfigDataFlow.swift in Sources */,
 				38E98A3025F52FF700C0CED0 /* Config.swift in Sources */,
+				CE1856F72ADC4869007E39C7 /* CarbPresetIntentRequest.swift in Sources */,
 				BD2B464E0745FBE7B79913F4 /* NightscoutConfigProvider.swift in Sources */,
 				9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */,
 				38A43598262E0E4900E80935 /* FetchAnnouncementsManager.swift in Sources */,

+ 7 - 0
FreeAPS/Sources/Shortcuts/AppShortcuts.swift

@@ -17,5 +17,12 @@ import Foundation
                 "\(.applicationName) state"
             ]
         )
+        AppShortcut(
+            intent: AddCarbPresentIntent(),
+            phrases: [
+                "Add carbs in \(.applicationName)",
+                "\(.applicationName) allows to add carbs"
+            ]
+        )
     }
 }

+ 3 - 0
FreeAPS/Sources/Shortcuts/BaseIntentsRequest.swift

@@ -10,6 +10,9 @@ import Swinject
     @Injected() var settingsManager: SettingsManager!
     @Injected() var storage: TempTargetsStorage!
     @Injected() var fileStorage: FileStorage!
+    @Injected() var carbsStorage: CarbsStorage!
+    @Injected() var glucoseStorage: GlucoseStorage!
+    @Injected() var apsManager: APSManager!
 
     let resolver: Resolver
 

+ 94 - 0
FreeAPS/Sources/Shortcuts/Carbs/AddCarbPresetIntent.swift

@@ -0,0 +1,94 @@
+import AppIntents
+import Foundation
+import Intents
+import Swinject
+
+@available(iOS 16.0,*) struct AddCarbPresentIntent: AppIntent {
+    // Title of the action in the Shortcuts app
+    static var title: LocalizedStringResource = "Add carbs"
+
+    // Description of the action in the Shortcuts app
+    static var description = IntentDescription("Allow to add carbs in iAPS.")
+
+    internal var carbRequest: CarbPresetIntentRequest
+
+    init() {
+        carbRequest = CarbPresetIntentRequest()
+        dateAdded = Date()
+    }
+
+    @Parameter(
+        title: "Quantity Carbs",
+        description: "Quantity of carbs in g",
+        controlStyle: .field,
+        inclusiveRange: (lowerBound: 0, upperBound: 200),
+        requestValueDialog: IntentDialog("What is the numeric value of the carb to add")
+    ) var carbQuantity: Double?
+
+    @Parameter(
+        title: "Quantity fat",
+        description: "Quantity of fat in g",
+        default: 0.0,
+        inclusiveRange: (0, 200)
+    ) var fatQuantity: Double
+
+    @Parameter(
+        title: "Quantity Protein",
+        description: "Quantity of Protein in g",
+        default: 0.0,
+        inclusiveRange: (0, 200)
+    ) var proteinQuantity: Double
+
+    @Parameter(
+        title: "Date",
+        description: "Date of adding"
+    ) var dateAdded: Date
+
+    @Parameter(
+        title: "Confirm Before applying",
+        description: "If toggled, you will need to confirm before applying",
+        default: true
+    ) var confirmBeforeApplying: Bool
+
+    static var parameterSummary: some ParameterSummary {
+        When(\.$confirmBeforeApplying, .equalTo, true, {
+            Summary("Applying \(\.$carbQuantity) at \(\.$dateAdded)") {
+                \.$fatQuantity
+                \.$proteinQuantity
+                \.$confirmBeforeApplying
+            }
+        }, otherwise: {
+            Summary("Immediately applying \(\.$carbQuantity) at \(\.$dateAdded)") {
+                \.$fatQuantity
+                \.$proteinQuantity
+                \.$confirmBeforeApplying
+            }
+        })
+    }
+
+    @MainActor func perform() async throws -> some ProvidesDialog {
+        do {
+            let quantityCarbs: Double
+            if let cq = carbQuantity {
+                quantityCarbs = cq
+            } else {
+                quantityCarbs = try await $carbQuantity.requestValue("How many carbs ?")
+            }
+
+            let quantityCarbsName = quantityCarbs.toString()
+            if confirmBeforeApplying {
+                try await requestConfirmation(
+                    result: .result(dialog: "Are you sure to add \(quantityCarbsName) g of carbs ?")
+                )
+            }
+
+            let finalQuantityCarbsDisplay = try carbRequest.addCarbs(quantityCarbs, fatQuantity, proteinQuantity, dateAdded)
+            return .result(
+                dialog: IntentDialog(stringLiteral: finalQuantityCarbsDisplay)
+            )
+
+        } catch {
+            throw error
+        }
+    }
+}

+ 36 - 0
FreeAPS/Sources/Shortcuts/Carbs/CarbPresetIntentRequest.swift

@@ -0,0 +1,36 @@
+import CoreData
+import Foundation
+
+@available(iOS 16.0,*) final class CarbPresetIntentRequest: BaseIntentsRequest {
+    func addCarbs(_ quantityCarbs: Double, _ quantityFat: Double, _ quantityProtein: Double, _ dateAdded: Date) throws -> String {
+        guard quantityCarbs >= 0.0 || quantityFat >= 0.0 || quantityProtein >= 0.0 else {
+            return "no adding carbs in iAPS"
+        }
+
+        let carbs = min(Decimal(quantityCarbs), settingsManager.settings.maxCarbs)
+
+        carbsStorage.storeCarbs(
+            [CarbsEntry(
+                id: UUID().uuidString,
+                createdAt: dateAdded,
+                carbs: carbs,
+                fat: Decimal(quantityFat),
+                protein: Decimal(quantityProtein),
+                note: "add with shortcuts",
+                enteredBy: CarbsEntry.manual,
+                isFPU: false, fpuID: nil
+            )]
+        )
+        var resultDisplay: String
+        resultDisplay = "\(carbs) g carbs"
+        if quantityFat > 0.0 {
+            resultDisplay = "\(resultDisplay) and \(quantityFat) g fats"
+        }
+        if quantityProtein > 0.0 {
+            resultDisplay = "\(resultDisplay) and \(quantityProtein) g protein"
+        }
+        let dateName = dateAdded.formatted()
+        resultDisplay = "\(resultDisplay) added at \(dateName)"
+        return resultDisplay
+    }
+}

+ 0 - 4
FreeAPS/Sources/Shortcuts/State/StateIntentRequest.swift

@@ -54,10 +54,6 @@ enum StateIntentError: Error {
 }
 
 @available(iOS 16.0, *) final class StateIntentRequest: BaseIntentsRequest {
-    @Injected() private var glucoseStorage: GlucoseStorage!
-    @Injected() private var carbsStorage: CarbsStorage!
-    @Injected() private var apsManager: APSManager!
-
     func getLastBG() throws -> (dateGlucose: Date, glucose: String, trend: String, delta: String) {
         let glucose = glucoseStorage.recent()
         guard let lastGlucose = glucose.last, let glucoseValue = lastGlucose.glucose else { throw StateIntentError.NoBG }