Pārlūkot izejas kodu

Fix CGM sheet glitch; minor cleanup and refactoring

Deniz Cengiz 1 gadu atpakaļ
vecāks
revīzija
75b3700f88

+ 1 - 1
Trio/Sources/APS/CGM/CGMType.swift

@@ -22,7 +22,7 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
         case .enlite:
             return "Medtronic Enlite"
         case .plugin:
-            return "plugin CGM"
+            return "Plugin CGM"
         }
     }
 

+ 28 - 19
Trio/Sources/Modules/CGM/CGMStateModel.swift

@@ -4,14 +4,19 @@ import G7SensorKit
 import LoopKitUI
 import SwiftUI
 
-struct cgmName: Identifiable, Hashable {
+struct CGMModel: Identifiable, Hashable {
     var id: String
     var type: CGMType
     var displayName: String
     var subtitle: String
 }
 
-let cgmDefaultName = cgmName(
+struct CGMOption {
+    let name: String
+    let predicate: (CGMModel) -> Bool
+}
+
+let cgmDefaultModel = CGMModel(
     id: CGMType.none.id,
     type: .none,
     displayName: CGMType.none.displayName,
@@ -30,11 +35,11 @@ extension CGM {
         @Injected() var nightscoutManager: NightscoutManager!
 
         @Published var units: GlucoseUnits = .mgdL
-        @Published var setupCGM: Bool = false
-        @Published var cgmCurrent = cgmDefaultName
+        @Published var shouldDisplayCGMSetupSheet: Bool = false
+        @Published var cgmCurrent = cgmDefaultModel
         @Published var smoothGlucose = false
         @Published var cgmTransmitterDeviceAddress: String? = nil
-        @Published var listOfCGM: [cgmName] = []
+        @Published var listOfCGM: [CGMModel] = []
         @Published var url: URL?
 
         override func subscribe() {
@@ -43,10 +48,10 @@ extension CGM {
             // collect the list of CGM available with plugins and CGMType defined manually
             listOfCGM = (
                 CGMType.allCases.filter { $0 != CGMType.plugin }.map {
-                    cgmName(id: $0.id, type: $0, displayName: $0.displayName, subtitle: $0.subtitle)
+                    CGMModel(id: $0.id, type: $0, displayName: $0.displayName, subtitle: $0.subtitle)
                 } +
                     pluginCGMManager.availableCGMManagers.map {
-                        cgmName(
+                        CGMModel(
                             id: $0.identifier,
                             type: CGMType.plugin,
                             displayName: $0.localizedTitle,
@@ -66,7 +71,7 @@ extension CGM {
             switch settingsManager.settings.cgm {
             case .plugin:
                 if let cgmPluginInfo = listOfCGM.first(where: { $0.id == settingsManager.settings.cgmPluginIdentifier }) {
-                    cgmCurrent = cgmName(
+                    cgmCurrent = CGMModel(
                         id: settingsManager.settings.cgmPluginIdentifier,
                         type: .plugin,
                         displayName: cgmPluginInfo.displayName,
@@ -74,10 +79,10 @@ extension CGM {
                     )
                 } else {
                     // no more type of plugin available - restart to defaut
-                    cgmCurrent = cgmDefaultName
+                    cgmCurrent = cgmDefaultModel
                 }
             default:
-                cgmCurrent = cgmName(
+                cgmCurrent = CGMModel(
                     id: settingsManager.settings.cgm.id,
                     type: settingsManager.settings.cgm,
                     displayName: settingsManager.settings.cgm.displayName,
@@ -123,11 +128,11 @@ extension CGM {
             }
         }
 
-        func addCGM(cgm: cgmName) {
+        func addCGM(cgm: CGMModel) {
             cgmCurrent = cgm
             switch cgmCurrent.type {
             case .plugin:
-                setupCGM.toggle()
+                shouldDisplayCGMSetupSheet.toggle()
             default:
                 cgmManager.cgmGlucoseSourceType = cgmCurrent.type
                 completionNotifyingDidComplete(EmptyCompletionNotifying())
@@ -135,21 +140,25 @@ extension CGM {
         }
 
         func deleteCGM() {
-            cgmManager.deleteGlucoseSource()
-            completionNotifyingDidComplete(EmptyCompletionNotifying())
+            shouldDisplayCGMSetupSheet = false
+
+            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
+                self.cgmManager.deleteGlucoseSource()
+                self.completionNotifyingDidComplete(EmptyCompletionNotifying())
+            })
         }
     }
 }
 
 extension CGM.StateModel: CompletionDelegate {
     func completionNotifyingDidComplete(_: CompletionNotifying) {
-        setupCGM = false
+        shouldDisplayCGMSetupSheet = false
 
         // if CGM was deleted
         if cgmManager.cgmGlucoseSourceType == .none {
-            cgmCurrent = cgmDefaultName
-            settingsManager.settings.cgm = cgmDefaultName.type
-            settingsManager.settings.cgmPluginIdentifier = cgmDefaultName.id
+            cgmCurrent = cgmDefaultModel
+            settingsManager.settings.cgm = cgmDefaultModel.type
+            settingsManager.settings.cgmPluginIdentifier = cgmDefaultModel.id
             cgmManager.deleteGlucoseSource()
         } else {
             settingsManager.settings.cgm = cgmCurrent.type
@@ -157,7 +166,7 @@ extension CGM.StateModel: CompletionDelegate {
             cgmManager.updateGlucoseSource(cgmGlucoseSourceType: cgmCurrent.type, cgmGlucosePluginId: cgmCurrent.id)
         }
 
-        // update if required the Glucose source
+        // update glucose source if required
         DispatchQueue.main.async {
             self.broadcaster.notify(GlucoseObserver.self, on: .main) {
                 $0.glucoseDidUpdate([])

+ 32 - 48
Trio/Sources/Modules/CGM/View/CGMRootView.swift

@@ -19,6 +19,32 @@ extension CGM {
         @Environment(\.colorScheme) var colorScheme
         @Environment(AppState.self) var appState
 
+        private let cgmOptions: [CGMOption] = [
+            CGMOption(name: "Dexcom G5", predicate: { $0.type == .plugin && $0.displayName.contains("G5") }),
+            CGMOption(name: "Dexcom G6 / ONE", predicate: { $0.type == .plugin && $0.displayName.contains("G6") }),
+            CGMOption(name: "Dexcom G7 / ONE+", predicate: { $0.type == .plugin && $0.displayName.contains("G7") }),
+            CGMOption(name: "Dexcom Share", predicate: { $0.type == .plugin && $0.displayName.contains("Dexcom Share") }),
+            CGMOption(name: "FreeStyle Libre", predicate: { $0.type == .plugin && $0.displayName == "FreeStyle Libre" }),
+            CGMOption(
+                name: "FreeStyle Libre Demo",
+                predicate: { $0.type == .plugin && $0.displayName == "FreeStyle Libre Demo" }
+            ),
+            CGMOption(name: "Glucose Simulator", predicate: { $0.type == .simulator }),
+            CGMOption(name: "Medtronic Enlite", predicate: { $0.type == .enlite }),
+            CGMOption(name: "Nightscout", predicate: { $0.type == .nightscout }),
+            CGMOption(name: "xDrip4iOS", predicate: { $0.type == .xdrip })
+        ]
+
+        @ViewBuilder var cgmSelectionButtons: some View {
+            ForEach(cgmOptions, id: \.name) { option in
+                if let cgm = state.listOfCGM.first(where: option.predicate) {
+                    Button(option.name) {
+                        state.addCGM(cgm: cgm)
+                    }
+                }
+            }
+        }
+
         var body: some View {
             NavigationView {
                 Form {
@@ -28,7 +54,7 @@ extension CGM {
                             let cgmState = state.cgmCurrent
                             if cgmState.type != .none {
                                 Button {
-                                    state.setupCGM = true
+                                    state.shouldDisplayCGMSetupSheet = true
                                 } label: {
                                     HStack {
                                         Image(systemName: "sensor.tag.radiowaves.forward.fill")
@@ -116,7 +142,7 @@ extension CGM {
                 .navigationTitle("CGM")
                 .navigationBarTitleDisplayMode(.automatic)
                 .navigationBarItems(leading: displayClose ? Button("Close", action: state.hideModal) : nil)
-                .sheet(isPresented: $state.setupCGM) {
+                .sheet(isPresented: $state.shouldDisplayCGMSetupSheet) {
                     switch state.cgmCurrent.type {
                     case .enlite,
                          .nightscout,
@@ -181,52 +207,10 @@ extension CGM {
                     )
                 }
                 .confirmationDialog("CGM Model", isPresented: $showCGMSelection) {
-                    Button("Nightscout") { state.addCGM(cgm: state.listOfCGM.first(where: { $0.type == .nightscout })!) }
-                    Button("Dexcom G5") {
-                        state.addCGM(cgm: state.listOfCGM.first(where: { $0.type == .plugin && $0.displayName.contains("G5") })!)
-                    }
-                    Button("Dexcom G6 / ONE") {
-                        state
-                            .addCGM(
-                                cgm: state.listOfCGM
-                                    .first(where: { $0.type == .plugin && $0.displayName.contains("G6") })!
-                            )
-                    }
-                    Button("Dexcom G7 / ONE+") {
-                        state
-                            .addCGM(
-                                cgm: state.listOfCGM
-                                    .first(where: { $0.type == .plugin && $0.displayName.contains("G7") })!
-                            )
-                    }
-                    Button("Dexcom Share") {
-                        state.addCGM(
-                            cgm: state.listOfCGM
-                                .first(where: { $0.type == .plugin && $0.displayName.contains("Dexcom Share") })!
-                        ) }
-                    Button("FreeStyle Libre") {
-                        state.addCGM(
-                            cgm: state.listOfCGM
-                                .first(
-                                    where: { $0.type == .plugin && $0.displayName == "FreeStyle Libre" }
-                                )!
-                        ) }
-                    Button("FreeStyle Libre Demo") {
-                        state.addCGM(
-                            cgm: state.listOfCGM
-                                .first(where: { $0.type == .plugin && $0.displayName == "FreeStyle Libre Demo" })!
-                        ) }
-                    Button("Medtronic Enlite") {
-                        state.addCGM(cgm: state.listOfCGM.first(where: { $0.type == .enlite })!) }
-                    Button("xDrip4iOS") {
-                        state.addCGM(cgm: state.listOfCGM.first(where: { $0.type == .xdrip })!) }
-                    Button("Glucose Simulator") {
-                        state
-                            .addCGM(
-                                cgm: state.listOfCGM
-                                    .first(where: { $0.type == .simulator })!
-                            ) }
-                } message: { Text("Select CGM Model") }
+                    cgmSelectionButtons
+                } message: {
+                    Text("Select CGM Model")
+                }
             }
         }
     }

+ 1 - 1
Trio/Sources/Modules/CGM/View/CGMSetupView.swift

@@ -5,7 +5,7 @@ import UIKit
 
 extension CGM {
     struct CGMSetupView: UIViewControllerRepresentable {
-        let CGMType: cgmName
+        let CGMType: CGMModel
         let bluetoothManager: BluetoothStateManager
         let unit: GlucoseUnits
         weak var completionDelegate: CompletionDelegate?

+ 57 - 52
Trio/Sources/Modules/CGM/View/OtherCGMView.swift

@@ -12,72 +12,77 @@ struct OtherCGMView: BaseView {
     var body: some View {
         NavigationView {
             Form {
-                Section(
-                    header: Text("Configuration"),
-                    content: {
-                        if state.cgmCurrent.type == .nightscout {
-                            NavigationLink(
-                                destination: NightscoutConfig.RootView(resolver: resolver, displayClose: false),
-                                label: { Text("Config Nightscout") }
-                            )
-                        } else if state.cgmCurrent.type == .xdrip {
-                            VStack(alignment: .leading) {
-                                if let cgmTransmitterDeviceAddress = state.cgmTransmitterDeviceAddress {
-                                    Text("CGM address :").padding(.top)
-                                    Text(cgmTransmitterDeviceAddress)
-                                } else {
-                                    Text("CGM is not used as heartbeat.").padding(.top)
-                                }
+                if state.cgmCurrent.type != .none {
+                    Section(
+                        header: Text("Configuration"),
+                        content: {
+                            if state.cgmCurrent.type == .nightscout {
+                                NavigationLink(
+                                    destination: NightscoutConfig.RootView(resolver: resolver, displayClose: false),
+                                    label: { Text("Config Nightscout") }
+                                )
+                            } else if state.cgmCurrent.type == .xdrip {
+                                VStack(alignment: .leading) {
+                                    if let cgmTransmitterDeviceAddress = state.cgmTransmitterDeviceAddress {
+                                        Text("CGM address :").padding(.top)
+                                        Text(cgmTransmitterDeviceAddress)
+                                    } else {
+                                        Text("CGM is not used as heartbeat.").padding(.top)
+                                    }
 
-                                HStack(alignment: .center) {
-                                    Text(
-                                        "A heartbeat tells Trio to start a loop cycle. This is required for closed loop."
-                                    )
-                                    .font(.footnote)
-                                    .foregroundColor(.secondary)
-                                    .lineLimit(nil)
-                                    Spacer()
-                                }.padding(.vertical)
+                                    HStack(alignment: .center) {
+                                        Text(
+                                            "A heartbeat tells Trio to start a loop cycle. This is required for closed loop."
+                                        )
+                                        .font(.footnote)
+                                        .foregroundColor(.secondary)
+                                        .lineLimit(nil)
+                                        Spacer()
+                                    }.padding(.vertical)
+                                }
+                            } else if state.cgmCurrent.type == .simulator {
+                                Text(
+                                    "Trio's glucose simulator does not offer any configuration. Its use is strictly for demonstration purposes only."
+                                )
                             }
-                        }
 
-                        if let link = state.cgmCurrent.type.externalLink {
-                            Button {
-                                UIApplication.shared.open(link, options: [:], completionHandler: nil)
-                            } label: {
-                                HStack {
-                                    Text("About this source")
-                                    Spacer()
-                                    Image(systemName: "chevron.right")
+                            if let link = state.cgmCurrent.type.externalLink {
+                                Button {
+                                    UIApplication.shared.open(link, options: [:], completionHandler: nil)
+                                } label: {
+                                    HStack {
+                                        Text("About this source")
+                                        Spacer()
+                                        Image(systemName: "chevron.right")
+                                    }
                                 }
+                                .frame(maxWidth: .infinity, alignment: .leading)
                             }
-                            .frame(maxWidth: .infinity, alignment: .leading)
-                        }
 
-                        if let appURL = state.urlOfApp() {
-                            Button {
-                                UIApplication.shared.open(appURL, options: [:]) { success in
-                                    if !success {
-                                        self.router.alertMessage
-                                            .send(MessageContent(content: "Unable to open the app", type: .warning))
+                            if let appURL = state.urlOfApp() {
+                                Button {
+                                    UIApplication.shared.open(appURL, options: [:]) { success in
+                                        if !success {
+                                            self.router.alertMessage
+                                                .send(MessageContent(content: "Unable to open the app", type: .warning))
+                                        }
                                     }
                                 }
-                            }
-                            label: {
-                                HStack {
-                                    Text(state.displayNameOfApp() ?? "-")
-                                    Spacer()
-                                    Image(systemName: "chevron.right")
+                                label: {
+                                    HStack {
+                                        Text(state.displayNameOfApp() ?? "-")
+                                        Spacer()
+                                        Image(systemName: "chevron.right")
+                                    }
                                 }
+                                .frame(maxWidth: .infinity, alignment: .leading)
                             }
-                            .frame(maxWidth: .infinity, alignment: .leading)
                         }
-                    }
-                ).listRowBackground(Color.chart)
+                    ).listRowBackground(Color.chart)
+                }
 
                 Button {
                     state.deleteCGM()
-                    presentationMode.wrappedValue.dismiss()
                 } label: {
                     Text("Delete CGM")
                         .font(.headline)