diff --git a/Common/Models/StatusExtensionContext.swift b/Common/Models/StatusExtensionContext.swift index 9f6896114b..9430895822 100644 --- a/Common/Models/StatusExtensionContext.swift +++ b/Common/Models/StatusExtensionContext.swift @@ -266,7 +266,7 @@ extension DatedRangeContext: RawRepresentable { struct StatusExtensionContext: RawRepresentable { typealias RawValue = [String: Any] - private let version = 3 + private let version = 4 var glucose: [GlucoseContext]? var predictedGlucose: PredictedGlucoseContext? @@ -274,6 +274,7 @@ struct StatusExtensionContext: RawRepresentable { var loop: LoopContext? var netBasal: NetBasalContext? var batteryPercentage: Double? + var activeInsulin: Double? var targetRanges: [DatedRangeContext]? var temporaryOverride: DatedRangeContext? var sensor: SensorDisplayableContext? @@ -307,6 +308,8 @@ struct StatusExtensionContext: RawRepresentable { batteryPercentage = rawValue["batteryPercentage"] as? Double + activeInsulin = rawValue["activeInsulin"] as? Double + if let rawValue = rawValue["targetRanges"] as? [DatedRangeContext.RawValue] { targetRanges = rawValue.flatMap({return DatedRangeContext(rawValue: $0)}) } @@ -331,6 +334,7 @@ struct StatusExtensionContext: RawRepresentable { raw["loop"] = loop?.rawValue raw["netBasal"] = netBasal?.rawValue raw["batteryPercentage"] = batteryPercentage + raw["activeInsulin"] = activeInsulin raw["targetRanges"] = targetRanges?.map({return $0.rawValue}) raw["temporaryOverride"] = temporaryOverride?.rawValue raw["sensor"] = sensor?.rawValue diff --git a/Loop Status Extension/Base.lproj/MainInterface.storyboard b/Loop Status Extension/Base.lproj/MainInterface.storyboard index 57419b7616..154bdf9b27 100644 --- a/Loop Status Extension/Base.lproj/MainInterface.storyboard +++ b/Loop Status Extension/Base.lproj/MainInterface.storyboard @@ -1,11 +1,11 @@ - - + + - + @@ -42,11 +42,24 @@ + + + + + @@ -76,6 +89,7 @@ + diff --git a/Loop Status Extension/StatusViewController.swift b/Loop Status Extension/StatusViewController.swift index 271b38b941..d388476b90 100644 --- a/Loop Status Extension/StatusViewController.swift +++ b/Loop Status Extension/StatusViewController.swift @@ -26,6 +26,7 @@ class StatusViewController: UIViewController, NCWidgetProviding { } } @IBOutlet weak var subtitleLabel: UILabel! + @IBOutlet weak var insulinLabel: UILabel! @IBOutlet weak var glucoseChartContentView: LoopUI.ChartContainerView! private lazy var charts: StatusChartsManager = { @@ -65,6 +66,8 @@ class StatusViewController: UIViewController, NCWidgetProviding { super.viewDidLoad() subtitleLabel.isHidden = true subtitleLabel.textColor = .subtitleLabelColor + insulinLabel.isHidden = true + insulinLabel.textColor = .subtitleLabelColor let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openLoopApp(_:))) view.addGestureRecognizer(tapGestureRecognizer) @@ -166,6 +169,7 @@ class StatusViewController: UIViewController, NCWidgetProviding { } subtitleLabel.isHidden = true + insulinLabel.isHidden = true let dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() @@ -175,7 +179,25 @@ class StatusViewController: UIViewController, NCWidgetProviding { return dateFormatter }() + let insulinFormatter: NumberFormatter = { + let numberFormatter = NumberFormatter() + + numberFormatter.numberStyle = .decimal + numberFormatter.minimumFractionDigits = 1 + numberFormatter.maximumFractionDigits = 1 + + return numberFormatter + }() + if let activeInsulin = context.activeInsulin, let valueStr = insulinFormatter.string(from:NSNumber(value:activeInsulin)) + { + insulinLabel.text = String(format: NSLocalizedString( + "IOB %1$@ U", + comment: "The subtitle format describing units of active insulin. (1: localized insulin value description)"), + valueStr) + insulinLabel.isHidden = false + } + if let glucose = context.glucose, glucose.count > 0 { let unit = glucose[0].unit @@ -193,6 +215,10 @@ class StatusViewController: UIViewController, NCWidgetProviding { if let first = glucose.first { charts.startDate = first.startDate } + + // Showing the whole history plus full prediction in the glucose plot + // is a little crowded, so limit it to three hours in the future: + charts.maxEndDate = Date().addingTimeInterval(TimeInterval(hours: 3)) if let predictedGlucose = context.predictedGlucose?.samples { charts.predictedGlucosePoints = predictedGlucose.map { @@ -209,7 +235,7 @@ class StatusViewController: UIViewController, NCWidgetProviding { subtitleLabel.text = String( format: NSLocalizedString( "Eventually %1$@ %2$@", - comment: "The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description)"), + comment: "The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description)"), eventualGlucoseNumberString, unit.glucoseUnitDisplayString ) diff --git a/Loop/Managers/StatusExtensionDataManager.swift b/Loop/Managers/StatusExtensionDataManager.swift index 0250b8ba8f..d77e8a0b6a 100644 --- a/Loop/Managers/StatusExtensionDataManager.swift +++ b/Loop/Managers/StatusExtensionDataManager.swift @@ -10,6 +10,7 @@ import HealthKit import UIKit import CarbKit import LoopKit +import InsulinKit import LoopUI @@ -134,6 +135,22 @@ final class StatusExtensionDataManager { ) } + updateGroup.enter() + manager.doseStore.insulinOnBoard(at: Date()) {(result) in + // This function completes asynchronously, so below + // is a completion that returns a value after eventual + // function completion. Currently the time of update + // isn't used in the code, but could e.g. check how + // recent it is. + switch result { + case .success(let iobValue): + context.activeInsulin = iobValue.value + case .failure: + context.activeInsulin = nil + } + updateGroup.leave() + } + if let batteryPercentage = dataManager.pumpBatteryChargeRemaining { context.batteryPercentage = batteryPercentage }