Skip to content

Commit 18be4cf

Browse files
author
Rick Pasetto
authored
LOOP-1833: Show spinner while pump is refreshing (#244)
* LOOP-1833: Show spinner while pump is refreshing This is mostly speculative. I'm not really sure how real pumps behave. I faked this by adding a 15 second delay between `PumpManager.assertCurrentPumpData` and `PumpManagerDelegate.pumpManagerRecommendsLoop` in MockPumpManager. * Change assertCurrentPumpData to fetchCurrentPumpData, with a completion block * PR Feedback * rename fetchCurrentPumpData -> ensureCurrentPumpData
1 parent c9e07c2 commit 18be4cf

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

Loop/Managers/DeviceDataManager.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,18 +317,18 @@ final class DeviceDataManager {
317317

318318
loopManager.addGlucose(values) { result in
319319
self.log.default("Asserting current pump data")
320-
self.pumpManager?.assertCurrentPumpData()
320+
self.pumpManager?.ensureCurrentPumpData(completion: nil)
321321
}
322322
case .noData:
323323
log.default("CGMManager:%{public}@ did update with no data", String(describing: type(of: manager)))
324324

325-
pumpManager?.assertCurrentPumpData()
325+
pumpManager?.ensureCurrentPumpData(completion: nil)
326326
case .error(let error):
327327
log.default("CGMManager:%{public}@ did update with error: %{public}@", String(describing: type(of: manager)), String(describing: error))
328328

329329
self.setLastError(error: error)
330330
log.default("Asserting current pump data")
331-
pumpManager?.assertCurrentPumpData()
331+
pumpManager?.ensureCurrentPumpData(completion: nil)
332332
}
333333

334334
updatePumpManagerBLEHeartbeatPreference()

Loop/View Models/BolusEntryViewModel.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ final class BolusEntryViewModel: ObservableObject {
7272
private let log = OSLog(category: "BolusEntryViewModel")
7373
private var cancellables: Set<AnyCancellable> = []
7474

75-
private var pumpManagerRefreshCompletion: (() -> Void)?
7675
private var isPumpDataStale: Bool {
7776
// "borrowed" from LoopDataManager
7877
Date().timeIntervalSince(dataManager.doseStore.lastAddedPumpData) <= dataManager.loopManager.settings.inputDataRecencyInterval
7978
}
79+
@Published var isRefreshingPump: Bool = false
8080

8181
let chartManager: ChartsManager = {
8282
let predictedGlucoseChart = PredictedGlucoseChart(predictedGlucoseBounds: FeatureFlags.predictedGlucoseChartClampEnabled ? .default : nil,
@@ -112,19 +112,13 @@ final class BolusEntryViewModel: ObservableObject {
112112

113113
update()
114114
}
115-
115+
116116
private func observeLoopUpdates() {
117117
NotificationCenter.default
118118
.publisher(for: .LoopDataUpdated, object: dataManager.loopManager)
119119
.receive(on: DispatchQueue.main)
120120
.sink { [weak self] _ in self?.update() }
121121
.store(in: &cancellables)
122-
123-
// Look for Loop starting, and assume that if it started after assertCurrentPumpData that we want to call pumpManagerRefreshCompletion
124-
NotificationCenter.default
125-
.publisher(for: .LoopRunning, object: dataManager.loopManager)
126-
.sink { [weak self] _ in self?.pumpManagerRefreshCompletion?(); self?.pumpManagerRefreshCompletion = nil }
127-
.store(in: &cancellables)
128122
}
129123

130124
private func observeEnteredBolusChanges() {
@@ -201,6 +195,7 @@ final class BolusEntryViewModel: ObservableObject {
201195
func setRecommendedBolus() {
202196
guard isBolusRecommended else { return }
203197
enteredBolus = recommendedBolus!
198+
isRefreshingPump = false
204199
dataManager.loopManager.getLoopState { [weak self] manager, state in
205200
self?.updatePredictedGlucoseValues(from: state)
206201
}
@@ -517,8 +512,25 @@ final class BolusEntryViewModel: ObservableObject {
517512
completion()
518513
return
519514
}
520-
pumpManagerRefreshCompletion = completion
521-
pumpManager.assertCurrentPumpData()
515+
516+
DispatchQueue.main.async {
517+
// v-- This needs to happen on the main queue
518+
self.isRefreshingPump = true
519+
let wrappedCompletion: () -> Void = { [weak self] in
520+
self?.dataManager.loopManager.getLoopState { [weak self] _, _ in
521+
// v-- This needs to happen in LoopDataManager's dataQueue
522+
completion()
523+
// ^v-- Unfortunately, these two things might happen concurrently, so in theory the
524+
// completion above may not "complete" by the time we clear isRefreshingPump. To fix that
525+
// would require some very confusing wiring, but I think it is a minor issue.
526+
DispatchQueue.main.async {
527+
// v-- This needs to happen on the main queue
528+
self?.isRefreshingPump = false
529+
}
530+
}
531+
}
532+
pumpManager.ensureCurrentPumpData(completion: wrappedCompletion)
533+
}
522534
}
523535

524536
private func updateRecommendedBolusAndNotice(from state: LoopState, isUpdatingFromUserInput: Bool) {

Loop/Views/BolusEntryView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ struct BolusEntryView: View, HorizontalSizeClassOverride {
253253
HStack {
254254
Text("Recommended Bolus", comment: "Label for recommended bolus row on bolus screen")
255255
Spacer()
256+
ActivityIndicator(isAnimating: $viewModel.isRefreshingPump, style: .default)
256257
HStack(alignment: .firstTextBaseline) {
257258
Text(recommendedBolusString)
258259
.font(.title)

0 commit comments

Comments
 (0)