Skip to content

Commit ff07802

Browse files
authored
Add CAGE and IAGE to reorganized and updated Minimed settings view (LoopKit#25)
1 parent 4115478 commit ff07802

7 files changed

Lines changed: 170 additions & 60 deletions

MinimedKit/PumpManager/MinimedPumpManager.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,10 @@ extension MinimedPumpManager {
752752

753753
// Reconcile history with pending doses
754754
let newPumpEvents = historyEvents.pumpEvents(from: model)
755-
755+
756+
// Track set change and rewind events for cannula/insulin age
757+
self.updateLastEventDates(from: newPumpEvents)
758+
756759
// During reconciliation, some pump events may be reconciled as pending doses and removed. Remaining events should be annotated with current insulinType
757760
let remainingHistoryEvents = self.reconcilePendingDosesWith(newPumpEvents, fetchedAt: self.dateGenerator()).map { (event) -> NewPumpEvent in
758761
return NewPumpEvent(
@@ -804,6 +807,40 @@ extension MinimedPumpManager {
804807
}
805808
}
806809

810+
private func updateLastEventDates(from events: [NewPumpEvent]) {
811+
var latestSetChange: Date?
812+
var latestRewind: Date?
813+
814+
for event in events {
815+
switch event.type {
816+
case .replaceComponent(componentType: .infusionSet):
817+
if latestSetChange == nil || event.date > latestSetChange! {
818+
latestSetChange = event.date
819+
}
820+
case .rewind:
821+
if latestRewind == nil || event.date > latestRewind! {
822+
latestRewind = event.date
823+
}
824+
default:
825+
break
826+
}
827+
}
828+
829+
// Only update state if newer events are found
830+
setState { state in
831+
if let setChange = latestSetChange {
832+
if state.lastSetChangeDate == nil || setChange > state.lastSetChangeDate! {
833+
state.lastSetChangeDate = setChange
834+
}
835+
}
836+
if let rewind = latestRewind {
837+
if state.lastRewindDate == nil || rewind > state.lastRewindDate! {
838+
state.lastRewindDate = rewind
839+
}
840+
}
841+
}
842+
}
843+
807844
private func storePendingPumpEvents(forceFinalization: Bool = false, _ completion: @escaping (_ error: MinimedPumpManagerError?) -> Void) {
808845
// Must be called from the sessionQueue
809846
let events = (self.state.pendingDoses + [self.state.unfinalizedBolus, self.state.unfinalizedTempBasal]).compactMap({ $0?.newPumpEvent(forceFinalization: forceFinalization) })

MinimedKit/PumpManager/MinimedPumpManagerState.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {
122122

123123
public var basalSchedule: BasalSchedule
124124

125+
public var lastSetChangeDate: Date?
126+
127+
public var lastRewindDate: Date?
128+
125129
public init(isOnboarded: Bool, useMySentry: Bool, pumpColor: PumpColor, pumpID: String, pumpModel: PumpModel, pumpFirmwareVersion: String, pumpRegion: PumpRegion, rileyLinkConnectionState: RileyLinkConnectionState?, timeZone: TimeZone, suspendState: SuspendState, insulinType: InsulinType, lastTuned: Date?, lastValidFrequency: Measurement<UnitFrequency>?, basalSchedule: BasalSchedule)
126130
{
127131
self.isOnboarded = isOnboarded
@@ -256,6 +260,9 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {
256260
} else {
257261
self.basalSchedule = BasalSchedule(entries: [])
258262
}
263+
264+
lastSetChangeDate = rawValue["lastSetChangeDate"] as? Date
265+
lastRewindDate = rawValue["lastRewindDate"] as? Date
259266
}
260267

261268
public var rawValue: RawValue {
@@ -287,6 +294,8 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {
287294
value["rileyLinkBatteryAlertLevel"] = rileyLinkBatteryAlertLevel
288295
value["lastRileyLinkBatteryAlertDate"] = lastRileyLinkBatteryAlertDate
289296
value["basalSchedule"] = basalSchedule.rawValue
297+
value["lastSetChangeDate"] = lastSetChangeDate
298+
value["lastRewindDate"] = lastRewindDate
290299

291300
return value
292301
}

MinimedKitUI/MinimedPumpUICoordinator.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ class MinimedUICoordinator: UINavigationController, PumpManagerOnboarding, Compl
136136
}
137137

138138
let view = MinimedPumpSettingsView(viewModel: viewModel, supportedInsulinTypes: allowedInsulinTypes, handleRileyLinkSelection: handleRileyLinkSelection, rileyLinkListDataSource: rileyLinkListDataSource)
139-
return hostingController(rootView: view)
139+
let controller = hostingController(rootView: view)
140+
controller.navigationItem.title = String(format: NSLocalizedString("Medtronic %1$@", comment: "Format string fof navigation bar title for MinimedPumpSettingsView (1: model number)"), pumpManager.state.pumpModel.description)
141+
return controller
140142
}
141143
}
142144

MinimedKitUI/Resources/Localizable.xcstrings

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,6 +2438,9 @@
24382438
}
24392439
}
24402440
},
2441+
"Cannula Age" : {
2442+
"comment" : "Text for time since last medtronic pump set change event"
2443+
},
24412444
"Changing" : {
24422445
"comment" : "Text shown in basal rate space when basal is changing",
24432446
"localizations" : {
@@ -3308,6 +3311,12 @@
33083311
}
33093312
}
33103313
},
3314+
"day" : {
3315+
"comment" : "Singular day unit"
3316+
},
3317+
"days" : {
3318+
"comment" : "Plural days unit"
3319+
},
33113320
"Delete Pump" : {
33123321
"comment" : "Button label for removing Pump\nText to delete pump",
33133322
"localizations" : {
@@ -3445,6 +3454,9 @@
34453454
}
34463455
}
34473456
},
3457+
"Details" : {
3458+
"comment" : "The title of the details section in MinimedPumpManager settings"
3459+
},
34483460
"Devices" : {
34493461
"comment" : "Header for devices section of RileyLinkSetupView",
34503462
"localizations" : {
@@ -5000,6 +5012,12 @@
50005012
}
50015013
}
50025014
},
5015+
"hour" : {
5016+
"comment" : "Singular hour unit"
5017+
},
5018+
"hours" : {
5019+
"comment" : "Plural hours unit"
5020+
},
50035021
"Insulin\nSuspended" : {
50045022
"comment" : "Text shown in insulin delivery space when insulin suspended",
50055023
"localizations" : {
@@ -5155,6 +5173,9 @@
51555173
}
51565174
}
51575175
},
5176+
"Insulin Age" : {
5177+
"comment" : "Text for time since last medtronic pump rewind event"
5178+
},
51585179
"Insulin Delivery" : {
51595180
"comment" : "Title of insulin delivery section",
51605181
"localizations" : {
@@ -8988,6 +9009,9 @@
89889009
}
89899010
}
89909011
},
9012+
"Status" : {
9013+
"comment" : "The title of the status section in MinimedPumpManager settings"
9014+
},
89919015
"Succeeded" : {
89929016
"comment" : "A message indicating a command succeeded",
89939017
"localizations" : {

MinimedKitUI/Views/MinimedPumpSettingsView.swift

Lines changed: 68 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ struct MinimedPumpSettingsView: View {
2424
var supportedInsulinTypes: [InsulinType]
2525

2626
@State private var showingDeletionSheet = false
27-
2827
@State private var showSyncTimeOptions = false;
2928

3029
var handleRileyLinkSelection: (RileyLinkDevice) -> Void
@@ -47,7 +46,6 @@ struct MinimedPumpSettingsView: View {
4746
reservoirStatus
4847
}
4948
.padding(.bottom, 5)
50-
5149
}
5250

5351
if let basalDeliveryState = viewModel.basalDeliveryState {
@@ -64,51 +62,6 @@ struct MinimedPumpSettingsView: View {
6462
}
6563
}
6664

67-
Section(header: SectionHeader(label: LocalizedString("Configuration", comment: "The title of the configuration section in MinimedPumpManager settings")))
68-
{
69-
NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.pumpManager.state.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) {
70-
HStack {
71-
Text(LocalizedString("Insulin Type", comment: "Text for confidence reminders navigation link")).foregroundColor(Color.primary)
72-
if let currentTitle = viewModel.pumpManager.state.insulinType?.brandName {
73-
Spacer()
74-
Text(currentTitle)
75-
.foregroundColor(.secondary)
76-
}
77-
}
78-
}
79-
NavigationLink(destination: BatteryTypeSelectionView(batteryType: $viewModel.batteryChemistryType)) {
80-
HStack {
81-
Text(LocalizedString("Pump Battery Type", comment: "Text for medtronic pump battery type")).foregroundColor(Color.primary)
82-
Spacer()
83-
Text(viewModel.batteryChemistryType.description)
84-
.foregroundColor(.secondary)
85-
}
86-
}
87-
88-
NavigationLink(destination: DataSourceSelectionView(batteryType: $viewModel.preferredDataSource)) {
89-
HStack {
90-
Text(LocalizedString("Preferred Data Source", comment: "Text for medtronic pump preferred data source")).foregroundColor(Color.primary)
91-
Spacer()
92-
Text(viewModel.preferredDataSource.description)
93-
.foregroundColor(.secondary)
94-
}
95-
}
96-
97-
if viewModel.pumpManager.state.pumpModel.hasMySentry {
98-
NavigationLink(destination: UseMySentrySelectionView(mySentryConfig: $viewModel.mySentryConfig)) {
99-
HStack {
100-
Text(LocalizedString("Use MySentry", comment: "Text for medtronic pump to use MySentry")).foregroundColor(Color.primary)
101-
Spacer()
102-
Text((viewModel.mySentryConfig == .useMySentry ?
103-
LocalizedString("Yes", comment: "Value string for MySentry config when MySentry is being used") :
104-
LocalizedString("No", comment: "Value string for MySentry config when MySentry is not being used"))
105-
)
106-
.foregroundColor(.secondary)
107-
}
108-
}
109-
}
110-
}
111-
11265
Section(header: HStack {
11366
Text(LocalizedString("Devices", comment: "Header for devices section of RileyLinkSetupView"))
11467
Spacer()
@@ -144,15 +97,32 @@ struct MinimedPumpSettingsView: View {
14497
rileyLinkListDataSource.isScanningEnabled = false
14598
}
14699

147-
148-
Section() {
100+
Section(header: Text(LocalizedString("Status", comment: "The title of the status section in MinimedPumpManager settings"))) {
101+
if let timeSinceLastCannulaFill = viewModel.timeSinceLastSetChange {
102+
HStack {
103+
Text(LocalizedString("Cannula Age", comment: "Text for time since last medtronic pump set change event"))
104+
Spacer()
105+
Text(timeSinceLastCannulaFill)
106+
.foregroundStyle(.secondary)
107+
}
108+
}
109+
if let timeSinceLastRewind = viewModel.timeSinceLastRewind {
110+
HStack {
111+
Text(LocalizedString("Insulin Age", comment: "Text for time since last medtronic pump rewind event"))
112+
Spacer()
113+
Text(timeSinceLastRewind)
114+
.foregroundStyle(.secondary)
115+
}
116+
}
149117
HStack {
150-
Text(LocalizedString("Pump Battery Remaining", comment: "Text for medtronic pump battery percent remaining")).foregroundColor(Color.primary)
118+
Text(LocalizedString("Pump Battery Remaining", comment: "Text for medtronic pump battery percent remaining"))
151119
Spacer()
152120
if let chargeRemaining = viewModel.pumpManager.status.pumpBatteryChargeRemaining {
153121
Text(String("\(Int(round(chargeRemaining * 100)))%"))
122+
.foregroundStyle(.secondary)
154123
} else {
155124
Text(String(LocalizedString("unknown", comment: "Text to indicate battery percentage is unknown")))
125+
.foregroundStyle(.secondary)
156126
}
157127
}
158128
HStack {
@@ -163,7 +133,7 @@ struct MinimedPumpSettingsView: View {
163133
.foregroundColor(guidanceColors.warning)
164134
}
165135
TimeView(timeZone: viewModel.pumpManager.status.timeZone)
166-
.foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : nil)
136+
.foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : .secondary)
167137
}
168138
if viewModel.synchronizingTime {
169139
HStack {
@@ -184,8 +154,53 @@ struct MinimedPumpSettingsView: View {
184154
}
185155
}
186156

157+
Section(header: Text(LocalizedString("Configuration", comment: "The title of the configuration section in MinimedPumpManager settings")))
158+
{
159+
NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.pumpManager.state.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) {
160+
HStack {
161+
Text(LocalizedString("Insulin Type", comment: "Text for confidence reminders navigation link")).foregroundColor(Color.primary)
162+
if let currentTitle = viewModel.pumpManager.state.insulinType?.brandName {
163+
Spacer()
164+
Text(currentTitle)
165+
.foregroundColor(.secondary)
166+
}
167+
}
168+
}
169+
NavigationLink(destination: BatteryTypeSelectionView(batteryType: $viewModel.batteryChemistryType)) {
170+
HStack {
171+
Text(LocalizedString("Pump Battery Type", comment: "Text for medtronic pump battery type")).foregroundColor(Color.primary)
172+
Spacer()
173+
Text(viewModel.batteryChemistryType.description)
174+
.foregroundColor(.secondary)
175+
}
176+
}
187177

188-
Section {
178+
NavigationLink(destination: DataSourceSelectionView(batteryType: $viewModel.preferredDataSource)) {
179+
HStack {
180+
Text(LocalizedString("Preferred Data Source", comment: "Text for medtronic pump preferred data source")).foregroundColor(Color.primary)
181+
Spacer()
182+
Text(viewModel.preferredDataSource.description)
183+
.foregroundColor(.secondary)
184+
}
185+
}
186+
187+
if viewModel.pumpManager.state.pumpModel.hasMySentry {
188+
NavigationLink(destination: UseMySentrySelectionView(mySentryConfig: $viewModel.mySentryConfig)) {
189+
HStack {
190+
Text(LocalizedString("Use MySentry", comment: "Text for medtronic pump to use MySentry")).foregroundColor(Color.primary)
191+
Spacer()
192+
Text((viewModel.mySentryConfig == .useMySentry ?
193+
LocalizedString("Yes", comment: "Value string for MySentry config when MySentry is being used") :
194+
LocalizedString("No", comment: "Value string for MySentry config when MySentry is not being used"))
195+
)
196+
.foregroundColor(.secondary)
197+
}
198+
}
199+
}
200+
}
201+
202+
Section(header: Text(LocalizedString("Details", comment: "The title of the details section in MinimedPumpManager settings")))
203+
{
189204
LabeledValueView(label: LocalizedString("Pump ID", comment: "The title text for the pump ID config value"),
190205
value: viewModel.pumpManager.state.pumpID)
191206
LabeledValueView(label: LocalizedString("Firmware Version", comment: "The title of the cell showing the pump firmware version"),
@@ -194,7 +209,6 @@ struct MinimedPumpSettingsView: View {
194209
value: String(describing: viewModel.pumpManager.state.pumpRegion))
195210
}
196211

197-
198212
Section() {
199213
deletePumpButton
200214
}
@@ -216,7 +230,6 @@ struct MinimedPumpSettingsView: View {
216230

217231
.insetGroupedListStyle()
218232
.navigationBarItems(trailing: doneButton)
219-
.navigationBarTitle(String(format: LocalizedString("Medtronic %1$@", comment: "Format string fof navigation bar title for MinimedPumpSettingsView (1: model number)"), viewModel.pumpManager.state.pumpModel.description))
220233
}
221234

222235
var deliverySectionTitle: String {
@@ -371,7 +384,7 @@ struct MinimedPumpSettingsView: View {
371384
Image(uiImage: viewModel.pumpImage)
372385
.resizable()
373386
.aspectRatio(contentMode: ContentMode.fit)
374-
.frame(height: 150)
387+
.frame(height: 100)
375388
.padding(.horizontal)
376389
}
377390
.frame(maxWidth: .infinity)

0 commit comments

Comments
 (0)