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

create a menu "Watch devices" for Garmin and Apple Watch

Pierre L 3 лет назад
Родитель
Сommit
cccc551fb3

+ 19 - 19
FreeAPS.xcodeproj/project.pbxproj

@@ -313,10 +313,10 @@
 		CE94597A29E9DF7B0047C9C6 /* ConnectIQ.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE94597929E9DF7B0047C9C6 /* ConnectIQ.framework */; };
 		CE94597B29E9DFA90047C9C6 /* ConnectIQ.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE94597929E9DF7B0047C9C6 /* ConnectIQ.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		CE94597E29E9E1EE0047C9C6 /* GarminManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94597D29E9E1EE0047C9C6 /* GarminManager.swift */; };
-		CE94598029E9E3BD0047C9C6 /* GarminConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94597F29E9E3BD0047C9C6 /* GarminConfigDataFlow.swift */; };
-		CE94598229E9E3D30047C9C6 /* GarminConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598129E9E3D30047C9C6 /* GarminConfigProvider.swift */; };
-		CE94598429E9E3E60047C9C6 /* GarminConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598329E9E3E60047C9C6 /* GarminConfigStateModel.swift */; };
-		CE94598729E9E4110047C9C6 /* GarminConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598629E9E4110047C9C6 /* GarminConfigRootView.swift */; };
+		CE94598029E9E3BD0047C9C6 /* WatchConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94597F29E9E3BD0047C9C6 /* WatchConfigDataFlow.swift */; };
+		CE94598229E9E3D30047C9C6 /* WatchConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598129E9E3D30047C9C6 /* WatchConfigProvider.swift */; };
+		CE94598429E9E3E60047C9C6 /* WatchConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598329E9E3E60047C9C6 /* WatchConfigStateModel.swift */; };
+		CE94598729E9E4110047C9C6 /* WatchConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE94598629E9E4110047C9C6 /* WatchConfigRootView.swift */; };
 		CEA4F62329BE10F70011ADF7 /* SavitzkyGolayFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA4F62229BE10F70011ADF7 /* SavitzkyGolayFilter.swift */; };
 		CEB434DC28B8F5B900B70274 /* MKRingProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */; };
 		CEB434DD28B8F5B900B70274 /* MKRingProgressView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -799,10 +799,10 @@
 		CE82E02628E869DF00473A9C /* AlertEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertEntry.swift; sourceTree = "<group>"; };
 		CE94597929E9DF7B0047C9C6 /* ConnectIQ.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ConnectIQ.framework; path = "Dependencies/ios-armv7_arm64/ConnectIQ.framework"; sourceTree = "<group>"; };
 		CE94597D29E9E1EE0047C9C6 /* GarminManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminManager.swift; sourceTree = "<group>"; };
-		CE94597F29E9E3BD0047C9C6 /* GarminConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminConfigDataFlow.swift; sourceTree = "<group>"; };
-		CE94598129E9E3D30047C9C6 /* GarminConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminConfigProvider.swift; sourceTree = "<group>"; };
-		CE94598329E9E3E60047C9C6 /* GarminConfigStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminConfigStateModel.swift; sourceTree = "<group>"; };
-		CE94598629E9E4110047C9C6 /* GarminConfigRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminConfigRootView.swift; sourceTree = "<group>"; };
+		CE94597F29E9E3BD0047C9C6 /* WatchConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigDataFlow.swift; sourceTree = "<group>"; };
+		CE94598129E9E3D30047C9C6 /* WatchConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigProvider.swift; sourceTree = "<group>"; };
+		CE94598329E9E3E60047C9C6 /* WatchConfigStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigStateModel.swift; sourceTree = "<group>"; };
+		CE94598629E9E4110047C9C6 /* WatchConfigRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigRootView.swift; sourceTree = "<group>"; };
 		CEA4F62229BE10F70011ADF7 /* SavitzkyGolayFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavitzkyGolayFilter.swift; sourceTree = "<group>"; };
 		CEB434DB28B8F5B900B70274 /* MKRingProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MKRingProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		CEB434DE28B8F5C400B70274 /* OmniBLE.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OmniBLE.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1059,7 +1059,7 @@
 		3811DE0325C9D31700A708ED /* Modules */ = {
 			isa = PBXGroup;
 			children = (
-				CE94597C29E9E1CD0047C9C6 /* GarminConfig */,
+				CE94597C29E9E1CD0047C9C6 /* WatchConfig */,
 				19E1F7E629D0828B005C8D20 /* IconConfig */,
 				19D466A129AA2B0A004D5F33 /* FPUConfig */,
 				F90692CD274B99850037068D /* HealthKit */,
@@ -1961,21 +1961,21 @@
 			path = Bolus;
 			sourceTree = "<group>";
 		};
-		CE94597C29E9E1CD0047C9C6 /* GarminConfig */ = {
+		CE94597C29E9E1CD0047C9C6 /* WatchConfig */ = {
 			isa = PBXGroup;
 			children = (
 				CE94598529E9E3FE0047C9C6 /* View */,
-				CE94597F29E9E3BD0047C9C6 /* GarminConfigDataFlow.swift */,
-				CE94598129E9E3D30047C9C6 /* GarminConfigProvider.swift */,
-				CE94598329E9E3E60047C9C6 /* GarminConfigStateModel.swift */,
+				CE94597F29E9E3BD0047C9C6 /* WatchConfigDataFlow.swift */,
+				CE94598129E9E3D30047C9C6 /* WatchConfigProvider.swift */,
+				CE94598329E9E3E60047C9C6 /* WatchConfigStateModel.swift */,
 			);
-			path = GarminConfig;
+			path = WatchConfig;
 			sourceTree = "<group>";
 		};
 		CE94598529E9E3FE0047C9C6 /* View */ = {
 			isa = PBXGroup;
 			children = (
-				CE94598629E9E4110047C9C6 /* GarminConfigRootView.swift */,
+				CE94598629E9E4110047C9C6 /* WatchConfigRootView.swift */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -2397,7 +2397,7 @@
 				3894873A2614928B004DF424 /* DispatchTimer.swift in Sources */,
 				3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */,
 				386A124F271707F000DDC61C /* DexcomSourceG6.swift in Sources */,
-				CE94598429E9E3E60047C9C6 /* GarminConfigStateModel.swift in Sources */,
+				CE94598429E9E3E60047C9C6 /* WatchConfigStateModel.swift in Sources */,
 				38DF1786276A73D400B3528F /* TagCloudView.swift in Sources */,
 				38B4F3CD25E5031100E76A18 /* Broadcaster.swift in Sources */,
 				383420D925FFEB3F002D46C1 /* Popup.swift in Sources */,
@@ -2410,7 +2410,7 @@
 				38A0364225ED069400FCBB52 /* TempBasal.swift in Sources */,
 				3811DE1725C9D40400A708ED /* Screen.swift in Sources */,
 				383948DA25CD64D500E91849 /* Glucose.swift in Sources */,
-				CE94598029E9E3BD0047C9C6 /* GarminConfigDataFlow.swift in Sources */,
+				CE94598029E9E3BD0047C9C6 /* WatchConfigDataFlow.swift in Sources */,
 				388E596C25AD95110019842D /* OpenAPS.swift in Sources */,
 				E00EEC0527368630002FF094 /* StorageAssembly.swift in Sources */,
 				384E803825C388640086DB71 /* Script.swift in Sources */,
@@ -2430,7 +2430,7 @@
 				CEB434E328B8F9DB00B70274 /* BluetoothStateManager.swift in Sources */,
 				3811DE4225C9D4A100A708ED /* SettingsDataFlow.swift in Sources */,
 				3811DE2525C9D48300A708ED /* MainRootView.swift in Sources */,
-				CE94598229E9E3D30047C9C6 /* GarminConfigProvider.swift in Sources */,
+				CE94598229E9E3D30047C9C6 /* WatchConfigProvider.swift in Sources */,
 				38E44535274E411700EC9A94 /* Disk+Data.swift in Sources */,
 				3811DE3125C9D49500A708ED /* HomeProvider.swift in Sources */,
 				FE41E4D629463EE20047FD55 /* NightscoutPreferences.swift in Sources */,
@@ -2635,7 +2635,7 @@
 				BA00D96F7B2FF169A06FB530 /* CGMStateModel.swift in Sources */,
 				61962FCAF8A2D222553AC5A3 /* LibreConfigDataFlow.swift in Sources */,
 				6EADD581738D64431902AC0A /* LibreConfigProvider.swift in Sources */,
-				CE94598729E9E4110047C9C6 /* GarminConfigRootView.swift in Sources */,
+				CE94598729E9E4110047C9C6 /* WatchConfigRootView.swift in Sources */,
 				903D18976088B09110BCBE29 /* LibreConfigStateModel.swift in Sources */,
 				9050F378F0063C064D7FFC86 /* LibreConfigRootView.swift in Sources */,
 				B7C465E9472624D8A2BE2A6A /* CalibrationsDataFlow.swift in Sources */,

+ 0 - 1
FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift

@@ -185,7 +185,6 @@ extension AddCarbs {
 
                         state.removePresetFromNewMeal()
                         if state.carbs == 0, state.fat == 0, state.protein == 0 { state.summation = [] }
-
                     }
                     label: { Text("[ -1 ]") }
                         .disabled(

+ 0 - 5
FreeAPS/Sources/Modules/GarminConfig/GarminConfigDataFlow.swift

@@ -1,5 +0,0 @@
-enum GarminConfig {
-    enum Config {}
-}
-
-protocol GarminConfigProvider {}

+ 0 - 3
FreeAPS/Sources/Modules/GarminConfig/GarminConfigProvider.swift

@@ -1,3 +0,0 @@
-extension GarminConfig {
-    final class Provider: BaseProvider, GarminConfigProvider {}
-}

+ 0 - 24
FreeAPS/Sources/Modules/GarminConfig/GarminConfigStateModel.swift

@@ -1,24 +0,0 @@
-import ConnectIQ
-import SwiftUI
-
-extension GarminConfig {
-    final class StateModel: BaseStateModel<Provider> {
-        @Injected() private var garmin: GarminManager!
-        @Published var devices: [IQDevice] = []
-
-        override func subscribe() {
-            devices = garmin.devices
-        }
-
-        func selectDevices() {
-            garmin.selectDevices()
-                .receive(on: DispatchQueue.main)
-                .weakAssign(to: \.devices, on: self)
-                .store(in: &lifetime)
-        }
-
-        func deleteDevice() {
-            garmin.updateListDevices(devices: devices)
-        }
-    }
-}

+ 0 - 38
FreeAPS/Sources/Modules/GarminConfig/View/GarminConfigRootView.swift

@@ -1,38 +0,0 @@
-import SwiftUI
-import Swinject
-
-extension GarminConfig {
-    struct RootView: BaseView {
-        let resolver: Resolver
-        @StateObject var state = StateModel()
-
-        var body: some View {
-            Form {
-                Section {
-                    Button("Select devices") {
-                        state.selectDevices()
-                    }
-                }
-
-                if state.devices.isNotEmpty {
-                    Section(header: Text("Connected devices")) {
-                        List {
-                            ForEach(state.devices, id: \.uuid) { device in
-                                Text(device.friendlyName)
-                            }
-                            .onDelete(perform: onDelete)
-                        }
-                    }
-                }
-            }
-            .onAppear(perform: configureView)
-            .navigationTitle("Garmin Watch")
-            .navigationBarTitleDisplayMode(.automatic)
-        }
-
-        private func onDelete(offsets: IndexSet) {
-            state.devices.remove(atOffsets: offsets)
-            state.deleteDevice()
-        }
-    }
-}

+ 1 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -242,7 +242,7 @@ extension Home {
                 }
 
                 Spacer()
-                
+
                 if let overrideString = overrideString {
                     Text(overrideString)
                         .font(.system(size: 12))

+ 0 - 2
FreeAPS/Sources/Modules/PreferencesEditor/PreferencesEditorStateModel.swift

@@ -7,7 +7,6 @@ extension PreferencesEditor {
         @Published var allowAnnouncements = false
         @Published var insulinReqFraction: Decimal = 2.0
         @Published var skipBolusScreenAfterCarbs = false
-        @Published var displayHR = false
         @Published var displayStatistics = false
         @Published var sections: [FieldSection] = []
 
@@ -15,7 +14,6 @@ extension PreferencesEditor {
             preferences = provider.preferences
             subscribeSetting(\.allowAnnouncements, on: $allowAnnouncements) { allowAnnouncements = $0 }
             subscribeSetting(\.insulinReqFraction, on: $insulinReqFraction) { insulinReqFraction = $0 }
-            subscribeSetting(\.displayHR, on: $displayHR) { displayHR = $0 }
             subscribeSetting(\.displayStatistics, on: $displayStatistics) { displayStatistics = $0 }
             subscribeSetting(\.skipBolusScreenAfterCarbs, on: $skipBolusScreenAfterCarbs) { skipBolusScreenAfterCarbs = $0 }
 

+ 0 - 2
FreeAPS/Sources/Modules/PreferencesEditor/View/PreferencesEditorRootView.swift

@@ -37,8 +37,6 @@ extension PreferencesEditor {
 
                     Toggle("Skip Bolus screen after carbs", isOn: $state.skipBolusScreenAfterCarbs)
 
-                    Toggle("Display HR on Watch", isOn: $state.displayHR)
-
                     Toggle("Display Statistics", isOn: $state.displayStatistics)
                 }
 

+ 1 - 1
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -21,7 +21,7 @@ extension Settings {
                 Section(header: Text("Devices")) {
                     Text("Pump").navigationLink(to: .pumpConfig, from: self)
                     Text("CGM").navigationLink(to: .cgm, from: self)
-                    Text("Garmin watch").navigationLink(to: .garmin, from: self)
+                    Text("Watch Devices").navigationLink(to: .watch, from: self)
                 }
 
                 Section(header: Text("Services")) {

+ 43 - 0
FreeAPS/Sources/Modules/WatchConfig/View/WatchConfigRootView.swift

@@ -0,0 +1,43 @@
+import SwiftUI
+import Swinject
+
+extension WatchConfig {
+    struct RootView: BaseView {
+        let resolver: Resolver
+        @StateObject var state = StateModel()
+
+        var body: some View {
+            Form {
+                Section(header: Text("Apple Watch")) {
+                    Picker(
+                        selection: $state.selectedAwConfig,
+                        label: Text("Display on Watch")
+                    ) {
+                        ForEach(AwConfig.allCases) { v in
+                            Text(v.rawValue).tag(v)
+                        }
+                    }
+                }
+                Section(header: Text("Garmin Watch")) {
+                    List {
+                        ForEach(state.devices, id: \.uuid) { device in
+                            Text(device.friendlyName)
+                        }
+                        .onDelete(perform: onDelete)
+                    }
+                    Button("Add devices") {
+                        state.selectGarminDevices()
+                    }
+                }
+            }
+            .onAppear(perform: configureView)
+            .navigationTitle("Watch Configuration")
+            .navigationBarTitleDisplayMode(.automatic)
+        }
+
+        private func onDelete(offsets: IndexSet) {
+            state.devices.remove(atOffsets: offsets)
+            state.deleteGarminDevice()
+        }
+    }
+}

+ 5 - 0
FreeAPS/Sources/Modules/WatchConfig/WatchConfigDataFlow.swift

@@ -0,0 +1,5 @@
+enum WatchConfig {
+    enum Config {}
+}
+
+protocol WatchConfigProvider {}

+ 20 - 0
FreeAPS/Sources/Modules/WatchConfig/WatchConfigProvider.swift

@@ -0,0 +1,20 @@
+import Foundation
+
+extension WatchConfig {
+    final class Provider: BaseProvider, WatchConfigProvider {
+        @Injected() private var settingsManager: SettingsManager!
+        private let processQueue = DispatchQueue(label: "WatchDeviceProvider.processQueue")
+
+        var preferences: Preferences {
+            settingsManager.preferences
+        }
+
+        func savePreferences(_ preferences: Preferences) {
+            processQueue.async {
+                var prefs = preferences
+                prefs.timestamp = Date()
+                self.storage.save(prefs, as: OpenAPS.Settings.preferences)
+            }
+        }
+    }
+}

+ 56 - 0
FreeAPS/Sources/Modules/WatchConfig/WatchConfigStateModel.swift

@@ -0,0 +1,56 @@
+import ConnectIQ
+import SwiftUI
+
+enum AwConfig: String, CaseIterable, Identifiable {
+    var id: Self { self }
+    case HR = "Heart Rate"
+    case BGTarget = "Glucose Target"
+}
+
+extension WatchConfig {
+    final class StateModel: BaseStateModel<Provider> {
+        @Injected() private var garmin: GarminManager!
+        @Published var devices: [IQDevice] = []
+        @Published var selectedAwConfig: AwConfig = .HR
+        @Published var displayHR = false
+
+        private(set) var preferences = Preferences()
+
+        override func subscribe() {
+            preferences = provider.preferences
+            switch settingsManager.settings.displayHR {
+            case true:
+                selectedAwConfig = .HR
+            case false:
+                selectedAwConfig = .BGTarget
+            }
+
+            $selectedAwConfig.removeDuplicates()
+                .map {
+                    switch $0 {
+                    case .HR:
+                        return true
+                    case .BGTarget:
+                        return false
+                    }
+                }
+                .sink { [weak self] value in
+                    self?.settingsManager.settings.displayHR = value
+                }
+                .store(in: &lifetime)
+
+            devices = garmin.devices
+        }
+
+        func selectGarminDevices() {
+            garmin.selectDevices()
+                .receive(on: DispatchQueue.main)
+                .weakAssign(to: \.devices, on: self)
+                .store(in: &lifetime)
+        }
+
+        func deleteGarminDevice() {
+            garmin.updateListDevices(devices: devices)
+        }
+    }
+}

+ 3 - 3
FreeAPS/Sources/Router/Screen.swift

@@ -29,7 +29,7 @@ enum Screen: Identifiable, Hashable {
     case iconConfig
     case overrideProfilesConfig
     case snooze
-    case garmin
+    case watch
 
     var id: Int { String(reflecting: self).hashValue }
 }
@@ -94,8 +94,8 @@ extension Screen {
             OverrideProfilesConfig.RootView(resolver: resolver)
         case .snooze:
             Snooze.RootView(resolver: resolver)
-        case .garmin:
-            GarminConfig.RootView(resolver: resolver)
+        case .watch:
+            WatchConfig.RootView(resolver: resolver)
         }
     }