Skip to content
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
39 changes: 38 additions & 1 deletion MinimedKit/PumpManager/MinimedPumpManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,10 @@ extension MinimedPumpManager {

// Reconcile history with pending doses
let newPumpEvents = historyEvents.pumpEvents(from: model)


// Track set change and rewind events for cannula/insulin age
self.updateLastEventDates(from: newPumpEvents)

// During reconciliation, some pump events may be reconciled as pending doses and removed. Remaining events should be annotated with current insulinType
let remainingHistoryEvents = self.reconcilePendingDosesWith(newPumpEvents, fetchedAt: self.dateGenerator()).map { (event) -> NewPumpEvent in
return NewPumpEvent(
Expand Down Expand Up @@ -804,6 +807,40 @@ extension MinimedPumpManager {
}
}

private func updateLastEventDates(from events: [NewPumpEvent]) {
var latestSetChange: Date?
var latestRewind: Date?

for event in events {
switch event.type {
case .replaceComponent(componentType: .infusionSet):
if latestSetChange == nil || event.date > latestSetChange! {
latestSetChange = event.date
}
case .rewind:
if latestRewind == nil || event.date > latestRewind! {
latestRewind = event.date
}
default:
break
}
}

// Only update state if newer events are found
setState { state in
if let setChange = latestSetChange {
if state.lastSetChangeDate == nil || setChange > state.lastSetChangeDate! {
state.lastSetChangeDate = setChange
}
}
if let rewind = latestRewind {
if state.lastRewindDate == nil || rewind > state.lastRewindDate! {
state.lastRewindDate = rewind
}
}
}
}

private func storePendingPumpEvents(forceFinalization: Bool = false, _ completion: @escaping (_ error: MinimedPumpManagerError?) -> Void) {
// Must be called from the sessionQueue
let events = (self.state.pendingDoses + [self.state.unfinalizedBolus, self.state.unfinalizedTempBasal]).compactMap({ $0?.newPumpEvent(forceFinalization: forceFinalization) })
Expand Down
9 changes: 9 additions & 0 deletions MinimedKit/PumpManager/MinimedPumpManagerState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {

public var basalSchedule: BasalSchedule

public var lastSetChangeDate: Date?

public var lastRewindDate: Date?

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)
{
self.isOnboarded = isOnboarded
Expand Down Expand Up @@ -256,6 +260,9 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {
} else {
self.basalSchedule = BasalSchedule(entries: [])
}

lastSetChangeDate = rawValue["lastSetChangeDate"] as? Date
lastRewindDate = rawValue["lastRewindDate"] as? Date
}

public var rawValue: RawValue {
Expand Down Expand Up @@ -287,6 +294,8 @@ public struct MinimedPumpManagerState: RawRepresentable, Equatable {
value["rileyLinkBatteryAlertLevel"] = rileyLinkBatteryAlertLevel
value["lastRileyLinkBatteryAlertDate"] = lastRileyLinkBatteryAlertDate
value["basalSchedule"] = basalSchedule.rawValue
value["lastSetChangeDate"] = lastSetChangeDate
value["lastRewindDate"] = lastRewindDate

return value
}
Expand Down
4 changes: 3 additions & 1 deletion MinimedKitUI/MinimedPumpUICoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ class MinimedUICoordinator: UINavigationController, PumpManagerOnboarding, Compl
}

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

Expand Down
24 changes: 24 additions & 0 deletions MinimedKitUI/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -2438,6 +2438,9 @@
}
}
},
"Cannula Age" : {
"comment" : "Text for time since last medtronic pump set change event"
},
"Changing" : {
"comment" : "Text shown in basal rate space when basal is changing",
"localizations" : {
Expand Down Expand Up @@ -3308,6 +3311,12 @@
}
}
},
"day" : {
"comment" : "Singular day unit"
},
"days" : {
"comment" : "Plural days unit"
},
"Delete Pump" : {
"comment" : "Button label for removing Pump\nText to delete pump",
"localizations" : {
Expand Down Expand Up @@ -3445,6 +3454,9 @@
}
}
},
"Details" : {
"comment" : "The title of the details section in MinimedPumpManager settings"
},
"Devices" : {
"comment" : "Header for devices section of RileyLinkSetupView",
"localizations" : {
Expand Down Expand Up @@ -5000,6 +5012,12 @@
}
}
},
"hour" : {
"comment" : "Singular hour unit"
},
"hours" : {
"comment" : "Plural hours unit"
},
"Insulin\nSuspended" : {
"comment" : "Text shown in insulin delivery space when insulin suspended",
"localizations" : {
Expand Down Expand Up @@ -5155,6 +5173,9 @@
}
}
},
"Insulin Age" : {
"comment" : "Text for time since last medtronic pump rewind event"
},
"Insulin Delivery" : {
"comment" : "Title of insulin delivery section",
"localizations" : {
Expand Down Expand Up @@ -8988,6 +9009,9 @@
}
}
},
"Status" : {
"comment" : "The title of the status section in MinimedPumpManager settings"
},
"Succeeded" : {
"comment" : "A message indicating a command succeeded",
"localizations" : {
Expand Down
123 changes: 68 additions & 55 deletions MinimedKitUI/Views/MinimedPumpSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ struct MinimedPumpSettingsView: View {
var supportedInsulinTypes: [InsulinType]

@State private var showingDeletionSheet = false

@State private var showSyncTimeOptions = false;

var handleRileyLinkSelection: (RileyLinkDevice) -> Void
Expand All @@ -47,7 +46,6 @@ struct MinimedPumpSettingsView: View {
reservoirStatus
}
.padding(.bottom, 5)

}

if let basalDeliveryState = viewModel.basalDeliveryState {
Expand All @@ -64,51 +62,6 @@ struct MinimedPumpSettingsView: View {
}
}

Section(header: SectionHeader(label: LocalizedString("Configuration", comment: "The title of the configuration section in MinimedPumpManager settings")))
{
NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.pumpManager.state.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) {
HStack {
Text(LocalizedString("Insulin Type", comment: "Text for confidence reminders navigation link")).foregroundColor(Color.primary)
if let currentTitle = viewModel.pumpManager.state.insulinType?.brandName {
Spacer()
Text(currentTitle)
.foregroundColor(.secondary)
}
}
}
NavigationLink(destination: BatteryTypeSelectionView(batteryType: $viewModel.batteryChemistryType)) {
HStack {
Text(LocalizedString("Pump Battery Type", comment: "Text for medtronic pump battery type")).foregroundColor(Color.primary)
Spacer()
Text(viewModel.batteryChemistryType.description)
.foregroundColor(.secondary)
}
}

NavigationLink(destination: DataSourceSelectionView(batteryType: $viewModel.preferredDataSource)) {
HStack {
Text(LocalizedString("Preferred Data Source", comment: "Text for medtronic pump preferred data source")).foregroundColor(Color.primary)
Spacer()
Text(viewModel.preferredDataSource.description)
.foregroundColor(.secondary)
}
}

if viewModel.pumpManager.state.pumpModel.hasMySentry {
NavigationLink(destination: UseMySentrySelectionView(mySentryConfig: $viewModel.mySentryConfig)) {
HStack {
Text(LocalizedString("Use MySentry", comment: "Text for medtronic pump to use MySentry")).foregroundColor(Color.primary)
Spacer()
Text((viewModel.mySentryConfig == .useMySentry ?
LocalizedString("Yes", comment: "Value string for MySentry config when MySentry is being used") :
LocalizedString("No", comment: "Value string for MySentry config when MySentry is not being used"))
)
.foregroundColor(.secondary)
}
}
}
}

Section(header: HStack {
Text(LocalizedString("Devices", comment: "Header for devices section of RileyLinkSetupView"))
Spacer()
Expand Down Expand Up @@ -144,15 +97,32 @@ struct MinimedPumpSettingsView: View {
rileyLinkListDataSource.isScanningEnabled = false
}


Section() {
Section(header: Text(LocalizedString("Status", comment: "The title of the status section in MinimedPumpManager settings"))) {
if let timeSinceLastCannulaFill = viewModel.timeSinceLastSetChange {
HStack {
Text(LocalizedString("Cannula Age", comment: "Text for time since last medtronic pump set change event"))
Spacer()
Text(timeSinceLastCannulaFill)
.foregroundStyle(.secondary)
}
}
if let timeSinceLastRewind = viewModel.timeSinceLastRewind {
HStack {
Text(LocalizedString("Insulin Age", comment: "Text for time since last medtronic pump rewind event"))
Spacer()
Text(timeSinceLastRewind)
.foregroundStyle(.secondary)
}
}
HStack {
Text(LocalizedString("Pump Battery Remaining", comment: "Text for medtronic pump battery percent remaining")).foregroundColor(Color.primary)
Text(LocalizedString("Pump Battery Remaining", comment: "Text for medtronic pump battery percent remaining"))
Spacer()
if let chargeRemaining = viewModel.pumpManager.status.pumpBatteryChargeRemaining {
Text(String("\(Int(round(chargeRemaining * 100)))%"))
.foregroundStyle(.secondary)
} else {
Text(String(LocalizedString("unknown", comment: "Text to indicate battery percentage is unknown")))
.foregroundStyle(.secondary)
}
}
HStack {
Expand All @@ -163,7 +133,7 @@ struct MinimedPumpSettingsView: View {
.foregroundColor(guidanceColors.warning)
}
TimeView(timeZone: viewModel.pumpManager.status.timeZone)
.foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : nil)
.foregroundColor( viewModel.isClockOffset ? guidanceColors.warning : .secondary)
}
if viewModel.synchronizingTime {
HStack {
Expand All @@ -184,8 +154,53 @@ struct MinimedPumpSettingsView: View {
}
}

Section(header: Text(LocalizedString("Configuration", comment: "The title of the configuration section in MinimedPumpManager settings")))
{
NavigationLink(destination: InsulinTypeSetting(initialValue: viewModel.pumpManager.state.insulinType, supportedInsulinTypes: supportedInsulinTypes, allowUnsetInsulinType: false, didChange: viewModel.didChangeInsulinType)) {
HStack {
Text(LocalizedString("Insulin Type", comment: "Text for confidence reminders navigation link")).foregroundColor(Color.primary)
if let currentTitle = viewModel.pumpManager.state.insulinType?.brandName {
Spacer()
Text(currentTitle)
.foregroundColor(.secondary)
}
}
}
NavigationLink(destination: BatteryTypeSelectionView(batteryType: $viewModel.batteryChemistryType)) {
HStack {
Text(LocalizedString("Pump Battery Type", comment: "Text for medtronic pump battery type")).foregroundColor(Color.primary)
Spacer()
Text(viewModel.batteryChemistryType.description)
.foregroundColor(.secondary)
}
}

Section {
NavigationLink(destination: DataSourceSelectionView(batteryType: $viewModel.preferredDataSource)) {
HStack {
Text(LocalizedString("Preferred Data Source", comment: "Text for medtronic pump preferred data source")).foregroundColor(Color.primary)
Spacer()
Text(viewModel.preferredDataSource.description)
.foregroundColor(.secondary)
}
}

if viewModel.pumpManager.state.pumpModel.hasMySentry {
NavigationLink(destination: UseMySentrySelectionView(mySentryConfig: $viewModel.mySentryConfig)) {
HStack {
Text(LocalizedString("Use MySentry", comment: "Text for medtronic pump to use MySentry")).foregroundColor(Color.primary)
Spacer()
Text((viewModel.mySentryConfig == .useMySentry ?
LocalizedString("Yes", comment: "Value string for MySentry config when MySentry is being used") :
LocalizedString("No", comment: "Value string for MySentry config when MySentry is not being used"))
)
.foregroundColor(.secondary)
}
}
}
}

Section(header: Text(LocalizedString("Details", comment: "The title of the details section in MinimedPumpManager settings")))
{
LabeledValueView(label: LocalizedString("Pump ID", comment: "The title text for the pump ID config value"),
value: viewModel.pumpManager.state.pumpID)
LabeledValueView(label: LocalizedString("Firmware Version", comment: "The title of the cell showing the pump firmware version"),
Expand All @@ -194,7 +209,6 @@ struct MinimedPumpSettingsView: View {
value: String(describing: viewModel.pumpManager.state.pumpRegion))
}


Section() {
deletePumpButton
}
Expand All @@ -216,7 +230,6 @@ struct MinimedPumpSettingsView: View {

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

var deliverySectionTitle: String {
Expand Down Expand Up @@ -371,7 +384,7 @@ struct MinimedPumpSettingsView: View {
Image(uiImage: viewModel.pumpImage)
.resizable()
.aspectRatio(contentMode: ContentMode.fit)
.frame(height: 150)
.frame(height: 100)
.padding(.horizontal)
}
.frame(maxWidth: .infinity)
Expand Down
Loading