Skip to content

Commit

Permalink
Add active insulin (IOB) value in Today widget (LoopKit#635)
Browse files Browse the repository at this point in the history
* Update character count syntax for Swift 4

Avoids warnings from deprecated 'characters' syntax.

* Add 1024x1024 icon

Avoids compile-time warning about missing icon.  Doesn't actually look good at this size - it's just a scaled-up version of a smaller icon, but it avoids the warning.

* Add IOB to status widget

* Don't set context.activeInsulin on error

* Remove ActiveInsulinContext; use NumberFormatter

Struct form of ActiveInsulinContext is removed; just use a Double value instead, as with batteryPercentage. 
Use NumberFormatter to format IOB value.

* Fix var vs. let for activeInsulinString

* Bump version on StatusExtensionContext

* Revert "Update character count syntax for Swift 4"

This reverts commit 009e895.

* Revert "Add 1024x1024 icon"

This reverts commit ca10d0a.

* Add IOB label to storyboard

* Put IOB label calculation into separate block

* Adjust placement of label on storyboard; add constraints

* Format IOB label as NSLocalizedString

* Set end date for widget glucose chart
  • Loading branch information
elnjensen authored and ps2 committed Dec 13, 2017
1 parent e10eff6 commit 6453d5c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
6 changes: 5 additions & 1 deletion Common/Models/StatusExtensionContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,15 @@ extension DatedRangeContext: RawRepresentable {

struct StatusExtensionContext: RawRepresentable {
typealias RawValue = [String: Any]
private let version = 3
private let version = 4

var glucose: [GlucoseContext]?
var predictedGlucose: PredictedGlucoseContext?
var reservoir: ReservoirContext?
var loop: LoopContext?
var netBasal: NetBasalContext?
var batteryPercentage: Double?
var activeInsulin: Double?
var targetRanges: [DatedRangeContext]?
var temporaryOverride: DatedRangeContext?
var sensor: SensorDisplayableContext?
Expand Down Expand Up @@ -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)})
}
Expand All @@ -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
Expand Down
20 changes: 17 additions & 3 deletions Loop Status Extension/Base.lproj/MainInterface.storyboard
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G24b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="64E-I5-5c4">
<device id="retina4_7" orientation="portrait">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="64E-I5-5c4">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand Down Expand Up @@ -42,11 +42,24 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" layoutMarginsFollowReadableWidth="YES" text="IOB 1.0 U" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UPi-dG-yYD">
<rect key="frame" x="8" y="0.0" width="343" height="50"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="40" id="Va8-zN-Zxc"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="UPi-dG-yYD" firstAttribute="leading" secondItem="9iF-xY-Bh4" secondAttribute="leading" id="7Jj-0n-7D1"/>
<constraint firstItem="UPi-dG-yYD" firstAttribute="bottom" secondItem="9iF-xY-Bh4" secondAttribute="bottom" id="GsE-4E-FbA"/>
<constraint firstItem="9iF-xY-Bh4" firstAttribute="top" secondItem="3n2-yC-jGi" secondAttribute="top" id="HSD-ba-SBR"/>
<constraint firstAttribute="bottom" secondItem="9iF-xY-Bh4" secondAttribute="bottom" id="LtS-Ct-5Wl"/>
<constraint firstItem="UPi-dG-yYD" firstAttribute="height" secondItem="9iF-xY-Bh4" secondAttribute="height" id="Qa0-KT-ozH"/>
<constraint firstItem="9iF-xY-Bh4" firstAttribute="leading" secondItem="3n2-yC-jGi" secondAttribute="leading" constant="8" id="cIA-WI-DT4"/>
<constraint firstAttribute="trailing" secondItem="UPi-dG-yYD" secondAttribute="trailing" constant="8" id="uU7-uQ-0lP"/>
<constraint firstAttribute="trailing" secondItem="9iF-xY-Bh4" secondAttribute="trailing" constant="8" id="x9b-EB-fji"/>
</constraints>
</view>
Expand Down Expand Up @@ -76,6 +89,7 @@
<connections>
<outlet property="glucoseChartContentView" destination="GVu-hk-PBg" id="gfZ-nx-P6V"/>
<outlet property="hudView" destination="VIh-8L-VsB" id="NsP-iq-J4a"/>
<outlet property="insulinLabel" destination="UPi-dG-yYD" id="mhC-fv-uD4"/>
<outlet property="subtitleLabel" destination="9iF-xY-Bh4" id="PM8-hd-IB3"/>
</connections>
</viewController>
Expand Down
28 changes: 27 additions & 1 deletion Loop Status Extension/StatusViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -166,6 +169,7 @@ class StatusViewController: UIViewController, NCWidgetProviding {
}

subtitleLabel.isHidden = true
insulinLabel.isHidden = true

let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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
)
Expand Down
17 changes: 17 additions & 0 deletions Loop/Managers/StatusExtensionDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import HealthKit
import UIKit
import CarbKit
import LoopKit
import InsulinKit
import LoopUI


Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit 6453d5c

Please sign in to comment.