Просмотр исходного кода

variable renaming

marv-out suggestion
Robert 6 месяцев назад
Родитель
Сommit
d046d6ebe6

+ 33 - 33
Trio.xcodeproj/project.pbxproj

@@ -2358,18 +2358,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			children = (
-				49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */,
-				DDFF204F2DB2C11900AB8A96 /* WatchStateSnapshot.swift */,
-				DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */,
-				3B2F77852D7E52ED005ED9FA /* TDD.swift */,
-				DD3078672D42F5CE00DE0490 /* WatchGlucoseObject.swift */,
-				BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */,
-				BD54A9722D281A9C00F9C1EE /* TempTargetPresetWatch.swift */,
-				BD54A95A2D28087700F9C1EE /* OverridePresetWatch.swift */,
-				BDA25EFC2D261BF200035F34 /* WatchState.swift */,
-				715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */,
-				DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */,
-				DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */,
+				CE82E02628E869DF00473A9C /* AlertEntry.swift */,
 				388E5A5F25B6F2310019842D /* Autosens.swift */,
 				388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */,
 				38D0B3B525EBE24900CB6E88 /* Battery.swift */,
@@ -2377,43 +2366,54 @@
 				3870FF4225EC13F40088248F /* BloodGlucose.swift */,
 				38A9260425F012D8009E3739 /* CarbRatios.swift */,
 				38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */,
-				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
+				19D4E4EA29FC6A9F00351451 /* Charts.swift */,
+				DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */,
+				DD9ECB692CA99F6C00AA7C45 /* CommandPayload.swift */,
 				E592A36F2CEEC01E009A472C /* ContactTrickEntry.swift */,
-				38AEE73C25F0200C0013F05B /* TrioSettings.swift */,
+				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
+				19A910352A24D6D700C8951B /* DateFilter.swift */,
+				DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */,
+				583684072BD195A700070A60 /* Determination.swift */,
+				DDD6D4D22CDE90720029439A /* EstimatedA1cDisplayUnit.swift */,
+				DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
+				49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
+				DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */,
+				715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */,
+				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
+				1967DFBD29D052C200759F30 /* Icons.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
 				38887CCD25F5725200944304 /* IOBEntry.swift */,
+				BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
+				193F6CDC2A512C8F001240FD /* Loops.swift */,
+				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
 				DD68889C2C386E17006E3C44 /* NightscoutExercise.swift */,
+				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
+				191F62672AD6B05A004D7911 /* NightscoutSettings.swift */,
 				385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */,
 				389442CA25F65F7100FA1F27 /* NightscoutTreatment.swift */,
+				BDC2EA462C3045AD00E5BBD0 /* Override.swift */,
+				BD54A95A2D28087700F9C1EE /* OverridePresetWatch.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				38A13D3125E28B4B00EAA382 /* PumpHistoryEvent.swift */,
 				3883583325EEB38000E024B2 /* PumpSettings.swift */,
 				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
+				CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */,
 				38BF021C25E7E3AF00579895 /* Reservoir.swift */,
+				19B0EF2028F6D66200069496 /* Statistics.swift */,
+				3B2F77852D7E52ED005ED9FA /* TDD.swift */,
 				38A0364125ED069400FCBB52 /* TempBasal.swift */,
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
-				3811DE8E25C9D80400A708ED /* User.swift */,
-				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
+				BD54A9722D281A9C00F9C1EE /* TempTargetPresetWatch.swift */,
+				DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */,
 				1935363F28496F7D001E0B16 /* TrioCustomOrefVariables.swift */,
-				CE82E02628E869DF00473A9C /* AlertEntry.swift */,
-				19B0EF2028F6D66200069496 /* Statistics.swift */,
-				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
-				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
-				191F62672AD6B05A004D7911 /* NightscoutSettings.swift */,
-				1967DFBD29D052C200759F30 /* Icons.swift */,
-				19D4E4EA29FC6A9F00351451 /* Charts.swift */,
-				19A910352A24D6D700C8951B /* DateFilter.swift */,
-				193F6CDC2A512C8F001240FD /* Loops.swift */,
-				CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */,
-				BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
-				583684072BD195A700070A60 /* Determination.swift */,
-				BDC2EA462C3045AD00E5BBD0 /* Override.swift */,
-				DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */,
-				DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */,
-				DD9ECB692CA99F6C00AA7C45 /* CommandPayload.swift */,
-				DDD6D4D22CDE90720029439A /* EstimatedA1cDisplayUnit.swift */,
+				38AEE73C25F0200C0013F05B /* TrioSettings.swift */,
+				3811DE8E25C9D80400A708ED /* User.swift */,
+				DD3078672D42F5CE00DE0490 /* WatchGlucoseObject.swift */,
+				BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */,
+				BDA25EFC2D261BF200035F34 /* WatchState.swift */,
+				DDFF204F2DB2C11900AB8A96 /* WatchStateSnapshot.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";

+ 6 - 6
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -59228,7 +59228,7 @@
         }
       }
     },
-    "Choose which data types, along BG and IOB etc., you want to show on your Garmin device. That data type will be shown both on watchface and datafield" : {
+    "Choose which data types, along with BG and IOB etc., you want to show on your Garmin device. That data type will be shown both on watchface and datafield." : {
 
     },
     "Choose which datafield to support. Can be used independently of watchface selection." : {
@@ -67573,10 +67573,10 @@
         }
       }
     },
-    "DataChoice 1" : {
+    "Data Choice 1" : {
 
     },
-    "DataChoice 2" : {
+    "Data Choice 2" : {
 
     },
     "Datafield Selection" : {
@@ -78940,9 +78940,6 @@
         }
       }
     },
-    "Disable Watchface Data" : {
-
-    },
     "Disabled" : {
       "comment" : "Title string for BeepPreference.silent",
       "extractionState" : "manual",
@@ -89227,6 +89224,9 @@
         }
       }
     },
+    "Enable Watchface Data" : {
+
+    },
     "Enabled" : {
       "comment" : "Title string for BeepPreference.manualCommands",
       "extractionState" : "manual",

+ 9 - 9
Trio/Sources/Models/GarminWatchSettings.swift

@@ -2,10 +2,10 @@ import Foundation
 
 // MARK: - Garmin Data Type Settings
 
-/// Primary data type selection for Garmin watchface and datafield.
-/// Determines whether to display COB or Sensitivity Ratio alongside glucose data.
+/// Primary attribute selection for Garmin watchface and datafield.
+/// Determines whether to display COB, ISF, or Sensitivity Ratio alongside glucose data.
 /// Used by both Trio and SwissAlpine watchfaces.
-enum GarminDataType1: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
+enum GarminPrimaryAttributeChoice: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
     var id: String { rawValue }
 
     case cob
@@ -24,9 +24,9 @@ enum GarminDataType1: String, JSON, CaseIterable, Identifiable, Codable, Hashabl
     }
 }
 
-/// Secondary data type selection for both Trio and SwissAlpine watchfaces.
+/// Secondary attribute selection for both Trio and SwissAlpine watchfaces.
 /// Determines whether to display Temp Basal Rate or Eventual BG.
-enum GarminDataType2: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
+enum GarminSecondaryAttributeChoice: String, JSON, CaseIterable, Identifiable, Codable, Hashable {
     var id: String { rawValue }
 
     case tbr
@@ -109,11 +109,11 @@ enum GarminDatafield: String, JSON, CaseIterable, Identifiable, Codable, Hashabl
 // MARK: - Garmin Watch Settings Group
 
 /// Groups related Garmin watch settings together for easier management.
-/// Both watchfaces use the same settings: dataType1 and dataType2.
+/// Both watchfaces use the same settings: primaryAttributeChoice and secondaryAttributeChoice.
 struct GarminWatchSettings: Codable, Hashable {
     var watchface: GarminWatchface = .trio
     var datafield: GarminDatafield = .trio
-    var dataType1: GarminDataType1 = .cob
-    var dataType2: GarminDataType2 = .tbr
-    var garminDisableWatchfaceData: Bool = true
+    var primaryAttributeChoice: GarminPrimaryAttributeChoice = .cob
+    var secondaryAttributeChoice: GarminSecondaryAttributeChoice = .tbr
+    var isWatchfaceDataEnabled: Bool = false
 }

+ 13 - 13
Trio/Sources/Models/GarminWatchState.swift

@@ -45,13 +45,13 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
 
     // MARK: - Display Configuration Fields
 
-    /// Specifies which data field to display as primary (dataType1)
-    /// Options: "cob" or "sensRatio"
-    var displayDataType1: String?
+    /// Specifies which primary attribute to display
+    /// Options: "cob", "isf", or "sensRatio"
+    var displayPrimaryAttributeChoice: String?
 
-    /// Specifies which data field to display as secondary (dataType2)
+    /// Specifies which secondary attribute to display
     /// Options: "tbr" or "eventualBG"
-    var displayDataType2: String?
+    var displaySecondaryAttributeChoice: String?
 
     static func == (lhs: GarminWatchState, rhs: GarminWatchState) -> Bool {
         lhs.date == rhs.date &&
@@ -66,8 +66,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
             lhs.eventualBG == rhs.eventualBG &&
             lhs.isf == rhs.isf &&
             lhs.sensRatio == rhs.sensRatio &&
-            lhs.displayDataType1 == rhs.displayDataType1 &&
-            lhs.displayDataType2 == rhs.displayDataType2
+            lhs.displayPrimaryAttributeChoice == rhs.displayPrimaryAttributeChoice &&
+            lhs.displaySecondaryAttributeChoice == rhs.displaySecondaryAttributeChoice
     }
 
     func hash(into hasher: inout Hasher) {
@@ -83,8 +83,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
         hasher.combine(eventualBG)
         hasher.combine(isf)
         hasher.combine(sensRatio)
-        hasher.combine(displayDataType1)
-        hasher.combine(displayDataType2)
+        hasher.combine(displayPrimaryAttributeChoice)
+        hasher.combine(displaySecondaryAttributeChoice)
     }
 
     enum CodingKeys: String, CodingKey {
@@ -100,8 +100,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
         case eventualBG
         case isf
         case sensRatio
-        case displayDataType1
-        case displayDataType2
+        case displayPrimaryAttributeChoice
+        case displaySecondaryAttributeChoice
     }
 
     /// Custom encoding that excludes nil values from the JSON output
@@ -119,7 +119,7 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
         try container.encodeIfPresent(eventualBG, forKey: .eventualBG)
         try container.encodeIfPresent(isf, forKey: .isf)
         try container.encodeIfPresent(sensRatio, forKey: .sensRatio)
-        try container.encodeIfPresent(displayDataType1, forKey: .displayDataType1)
-        try container.encodeIfPresent(displayDataType2, forKey: .displayDataType2)
+        try container.encodeIfPresent(displayPrimaryAttributeChoice, forKey: .displayPrimaryAttributeChoice)
+        try container.encodeIfPresent(displaySecondaryAttributeChoice, forKey: .displaySecondaryAttributeChoice)
     }
 }

+ 39 - 14
Trio/Sources/Models/TrioSettings.swift

@@ -79,14 +79,34 @@ struct TrioSettings: JSON, Equatable, Encodable {
     var garminWatchface: GarminWatchface = .trio
     var garminDatafield: GarminDatafield = .none
 
-    /// Primary data type for Garmin display (COB or Sensitivity Ratio)
-    var garminDataType1: GarminDataType1 = .cob
-
-    /// Secondary data type for SwissAlpine watchface (TBR or Eventual BG)
-    var garminDataType2: GarminDataType2 = .tbr
-
-    /// Controls whether watchface data transmission is disabled
-    var garminDisableWatchfaceData: Bool = true
+    /// Primary attribute choice for Garmin display (COB, ISF, or Sensitivity Ratio)
+    var primaryAttributeChoice: GarminPrimaryAttributeChoice = .cob
+
+    /// Secondary attribute choice for Garmin display (TBR or Eventual BG)
+    var secondaryAttributeChoice: GarminSecondaryAttributeChoice = .tbr
+
+    /// Controls whether watchface data transmission is enabled
+    var isWatchfaceDataEnabled: Bool = false
+
+    /// Computed property that groups all Garmin settings into a single struct
+    var garminSettings: GarminWatchSettings {
+        get {
+            GarminWatchSettings(
+                watchface: garminWatchface,
+                datafield: garminDatafield,
+                primaryAttributeChoice: primaryAttributeChoice,
+                secondaryAttributeChoice: secondaryAttributeChoice,
+                isWatchfaceDataEnabled: isWatchfaceDataEnabled
+            )
+        }
+        set {
+            garminWatchface = newValue.watchface
+            garminDatafield = newValue.datafield
+            primaryAttributeChoice = newValue.primaryAttributeChoice
+            secondaryAttributeChoice = newValue.secondaryAttributeChoice
+            isWatchfaceDataEnabled = newValue.isWatchfaceDataEnabled
+        }
+    }
 }
 
 extension TrioSettings: Decodable {
@@ -341,16 +361,21 @@ extension TrioSettings: Decodable {
             settings.garminDatafield = garminDatafield
         }
 
-        if let garminDataType1 = try? container.decode(GarminDataType1.self, forKey: .garminDataType1) {
-            settings.garminDataType1 = garminDataType1
+        if let primaryAttributeChoice = try? container
+            .decode(GarminPrimaryAttributeChoice.self, forKey: .primaryAttributeChoice)
+        {
+            settings.primaryAttributeChoice = primaryAttributeChoice
         }
 
-        if let garminDataType2 = try? container.decode(GarminDataType2.self, forKey: .garminDataType2) {
-            settings.garminDataType2 = garminDataType2
+        if let secondaryAttributeChoice = try? container.decode(
+            GarminSecondaryAttributeChoice.self,
+            forKey: .secondaryAttributeChoice
+        ) {
+            settings.secondaryAttributeChoice = secondaryAttributeChoice
         }
 
-        if let garminDisableWatchfaceData = try? container.decode(Bool.self, forKey: .garminDisableWatchfaceData) {
-            settings.garminDisableWatchfaceData = garminDisableWatchfaceData
+        if let isWatchfaceDataEnabled = try? container.decode(Bool.self, forKey: .isWatchfaceDataEnabled) {
+            settings.isWatchfaceDataEnabled = isWatchfaceDataEnabled
         }
 
         self = settings

+ 18 - 18
Trio/Sources/Modules/WatchConfig/View/WatchConfigGarminAppConfigView.swift

@@ -21,7 +21,7 @@ struct WatchConfigGarminAppConfigView: View {
                 content: {
                     VStack {
                         Picker(
-                            selection: $state.garminWatchface,
+                            selection: $state.garminSettings.watchface,
                             label: Text("Watchface Selection").multilineTextAlignment(.leading)
                         ) {
                             ForEach(GarminWatchface.allCases) { selection in
@@ -29,7 +29,7 @@ struct WatchConfigGarminAppConfigView: View {
                             }
                         }
                         .padding(.top)
-                        .onChange(of: state.garminWatchface) { _ in
+                        .onChange(of: state.garminSettings.watchface) { _ in
                             state.handleWatchfaceChange()
                         }
 
@@ -53,14 +53,14 @@ struct WatchConfigGarminAppConfigView: View {
                             ).buttonStyle(BorderlessButtonStyle())
                         }.padding(.top)
                         Spacer()
-                        Toggle("Disable Watchface Data", isOn: $state.garminDisableWatchfaceData)
-                            .disabled(state.isDisableToggleLocked)
+                        Toggle("Enable Watchface Data", isOn: $state.garminSettings.isWatchfaceDataEnabled)
+                            .disabled(state.isWatchfaceDataCooldownActive)
 
                         // Display cooldown warning when toggle is locked
-                        if state.isDisableToggleLocked {
+                        if state.isWatchfaceDataCooldownActive {
                             HStack {
                                 Text(
-                                    "Please wait \(state.remainingCooldownSeconds) seconds!\n\n" +
+                                    "Please wait \(state.watchfaceSwitchCooldownSeconds) seconds!\n\n" +
                                         "After the lockout you can re-enable watchface data transmission, but you need to change to the new watchface on your Garmin watch before that - e.g. now!"
                                 )
                                 .font(.footnote)
@@ -101,7 +101,7 @@ struct WatchConfigGarminAppConfigView: View {
                 content: {
                     VStack {
                         Picker(
-                            selection: $state.garminDatafield,
+                            selection: $state.garminSettings.datafield,
                             label: Text("Datafield Selection").multilineTextAlignment(.leading)
                         ) {
                             ForEach(GarminDatafield.allCases) { selection in
@@ -133,25 +133,25 @@ struct WatchConfigGarminAppConfigView: View {
                 }
             ).listRowBackground(Color.chart)
 
-            // MARK: - Data Type 1 Selection Section
+            // MARK: - Data Field Selection Section
 
             Section(
                 header: Text("Watch App Display Settings"),
                 content: {
                     VStack {
                         Picker(
-                            selection: $state.garminDataType1,
-                            label: Text("DataChoice 1").multilineTextAlignment(.leading)
+                            selection: $state.garminSettings.primaryAttributeChoice,
+                            label: Text("Data Choice 1").multilineTextAlignment(.leading)
                         ) {
-                            ForEach(GarminDataType1.allCases) { selection in
+                            ForEach(GarminPrimaryAttributeChoice.allCases) { selection in
                                 Text(selection.displayName).tag(selection)
                             }
                         }.padding(.top)
                         Picker(
-                            selection: $state.garminDataType2,
-                            label: Text("DataChoice 2").multilineTextAlignment(.leading)
+                            selection: $state.garminSettings.secondaryAttributeChoice,
+                            label: Text("Data Choice 2").multilineTextAlignment(.leading)
                         ) {
-                            ForEach(GarminDataType2.allCases) { selection in
+                            ForEach(GarminSecondaryAttributeChoice.allCases) { selection in
                                 Text(selection.displayName).tag(selection)
                             }
                         }.padding(.top)
@@ -204,7 +204,7 @@ struct WatchConfigGarminAppConfigView: View {
                 hintLabel: "Choose Garmin Datafield",
                 hintText: Text(
                     "Choose which datafield on your Garmin device you wish to provide data for. The datafield can be used independently from the watchface selection.\n\n" +
-                        "Select 'None' if you don't want to use a datafield,or want to preserve battery while not exercising."
+                        "Select 'None' if you don't want to use a datafield, or want to preserve battery while not exercising."
                 ),
                 sheetTitle: String(localized: "Help", comment: "Help sheet title")
             )
@@ -213,9 +213,9 @@ struct WatchConfigGarminAppConfigView: View {
             SettingInputHintView(
                 hintDetent: $hintDetent,
                 shouldDisplayHint: $shouldDisplayHint2,
-                hintLabel: "Disable watchface data transmission",
+                hintLabel: "Enable/disable watchface data transmission",
                 hintText: Text(
-                    "Important: If you want to use a different watchface on your Garmin device that has no data requirement from this app, use this toggle to disable all data transmission to the Garmin watchface app! Otherwise you will not be able to get current data once you re-enable the supported watchface that shows Trio data and you will have to re-install it on your Garmin device.\n\n" +
+                    "Important: If you want to use a different watchface on your Garmin device that has no data requirement from this app, disable data transmission to the Garmin watchface app! Otherwise you will not be able to get current data once you re-enable the supported watchface that shows Trio data and you will have to re-install it on your Garmin device.\n\n" +
                         "Note: When switching between supported watchfaces, data transmission is automatically disabled for 20 seconds. You would manually need to re-enable it."
                 ),
                 sheetTitle: String(localized: "Help", comment: "Help sheet title")
@@ -227,7 +227,7 @@ struct WatchConfigGarminAppConfigView: View {
                 shouldDisplayHint: $shouldDisplayHint3,
                 hintLabel: "Choose data support",
                 hintText: Text(
-                    "Choose which data types, along BG and IOB etc., you want to show on your Garmin device. That data type will be shown both on watchface and datafield"
+                    "Choose which data types, along with BG and IOB etc., you want to show on your Garmin device. That data type will be shown both on watchface and datafield."
                 ),
                 sheetTitle: String(localized: "Help", comment: "Help sheet title")
             )

+ 25 - 39
Trio/Sources/Modules/WatchConfig/WatchConfigStateModel.swift

@@ -10,43 +10,29 @@ extension WatchConfig {
         @Published var devices: [IQDevice] = []
         @Published var confirmBolusFaster = false
 
-        /// Current selected Garmin watchface (Trio, SwissAlpine, or None)
-        @Published var garminWatchface: GarminWatchface = .trio
+        /// Garmin watch settings containing all watch-related configuration
+        @Published var garminSettings = GarminWatchSettings()
 
-        /// Current selected Garmin datafield (Trio or None)
-        @Published var garminDatafield: GarminDatafield = .trio
-
-        /// Primary data type selection (COB or Sensitivity Ratio)
-        @Published var garminDataType1: GarminDataType1 = .cob
-
-        /// Secondary data type selection (TBR or Eventual BG)
-        @Published var garminDataType2: GarminDataType2 = .tbr
-
-        /// Controls whether watchface data transmission is disabled
-        @Published var garminDisableWatchfaceData: Bool = true
-
-        /// Indicates if the disable toggle is locked during cooldown period
-        @Published var isDisableToggleLocked: Bool = false
+        /// Indicates if the enable/disable toggle is locked during cooldown period
+        @Published var isWatchfaceDataCooldownActive: Bool = false
 
         /// Remaining seconds in the cooldown period
-        @Published var remainingCooldownSeconds: Int = 0
+        @Published var watchfaceSwitchCooldownSeconds: Int = 0
 
         private(set) var preferences = Preferences()
 
         /// Timer for managing the 20-second cooldown after watchface changes
-        private var cooldownTimer: Timer?
+        private var watchfaceSwitchTimer: Timer?
 
         /// The timestamp when the current cooldown period will end
-        private var cooldownEndTime: Date?
+        private var watchfaceSwitchCooldownEndTime: Date?
 
         override func subscribe() {
             preferences = provider.preferences
             units = settingsManager.settings.units
-            subscribeSetting(\.garminDataType1, on: $garminDataType1) { garminDataType1 = $0 }
-            subscribeSetting(\.garminDataType2, on: $garminDataType2) { garminDataType2 = $0 }
-            subscribeSetting(\.garminWatchface, on: $garminWatchface) { garminWatchface = $0 }
-            subscribeSetting(\.garminDatafield, on: $garminDatafield) { garminDatafield = $0 }
-            subscribeSetting(\.garminDisableWatchfaceData, on: $garminDisableWatchfaceData) { garminDisableWatchfaceData = $0 }
+
+            // Subscribe to the entire garminSettings struct from TrioSettings
+            subscribeSetting(\.garminSettings, on: $garminSettings) { garminSettings = $0 }
             subscribeSetting(\.confirmBolusFaster, on: $confirmBolusFaster) { confirmBolusFaster = $0 }
 
             devices = garmin.devices
@@ -69,39 +55,39 @@ extension WatchConfig {
         /// and starting a 20-second cooldown period to allow the user to switch watchfaces
         /// on their Garmin device without data conflicts
         func handleWatchfaceChange() {
-            garminDisableWatchfaceData = true
+            garminSettings.isWatchfaceDataEnabled = false
             startCooldownTimer()
         }
 
-        /// Starts a 20-second countdown timer that locks the disable toggle and updates
+        /// Starts a 20-second countdown timer that locks the enable/disable toggle and updates
         /// the remaining seconds display every second until the cooldown period expires
         private func startCooldownTimer() {
-            cooldownTimer?.invalidate()
+            watchfaceSwitchTimer?.invalidate()
 
-            cooldownEndTime = Date().addingTimeInterval(20)
-            isDisableToggleLocked = true
-            remainingCooldownSeconds = 20
+            watchfaceSwitchCooldownEndTime = Date().addingTimeInterval(20)
+            isWatchfaceDataCooldownActive = true
+            watchfaceSwitchCooldownSeconds = 20
 
-            cooldownTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
+            watchfaceSwitchTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
                 guard let self = self else { return }
 
-                if let endTime = self.cooldownEndTime {
+                if let endTime = self.watchfaceSwitchCooldownEndTime {
                     let remaining = Int(endTime.timeIntervalSinceNow)
                     if remaining <= 0 {
-                        self.isDisableToggleLocked = false
-                        self.remainingCooldownSeconds = 0
-                        self.cooldownTimer?.invalidate()
-                        self.cooldownTimer = nil
-                        self.cooldownEndTime = nil
+                        self.isWatchfaceDataCooldownActive = false
+                        self.watchfaceSwitchCooldownSeconds = 0
+                        self.watchfaceSwitchTimer?.invalidate()
+                        self.watchfaceSwitchTimer = nil
+                        self.watchfaceSwitchCooldownEndTime = nil
                     } else {
-                        self.remainingCooldownSeconds = remaining
+                        self.watchfaceSwitchCooldownSeconds = remaining
                     }
                 }
             }
         }
 
         deinit {
-            cooldownTimer?.invalidate()
+            watchfaceSwitchTimer?.invalidate()
         }
     }
 }

+ 48 - 71
Trio/Sources/Services/WatchManager/GarminManager.swift

@@ -145,12 +145,8 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
 
     /// Current glucose units, either mg/dL or mmol/L, read from user settings.
     private var units: GlucoseUnits = .mgdL
-    /// Track previous watchface settings
-    private var previousWatchface: GarminWatchface = .trio
-    private var previousDatafield: GarminDatafield = .none
-    private var previousDataType1: GarminDataType1 = .cob
-    private var previousDataType2: GarminDataType2 = .tbr
-    private var previousDisableWatchfaceData: Bool = true
+    /// Track previous Garmin settings as a single struct
+    private var previousGarminSettings = GarminWatchSettings()
 
     /// Queue for handling Core Data change notifications
     private let queue = DispatchQueue(label: "BaseGarminManager.queue", qos: .utility)
@@ -196,10 +192,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
 
         units = settingsManager.settings.units
 
-        previousWatchface = settingsManager.settings.garminWatchface
-        previousDataType1 = settingsManager.settings.garminDataType1
-        previousDataType2 = settingsManager.settings.garminDataType2
-        previousDisableWatchfaceData = settingsManager.settings.garminDisableWatchfaceData
+        previousGarminSettings = settingsManager.settings.garminSettings
 
         broadcaster.register(SettingsObserver.self, observer: self)
 
@@ -313,7 +306,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
     /// Safely gets the current Garmin watchface setting
     private var currentWatchface: GarminWatchface {
         // Direct access since it's not optional
-        settingsManager.settings.garminWatchface
+        settingsManager.settings.garminSettings.watchface
     }
 
     /// Check if current watchface needs historical glucose data (23 additional readings)
@@ -324,27 +317,14 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         currentWatchface == .swissalpine
     }
 
-    /// Safely gets the current Garmin data type setting
-    private var currentDataType1: GarminDataType1 {
-        // Direct access since it's not optional
-        settingsManager.settings.garminDataType1
-    }
-
-    /// Safely gets the current Garmin data type setting
-    private var currentDataType2: GarminDataType2 {
-        // Direct access since it's not optional
-        settingsManager.settings.garminDataType2
-    }
-
-    /// Safely gets the current Garmin datafield setting
-    private var currentDatafield: GarminDatafield {
-        // Direct access since it's not optional
-        settingsManager.settings.garminDatafield
+    /// Gets the current Garmin settings struct
+    private var currentGarminSettings: GarminWatchSettings {
+        settingsManager.settings.garminSettings
     }
 
-    /// Check if watchface data is disabled
-    private var isWatchfaceDataDisabled: Bool {
-        settingsManager.settings.garminDisableWatchfaceData
+    /// Check if watchface data is enabled (note: reversed logic from previous)
+    private var isWatchfaceDataEnabled: Bool {
+        settingsManager.settings.garminSettings.isWatchfaceDataEnabled
     }
 
     // MARK: - Internal Setup / Handlers
@@ -819,8 +799,9 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
                 }
 
                 // Get display configuration from settings
-                let displayDataType1 = self.settingsManager.settings.garminDataType1.rawValue
-                let displayDataType2 = self.settingsManager.settings.garminDataType2.rawValue
+                let displayPrimaryAttributeChoice = self.settingsManager.settings.garminSettings.primaryAttributeChoice.rawValue
+                let displaySecondaryAttributeChoice = self.settingsManager.settings.garminSettings.secondaryAttributeChoice
+                    .rawValue
 
                 // Process glucose readings
                 // For Trio: Process 2 readings (to calculate delta) but only send 1 entry
@@ -903,8 +884,8 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
                         watchState.isf = isfValue
                         watchState.eventualBG = eventualBGValue
                         watchState.sensRatio = sensRatioValue
-                        watchState.displayDataType1 = displayDataType1
-                        watchState.displayDataType2 = displayDataType2
+                        watchState.displayPrimaryAttributeChoice = displayPrimaryAttributeChoice
+                        watchState.displaySecondaryAttributeChoice = displaySecondaryAttributeChoice
                         // noise is left as nil (will be excluded from JSON)
                     }
 
@@ -939,7 +920,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         guard debugWatchState else { return }
 
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
         let watchfaceUUID = watchface.watchfaceUUID?.uuidString ?? "Unknown"
         let datafieldUUID = datafield.datafieldUUID?.uuidString ?? "Unknown"
 
@@ -951,7 +932,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
 
                 // Show which apps will actually receive data
                 let destinations: String
-                if isWatchfaceDataDisabled {
+                if !isWatchfaceDataEnabled {
                     destinations = "datafield \(datafieldUUID) only (watchface disabled)"
                 } else {
                     destinations = "watchface \(watchfaceUUID) / datafield \(datafieldUUID)"
@@ -1045,11 +1026,11 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
             let watchface = currentWatchface
 
             // Get current datafield setting
-            let datafield = currentDatafield
+            let datafield = currentGarminSettings.datafield
 
             // Create a watchface app using the UUID from the enum
             // Only register watchface if data is NOT disabled
-            if !isWatchfaceDataDisabled {
+            if isWatchfaceDataEnabled {
                 if let watchfaceUUID = watchface.watchfaceUUID,
                    let watchfaceApp = IQApp(uuid: watchfaceUUID, store: UUID(), device: device)
                 {
@@ -1203,7 +1184,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         }
 
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
 
         watchApps.forEach { app in
             let isWatchfaceApp = app.uuid == watchface.watchfaceUUID
@@ -1218,7 +1199,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
             }
 
             // 2. If it's a watchface and data is disabled, skip
-            if isWatchfaceApp, isWatchfaceDataDisabled {
+            if isWatchfaceApp, !isWatchfaceDataEnabled {
                 debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, skipping")
                 return
             }
@@ -1246,25 +1227,25 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
 
     /// Updates display type fields in the state array/object with current settings
     /// - Parameter state: The state object (either array or dict) to update
-    /// - Returns: Updated state with current displayDataType1 and displayDataType2
+    /// - Returns: Updated state with current displayPrimaryAttributeChoice and displaySecondaryAttributeChoice
     private func updateDisplayTypesInState(_ state: Any) -> Any {
-        let displayType1 = currentDataType1.rawValue
-        let displayType2 = currentDataType2.rawValue
+        let displayType1 = currentGarminSettings.primaryAttributeChoice.rawValue
+        let displayType2 = currentGarminSettings.secondaryAttributeChoice.rawValue
 
         // Handle array of states (normal case)
         if var stateArray = state as? [[String: Any]] {
             // Only update the first element (index 0) which contains extended data
             if !stateArray.isEmpty {
-                stateArray[0]["displayDataType1"] = displayType1
-                stateArray[0]["displayDataType2"] = displayType2
+                stateArray[0]["displayPrimaryAttributeChoice"] = displayType1
+                stateArray[0]["displaySecondaryAttributeChoice"] = displayType2
             }
             return stateArray
         }
 
         // Handle single state dict (shouldn't happen but be safe)
         if var stateDict = state as? [String: Any] {
-            stateDict["displayDataType1"] = displayType1
-            stateDict["displayDataType2"] = displayType2
+            stateDict["displayPrimaryAttributeChoice"] = displayType1
+            stateDict["displaySecondaryAttributeChoice"] = displayType2
             return stateDict
         }
 
@@ -1289,7 +1270,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
     /// False only if: no apps at all OR (only watchface AND data disabled)
     private func areAppsLikelyInstalled() -> Bool {
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
 
         // If datafield UUID exists, ALWAYS return true
         if datafield.datafieldUUID != nil {
@@ -1299,7 +1280,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         // No datafield, check watchface
         if watchface.watchfaceUUID != nil {
             // Watchface exists, check if data is enabled
-            if isWatchfaceDataDisabled {
+            if !isWatchfaceDataEnabled {
                 debugGarmin("[\(formatTimeForLog())] Garmin: ⏩ Skipping - only watchface exists and data disabled")
                 return false
             }
@@ -1400,7 +1381,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         let isWatchfaceApp = app.uuid == watchface.watchfaceUUID
 
         // Skip sending if data is disabled AND this is the watchface app
-        if isWatchfaceDataDisabled, isWatchfaceApp {
+        if !isWatchfaceDataEnabled, isWatchfaceApp {
             debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, not sending message to watchface")
             return
         }
@@ -1508,7 +1489,7 @@ extension BaseGarminManager: IQUIOverrideDelegate, IQDeviceEventDelegate, IQAppM
         debugGarmin("[\(formatTimeForLog())] Garmin: Received message \(message) from app \(app.uuid!)")
 
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
         let validUUIDs = Set([watchface.watchfaceUUID, datafield.datafieldUUID].compactMap { $0 })
 
         // Must be from a configured app
@@ -1522,7 +1503,7 @@ extension BaseGarminManager: IQUIOverrideDelegate, IQDeviceEventDelegate, IQAppM
 
         // SIMPLIFIED LOGIC:
         // Skip watchface messages only if data is disabled
-        if isFromWatchface, isWatchfaceDataDisabled {
+        if isFromWatchface, !isWatchfaceDataEnabled {
             debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, ignoring watchface message")
             return
         }
@@ -1570,39 +1551,39 @@ extension BaseGarminManager: SettingsObserver {
         debug(.watchManager, "🔔 settingsDidChange triggered")
 
         // Check what changed by comparing with stored previous values
-        let watchfaceChanged = previousWatchface != settings.garminWatchface
-        let datafieldChanged = previousDatafield != settings.garminDatafield
-        let dataType1Changed = previousDataType1 != settings.garminDataType1
-        let dataType2Changed = previousDataType2 != settings.garminDataType2
+        let watchfaceChanged = previousGarminSettings.watchface != settings.garminSettings.watchface
+        let datafieldChanged = previousGarminSettings.datafield != settings.garminSettings.datafield
+        let dataType1Changed = previousGarminSettings.primaryAttributeChoice != settings.garminSettings.primaryAttributeChoice
+        let dataType2Changed = previousGarminSettings.secondaryAttributeChoice != settings.garminSettings.secondaryAttributeChoice
         let unitsChanged = units != settings.units
-        let disabledChanged = previousDisableWatchfaceData != settings.garminDisableWatchfaceData
+        let enabledChanged = previousGarminSettings.isWatchfaceDataEnabled != settings.garminSettings.isWatchfaceDataEnabled
 
         // Debug what changed BEFORE updating stored values
         if watchfaceChanged {
             debug(
                 .watchManager,
-                "Garmin: Watchface changed from \(previousWatchface.displayName) to \(settings.garminWatchface.displayName). Re-registering devices only, no data update"
+                "Garmin: Watchface changed from \(previousGarminSettings.watchface.displayName) to \(settings.garminSettings.watchface.displayName). Re-registering devices only, no data update"
             )
         }
 
         if datafieldChanged {
             debug(
                 .watchManager,
-                "Garmin: Datafield changed from \(previousDatafield.displayName) to \(settings.garminDatafield.displayName). Re-registering devices only, no data update"
+                "Garmin: Datafield changed from \(previousGarminSettings.datafield.displayName) to \(settings.garminSettings.datafield.displayName). Re-registering devices only, no data update"
             )
         }
 
         if dataType1Changed {
             debug(
                 .watchManager,
-                "Garmin: Data type 1 changed from \(previousDataType1.displayName) to \(settings.garminDataType1.displayName)"
+                "Garmin: Primary attribute choice changed from \(previousGarminSettings.primaryAttributeChoice.displayName) to \(settings.garminSettings.primaryAttributeChoice.displayName)"
             )
         }
 
         if dataType2Changed {
             debug(
                 .watchManager,
-                "Garmin: Data type 2 changed from \(previousDataType2.displayName) to \(settings.garminDataType2.displayName)"
+                "Garmin: Secondary attribute choice changed from \(previousGarminSettings.secondaryAttributeChoice.displayName) to \(settings.garminSettings.secondaryAttributeChoice.displayName)"
             )
         }
 
@@ -1610,16 +1591,16 @@ extension BaseGarminManager: SettingsObserver {
             debugGarmin("Garmin: Units changed - immediate update required")
         }
 
-        if disabledChanged {
+        if enabledChanged {
             debug(
                 .watchManager,
-                "Garmin: Watchface data disabled changed from \(previousDisableWatchfaceData) to \(settings.garminDisableWatchfaceData)"
+                "Garmin: Watchface data enabled changed from \(previousGarminSettings.isWatchfaceDataEnabled) to \(settings.garminSettings.isWatchfaceDataEnabled)"
             )
 
-            // Re-register devices to add/remove watchface app based on disabled state
+            // Re-register devices to add/remove watchface app based on enabled state
             registerDevices(devices)
 
-            if settings.garminDisableWatchfaceData {
+            if !settings.garminSettings.isWatchfaceDataEnabled { // ← REVERSED LOGIC
                 debugGarmin("Garmin: Watchface app unregistered, datafield continues")
             } else {
                 debugGarmin("Garmin: Watchface app re-registered - sending immediate update")
@@ -1628,11 +1609,7 @@ extension BaseGarminManager: SettingsObserver {
 
         // NOW update stored values AFTER logging the changes
         units = settings.units
-        previousWatchface = settings.garminWatchface
-        previousDatafield = settings.garminDatafield
-        previousDataType1 = settings.garminDataType1
-        previousDataType2 = settings.garminDataType2
-        previousDisableWatchfaceData = settings.garminDisableWatchfaceData
+        previousGarminSettings = settings.garminSettings
 
         // Handle watchface or datafield change - ONLY re-register, NO data send
         if watchfaceChanged || datafieldChanged {
@@ -1656,7 +1633,7 @@ extension BaseGarminManager: SettingsObserver {
         // Determine which type of update is needed (if any)
         let needsImmediateUpdate = (
             unitsChanged ||
-                (disabledChanged && !settings.garminDisableWatchfaceData)
+                (enabledChanged && settings.garminSettings.isWatchfaceDataEnabled) // ← REVERSED LOGIC
         ) &&
             !watchfaceChanged && !datafieldChanged // Don't send if only watchface or datafield changed