Jelajahi Sumber

Add Glucose Notifications Picker

kskandis 1 tahun lalu
induk
melakukan
624fa1f5c6

+ 4 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -297,6 +297,7 @@
 		6EADD581738D64431902AC0A /* (null) in Sources */ = {isa = PBXBuildFile; };
 		6FFAE524D1D9C262F2407CAE /* SnoozeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CAE81192B118804DCD23034 /* SnoozeProvider.swift */; };
 		711C0CB42CAABE788916BC9D /* ManualTempBasalDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96653287EDB276A111288305 /* ManualTempBasalDataFlow.swift */; };
+		715120D22D3C2BB4005D9FB6 /* GlucoseNotificationsOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */; };
 		71D44AAB2CA5F5EA0036EE9E /* AlertPermissionsChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D44AAA2CA5F5EA0036EE9E /* AlertPermissionsChecker.swift */; };
 		72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */; };
 		7BCFACB97C821041BA43A114 /* ManualTempBasalRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C377490C77661D75E8C50649 /* ManualTempBasalRootView.swift */; };
@@ -999,6 +1000,7 @@
 		6B1A8D252B14D91700E76752 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		6B1A8D2D2B156EEF00E76752 /* LiveActivityBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivityBridge.swift; sourceTree = "<group>"; };
 		6BCF84DC2B16843A003AD46E /* LiveActitiyAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActitiyAttributes.swift; sourceTree = "<group>"; };
+		715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseNotificationsOption.swift; sourceTree = "<group>"; };
 		71D44AAA2CA5F5EA0036EE9E /* AlertPermissionsChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertPermissionsChecker.swift; sourceTree = "<group>"; };
 		79BDA519C9B890FD9A5DFCF3 /* ISFEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorDataFlow.swift; sourceTree = "<group>"; };
 		7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarbRatioEditorDataFlow.swift; sourceTree = "<group>"; };
@@ -2001,6 +2003,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			children = (
+				715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */,
 				DD07CA132CE80B73002D45A9 /* TimeInRangeChartStyle.swift */,
 				DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */,
 				DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */,
@@ -3802,6 +3805,7 @@
 				DD32CF9E2CC824C5003686D6 /* TrioRemoteControl+Override.swift in Sources */,
 				23888883D4EA091C88480FF2 /* TreatmentsProvider.swift in Sources */,
 				38E98A2D25F52DC400C0CED0 /* NSLocking+Extensions.swift in Sources */,
+				715120D22D3C2BB4005D9FB6 /* GlucoseNotificationsOption.swift in Sources */,
 				BDBAACFA2C2D439700370AAE /* OverrideData.swift in Sources */,
 				DD9ECB682CA99F4500AA7C45 /* TrioRemoteControl.swift in Sources */,
 				38569353270B5E350002C50D /* CGMRootView.swift in Sources */,

+ 6 - 3
FreeAPS/Sources/Models/FreeAPSSettings.swift

@@ -35,7 +35,7 @@ struct FreeAPSSettings: JSON, Equatable {
     var notificationsCgm: Bool = true
     var notificationsCarb: Bool = true
     var notificationsAlgorithm: Bool = true
-    var glucoseNotificationsAlways: Bool = false
+    var glucoseNotificationsOption: GlucoseNotificationsOption = .onlyLowHigh
     var useAlarmSound: Bool = false
     var addSourceInfoToGlucoseNotifications: Bool = false
     var lowGlucose: Decimal = 72
@@ -213,8 +213,11 @@ extension FreeAPSSettings: Decodable {
             settings.notificationsAlgorithm = notificationsAlgorithm
         }
 
-        if let glucoseNotificationsAlways = try? container.decode(Bool.self, forKey: .glucoseNotificationsAlways) {
-            settings.glucoseNotificationsAlways = glucoseNotificationsAlways
+        if let glucoseNotificationsOption = try? container.decode(
+            GlucoseNotificationsOption.self,
+            forKey: .glucoseNotificationsOption
+        ) {
+            settings.glucoseNotificationsOption = glucoseNotificationsOption
         }
 
         if let useAlarmSound = try? container.decode(Bool.self, forKey: .useAlarmSound) {

+ 22 - 0
FreeAPS/Sources/Models/GlucoseNotificationsOption.swift

@@ -0,0 +1,22 @@
+//
+//  GlucoseNotificationOption.swift
+//  FreeAPS
+//
+//  Created by Kimberlie Skandis on 1/18/25.
+//
+import Foundation
+
+public enum GlucoseNotificationsOption: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
+    public var id: String { rawValue }
+    case disabled
+    case alwaysEveryCGM
+    case onlyLowHigh
+
+    var displayName: String {
+        switch self {
+        case .disabled: return "Disabled"
+        case .alwaysEveryCGM: return "Always"
+        case .onlyLowHigh: return "Only LOW/HIGH"
+        }
+    }
+}

+ 2 - 2
FreeAPS/Sources/Modules/GlucoseNotificationSettings/GlucoseNotificationSettingsStateModel.swift

@@ -3,7 +3,7 @@ import SwiftUI
 extension GlucoseNotificationSettings {
     final class StateModel: BaseStateModel<Provider> {
         @Published var glucoseBadge = false
-        @Published var glucoseNotificationsAlways = false
+        @Published var glucoseNotificationsOption: GlucoseNotificationsOption = .onlyLowHigh
         @Published var useAlarmSound = false
         @Published var addSourceInfoToGlucoseNotifications = false
         @Published var lowGlucose: Decimal = 0
@@ -26,7 +26,7 @@ extension GlucoseNotificationSettings {
             subscribeSetting(\.notificationsAlgorithm, on: $notificationsAlgorithm) { notificationsAlgorithm = $0 }
 
             subscribeSetting(\.glucoseBadge, on: $glucoseBadge) { glucoseBadge = $0 }
-            subscribeSetting(\.glucoseNotificationsAlways, on: $glucoseNotificationsAlways) { glucoseNotificationsAlways = $0 }
+            subscribeSetting(\.glucoseNotificationsOption, on: $glucoseNotificationsOption) { glucoseNotificationsOption = $0 }
             subscribeSetting(\.useAlarmSound, on: $useAlarmSound) { useAlarmSound = $0 }
             subscribeSetting(\.addSourceInfoToGlucoseNotifications, on: $addSourceInfoToGlucoseNotifications) {
                 addSourceInfoToGlucoseNotifications = $0 }

+ 106 - 63
FreeAPS/Sources/Modules/GlucoseNotificationSettings/View/GlucoseNotificationSettingsRootView.swift

@@ -42,6 +42,26 @@ extension GlucoseNotificationSettings {
             List {
                 SettingInputSection(
                     decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.useAlarmSound,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0.map { AnyView($0) }
+                            hintLabel = "Play Alarm Sound"
+                        }
+                    ),
+                    units: state.units,
+                    type: .boolean,
+                    label: "Play Alarm Sound",
+                    miniHint: "Alarm with every Trio notification.",
+                    verboseHint: VStack(alignment: .leading, spacing: 10) {
+                        Text("Default: OFF").bold()
+                        Text("This will cause a sound to be triggered by every Trio notification.")
+                    }
+                )
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
                     booleanValue: $state.notificationsPump,
                     shouldDisplayHint: $shouldDisplayHint,
                     selectedVerboseHint: Binding(
@@ -166,70 +186,87 @@ extension GlucoseNotificationSettings {
                     headerText: "Various Glucose Notifications"
                 )
 
-                SettingInputSection(
-                    decimalValue: $decimalPlaceholder,
-                    booleanValue: $state.glucoseNotificationsAlways,
-                    shouldDisplayHint: $shouldDisplayHint,
-                    selectedVerboseHint: Binding(
-                        get: { selectedVerboseHint },
-                        set: {
-                            selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Always Notify Glucose"
-                        }
-                    ),
-                    units: state.units,
-                    type: .boolean,
-                    label: "Always Notify Glucose",
-                    miniHint: "Trigger a notification every time your glucose is updated.",
-                    verboseHint: VStack(alignment: .leading, spacing: 10) {
-                        Text("Default: OFF").bold()
-                        Text("A notification will be triggered every time your glucose is updated in Trio.")
-                    }
-                )
+                Section {
+                    VStack {
+                        Picker(
+                            selection: $state.glucoseNotificationsOption,
+                            label: Text("Glucose Notifications")
+                        ) {
+                            ForEach(GlucoseNotificationsOption.allCases) { selection in
+                                Text(selection.displayName).tag(selection)
+                            }
+                        }.padding(.top)
 
-                SettingInputSection(
-                    decimalValue: $decimalPlaceholder,
-                    booleanValue: $state.useAlarmSound,
-                    shouldDisplayHint: $shouldDisplayHint,
-                    selectedVerboseHint: Binding(
-                        get: { selectedVerboseHint },
-                        set: {
-                            selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Play Alarm Sound"
-                        }
-                    ),
-                    units: state.units,
-                    type: .boolean,
-                    label: "Play Alarm Sound",
-                    miniHint: "Alarm with every Trio notification.",
-                    verboseHint: VStack(alignment: .leading, spacing: 10) {
-                        Text("Default: OFF").bold()
-                        Text("This will cause a sound to be triggered by every Trio notification.")
-                    }
-                )
+                        HStack(alignment: .center) {
+                            Text(
+                                "Choose glucose notifications option. See hint for more details."
+                            )
+                            .font(.footnote)
+                            .foregroundColor(.secondary)
+                            .lineLimit(nil)
+                            Spacer()
+                            Button(
+                                action: {
+                                    hintLabel = "Glucose Notifications"
+                                    selectedVerboseHint =
+                                        AnyView(
+                                            VStack(alignment: .leading, spacing: 10) {
+                                                Text(
+                                                    "Set the Glucose Notifications Option. Descriptions for each option found below."
+                                                )
+                                                VStack(alignment: .leading, spacing: 5) {
+                                                    Text("Disabled:").bold()
+                                                    Text("No Glucose Notificatitons will be triggered.")
+                                                }
+                                                VStack(alignment: .leading, spacing: 5) {
+                                                    Text("Always:").bold()
+                                                    Text(
+                                                        "A notification will be triggered every time your glucose is updated in Trio."
+                                                    )
+                                                }
+                                                VStack(alignment: .leading, spacing: 5) {
+                                                    Text("Only LOW/HIGH:").bold()
+                                                    Text(
+                                                        "A notification will be triggered only when glucose is below LOW and above HIGH settings as defined in Glucose Alarm Limits below."
+                                                    )
+                                                }
+                                            }
+                                        )
+                                    shouldDisplayHint.toggle()
+                                },
+                                label: {
+                                    HStack {
+                                        Image(systemName: "questionmark.circle")
+                                    }
+                                }
+                            ).buttonStyle(BorderlessButtonStyle())
+                        }.padding(.top)
+                    }.padding(.bottom)
+                }.listRowBackground(Color.chart)
 
-                SettingInputSection(
-                    decimalValue: $decimalPlaceholder,
-                    booleanValue: $state.addSourceInfoToGlucoseNotifications,
-                    shouldDisplayHint: $shouldDisplayHint,
-                    selectedVerboseHint: Binding(
-                        get: { selectedVerboseHint },
-                        set: {
-                            selectedVerboseHint = $0.map { AnyView($0) }
-                            hintLabel = "Add Glucose Source to Alarm"
+                if state.glucoseNotificationsOption != GlucoseNotificationsOption.disabled {
+                    self.lowAndHighGlucoseAlertSection
+                    SettingInputSection(
+                        decimalValue: $decimalPlaceholder,
+                        booleanValue: $state.addSourceInfoToGlucoseNotifications,
+                        shouldDisplayHint: $shouldDisplayHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0.map { AnyView($0) }
+                                hintLabel = "Add Glucose Source to Alarm"
+                            }
+                        ),
+                        units: state.units,
+                        type: .boolean,
+                        label: "Add Glucose Source to Alarm",
+                        miniHint: "Source of the glucose reading will be added to the notification.",
+                        verboseHint: VStack(alignment: .leading, spacing: 10) {
+                            Text("Default: OFF").bold()
+                            Text("The source of the glucose reading will be added to the notification.")
                         }
-                    ),
-                    units: state.units,
-                    type: .boolean,
-                    label: "Add Glucose Source to Alarm",
-                    miniHint: "Source of the glucose reading will be added to the notification.",
-                    verboseHint: VStack(alignment: .leading, spacing: 10) {
-                        Text("Default: OFF").bold()
-                        Text("The source of the glucose reading will be added to the notification.")
-                    }
-                )
-
-                self.lowAndHighGlucoseAlertSection
+                    )
+                }
             }
             .listSectionSpacing(sectionSpacing)
             .sheet(isPresented: $shouldDisplayHint) {
@@ -336,8 +373,14 @@ extension GlucoseNotificationSettings {
                                 hintLabel = "Low and High Glucose Alarm Limits"
                                 selectedVerboseHint =
                                     AnyView(VStack(alignment: .leading, spacing: 10) {
-                                        Text("Low Default: 70 mg/dL").bold()
-                                        Text("High Default: 180 mg/dL").bold()
+                                        let low: Decimal = 70
+                                        let high: Decimal = 180
+                                        let labelLow = (state.units == .mgdL ? low.description : low.formattedAsMmolL) + " " +
+                                            state.units.rawValue
+                                        let labelHigh = (state.units == .mgdL ? high.description : high.formattedAsMmolL) + " " +
+                                            state.units.rawValue
+                                        Text("Low Default: " + labelLow).bold()
+                                        Text("High Default: " + labelHigh).bold()
                                         VStack(alignment: .leading, spacing: 10) {
                                             Text(
                                                 "These two settings determine the range outside of which you will be notified via push notifications."

+ 3 - 3
FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift

@@ -89,17 +89,17 @@ extension NightscoutConfig {
                 let fixedURL = url.dropLast()
                 url = String(fixedURL)
             }
-            
+
             guard let url = URL(string: url), self.url.hasPrefix("https://") else {
                 message = "Invalid URL"
                 isValidURL = false
                 return
             }
-            
+
             connecting = true
             isValidURL = true
             message = ""
-            
+
             provider.checkConnection(url: url, secret: secret.isEmpty ? nil : secret)
                 .receive(on: DispatchQueue.main)
                 .sink { completion in

+ 2 - 2
FreeAPS/Sources/Modules/Settings/SettingItems.swift

@@ -219,13 +219,13 @@ enum SettingItems {
             title: "Trio Notifications",
             view: .glucoseNotificationSettings,
             searchContents: [
+                "Play Alarm Sound",
                 "Always Notify Pump",
                 "Always Notify CGM",
                 "Always Notify Carb",
                 "Always Notify Algorithm",
                 "Show Glucose App Badge",
-                "Always Notify Glucose",
-                "Play Alarm Sound",
+                "Glucose Notifications",
                 "Add Glucose Source to Alarm",
                 "Low Glucose Alarm Limit",
                 "High Glucose Alarm Limit"

+ 2 - 1
FreeAPS/Sources/Router/Router.swift

@@ -60,7 +60,8 @@ final class BaseRouter: Router {
         case .carb:
             guard settings.notificationsCarb else { return false }
         case .glucose:
-            guard settings.glucoseNotificationsAlways else { return false }
+            guard (message.type == .warning && settings.glucoseNotificationsOption == GlucoseNotificationsOption.onlyLowHigh) ||
+                settings.glucoseNotificationsOption == GlucoseNotificationsOption.alwaysEveryCGM else { return false }
         case .algorithm:
             guard settings.notificationsAlgorithm else { return false }
         case .misc:

+ 1 - 1
FreeAPS/Sources/Services/UserNotifications/UserNotificationsManager.swift

@@ -270,7 +270,7 @@ final class BaseUserNotificationsManager: NSObject, UserNotificationsManager, In
 
             addAppBadge(glucose: (glucoseObjects.first?.glucose).map { Int($0) })
 
-            guard glucoseStorage.alarm != nil || settingsManager.settings.glucoseNotificationsAlways else { return }
+            guard settingsManager.settings.glucoseNotificationsOption != GlucoseNotificationsOption.disabled else { return }
 
             var titles: [String] = []
             var notificationAlarm = false