Ivan Valkou 5 лет назад
Родитель
Сommit
1f2fb85234

+ 8 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -92,6 +92,7 @@
 		388E5A5C25B6F0770019842D /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5B25B6F0770019842D /* JSON.swift */; };
 		388E5A5C25B6F0770019842D /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5B25B6F0770019842D /* JSON.swift */; };
 		388E5A6025B6F2310019842D /* Autosens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5F25B6F2310019842D /* Autosens.swift */; };
 		388E5A6025B6F2310019842D /* Autosens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5F25B6F2310019842D /* Autosens.swift */; };
 		3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3895E4C525B9E00D00214B37 /* Preferences.swift */; };
 		3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3895E4C525B9E00D00214B37 /* Preferences.swift */; };
+		38A13D3225E28B4B00EAA382 /* PumpHystoryEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38A13D3125E28B4B00EAA382 /* PumpHystoryEvent.swift */; };
 		38A504A425DD9C4000C5B9E8 /* UserDefaultsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */; };
 		38A504A425DD9C4000C5B9E8 /* UserDefaultsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */; };
 		38A504A525DD9FDA00C5B9E8 /* OmniKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B2625DD6BBE005CAE3D /* OmniKit.framework */; };
 		38A504A525DD9FDA00C5B9E8 /* OmniKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B2625DD6BBE005CAE3D /* OmniKit.framework */; };
 		38A504A625DD9FDA00C5B9E8 /* OmniKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B2625DD6BBE005CAE3D /* OmniKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		38A504A625DD9FDA00C5B9E8 /* OmniKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B2625DD6BBE005CAE3D /* OmniKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -121,6 +122,7 @@
 		38B17B9925DD941A005CAE3D /* RileyLinkKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1825DD6BBE005CAE3D /* RileyLinkKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		38B17B9925DD941A005CAE3D /* RileyLinkKitUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1825DD6BBE005CAE3D /* RileyLinkKitUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		38B17BED25DD987B005CAE3D /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1A25DD6BBE005CAE3D /* NightscoutUploadKit.framework */; };
 		38B17BED25DD987B005CAE3D /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1A25DD6BBE005CAE3D /* NightscoutUploadKit.framework */; };
 		38B17BEE25DD987B005CAE3D /* NightscoutUploadKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1A25DD6BBE005CAE3D /* NightscoutUploadKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		38B17BEE25DD987B005CAE3D /* NightscoutUploadKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38B17B1A25DD6BBE005CAE3D /* NightscoutUploadKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		38B4F3AF25E2979F00E76A18 /* IndexedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38B4F3AE25E2979F00E76A18 /* IndexedCollection.swift */; };
 		38FE826A25CC82DB001FF17A /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FE826925CC82DB001FF17A /* NetworkService.swift */; };
 		38FE826A25CC82DB001FF17A /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FE826925CC82DB001FF17A /* NetworkService.swift */; };
 		38FE826D25CC8461001FF17A /* NightscoutAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FE826C25CC8461001FF17A /* NightscoutAPI.swift */; };
 		38FE826D25CC8461001FF17A /* NightscoutAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FE826C25CC8461001FF17A /* NightscoutAPI.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
@@ -579,12 +581,14 @@
 		388E5A5B25B6F0770019842D /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
 		388E5A5B25B6F0770019842D /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
 		388E5A5F25B6F2310019842D /* Autosens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Autosens.swift; sourceTree = "<group>"; };
 		388E5A5F25B6F2310019842D /* Autosens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Autosens.swift; sourceTree = "<group>"; };
 		3895E4C525B9E00D00214B37 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
 		3895E4C525B9E00D00214B37 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
+		38A13D3125E28B4B00EAA382 /* PumpHystoryEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpHystoryEvent.swift; sourceTree = "<group>"; };
 		38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtensions.swift; sourceTree = "<group>"; };
 		38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtensions.swift; sourceTree = "<group>"; };
 		38B17AAE25DD69FA005CAE3D /* SwiftCharts.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftCharts.xcodeproj; path = SwiftCharts/SwiftCharts.xcodeproj; sourceTree = "<group>"; };
 		38B17AAE25DD69FA005CAE3D /* SwiftCharts.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftCharts.xcodeproj; path = SwiftCharts/SwiftCharts.xcodeproj; sourceTree = "<group>"; };
 		38B17AC025DD6A40005CAE3D /* LoopKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LoopKit.xcodeproj; path = LoopKit/LoopKit.xcodeproj; sourceTree = "<group>"; };
 		38B17AC025DD6A40005CAE3D /* LoopKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LoopKit.xcodeproj; path = LoopKit/LoopKit.xcodeproj; sourceTree = "<group>"; };
 		38B17AF025DD6AE6005CAE3D /* MKRingProgressView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MKRingProgressView.xcodeproj; path = MKRingProgressView/MKRingProgressView.xcodeproj; sourceTree = "<group>"; };
 		38B17AF025DD6AE6005CAE3D /* MKRingProgressView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MKRingProgressView.xcodeproj; path = MKRingProgressView/MKRingProgressView.xcodeproj; sourceTree = "<group>"; };
 		38B17AF925DD6BBD005CAE3D /* RileyLink.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RileyLink.xcodeproj; path = rileylink_ios/RileyLink.xcodeproj; sourceTree = "<group>"; };
 		38B17AF925DD6BBD005CAE3D /* RileyLink.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RileyLink.xcodeproj; path = rileylink_ios/RileyLink.xcodeproj; sourceTree = "<group>"; };
 		38B17B6225DD8B5B005CAE3D /* DeviceDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceDataManager.swift; sourceTree = "<group>"; };
 		38B17B6225DD8B5B005CAE3D /* DeviceDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceDataManager.swift; sourceTree = "<group>"; };
+		38B4F3AE25E2979F00E76A18 /* IndexedCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexedCollection.swift; sourceTree = "<group>"; };
 		38FE826925CC82DB001FF17A /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = "<group>"; };
 		38FE826925CC82DB001FF17A /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = "<group>"; };
 		38FE826C25CC8461001FF17A /* NightscoutAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutAPI.swift; sourceTree = "<group>"; };
 		38FE826C25CC8461001FF17A /* NightscoutAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutAPI.swift; sourceTree = "<group>"; };
 		3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigProvider.swift; sourceTree = "<group>"; };
 		3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigProvider.swift; sourceTree = "<group>"; };
@@ -1010,6 +1014,7 @@
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
 				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
 				383948D925CD64D500E91849 /* Glucose.swift */,
 				383948D925CD64D500E91849 /* Glucose.swift */,
+				38A13D3125E28B4B00EAA382 /* PumpHystoryEvent.swift */,
 			);
 			);
 			path = Models;
 			path = Models;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1023,6 +1028,7 @@
 				3811DE5525C9D4D500A708ED /* Publisher.swift */,
 				3811DE5525C9D4D500A708ED /* Publisher.swift */,
 				3811DE5925C9D4D500A708ED /* ViewModifiers.swift */,
 				3811DE5925C9D4D500A708ED /* ViewModifiers.swift */,
 				388E5A5B25B6F0770019842D /* JSON.swift */,
 				388E5A5B25B6F0770019842D /* JSON.swift */,
+				38B4F3AE25E2979F00E76A18 /* IndexedCollection.swift */,
 			);
 			);
 			path = Helpers;
 			path = Helpers;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1562,6 +1568,7 @@
 				388E5A5C25B6F0770019842D /* JSON.swift in Sources */,
 				388E5A5C25B6F0770019842D /* JSON.swift in Sources */,
 				3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */,
 				3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
+				38A13D3225E28B4B00EAA382 /* PumpHystoryEvent.swift in Sources */,
 				3811DE1825C9D40400A708ED /* Router.swift in Sources */,
 				3811DE1825C9D40400A708ED /* Router.swift in Sources */,
 				3811DEE825CA063400A708ED /* Injected.swift in Sources */,
 				3811DEE825CA063400A708ED /* Injected.swift in Sources */,
 				3811DEAF25C9D88300A708ED /* KeyValueStorage.swift in Sources */,
 				3811DEAF25C9D88300A708ED /* KeyValueStorage.swift in Sources */,
@@ -1575,6 +1582,7 @@
 				384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */,
 				384E803425C385E60086DB71 /* JavaScriptWorker.swift in Sources */,
 				3811DE7A25C9D6D300A708ED /* LoginDataFlow.swift in Sources */,
 				3811DE7A25C9D6D300A708ED /* LoginDataFlow.swift in Sources */,
 				3811DE5D25C9D4D500A708ED /* Publisher.swift in Sources */,
 				3811DE5D25C9D4D500A708ED /* Publisher.swift in Sources */,
+				38B4F3AF25E2979F00E76A18 /* IndexedCollection.swift in Sources */,
 				3811DEAE25C9D88300A708ED /* Cache.swift in Sources */,
 				3811DEAE25C9D88300A708ED /* Cache.swift in Sources */,
 				3811DEAD25C9D88300A708ED /* UserDefaults+Cache.swift in Sources */,
 				3811DEAD25C9D88300A708ED /* UserDefaults+Cache.swift in Sources */,
 				3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */,
 				3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */,

+ 14 - 2
FreeAPS/Sources/APS/APSManager.swift

@@ -1,11 +1,23 @@
 import Combine
 import Combine
 import RileyLinkBLEKit
 import RileyLinkBLEKit
 
 
-struct RileyDisplayState: Identifiable {
+class RileyDisplayState: ObservableObject, Identifiable {
     let id: UUID
     let id: UUID
     let name: String
     let name: String
     let rssi: Int?
     let rssi: Int?
-    let connected: Bool
+    var connected: Bool {
+        didSet { didChangeConnection(connected) }
+    }
+
+    let didChangeConnection: (Bool) -> Void
+
+    init(id: UUID, name: String, rssi: Int?, connected: Bool, didChangeConnection: @escaping (Bool) -> Void) {
+        self.id = id
+        self.name = name
+        self.rssi = rssi
+        self.connected = connected
+        self.didChangeConnection = didChangeConnection
+    }
 }
 }
 
 
 protocol APSManager {
 protocol APSManager {

+ 15 - 8
FreeAPS/Sources/APS/BaseAPSManager.swift

@@ -53,13 +53,21 @@ final class BaseAPSManager: APSManager, Injectable {
     }
     }
 
 
     private func updateDisplayStates() {
     private func updateDisplayStates() {
-        rileyDisplayStates.value = devices.map {
-            RileyDisplayState(
-                id: $0.peripheralIdentifier,
-                name: $0.name ?? "unknown",
-                rssi: self.deviceRSSI[$0.peripheralIdentifier],
-                connected: false
-            )
+        rileyDisplayStates.value = devices.map { device in
+            let connected = rileyLinkPumpManager.rileyLinkConnectionManager?
+                .shouldConnect(to: device.peripheralIdentifier.uuidString) ?? false
+            return RileyDisplayState(
+                id: device.peripheralIdentifier,
+                name: device.name ?? "unknown",
+                rssi: self.deviceRSSI[device.peripheralIdentifier],
+                connected: connected
+            ) { [weak self] connect in
+                if connect {
+                    self?.rileyLinkPumpManager.connectToRileyLink(device)
+                } else {
+                    self?.rileyLinkPumpManager.disconnectFromRileyLink(device)
+                }
+            }
         }
         }
     }
     }
 
 
@@ -82,7 +90,6 @@ final class BaseAPSManager: APSManager, Injectable {
         rileyLinkPumpManager.rileyLinkDeviceProvider.getDevices { devices in
         rileyLinkPumpManager.rileyLinkDeviceProvider.getDevices { devices in
             DispatchQueue.main.async { [weak self] in
             DispatchQueue.main.async { [weak self] in
                 self?.devices = devices
                 self?.devices = devices
-                devices.forEach { self?.rileyLinkPumpManager.connectToRileyLink($0) }
             }
             }
         }
         }
     }
     }

+ 34 - 0
FreeAPS/Sources/Helpers/IndexedCollection.swift

@@ -0,0 +1,34 @@
+import Foundation
+
+struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
+    typealias Index = Base.Index
+    typealias Element = (index: Index, element: Base.Element)
+
+    let base: Base
+
+    var startIndex: Index { base.startIndex }
+
+    var endIndex: Index { base.endIndex }
+
+    func index(after i: Index) -> Index {
+        base.index(after: i)
+    }
+
+    func index(before i: Index) -> Index {
+        base.index(before: i)
+    }
+
+    func index(_ i: Index, offsetBy distance: Int) -> Index {
+        base.index(i, offsetBy: distance)
+    }
+
+    subscript(position: Index) -> Element {
+        (index: position, element: base[position])
+    }
+}
+
+extension RandomAccessCollection {
+    func indexed() -> IndexedCollection<Self> {
+        IndexedCollection(base: self)
+    }
+}

+ 40 - 0
FreeAPS/Sources/Models/PumpHystoryEvent.swift

@@ -0,0 +1,40 @@
+import Foundation
+
+struct PumpHystoryEvent: JSON {
+    let id: UUID
+    let type: PumpHystoryEventType
+    let timestamp: Date
+    let amount: Decimal?
+    let duration: Int?
+    let durationMin: Int?
+    let rate: Decimal?
+    let temp: PumpHystoryTempType?
+}
+
+enum PumpHystoryEventType: String, JSON {
+    case bolus = "Bolus"
+    case mealBulus = "Meal Bolus"
+    case correctionBolus = "Correction Bolus"
+    case snackBolus = "Snack Bolus"
+    case bolusWizard = "Bolus Wizard"
+    case tempBasal = "TempBasal"
+    case tempBasalDuration = "TempBasalDuration"
+}
+
+enum PumpHystoryTempType: String, JSON {
+    case absolute
+    case percent
+}
+
+extension PumpHystoryEvent {
+    private enum CodingKeys: String, CodingKey {
+        case id
+        case type = "_type"
+        case timestamp
+        case amount
+        case duration
+        case durationMin = "duration (min)"
+        case rate
+        case temp
+    }
+}

+ 7 - 5
FreeAPS/Sources/Modules/PumpConfig/View/PumpConfigRootView.swift

@@ -7,11 +7,13 @@ extension PumpConfig {
         var body: some View {
         var body: some View {
             Form {
             Form {
                 Section(header: Text("Devices")) {
                 Section(header: Text("Devices")) {
-                    ForEach(viewModel.rileyDisplayStates) { state in
-                        HStack {
-                            Text(state.name)
-                            Spacer()
-                            Text(state.rssi.map { "\($0) " } ?? "")
+                    ForEach(viewModel.rileyDisplayStates.indexed(), id: \.1.id) { index, state in
+                        Toggle(isOn: self.$viewModel.rileyDisplayStates[index].connected) {
+                            HStack {
+                                Text(state.name)
+                                Spacer()
+                                Text(state.rssi.map { "\($0) " } ?? "").foregroundColor(.secondary)
+                            }
                         }
                         }
                     }
                     }
                 }
                 }