| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import LoopKitUI
- /// Notes on the CGM lifecycle:
- /// There are two classes of CGM devices: plugins and non-plugins. Plugins are implemented using
- /// LoopKit APIs and include most hardware CGMs like Dexcom G6, G7, Libre, and so on. Non-plugins
- /// drivers are implemented directly in Trio, and include the CGM Simulator and Nightscout CGM. For
- /// these different CGMs, there are a few different events, handled in different places, that happen to
- /// signify a change in the CGM lifecycle.
- ///
- /// Both:
- /// - addCGM function invocation: Called by the UI in response to a user clicking the "add CGM" button
- ///
- /// Non-plugins only:
- /// - deleteCGM function invocation: Called by the CGM View in response to a user clicking the "delete CGM" button
- ///
- /// Plugins only:
- /// - completionNotifyingDidComplete: Called by the CGM driver to signify that Trio should close its UIViewController
- /// - cgmManagerOnboarding didCreateCGMManager: Called by the CGM driver after adding a new CGM
- /// - cgmManagerWantsDeletion: Called by the CGM driver when the user asks to delete a CGM
- /// There are no ordering constraints between completionNotifyingDidComplete and the other two
- /// Plugin events (it's up to the implementation of each individual driver). For example, the G7 driver invokes
- /// cgmManagerWantsDeletion on the delegate's queue while calling completionNotifyingDidComplete in parallel
- /// on the main queue.
- ///
- /// In additinon to having different events for different types of CGMs, the handling of these events is spread out
- /// across various state managers, like HomeStateModel, CGMSettingsStateModel, and PluginSource.
- ///
- /// There is CGM state in the HomeStateModel and CGMSettingsStateModel, FetchGlucoseManager, and
- /// SettingsManger
- ///
- /// The flow for adding a CGM:
- /// - Non-plugin: addCGM (considered onboarded at this point)
- /// - Plugin: addCGM -> cgmManagerOnboarding (after success)
- ///
- /// For deleting a CGM:
- /// - Non-plugin: deleteCGM (in HomeStateModel and CGMSettingsStateModel)
- /// - Plugin: cgmManagerWantsDeletion (in PluginSource)
- /// Then, both non-plugin and plugin: set settings.cgm (in FetchGlucoseManager) ->
- /// settingsDidChange (in HomeStateModel and CGMSettingsStateModel)
- extension Home.StateModel: CompletionDelegate {
- func completionNotifyingDidComplete(_ notifying: CompletionNotifying) {
- debug(.service, "Completion fired by: \(type(of: notifying))")
- Task {
- // this sleep is because this event and cgmManagerWantsDeletion
- // are called in parallel.
- try await Task.sleep(for: .seconds(0.2))
- await MainActor.run {
- if fetchGlucoseManager.cgmGlucoseSourceType == .none {
- cgmCurrent = cgmDefaultModel
- }
- }
- }
- shouldDisplayCGMSetupSheet = false
- }
- }
- extension Home.StateModel: CGMManagerOnboardingDelegate {
- func cgmManagerOnboarding(didCreateCGMManager manager: LoopKitUI.CGMManagerUI) {
- settingsManager.settings.cgm = cgmCurrent.type
- settingsManager.settings.cgmPluginIdentifier = cgmCurrent.id
- fetchGlucoseManager.updateGlucoseSource(
- cgmGlucoseSourceType: cgmCurrent.type,
- cgmGlucosePluginId: cgmCurrent.id,
- newManager: manager
- )
- DispatchQueue.main.async {
- self.broadcaster.notify(GlucoseObserver.self, on: .main) {
- $0.glucoseDidUpdate([])
- }
- }
- }
- func cgmManagerOnboarding(didOnboardCGMManager _: LoopKitUI.CGMManagerUI) {
- // nothing to do
- }
- }
|