Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add button to open the CGM app in settings view and fix heartbeat pump #89

Merged
merged 3 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions FreeAPS/Sources/APS/CGM/CGMType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,8 @@ enum CGMType: String, JSON, CaseIterable, Identifiable {
return URL(string: "xdripswift://")!
case .glucoseDirect:
return URL(string: "libredirect://")!
// case .dexcomG5:
// return URL(string: "dexcomgcgm://")!
// case .dexcomG6:
// return URL(string: "dexcomg6://")!
// case .dexcomG7:
// return URL(string: "dexcomg7://")!
case .simulator:
return nil
// case .libreTransmitter:
// return URL(string: "Open-iAPS://libre-transmitter")!
case .plugin:
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion FreeAPS/Sources/APS/CGM/PluginSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ extension PluginSource: CGMManagerDelegate {
dispatchPrecondition(condition: .onQueue(processQueue))
debug(.deviceManager, " CGM Manager with identifier \(manager.pluginIdentifier) wants deletion")
// TODO:
glucoseManager?.cgmGlucoseSourceType = nil
glucoseManager?.cgmGlucoseSourceType = .none
}

func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) {
Expand Down
1 change: 1 addition & 0 deletions FreeAPS/Sources/APS/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {

var glucoseManager: FetchGlucoseManager?
var cgmManager: CGMManagerUI?
var cgmType: CGMType = .enlite

func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> {
fetch(nil)
Expand Down
37 changes: 27 additions & 10 deletions FreeAPS/Sources/APS/FetchGlucoseManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ protocol FetchGlucoseManager: SourceInfoProvider {
func removeCalibrations()
var glucoseSource: GlucoseSource! { get }
var cgmManager: CGMManagerUI? { get }
var cgmGlucoseSourceType: CGMType? { get set }
var cgmGlucosePluginId: String? { get }
var cgmGlucoseSourceType: CGMType { get set }
var cgmGlucosePluginId: String { get }
var settingsManager: SettingsManager! { get }
var shouldSyncToRemoteService: Bool { get }
}
Expand All @@ -40,8 +40,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {

private var lifetime = Lifetime()
private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval)
var cgmGlucoseSourceType: CGMType?
var cgmGlucosePluginId: String?
var cgmGlucoseSourceType: CGMType = .none
var cgmGlucosePluginId: String = ""
var cgmManager: CGMManagerUI? {
didSet {
rawCGMManager = cgmManager?.rawValue
Expand All @@ -61,6 +61,10 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {

init(resolver: Resolver) {
injectServices(resolver)
// init at the start of the app
cgmGlucoseSourceType = settingsManager.settings.cgm
cgmGlucosePluginId = settingsManager.settings.cgmPluginIdentifier
// load cgmManager
updateGlucoseSource(
cgmGlucoseSourceType: settingsManager.settings.cgm,
cgmGlucosePluginId: settingsManager.settings.cgmPluginIdentifier
Expand All @@ -82,10 +86,22 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
)
}

func saveConfigManager() {
guard let cgmM = cgmManager else {
return
}
// save the config in rawCGMManager
rawCGMManager = cgmM.rawValue

// sync with upload glucose
settingsManager.settings.uploadGlucose = cgmM.shouldSyncToRemoteService
}

func updateGlucoseSource(cgmGlucoseSourceType: CGMType, cgmGlucosePluginId: String, newManager: CGMManagerUI?) {
// if changed, remove all calibrations
if self.cgmGlucoseSourceType != cgmGlucoseSourceType || self.cgmGlucosePluginId != cgmGlucosePluginId {
removeCalibrations()
cgmManager = nil
}

self.cgmGlucoseSourceType = cgmGlucoseSourceType
Expand All @@ -102,11 +118,12 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
removeCalibrations()
} else if self.cgmGlucoseSourceType == .plugin, cgmManager == nil, let rawCGMManager = rawCGMManager {
cgmManager = cgmManagerFromRawValue(rawCGMManager)
} else {
saveConfigManager()
}

switch self.cgmGlucoseSourceType {
case nil,
.none?:
case .none:
glucoseSource = nil
case .xdrip:
glucoseSource = AppGroupSource(from: "xDrip", cgmType: .xdrip)
Expand All @@ -127,7 +144,6 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
/// Upload cgmManager from raw value
func cgmManagerFromRawValue(_ rawValue: [String: Any]) -> CGMManagerUI? {
guard let rawState = rawValue["state"] as? CGMManager.RawStateValue,
let cgmGlucosePluginId = self.cgmGlucosePluginId,
let Manager = pluginCGMManager.getCGMManagerTypeByIdentifier(cgmGlucosePluginId)
else {
return nil
Expand Down Expand Up @@ -244,9 +260,8 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
private func subscribe() {
timer.publisher
.receive(on: processQueue)
.flatMap { _ -> AnyPublisher<[BloodGlucose], Never> in
.flatMap { [self] _ -> AnyPublisher<[BloodGlucose], Never> in
debug(.nightscout, "FetchGlucoseManager timer heartbeat")
// self.updateGlucoseSource(manager: nil)
if let glucoseSource = self.glucoseSource {
return glucoseSource.fetch(self.timer).eraseToAnyPublisher()
} else {
Expand Down Expand Up @@ -282,7 +297,9 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
private func overcalibrate(entries: [BloodGlucose]) -> [BloodGlucose] {
// overcalibrate
var overcalibration: ((Int) -> (Double))?
processQueue.sync { overcalibration = calibrationService.calibrate }
processQueue.sync {
overcalibration = calibrationService.calibrate
}

if let overcalibration = overcalibration {
return entries.map { entry in
Expand Down
29 changes: 22 additions & 7 deletions FreeAPS/Sources/Modules/CGM/CGMStateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ extension CGM {
.sink { [weak self] value in
guard let self = self else { return }
guard self.cgmManager.cgmGlucoseSourceType != nil else {
self.settingsManager.settings.cgm = .nightscout
self.settingsManager.settings.cgm = .none
return
}
if value.type != self.settingsManager.settings.cgm ||
Expand All @@ -103,6 +103,7 @@ extension CGM {
cgmGlucoseSourceType: value.type,
cgmGlucosePluginId: value.id
)
self.setupCGM = false
}
}
.store(in: &lifetime)
Expand Down Expand Up @@ -132,6 +133,26 @@ extension CGM {
}
.store(in: &lifetime)
}

func displayNameOfApp() -> String {
var nameOfApp = "Open Application"
switch cgmManager.cgmGlucoseSourceType {
case .plugin:
nameOfApp = "Open " + (cgmManager.cgmManager?.localizedTitle ?? "Application")
default:
nameOfApp = "Open " + (cgmManager.cgmGlucoseSourceType.displayName ?? "Application")
}
return nameOfApp
}

func urlOfApp() -> URL? {
switch cgmManager.cgmGlucoseSourceType {
case .plugin:
return cgmManager.cgmManager?.appURL
default:
return cgmManager.cgmGlucoseSourceType.appURL
}
}
}
}

Expand All @@ -149,9 +170,6 @@ extension CGM.StateModel: CompletionDelegate {
cgmManager.updateGlucoseSource(cgmGlucoseSourceType: cgmCurrent.type, cgmGlucosePluginId: cgmCurrent.id)
}

// refresh the upload options
settingsManager.settings.uploadGlucose = cgmManager.shouldSyncToRemoteService

// update if required the Glucose source
DispatchQueue.main.async {
self.broadcaster.notify(GlucoseObserver.self, on: .main) {
Expand All @@ -163,9 +181,6 @@ extension CGM.StateModel: CompletionDelegate {

extension CGM.StateModel: CGMManagerOnboardingDelegate {
func cgmManagerOnboarding(didCreateCGMManager manager: LoopKitUI.CGMManagerUI) {
// update the setting of upload Glucose in services
settingsManager.settings.uploadGlucose = cgmManager.shouldSyncToRemoteService

// update the glucose source
cgmManager.updateGlucoseSource(
cgmGlucoseSourceType: cgmCurrent.type,
Expand Down
50 changes: 39 additions & 11 deletions FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,44 @@ extension CGM {
}
}
}

if let cgmFetchManager = state.cgmManager {
if let appURL = state.urlOfApp()
{
Section {
Button {
UIApplication.shared.open(appURL, options: [:]) { success in
if !success {
self.router.alertMessage
.send(MessageContent(content: "Unable to open the app", type: .warning))
}
}
}

label: {
Label(state.displayNameOfApp(), systemImage: "waveform.path.ecg.rectangle").font(.title3) }
.frame(maxWidth: .infinity, alignment: .center)
.buttonStyle(.bordered)
}
.listRowBackground(Color.clear)
} else if state.cgmCurrent.type == .nightscout && state.url != nil {
Section {
Button {
UIApplication.shared.open(state.url!, options: [:]) { success in
if !success {
self.router.alertMessage
.send(MessageContent(content: "No URL available", type: .warning))
}
}
}
label: { Label("Open URL", systemImage: "waveform.path.ecg.rectangle").font(.title3) }
.frame(maxWidth: .infinity, alignment: .center)
.buttonStyle(.bordered)
}
.listRowBackground(Color.clear)
}
}

if state.cgmCurrent.type == .plugin {
Section {
Button("CGM Configuration") {
Expand All @@ -54,17 +92,7 @@ extension CGM {
}
}

if state.cgmCurrent.type == .nightscout {
Section(header: Text("Nightscout")) {
if state.url != nil {
Button(state.url!.absoluteString) {
UIApplication.shared.open(state.url!, options: [:], completionHandler: nil)
}
} else {
Text("You need to configure Nightscout URL")
}
}
}
// }

Section(header: Text("Calendar")) {
Toggle("Create events in calendar", isOn: $state.createCalendarEvents)
Expand Down