Преглед изворни кода

variable renaming

marv-out suggestion
Robert пре 6 месеци
родитељ
комит
d046d6ebe6

+ 33 - 33
Trio.xcodeproj/project.pbxproj

@@ -2358,18 +2358,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			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 */,
 				388E5A5F25B6F2310019842D /* Autosens.swift */,
 				388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */,
 				388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */,
 				38D0B3B525EBE24900CB6E88 /* Battery.swift */,
 				38D0B3B525EBE24900CB6E88 /* Battery.swift */,
@@ -2377,43 +2366,54 @@
 				3870FF4225EC13F40088248F /* BloodGlucose.swift */,
 				3870FF4225EC13F40088248F /* BloodGlucose.swift */,
 				38A9260425F012D8009E3739 /* CarbRatios.swift */,
 				38A9260425F012D8009E3739 /* CarbRatios.swift */,
 				38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */,
 				38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */,
-				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
+				19D4E4EA29FC6A9F00351451 /* Charts.swift */,
+				DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */,
+				DD9ECB692CA99F6C00AA7C45 /* CommandPayload.swift */,
 				E592A36F2CEEC01E009A472C /* ContactTrickEntry.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 */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
+				49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
+				DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */,
+				715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */,
+				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
+				1967DFBD29D052C200759F30 /* Icons.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
 				38887CCD25F5725200944304 /* IOBEntry.swift */,
 				38887CCD25F5725200944304 /* IOBEntry.swift */,
+				BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
+				193F6CDC2A512C8F001240FD /* Loops.swift */,
+				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
 				DD68889C2C386E17006E3C44 /* NightscoutExercise.swift */,
 				DD68889C2C386E17006E3C44 /* NightscoutExercise.swift */,
+				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
+				191F62672AD6B05A004D7911 /* NightscoutSettings.swift */,
 				385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */,
 				385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */,
 				389442CA25F65F7100FA1F27 /* NightscoutTreatment.swift */,
 				389442CA25F65F7100FA1F27 /* NightscoutTreatment.swift */,
+				BDC2EA462C3045AD00E5BBD0 /* Override.swift */,
+				BD54A95A2D28087700F9C1EE /* OverridePresetWatch.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				38A13D3125E28B4B00EAA382 /* PumpHistoryEvent.swift */,
 				38A13D3125E28B4B00EAA382 /* PumpHistoryEvent.swift */,
 				3883583325EEB38000E024B2 /* PumpSettings.swift */,
 				3883583325EEB38000E024B2 /* PumpSettings.swift */,
 				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
 				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
+				CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */,
 				38BF021C25E7E3AF00579895 /* Reservoir.swift */,
 				38BF021C25E7E3AF00579895 /* Reservoir.swift */,
+				19B0EF2028F6D66200069496 /* Statistics.swift */,
+				3B2F77852D7E52ED005ED9FA /* TDD.swift */,
 				38A0364125ED069400FCBB52 /* TempBasal.swift */,
 				38A0364125ED069400FCBB52 /* TempBasal.swift */,
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
-				3811DE8E25C9D80400A708ED /* User.swift */,
-				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
+				BD54A9722D281A9C00F9C1EE /* TempTargetPresetWatch.swift */,
+				DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */,
 				1935363F28496F7D001E0B16 /* TrioCustomOrefVariables.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;
 			path = Models;
 			sourceTree = "<group>";
 			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." : {
     "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" : {
     "Datafield Selection" : {
@@ -78940,9 +78940,6 @@
         }
         }
       }
       }
     },
     },
-    "Disable Watchface Data" : {
-
-    },
     "Disabled" : {
     "Disabled" : {
       "comment" : "Title string for BeepPreference.silent",
       "comment" : "Title string for BeepPreference.silent",
       "extractionState" : "manual",
       "extractionState" : "manual",
@@ -89227,6 +89224,9 @@
         }
         }
       }
       }
     },
     },
+    "Enable Watchface Data" : {
+
+    },
     "Enabled" : {
     "Enabled" : {
       "comment" : "Title string for BeepPreference.manualCommands",
       "comment" : "Title string for BeepPreference.manualCommands",
       "extractionState" : "manual",
       "extractionState" : "manual",

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

@@ -2,10 +2,10 @@ import Foundation
 
 
 // MARK: - Garmin Data Type Settings
 // 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.
 /// 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 }
     var id: String { rawValue }
 
 
     case cob
     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.
 /// 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 }
     var id: String { rawValue }
 
 
     case tbr
     case tbr
@@ -109,11 +109,11 @@ enum GarminDatafield: String, JSON, CaseIterable, Identifiable, Codable, Hashabl
 // MARK: - Garmin Watch Settings Group
 // MARK: - Garmin Watch Settings Group
 
 
 /// Groups related Garmin watch settings together for easier management.
 /// 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 {
 struct GarminWatchSettings: Codable, Hashable {
     var watchface: GarminWatchface = .trio
     var watchface: GarminWatchface = .trio
     var datafield: GarminDatafield = .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
     // 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"
     /// Options: "tbr" or "eventualBG"
-    var displayDataType2: String?
+    var displaySecondaryAttributeChoice: String?
 
 
     static func == (lhs: GarminWatchState, rhs: GarminWatchState) -> Bool {
     static func == (lhs: GarminWatchState, rhs: GarminWatchState) -> Bool {
         lhs.date == rhs.date &&
         lhs.date == rhs.date &&
@@ -66,8 +66,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
             lhs.eventualBG == rhs.eventualBG &&
             lhs.eventualBG == rhs.eventualBG &&
             lhs.isf == rhs.isf &&
             lhs.isf == rhs.isf &&
             lhs.sensRatio == rhs.sensRatio &&
             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) {
     func hash(into hasher: inout Hasher) {
@@ -83,8 +83,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
         hasher.combine(eventualBG)
         hasher.combine(eventualBG)
         hasher.combine(isf)
         hasher.combine(isf)
         hasher.combine(sensRatio)
         hasher.combine(sensRatio)
-        hasher.combine(displayDataType1)
-        hasher.combine(displayDataType2)
+        hasher.combine(displayPrimaryAttributeChoice)
+        hasher.combine(displaySecondaryAttributeChoice)
     }
     }
 
 
     enum CodingKeys: String, CodingKey {
     enum CodingKeys: String, CodingKey {
@@ -100,8 +100,8 @@ struct GarminWatchState: Hashable, Equatable, Sendable, Encodable {
         case eventualBG
         case eventualBG
         case isf
         case isf
         case sensRatio
         case sensRatio
-        case displayDataType1
-        case displayDataType2
+        case displayPrimaryAttributeChoice
+        case displaySecondaryAttributeChoice
     }
     }
 
 
     /// Custom encoding that excludes nil values from the JSON output
     /// 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(eventualBG, forKey: .eventualBG)
         try container.encodeIfPresent(isf, forKey: .isf)
         try container.encodeIfPresent(isf, forKey: .isf)
         try container.encodeIfPresent(sensRatio, forKey: .sensRatio)
         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 garminWatchface: GarminWatchface = .trio
     var garminDatafield: GarminDatafield = .none
     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 {
 extension TrioSettings: Decodable {
@@ -341,16 +361,21 @@ extension TrioSettings: Decodable {
             settings.garminDatafield = garminDatafield
             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
         self = settings

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

@@ -21,7 +21,7 @@ struct WatchConfigGarminAppConfigView: View {
                 content: {
                 content: {
                     VStack {
                     VStack {
                         Picker(
                         Picker(
-                            selection: $state.garminWatchface,
+                            selection: $state.garminSettings.watchface,
                             label: Text("Watchface Selection").multilineTextAlignment(.leading)
                             label: Text("Watchface Selection").multilineTextAlignment(.leading)
                         ) {
                         ) {
                             ForEach(GarminWatchface.allCases) { selection in
                             ForEach(GarminWatchface.allCases) { selection in
@@ -29,7 +29,7 @@ struct WatchConfigGarminAppConfigView: View {
                             }
                             }
                         }
                         }
                         .padding(.top)
                         .padding(.top)
-                        .onChange(of: state.garminWatchface) { _ in
+                        .onChange(of: state.garminSettings.watchface) { _ in
                             state.handleWatchfaceChange()
                             state.handleWatchfaceChange()
                         }
                         }
 
 
@@ -53,14 +53,14 @@ struct WatchConfigGarminAppConfigView: View {
                             ).buttonStyle(BorderlessButtonStyle())
                             ).buttonStyle(BorderlessButtonStyle())
                         }.padding(.top)
                         }.padding(.top)
                         Spacer()
                         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
                         // Display cooldown warning when toggle is locked
-                        if state.isDisableToggleLocked {
+                        if state.isWatchfaceDataCooldownActive {
                             HStack {
                             HStack {
                                 Text(
                                 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!"
                                         "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)
                                 .font(.footnote)
@@ -101,7 +101,7 @@ struct WatchConfigGarminAppConfigView: View {
                 content: {
                 content: {
                     VStack {
                     VStack {
                         Picker(
                         Picker(
-                            selection: $state.garminDatafield,
+                            selection: $state.garminSettings.datafield,
                             label: Text("Datafield Selection").multilineTextAlignment(.leading)
                             label: Text("Datafield Selection").multilineTextAlignment(.leading)
                         ) {
                         ) {
                             ForEach(GarminDatafield.allCases) { selection in
                             ForEach(GarminDatafield.allCases) { selection in
@@ -133,25 +133,25 @@ struct WatchConfigGarminAppConfigView: View {
                 }
                 }
             ).listRowBackground(Color.chart)
             ).listRowBackground(Color.chart)
 
 
-            // MARK: - Data Type 1 Selection Section
+            // MARK: - Data Field Selection Section
 
 
             Section(
             Section(
                 header: Text("Watch App Display Settings"),
                 header: Text("Watch App Display Settings"),
                 content: {
                 content: {
                     VStack {
                     VStack {
                         Picker(
                         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)
                                 Text(selection.displayName).tag(selection)
                             }
                             }
                         }.padding(.top)
                         }.padding(.top)
                         Picker(
                         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)
                                 Text(selection.displayName).tag(selection)
                             }
                             }
                         }.padding(.top)
                         }.padding(.top)
@@ -204,7 +204,7 @@ struct WatchConfigGarminAppConfigView: View {
                 hintLabel: "Choose Garmin Datafield",
                 hintLabel: "Choose Garmin Datafield",
                 hintText: Text(
                 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" +
                     "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")
                 sheetTitle: String(localized: "Help", comment: "Help sheet title")
             )
             )
@@ -213,9 +213,9 @@ struct WatchConfigGarminAppConfigView: View {
             SettingInputHintView(
             SettingInputHintView(
                 hintDetent: $hintDetent,
                 hintDetent: $hintDetent,
                 shouldDisplayHint: $shouldDisplayHint2,
                 shouldDisplayHint: $shouldDisplayHint2,
-                hintLabel: "Disable watchface data transmission",
+                hintLabel: "Enable/disable watchface data transmission",
                 hintText: Text(
                 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."
                         "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")
                 sheetTitle: String(localized: "Help", comment: "Help sheet title")
@@ -227,7 +227,7 @@ struct WatchConfigGarminAppConfigView: View {
                 shouldDisplayHint: $shouldDisplayHint3,
                 shouldDisplayHint: $shouldDisplayHint3,
                 hintLabel: "Choose data support",
                 hintLabel: "Choose data support",
                 hintText: Text(
                 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")
                 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 devices: [IQDevice] = []
         @Published var confirmBolusFaster = false
         @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
         /// Remaining seconds in the cooldown period
-        @Published var remainingCooldownSeconds: Int = 0
+        @Published var watchfaceSwitchCooldownSeconds: Int = 0
 
 
         private(set) var preferences = Preferences()
         private(set) var preferences = Preferences()
 
 
         /// Timer for managing the 20-second cooldown after watchface changes
         /// 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
         /// The timestamp when the current cooldown period will end
-        private var cooldownEndTime: Date?
+        private var watchfaceSwitchCooldownEndTime: Date?
 
 
         override func subscribe() {
         override func subscribe() {
             preferences = provider.preferences
             preferences = provider.preferences
             units = settingsManager.settings.units
             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 }
             subscribeSetting(\.confirmBolusFaster, on: $confirmBolusFaster) { confirmBolusFaster = $0 }
 
 
             devices = garmin.devices
             devices = garmin.devices
@@ -69,39 +55,39 @@ extension WatchConfig {
         /// and starting a 20-second cooldown period to allow the user to switch watchfaces
         /// and starting a 20-second cooldown period to allow the user to switch watchfaces
         /// on their Garmin device without data conflicts
         /// on their Garmin device without data conflicts
         func handleWatchfaceChange() {
         func handleWatchfaceChange() {
-            garminDisableWatchfaceData = true
+            garminSettings.isWatchfaceDataEnabled = false
             startCooldownTimer()
             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
         /// the remaining seconds display every second until the cooldown period expires
         private func startCooldownTimer() {
         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 }
                 guard let self = self else { return }
 
 
-                if let endTime = self.cooldownEndTime {
+                if let endTime = self.watchfaceSwitchCooldownEndTime {
                     let remaining = Int(endTime.timeIntervalSinceNow)
                     let remaining = Int(endTime.timeIntervalSinceNow)
                     if remaining <= 0 {
                     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 {
                     } else {
-                        self.remainingCooldownSeconds = remaining
+                        self.watchfaceSwitchCooldownSeconds = remaining
                     }
                     }
                 }
                 }
             }
             }
         }
         }
 
 
         deinit {
         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.
     /// Current glucose units, either mg/dL or mmol/L, read from user settings.
     private var units: GlucoseUnits = .mgdL
     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
     /// Queue for handling Core Data change notifications
     private let queue = DispatchQueue(label: "BaseGarminManager.queue", qos: .utility)
     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
         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)
         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
     /// Safely gets the current Garmin watchface setting
     private var currentWatchface: GarminWatchface {
     private var currentWatchface: GarminWatchface {
         // Direct access since it's not optional
         // 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)
     /// 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
         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
     // MARK: - Internal Setup / Handlers
@@ -819,8 +799,9 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
                 }
                 }
 
 
                 // Get display configuration from settings
                 // 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
                 // Process glucose readings
                 // For Trio: Process 2 readings (to calculate delta) but only send 1 entry
                 // 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.isf = isfValue
                         watchState.eventualBG = eventualBGValue
                         watchState.eventualBG = eventualBGValue
                         watchState.sensRatio = sensRatioValue
                         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)
                         // 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 }
         guard debugWatchState else { return }
 
 
         let watchface = currentWatchface
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
         let watchfaceUUID = watchface.watchfaceUUID?.uuidString ?? "Unknown"
         let watchfaceUUID = watchface.watchfaceUUID?.uuidString ?? "Unknown"
         let datafieldUUID = datafield.datafieldUUID?.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
                 // Show which apps will actually receive data
                 let destinations: String
                 let destinations: String
-                if isWatchfaceDataDisabled {
+                if !isWatchfaceDataEnabled {
                     destinations = "datafield \(datafieldUUID) only (watchface disabled)"
                     destinations = "datafield \(datafieldUUID) only (watchface disabled)"
                 } else {
                 } else {
                     destinations = "watchface \(watchfaceUUID) / datafield \(datafieldUUID)"
                     destinations = "watchface \(watchfaceUUID) / datafield \(datafieldUUID)"
@@ -1045,11 +1026,11 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
             let watchface = currentWatchface
             let watchface = currentWatchface
 
 
             // Get current datafield setting
             // Get current datafield setting
-            let datafield = currentDatafield
+            let datafield = currentGarminSettings.datafield
 
 
             // Create a watchface app using the UUID from the enum
             // Create a watchface app using the UUID from the enum
             // Only register watchface if data is NOT disabled
             // Only register watchface if data is NOT disabled
-            if !isWatchfaceDataDisabled {
+            if isWatchfaceDataEnabled {
                 if let watchfaceUUID = watchface.watchfaceUUID,
                 if let watchfaceUUID = watchface.watchfaceUUID,
                    let watchfaceApp = IQApp(uuid: watchfaceUUID, store: UUID(), device: device)
                    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 watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
 
 
         watchApps.forEach { app in
         watchApps.forEach { app in
             let isWatchfaceApp = app.uuid == watchface.watchfaceUUID
             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
             // 2. If it's a watchface and data is disabled, skip
-            if isWatchfaceApp, isWatchfaceDataDisabled {
+            if isWatchfaceApp, !isWatchfaceDataEnabled {
                 debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, skipping")
                 debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, skipping")
                 return
                 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
     /// Updates display type fields in the state array/object with current settings
     /// - Parameter state: The state object (either array or dict) to update
     /// - 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 {
     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)
         // Handle array of states (normal case)
         if var stateArray = state as? [[String: Any]] {
         if var stateArray = state as? [[String: Any]] {
             // Only update the first element (index 0) which contains extended data
             // Only update the first element (index 0) which contains extended data
             if !stateArray.isEmpty {
             if !stateArray.isEmpty {
-                stateArray[0]["displayDataType1"] = displayType1
-                stateArray[0]["displayDataType2"] = displayType2
+                stateArray[0]["displayPrimaryAttributeChoice"] = displayType1
+                stateArray[0]["displaySecondaryAttributeChoice"] = displayType2
             }
             }
             return stateArray
             return stateArray
         }
         }
 
 
         // Handle single state dict (shouldn't happen but be safe)
         // Handle single state dict (shouldn't happen but be safe)
         if var stateDict = state as? [String: Any] {
         if var stateDict = state as? [String: Any] {
-            stateDict["displayDataType1"] = displayType1
-            stateDict["displayDataType2"] = displayType2
+            stateDict["displayPrimaryAttributeChoice"] = displayType1
+            stateDict["displaySecondaryAttributeChoice"] = displayType2
             return stateDict
             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)
     /// False only if: no apps at all OR (only watchface AND data disabled)
     private func areAppsLikelyInstalled() -> Bool {
     private func areAppsLikelyInstalled() -> Bool {
         let watchface = currentWatchface
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
 
 
         // If datafield UUID exists, ALWAYS return true
         // If datafield UUID exists, ALWAYS return true
         if datafield.datafieldUUID != nil {
         if datafield.datafieldUUID != nil {
@@ -1299,7 +1280,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         // No datafield, check watchface
         // No datafield, check watchface
         if watchface.watchfaceUUID != nil {
         if watchface.watchfaceUUID != nil {
             // Watchface exists, check if data is enabled
             // Watchface exists, check if data is enabled
-            if isWatchfaceDataDisabled {
+            if !isWatchfaceDataEnabled {
                 debugGarmin("[\(formatTimeForLog())] Garmin: ⏩ Skipping - only watchface exists and data disabled")
                 debugGarmin("[\(formatTimeForLog())] Garmin: ⏩ Skipping - only watchface exists and data disabled")
                 return false
                 return false
             }
             }
@@ -1400,7 +1381,7 @@ final class BaseGarminManager: NSObject, GarminManager, Injectable, @unchecked S
         let isWatchfaceApp = app.uuid == watchface.watchfaceUUID
         let isWatchfaceApp = app.uuid == watchface.watchfaceUUID
 
 
         // Skip sending if data is disabled AND this is the watchface app
         // 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")
             debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, not sending message to watchface")
             return
             return
         }
         }
@@ -1508,7 +1489,7 @@ extension BaseGarminManager: IQUIOverrideDelegate, IQDeviceEventDelegate, IQAppM
         debugGarmin("[\(formatTimeForLog())] Garmin: Received message \(message) from app \(app.uuid!)")
         debugGarmin("[\(formatTimeForLog())] Garmin: Received message \(message) from app \(app.uuid!)")
 
 
         let watchface = currentWatchface
         let watchface = currentWatchface
-        let datafield = currentDatafield
+        let datafield = currentGarminSettings.datafield
         let validUUIDs = Set([watchface.watchfaceUUID, datafield.datafieldUUID].compactMap { $0 })
         let validUUIDs = Set([watchface.watchfaceUUID, datafield.datafieldUUID].compactMap { $0 })
 
 
         // Must be from a configured app
         // Must be from a configured app
@@ -1522,7 +1503,7 @@ extension BaseGarminManager: IQUIOverrideDelegate, IQDeviceEventDelegate, IQAppM
 
 
         // SIMPLIFIED LOGIC:
         // SIMPLIFIED LOGIC:
         // Skip watchface messages only if data is disabled
         // Skip watchface messages only if data is disabled
-        if isFromWatchface, isWatchfaceDataDisabled {
+        if isFromWatchface, !isWatchfaceDataEnabled {
             debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, ignoring watchface message")
             debugGarmin("[\(formatTimeForLog())] Garmin: Watchface data disabled, ignoring watchface message")
             return
             return
         }
         }
@@ -1570,39 +1551,39 @@ extension BaseGarminManager: SettingsObserver {
         debug(.watchManager, "🔔 settingsDidChange triggered")
         debug(.watchManager, "🔔 settingsDidChange triggered")
 
 
         // Check what changed by comparing with stored previous values
         // 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 unitsChanged = units != settings.units
-        let disabledChanged = previousDisableWatchfaceData != settings.garminDisableWatchfaceData
+        let enabledChanged = previousGarminSettings.isWatchfaceDataEnabled != settings.garminSettings.isWatchfaceDataEnabled
 
 
         // Debug what changed BEFORE updating stored values
         // Debug what changed BEFORE updating stored values
         if watchfaceChanged {
         if watchfaceChanged {
             debug(
             debug(
                 .watchManager,
                 .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 {
         if datafieldChanged {
             debug(
             debug(
                 .watchManager,
                 .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 {
         if dataType1Changed {
             debug(
             debug(
                 .watchManager,
                 .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 {
         if dataType2Changed {
             debug(
             debug(
                 .watchManager,
                 .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")
             debugGarmin("Garmin: Units changed - immediate update required")
         }
         }
 
 
-        if disabledChanged {
+        if enabledChanged {
             debug(
             debug(
                 .watchManager,
                 .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)
             registerDevices(devices)
 
 
-            if settings.garminDisableWatchfaceData {
+            if !settings.garminSettings.isWatchfaceDataEnabled { // ← REVERSED LOGIC
                 debugGarmin("Garmin: Watchface app unregistered, datafield continues")
                 debugGarmin("Garmin: Watchface app unregistered, datafield continues")
             } else {
             } else {
                 debugGarmin("Garmin: Watchface app re-registered - sending immediate update")
                 debugGarmin("Garmin: Watchface app re-registered - sending immediate update")
@@ -1628,11 +1609,7 @@ extension BaseGarminManager: SettingsObserver {
 
 
         // NOW update stored values AFTER logging the changes
         // NOW update stored values AFTER logging the changes
         units = settings.units
         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
         // Handle watchface or datafield change - ONLY re-register, NO data send
         if watchfaceChanged || datafieldChanged {
         if watchfaceChanged || datafieldChanged {
@@ -1656,7 +1633,7 @@ extension BaseGarminManager: SettingsObserver {
         // Determine which type of update is needed (if any)
         // Determine which type of update is needed (if any)
         let needsImmediateUpdate = (
         let needsImmediateUpdate = (
             unitsChanged ||
             unitsChanged ||
-                (disabledChanged && !settings.garminDisableWatchfaceData)
+                (enabledChanged && settings.garminSettings.isWatchfaceDataEnabled) // ← REVERSED LOGIC
         ) &&
         ) &&
             !watchfaceChanged && !datafieldChanged // Don't send if only watchface or datafield changed
             !watchfaceChanged && !datafieldChanged // Don't send if only watchface or datafield changed