From c9e747a62cbaaa346a8c770abc17b7d6512033d7 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Thu, 6 Jun 2024 11:11:58 +0200 Subject: [PATCH 1/4] Port over pump loss fix via LoopKit/Loop#1702 Co-authored-by: kskandis --- FreeAPS/Sources/APS/DeviceDataManager.swift | 60 ++++--------------- .../Extensions/PumpManagerExtensions.swift | 18 +----- .../Extensions/UserDefaultsExtensions.swift | 29 +++++---- FreeAPS/Sources/APS/FetchGlucoseManager.swift | 1 + .../PropertyWrappers/PersistedProperty.swift | 1 - 5 files changed, 33 insertions(+), 76 deletions(-) diff --git a/FreeAPS/Sources/APS/DeviceDataManager.swift b/FreeAPS/Sources/APS/DeviceDataManager.swift index 349149a1e..138e292c4 100644 --- a/FreeAPS/Sources/APS/DeviceDataManager.swift +++ b/FreeAPS/Sources/APS/DeviceDataManager.swift @@ -43,10 +43,6 @@ private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = [ MockPumpManager.pluginIdentifier: MockPumpManager.self ] -// private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = staticPumpManagers.reduce(into: [:]) { map, Type in -// map[Type.managerIdentifier] = Type -// } - private let accessLock = NSRecursiveLock(label: "BaseDeviceDataManager.accessLock") final class BaseDeviceDataManager: DeviceDataManager, Injectable { @@ -78,7 +74,8 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { didSet { pumpManager?.pumpManagerDelegate = self pumpManager?.delegateQueue = processQueue - UserDefaults.standard.pumpManagerRawValue = pumpManager?.rawValue + rawPumpManager = pumpManager?.rawValue + UserDefaults.standard.clearLegacyPumpManagerRawValue() if let pumpManager = pumpManager { pumpDisplayState.value = PumpDisplayState(name: pumpManager.localizedTitle, image: pumpManager.smallImage) pumpName.send(pumpManager.localizedTitle) @@ -105,6 +102,8 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { } } + @PersistedProperty(key: "PumpManagerState") var rawPumpManager: PumpManager.RawValue? + var bluetoothManager: BluetoothStateManager { bluetoothProvider } var hasBLEHeartbeat: Bool { @@ -123,7 +122,11 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { } func setupPumpManager() { - pumpManager = UserDefaults.standard.pumpManagerRawValue.flatMap { pumpManagerFromRawValue($0) } + if let pumpManagerRawValue = rawPumpManager ?? UserDefaults.standard.legacyPumpManagerRawValue { + pumpManager = pumpManagerFromRawValue(pumpManagerRawValue) + } else { + pumpManager = nil + } } func createBolusProgressReporter() -> DoseProgressReporter? { @@ -163,20 +166,6 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { self.updateUpdateFinished(true) } } - -// pumpUpdateCancellable = Future { [unowned self] promise in -// pumpUpdatePromise = promise -// debug(.deviceManager, "Waiting for pump update and loop recommendation") -// processQueue.safeSync { -// pumpManager.ensureCurrentPumpData { _ in -// debug(.deviceManager, "Pump data updated.") -// } -// } -// } -// .timeout(30, scheduler: processQueue) -// .replaceError(with: false) -// .replaceEmpty(with: false) -// .sink(receiveValue: updateUpdateFinished) } private func updateUpdateFinished(_ recommendsLoop: Bool) { @@ -186,11 +175,6 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable { warning(.deviceManager, "Loop recommendation time out or got error. Trying to loop right now.") } - // directly in loop() function -// guard !loopInProgress else { -// warning(.deviceManager, "Loop already in progress. Skip recommendation.") -// return -// } self.recommendsLoop.send() } @@ -319,7 +303,8 @@ extension BaseDeviceDataManager: PumpManagerDelegate { } func pumpManagerDidUpdateState(_ pumpManager: PumpManager) { - UserDefaults.standard.pumpManagerRawValue = pumpManager.rawValue + rawPumpManager = pumpManager.rawValue + UserDefaults.standard.clearLegacyPumpManagerRawValue() if self.pumpManager == nil, let newPumpManager = pumpManager as? PumpManagerUI { self.pumpManager = newPumpManager } @@ -537,29 +522,6 @@ extension BaseDeviceDataManager: DeviceManagerDelegate { func recordRetractedAlert(_: Alert, at _: Date) {} -// func scheduleNotification( -// for _: DeviceManager, -// identifier: String, -// content: UNNotificationContent, -// trigger: UNNotificationTrigger? -// ) { -// let request = UNNotificationRequest( -// identifier: identifier, -// content: content, -// trigger: trigger -// ) -// -// DispatchQueue.main.async { -// UNUserNotificationCenter.current().add(request) -// } -// } -// -// func clearNotification(for _: DeviceManager, identifier: String) { -// DispatchQueue.main.async { -// UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier]) -// } -// } - func removeNotificationRequests(for _: DeviceManager, identifiers: [String]) { DispatchQueue.main.async { UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers) diff --git a/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift b/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift index 237aaa8d8..db6a3c9e3 100644 --- a/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift +++ b/FreeAPS/Sources/APS/Extensions/PumpManagerExtensions.swift @@ -2,6 +2,8 @@ import LoopKit import LoopKitUI extension PumpManager { + typealias RawValue = [String: Any] + var rawValue: [String: Any] { [ "managerIdentifier": pluginIdentifier, // "managerIdentifier": type(of: self).managerIdentifier, @@ -11,14 +13,6 @@ extension PumpManager { } extension PumpManagerUI { -// static func setupViewController() -> PumpManagerSetupViewController & UIViewController & CompletionNotifying { -// setupViewController( -// insulinTintColor: .accentColor, -// guidanceColors: GuidanceColors(acceptable: .green, warning: .orange, critical: .red), -// allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] -// ) -// } - func settingsViewController( bluetoothProvider: BluetoothProvider, pumpManagerOnboardingDelegate: PumpManagerOnboardingDelegate? @@ -32,14 +26,6 @@ extension PumpManagerUI { vc.pumpManagerOnboardingDelegate = pumpManagerOnboardingDelegate return vc } - -// func settingsViewController() -> UIViewController & CompletionNotifying { -// settingsViewController( -// insulinTintColor: .accentColor, -// guidanceColors: GuidanceColors(acceptable: .green, warning: .orange, critical: .red), -// allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev] -// ) -// } } protocol PumpSettingsBuilder { diff --git a/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift b/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift index 6c5428207..77c82eb6e 100644 --- a/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift +++ b/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift @@ -5,17 +5,10 @@ import RileyLinkKit extension UserDefaults { private enum Key: String { - case pumpManagerRawValue = "com.rileylink.PumpManagerRawValue" + case legacyPumpManagerRawValue = "com.rileylink.PumpManagerRawValue" case rileyLinkConnectionManagerState = "com.rileylink.RileyLinkConnectionManagerState" - } - - var pumpManagerRawValue: PumpManager.RawStateValue? { - get { - dictionary(forKey: Key.pumpManagerRawValue.rawValue) - } - set { - set(newValue, forKey: Key.pumpManagerRawValue.rawValue) - } + case legacyPumpManagerState = "com.loopkit.Loop.PumpManagerState" + case legacyCGMManagerState = "com.loopkit.Loop.CGMManagerState" } var rileyLinkConnectionManagerState: RileyLinkConnectionState? { @@ -30,4 +23,20 @@ extension UserDefaults { set(newValue?.rawValue, forKey: Key.rileyLinkConnectionManagerState.rawValue) } } + + var legacyPumpManagerRawValue: PumpManager.RawValue? { + dictionary(forKey: Key.legacyPumpManagerState.rawValue) + } + + func clearLegacyPumpManagerRawValue() { + set(nil, forKey: Key.legacyPumpManagerState.rawValue) + } + + var legacyCGMManagerRawValue: CGMManager.RawValue? { + dictionary(forKey: Key.legacyCGMManagerState.rawValue) + } + + func clearLegacyCGMManagerRawValue() { + set(nil, forKey: Key.legacyCGMManagerState.rawValue) + } } diff --git a/FreeAPS/Sources/APS/FetchGlucoseManager.swift b/FreeAPS/Sources/APS/FetchGlucoseManager.swift index 95ae1bfc4..113de1eca 100644 --- a/FreeAPS/Sources/APS/FetchGlucoseManager.swift +++ b/FreeAPS/Sources/APS/FetchGlucoseManager.swift @@ -45,6 +45,7 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable { var cgmManager: CGMManagerUI? { didSet { rawCGMManager = cgmManager?.rawValue + UserDefaults.standard.clearLegacyCGMManagerRawValue() } } diff --git a/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift b/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift index 3e50baa15..46419be33 100644 --- a/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift +++ b/FreeAPS/Sources/Helpers/PropertyWrappers/PersistedProperty.swift @@ -57,7 +57,6 @@ import Foundation self.key = key let documents: URL - guard let localDocuments = try? FileManager.default.url( for: .documentDirectory, in: .userDomainMask, From 75df98a6265377c833625cca74ec88af660cc145 Mon Sep 17 00:00:00 2001 From: kimberlieskandis Date: Fri, 7 Jun 2024 11:30:22 -0400 Subject: [PATCH 2/4] revert get and clean property value to original; add resetLoopDocuments method to delete pump state used for testing only --- FreeAPS/Sources/APS/DeviceDataManager.swift | 1 - .../APS/Extensions/UserDefaultsExtensions.swift | 4 ++-- .../Modules/Settings/SettingsStateModel.swift | 13 +++++++++++++ .../Modules/Settings/View/SettingsRootView.swift | 6 ++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/FreeAPS/Sources/APS/DeviceDataManager.swift b/FreeAPS/Sources/APS/DeviceDataManager.swift index 138e292c4..c6d5ca4fa 100644 --- a/FreeAPS/Sources/APS/DeviceDataManager.swift +++ b/FreeAPS/Sources/APS/DeviceDataManager.swift @@ -304,7 +304,6 @@ extension BaseDeviceDataManager: PumpManagerDelegate { func pumpManagerDidUpdateState(_ pumpManager: PumpManager) { rawPumpManager = pumpManager.rawValue - UserDefaults.standard.clearLegacyPumpManagerRawValue() if self.pumpManager == nil, let newPumpManager = pumpManager as? PumpManagerUI { self.pumpManager = newPumpManager } diff --git a/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift b/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift index 77c82eb6e..31d53c02d 100644 --- a/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift +++ b/FreeAPS/Sources/APS/Extensions/UserDefaultsExtensions.swift @@ -25,11 +25,11 @@ extension UserDefaults { } var legacyPumpManagerRawValue: PumpManager.RawValue? { - dictionary(forKey: Key.legacyPumpManagerState.rawValue) + dictionary(forKey: Key.legacyPumpManagerRawValue.rawValue) } func clearLegacyPumpManagerRawValue() { - set(nil, forKey: Key.legacyPumpManagerState.rawValue) + set(nil, forKey: Key.legacyPumpManagerRawValue.rawValue) } var legacyCGMManagerRawValue: CGMManager.RawValue? { diff --git a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift index a62aaa1bb..e90179b31 100644 --- a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift +++ b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift @@ -62,6 +62,19 @@ extension Settings { func hideSettingsModal() { hideModal() } + + func resetLoopDocuments() { + guard let localDocuments = try? FileManager.default.url( + for: .documentDirectory, + in: .userDomainMask, + appropriateFor: nil, + create: true + ) else { + preconditionFailure("Could not get a documents directory URL.") + } + let storageURL = localDocuments.appendingPathComponent("PumpManagerState" + ".plist") + try? FileManager.default.removeItem(at: storageURL) + } } } diff --git a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift index b46e098e9..aa06318f7 100644 --- a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift +++ b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift @@ -61,6 +61,12 @@ extension Settings { .frame(maxWidth: .infinity, alignment: .trailing) .buttonStyle(.borderedProminent) } + HStack { + Text("Delete Pump State nlist") + Button("Delete") { state.resetLoopDocuments() } + .frame(maxWidth: .infinity, alignment: .trailing) + .buttonStyle(.borderedProminent) + } } Group { Text("Preferences") From 3ac4c31767fc615f7eb5619646e948c6dacf67f7 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 8 Jun 2024 18:40:28 +0200 Subject: [PATCH 3/4] Comment out but keep `resetLoopDocuments()` --- .../Modules/Settings/SettingsStateModel.swift | 29 ++++++++++--------- .../Settings/View/SettingsRootView.swift | 16 ++++++---- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift index e90179b31..49bca4936 100644 --- a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift +++ b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift @@ -62,19 +62,22 @@ extension Settings { func hideSettingsModal() { hideModal() } - - func resetLoopDocuments() { - guard let localDocuments = try? FileManager.default.url( - for: .documentDirectory, - in: .userDomainMask, - appropriateFor: nil, - create: true - ) else { - preconditionFailure("Could not get a documents directory URL.") - } - let storageURL = localDocuments.appendingPathComponent("PumpManagerState" + ".plist") - try? FileManager.default.removeItem(at: storageURL) - } +// Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu +// Leaving it in here, as it may be a handy functionality for further testing or developers. +// See https://github.com/nightscout/Trio/pull/277 for more information +// +// func resetLoopDocuments() { +// guard let localDocuments = try? FileManager.default.url( +// for: .documentDirectory, +// in: .userDomainMask, +// appropriateFor: nil, +// create: true +// ) else { +// preconditionFailure("Could not get a documents directory URL.") +// } +// let storageURL = localDocuments.appendingPathComponent("PumpManagerState" + ".plist") +// try? FileManager.default.removeItem(at: storageURL) +// } } } diff --git a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift index aa06318f7..48031a088 100644 --- a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift +++ b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift @@ -61,12 +61,16 @@ extension Settings { .frame(maxWidth: .infinity, alignment: .trailing) .buttonStyle(.borderedProminent) } - HStack { - Text("Delete Pump State nlist") - Button("Delete") { state.resetLoopDocuments() } - .frame(maxWidth: .infinity, alignment: .trailing) - .buttonStyle(.borderedProminent) - } +// Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu +// Leaving it in here, as it may be a handy functionality for further testing or developers. +// See https://github.com/nightscout/Trio/pull/277 for more information +// +// HStack { +// Text("Delete Stored Pump State Binary Files") +// Button("Delete") { state.resetLoopDocuments() } +// .frame(maxWidth: .infinity, alignment: .trailing) +// .buttonStyle(.borderedProminent) +// } } Group { Text("Preferences") From 4445e1d0cfa0d0a5ca65652dd25d067da0b2b93e Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 8 Jun 2024 19:45:30 +0200 Subject: [PATCH 4/4] Fix formatting for commented out code --- FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift | 7 ++++--- .../Sources/Modules/Settings/View/SettingsRootView.swift | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift index 49bca4936..3910fb3a7 100644 --- a/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift +++ b/FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift @@ -62,9 +62,10 @@ extension Settings { func hideSettingsModal() { hideModal() } -// Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu -// Leaving it in here, as it may be a handy functionality for further testing or developers. -// See https://github.com/nightscout/Trio/pull/277 for more information + + // Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu + // Leaving it in here, as it may be a handy functionality for further testing or developers. + // See https://github.com/nightscout/Trio/pull/277 for more information // // func resetLoopDocuments() { // guard let localDocuments = try? FileManager.default.url( diff --git a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift index 48031a088..fa56f5823 100644 --- a/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift +++ b/FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift @@ -61,9 +61,9 @@ extension Settings { .frame(maxWidth: .infinity, alignment: .trailing) .buttonStyle(.borderedProminent) } -// Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu -// Leaving it in here, as it may be a handy functionality for further testing or developers. -// See https://github.com/nightscout/Trio/pull/277 for more information + // Commenting this out for now, as not needed and possibly dangerous for users to be able to nuke their pump pairing informations via the debug menu + // Leaving it in here, as it may be a handy functionality for further testing or developers. + // See https://github.com/nightscout/Trio/pull/277 for more information // // HStack { // Text("Delete Stored Pump State Binary Files")