NightscoutConfigStateModel.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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. if let CheckURL = url.last, CheckURL == "/" {
  44. let fixedURL = url.dropLast()
  45. url = String(fixedURL)
  46. }
  47. guard let url = URL(string: url) else {
  48. message = "Invalid URL"
  49. return
  50. }
  51. connecting = true
  52. message = ""
  53. provider.checkConnection(url: url, secret: secret.isEmpty ? nil : secret)
  54. .receive(on: DispatchQueue.main)
  55. .sink { completion in
  56. switch completion {
  57. case .finished: break
  58. case let .failure(error):
  59. self.message = "Error: \(error.localizedDescription)"
  60. }
  61. self.connecting = false
  62. } receiveValue: {
  63. self.message = "Connected!"
  64. self.keychain.setValue(self.url, forKey: Config.urlKey)
  65. self.keychain.setValue(self.secret, forKey: Config.secretKey)
  66. }
  67. .store(in: &lifetime)
  68. }
  69. func backfillGlucose() {
  70. backfilling = true
  71. nightscoutManager.fetchGlucose(since: Date().addingTimeInterval(-1.days.timeInterval))
  72. .sink { [weak self] glucose in
  73. guard let self = self else { return }
  74. DispatchQueue.main.async {
  75. self.backfilling = false
  76. }
  77. guard glucose.isNotEmpty else { return }
  78. self.healthKitManager.saveIfNeeded(bloodGlucose: glucose)
  79. self.glucoseStorage.storeGlucose(glucose)
  80. }
  81. .store(in: &lifetime)
  82. }
  83. func delete() {
  84. keychain.removeObject(forKey: Config.urlKey)
  85. keychain.removeObject(forKey: Config.secretKey)
  86. url = ""
  87. secret = ""
  88. }
  89. }
  90. }