NightscoutConfigStateModel.swift 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import CGMBLEKit
  2. import Combine
  3. import G7SensorKit
  4. import SwiftDate
  5. import SwiftUI
  6. extension NightscoutConfig {
  7. final class StateModel: BaseStateModel<Provider> {
  8. @Injected() private var keychain: Keychain!
  9. @Injected() private var nightscoutManager: NightscoutManager!
  10. @Injected() private var glucoseStorage: GlucoseStorage!
  11. @Injected() private var healthKitManager: HealthKitManager!
  12. @Injected() private var cgmManager: FetchGlucoseManager!
  13. @Published var url = ""
  14. @Published var secret = ""
  15. @Published var message = ""
  16. @Published var connecting = false
  17. @Published var backfilling = false
  18. @Published var isUploadEnabled = false // Allow uploads
  19. @Published var uploadStats = false // Upload Statistics
  20. @Published var uploadGlucose = true // Upload Glucose
  21. @Published var useLocalSource = false
  22. @Published var localPort: Decimal = 0
  23. override func subscribe() {
  24. url = keychain.getValue(String.self, forKey: Config.urlKey) ?? ""
  25. secret = keychain.getValue(String.self, forKey: Config.secretKey) ?? ""
  26. subscribeSetting(\.isUploadEnabled, on: $isUploadEnabled) { isUploadEnabled = $0 }
  27. subscribeSetting(\.useLocalGlucoseSource, on: $useLocalSource) { useLocalSource = $0 }
  28. subscribeSetting(\.localGlucosePort, on: $localPort.map(Int.init)) { localPort = Decimal($0) }
  29. subscribeSetting(\.uploadStats, on: $uploadStats) { uploadStats = $0 }
  30. subscribeSetting(\.uploadGlucose, on: $uploadGlucose, initial: { uploadGlucose = $0 }, didSet: { val in
  31. if let cgmManagerG5 = self.cgmManager.glucoseSource.cgmManager as? G5CGMManager {
  32. cgmManagerG5.shouldSyncToRemoteService = val
  33. }
  34. if let cgmManagerG6 = self.cgmManager.glucoseSource.cgmManager as? G6CGMManager {
  35. cgmManagerG6.shouldSyncToRemoteService = val
  36. }
  37. if let cgmManagerG7 = self.cgmManager.glucoseSource.cgmManager as? G7CGMManager {
  38. cgmManagerG7.uploadReadings = val
  39. }
  40. })
  41. }
  42. func connect() {
  43. guard let url = URL(string: url) else {
  44. message = "Invalid URL"
  45. return
  46. }
  47. connecting = true
  48. message = ""
  49. provider.checkConnection(url: url, secret: secret.isEmpty ? nil : secret)
  50. .receive(on: DispatchQueue.main)
  51. .sink { completion in
  52. switch completion {
  53. case .finished: break
  54. case let .failure(error):
  55. self.message = "Error: \(error.localizedDescription)"
  56. }
  57. self.connecting = false
  58. } receiveValue: {
  59. self.message = "Connected!"
  60. self.keychain.setValue(self.url, forKey: Config.urlKey)
  61. self.keychain.setValue(self.secret, forKey: Config.secretKey)
  62. }
  63. .store(in: &lifetime)
  64. }
  65. func backfillGlucose() {
  66. backfilling = true
  67. nightscoutManager.fetchGlucose(since: Date().addingTimeInterval(-1.days.timeInterval))
  68. .sink { [weak self] glucose in
  69. guard let self = self else { return }
  70. DispatchQueue.main.async {
  71. self.backfilling = false
  72. }
  73. guard glucose.isNotEmpty else { return }
  74. self.healthKitManager.saveIfNeeded(bloodGlucose: glucose)
  75. self.glucoseStorage.storeGlucose(glucose)
  76. }
  77. .store(in: &lifetime)
  78. }
  79. func delete() {
  80. keychain.removeObject(forKey: Config.urlKey)
  81. keychain.removeObject(forKey: Config.secretKey)
  82. url = ""
  83. secret = ""
  84. }
  85. }
  86. }