فهرست منبع

Merge branch 'core-data-sync-trio' of github.com:dnzxy/Trio-dev into tempTargets

Deniz Cengiz 1 سال پیش
والد
کامیت
31c129b321

+ 1 - 0
FreeAPS/Sources/APS/Storage/CarbsStorage.swift

@@ -405,6 +405,7 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
                     enteredBy: CarbsEntry.local,
                     bolus: nil,
                     insulin: nil,
+                    notes: result.note,
                     carbs: Decimal(result.carbs),
                     fat: Decimal(result.fat),
                     protein: Decimal(result.protein),

+ 26 - 0
FreeAPS/Sources/APS/Storage/GlucoseStorage.swift

@@ -10,6 +10,7 @@ import Swinject
 protocol GlucoseStorage {
     var updatePublisher: AnyPublisher<Void, Never> { get }
     func storeGlucose(_ glucose: [BloodGlucose])
+    func addManualGlucose(glucose: Int)
     func isGlucoseDataFresh(_ glucoseDate: Date?) -> Bool
     func syncDate() -> Date
     func filterTooFrequentGlucose(_ glucose: [BloodGlucose], at: Date) -> [BloodGlucose]
@@ -173,6 +174,31 @@ final class BaseGlucoseStorage: GlucoseStorage, Injectable {
         }
     }
 
+    func addManualGlucose(glucose: Int) {
+        coredataContext.perform {
+            let newItem = GlucoseStored(context: self.coredataContext)
+            newItem.id = UUID()
+            newItem.date = Date()
+            newItem.glucose = Int16(glucose)
+            newItem.isManual = true
+            newItem.isUploadedToNS = false
+            newItem.isUploadedToHealth = false
+            newItem.isUploadedToTidepool = false
+
+            do {
+                guard self.coredataContext.hasChanges else { return }
+                try self.coredataContext.save()
+
+                // Glucose subscribers already listen to the update publisher, so call here to update glucose-related data.
+                self.updateSubject.send(())
+            } catch let error as NSError {
+                debugPrint(
+                    "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save manual glucose to Core Data with error: \(error)"
+                )
+            }
+        }
+    }
+
     func isGlucoseDataFresh(_ glucoseDate: Date?) -> Bool {
         guard let glucoseDate = glucoseDate else { return false }
         return glucoseDate > Date().addingTimeInterval(-6 * 60)

+ 20 - 0
FreeAPS/Sources/Application/FreeAPSApp.swift

@@ -62,12 +62,32 @@ import Swinject
             .default,
             "Trio Started: v\(Bundle.main.releaseVersionNumber ?? "")(\(Bundle.main.buildVersionNumber ?? "")) [buildDate: \(BuildDetails.default.buildDate())] [buildExpires: \(BuildDetails.default.calculateExpirationDate())]"
         )
+
+        // Configure global appearance for UITabBar
+        configureTabBarAppearance()
+
+        // Load services
         loadServices()
 
         // Clear the persistentHistory and the NSManagedObjects that are older than 90 days every time the app starts
         cleanupOldData()
     }
 
+    // Function to configure global tab bar appearance
+    private func configureTabBarAppearance() {
+        let appearance = UITabBarAppearance()
+        appearance.configureWithDefaultBackground()
+
+        // Blur the background
+        appearance.backgroundEffect = UIBlurEffect(style: .systemChromeMaterial)
+
+        // Keep background semi-transparent
+        appearance.backgroundColor = UIColor.clear
+
+        UITabBar.appearance().standardAppearance = appearance
+        UITabBar.appearance().scrollEdgeAppearance = appearance
+    }
+
     var body: some Scene {
         WindowGroup {
             Main.RootView(resolver: resolver)

+ 2 - 0
FreeAPS/Sources/Models/Battery.swift

@@ -10,4 +10,6 @@ struct Battery: JSON {
 enum BatteryState: String, JSON {
     case normal
     case low
+    case unknown
+    case error
 }

+ 1 - 1
FreeAPS/Sources/Models/CarbsEntry.swift

@@ -33,7 +33,7 @@ extension CarbsEntry {
         case carbs
         case fat
         case protein
-        case note
+        case note = "notes"
         case enteredBy
         case isFPU
         case fpuID

+ 1 - 0
FreeAPS/Sources/Models/NightscoutStatus.swift

@@ -24,6 +24,7 @@ struct NSPumpStatus: JSON {
 struct Uploader: JSON {
     let batteryVoltage: Decimal?
     let battery: Int
+    let isCharging: Bool?
 }
 
 struct NightscoutTimevalue: JSON {

+ 14 - 27
FreeAPS/Sources/Modules/DataTable/DataTableStateModel.swift

@@ -21,7 +21,6 @@ extension DataTable {
         var glucose: [Glucose] = []
         var meals: [Treatment] = []
         var manualGlucose: Decimal = 0
-        var maxBolus: Decimal = 0
         var waitForSuggestion: Bool = false
 
         var insulinEntryDeleted: Bool = false
@@ -31,8 +30,8 @@ extension DataTable {
 
         override func subscribe() {
             units = settingsManager.settings.units
-            maxBolus = provider.pumpSettings().maxBolus
             broadcaster.register(DeterminationObserver.self, observer: self)
+            broadcaster.register(SettingsObserver.self, observer: self)
         }
 
         func isGlucoseDataFresh(_ glucoseDate: Date?) -> Bool {
@@ -90,6 +89,14 @@ extension DataTable {
             }
         }
 
+        func addManualGlucose() {
+            // Always save value in mg/dL
+            let glucose = units == .mmolL ? manualGlucose.asMgdL : manualGlucose
+            let glucoseAsInt = Int(glucose)
+
+            glucoseStorage.addManualGlucose(glucose: glucoseAsInt)
+        }
+
         // Carb and FPU deletion from history
         /// - **Parameter**: NSManagedObjectID to be able to transfer the object safely from one thread to another thread
         func invokeCarbDeletionTask(_ treatmentObjectID: NSManagedObjectID) {
@@ -239,37 +246,17 @@ extension DataTable {
                 }
             }
         }
-
-        func addManualGlucose() {
-            let glucose = units == .mmolL ? manualGlucose.asMgdL : manualGlucose
-            let glucoseAsInt = Int(glucose)
-
-            // save to core data
-            coredataContext.perform {
-                let newItem = GlucoseStored(context: self.coredataContext)
-                newItem.id = UUID()
-                newItem.date = Date()
-                newItem.glucose = Int16(glucoseAsInt)
-                newItem.isManual = true
-                newItem.isUploadedToNS = false
-                newItem.isUploadedToHealth = false
-                newItem.isUploadedToTidepool = false
-
-                do {
-                    guard self.coredataContext.hasChanges else { return }
-                    try self.coredataContext.save()
-                } catch {
-                    print(error.localizedDescription)
-                }
-            }
-        }
     }
 }
 
-extension DataTable.StateModel: DeterminationObserver {
+extension DataTable.StateModel: DeterminationObserver, SettingsObserver {
     func determinationDidUpdate(_: Determination) {
         DispatchQueue.main.async {
             self.waitForSuggestion = false
         }
     }
+
+    func settingsDidChange(_: FreeAPSSettings) {
+        units = settingsManager.settings.units
+    }
 }

+ 17 - 9
FreeAPS/Sources/Services/Network/Nightscout/NightscoutManager.swift

@@ -368,24 +368,27 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
                     let status: String? = last.status
                     let display: Bool? = last.display
 
-                    if let percent = percent, let voltage = voltage, let status = status, let display = display {
+                    if let status {
                         debugPrint(
-                            "Home State Model: \(#function) \(DebuggingIdentifiers.succeeded) setup battery from core data successfully"
+                            "NightscoutManager: \(#function) \(DebuggingIdentifiers.succeeded) setup battery from core data successfully"
                         )
                         return Battery(
                             percent: percent,
                             voltage: voltage,
-                            string: BatteryState(rawValue: status) ?? BatteryState.normal,
+                            string: BatteryState(rawValue: status) ?? BatteryState.unknown,
                             display: display
                         )
                     }
                 }
-                return Battery(percent: 100, voltage: 100, string: BatteryState.normal, display: false)
+                debugPrint(
+                    "NightscoutManager: \(#function) \(DebuggingIdentifiers.succeeded) successfully fetched; but no battery data available. Returning fallback default."
+                )
+                return Battery(percent: nil, voltage: nil, string: BatteryState.error, display: nil)
             } catch {
                 debugPrint(
-                    "Home State Model: \(#function) \(DebuggingIdentifiers.failed) failed to setup battery from core data"
+                    "NightscoutManager: \(#function) \(DebuggingIdentifiers.failed) failed to setup battery from core data"
                 )
-                return Battery(percent: 100, voltage: 100, string: BatteryState.normal, display: false)
+                return Battery(percent: nil, voltage: nil, string: BatteryState.error, display: nil)
             }
         }
     }
@@ -460,7 +463,7 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             iob: iob?.first,
             suggested: modifiedSuggestedDetermination,
             enacted: settingsManager.settings.closedLoop ? fetchedEnactedDetermination : nil,
-            version: "0.7.1"
+            version: Bundle.main.releaseVersionNumber ?? "Unknown"
         )
 
         // Gather all relevant data for NS Status
@@ -474,8 +477,13 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             status: pumpStatus
         )
 
-        let device = await UIDevice.current
-        let uploader = await Uploader(batteryVoltage: nil, battery: Int(device.batteryLevel * 100))
+        let batteryLevel = await UIDevice.current.batteryLevel
+        let batteryState = await UIDevice.current.batteryState
+        let uploader = Uploader(
+            batteryVoltage: nil,
+            battery: Int(batteryLevel * 100),
+            isCharging: batteryState == .charging || batteryState == .full
+        )
         let status = NightscoutStatus(
             device: NightscoutTreatment.local,
             openaps: openapsStatus,

+ 1 - 1
FreeAPS/Sources/Services/WatchManager/WatchManager.swift

@@ -432,7 +432,7 @@ extension BaseWatchManager: WCSessionDelegate {
                         carbs: Decimal(carbs),
                         fat: Decimal(fat),
                         protein: Decimal(protein),
-                        note: nil,
+                        note: message["note"] as? String,
                         enteredBy: CarbsEntry.local,
                         isFPU: false,
                         fpuID: nil

+ 15 - 2
FreeAPS/Sources/Shortcuts/Carbs/AddCarbPresetIntent.swift

@@ -8,7 +8,7 @@ import Swinject
     static var title: LocalizedStringResource = "Add carbs"
 
     // Description of the action in the Shortcuts app
-    static var description = IntentDescription("Allow to add carbs in iAPS.")
+    static var description = IntentDescription("Allow to add carbs in Trio.")
 
     internal var carbRequest: CarbPresetIntentRequest
 
@@ -45,6 +45,11 @@ import Swinject
     ) var dateAdded: Date
 
     @Parameter(
+        title: "Notes",
+        description: "Emoji or short text"
+    ) var note: String?
+
+    @Parameter(
         title: "Confirm Before applying",
         description: "If toggled, you will need to confirm before applying",
         default: true
@@ -55,12 +60,14 @@ import Swinject
             Summary("Applying \(\.$carbQuantity) at \(\.$dateAdded)") {
                 \.$fatQuantity
                 \.$proteinQuantity
+                \.$note
                 \.$confirmBeforeApplying
             }
         }, otherwise: {
             Summary("Immediately applying \(\.$carbQuantity) at \(\.$dateAdded)") {
                 \.$fatQuantity
                 \.$proteinQuantity
+                \.$note
                 \.$confirmBeforeApplying
             }
         })
@@ -82,7 +89,13 @@ import Swinject
                 )
             }
 
-            let finalQuantityCarbsDisplay = try await carbRequest.addCarbs(quantityCarbs, fatQuantity, proteinQuantity, dateAdded)
+            let finalQuantityCarbsDisplay = try await carbRequest.addCarbs(
+                quantityCarbs,
+                fatQuantity,
+                proteinQuantity,
+                dateAdded,
+                note
+            )
             return .result(
                 dialog: IntentDialog(stringLiteral: finalQuantityCarbsDisplay)
             )

+ 4 - 3
FreeAPS/Sources/Shortcuts/Carbs/CarbPresetIntentRequest.swift

@@ -6,10 +6,11 @@ import Foundation
         _ quantityCarbs: Double,
         _ quantityFat: Double,
         _ quantityProtein: Double,
-        _ dateAdded: Date
+        _ dateAdded: Date,
+        _ note: String?
     ) async throws -> String {
         guard quantityCarbs >= 0.0 || quantityFat >= 0.0 || quantityProtein >= 0.0 else {
-            return "no adding carbs in iAPS"
+            return "not adding carbs in Trio"
         }
 
         let carbs = min(Decimal(quantityCarbs), settingsManager.settings.maxCarbs)
@@ -22,7 +23,7 @@ import Foundation
                 carbs: carbs,
                 fat: Decimal(quantityFat),
                 protein: Decimal(quantityProtein),
-                note: "add with shortcuts",
+                note: (note?.isEmpty ?? true) ? "Via Shortcut" : note!,
                 enteredBy: CarbsEntry.local,
                 isFPU: false, fpuID: nil
             )],

+ 2 - 1
FreeAPSWatch WatchKit Extension/Views/CarbsView.swift

@@ -221,7 +221,8 @@ struct CarbsView: View {
                 let amountFat = Int(numberFormatter.string(from: fatAmount as NSNumber)!) ?? Int(fatAmount.rounded())
                 let amountProtein = Int(numberFormatter.string(from: proteinAmount as NSNumber)!) ??
                     Int(proteinAmount.rounded())
-                state.addMeal(amountCarbs, fat: amountFat, protein: amountProtein)
+                let note = "Via Watch" // Hard-coded note for entries from watch
+                state.addMeal(amountCarbs, fat: amountFat, protein: amountProtein, note: note)
             }
             label: { Text("Save") }
                 .buttonStyle(.borderless)

+ 2 - 2
FreeAPSWatch WatchKit Extension/WatchStateModel.swift

@@ -69,11 +69,11 @@ class WatchStateModel: NSObject, ObservableObject {
         session.activate()
     }
 
-    func addMeal(_ carbs: Int, fat: Int, protein: Int) {
+    func addMeal(_ carbs: Int, fat: Int, protein: Int, note: String) {
         confirmationSuccess = nil
         isConfirmationViewActive = true
         isCarbsViewActive = false
-        session.sendMessage(["carbs": carbs, "fat": fat, "protein": protein], replyHandler: { reply in
+        session.sendMessage(["carbs": carbs, "fat": fat, "protein": protein, "note": note], replyHandler: { reply in
             self.completionHandler(reply)
             if let ok = reply["confirmation"] as? Bool, ok {
                 DispatchQueue.main.asyncAfter(deadline: .now() + 1) {