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
2 changes: 1 addition & 1 deletion Loop/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {

dataManager.enactBolus(units) { (error) in
if error != nil {
NotificationManager.sendBolusFailureNotificationForAmount(units, atDate: startDate)
NotificationManager.sendBolusFailureNotificationForAmount(units, atStartDate: startDate)
}

completionHandler()
Expand Down
18 changes: 12 additions & 6 deletions Loop/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" summaryElement="YES"/>
<accessibilityTraits key="traits" none="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
Expand Down Expand Up @@ -333,8 +333,7 @@
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" summaryElement="YES"/>
<accessibility key="accessibilityConfiguration" label="Glucose">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
Expand Down Expand Up @@ -378,7 +377,7 @@
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration">
<accessibility key="accessibilityConfiguration" label="Net Basal Rate">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
Expand Down Expand Up @@ -434,7 +433,7 @@
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration">
<accessibility key="accessibilityConfiguration" label="Reservoir Volume">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
Expand Down Expand Up @@ -483,7 +482,7 @@
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration">
<accessibility key="accessibilityConfiguration" label="Battery Level">
<bool key="isElement" value="YES"/>
</accessibility>
<constraints>
Expand Down Expand Up @@ -637,6 +636,7 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="U" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mVz-dr-xLU">
<accessibility key="accessibilityConfiguration" label="Units"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.55676333109537768" green="0.55676333109537768" blue="0.55676333109537768" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand All @@ -660,6 +660,10 @@
<constraint firstItem="mVz-dr-xLU" firstAttribute="leading" secondItem="5QS-Yf-Pua" secondAttribute="trailing" constant="8" symbolic="YES" id="z7E-fc-REL"/>
</constraints>
</tableViewCellContentView>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" none="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="us0-UE-Wqz">
<rect key="frame" x="0.0" y="143" width="375" height="44"/>
Expand All @@ -674,6 +678,7 @@
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="0.0" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7LT-50-ZzK">
<accessibility key="accessibilityConfiguration" label="Bolus Amount"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="hZ2-Aq-FHT"/>
</constraints>
Expand All @@ -684,6 +689,7 @@
</connections>
</textField>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="U" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BR0-dr-Fj2">
<accessibility key="accessibilityConfiguration" label="Units"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<color key="textColor" red="0.55676333109537768" green="0.55676333109537768" blue="0.55676333109537768" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand Down
8 changes: 4 additions & 4 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ final class DeviceDataManager: CarbStoreDelegate, DoseStoreDelegate, Transmitter

// Sentry packets are sent in groups of 3, 5s apart. Wait 11s before allowing the loop data to continue to avoid conflicting comms.
DispatchQueue.global(qos: DispatchQoS.QoSClass.utility).asyncAfter(deadline: DispatchTime.now() + Double(Int64(11 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) {
self.updateReservoirVolume(status.reservoirRemainingUnits, atDate: pumpDate, withTimeLeft: TimeInterval(minutes: Double(status.reservoirRemainingMinutes)))
self.updateReservoirVolume(status.reservoirRemainingUnits, at: pumpDate, withTimeLeft: TimeInterval(minutes: Double(status.reservoirRemainingMinutes)))
}

// Check for an empty battery. Sentry packets are still broadcast for a few hours after this value reaches 0.
Expand All @@ -223,7 +223,7 @@ final class DeviceDataManager: CarbStoreDelegate, DoseStoreDelegate, Transmitter
- parameter date: The date the reservoir was read
- parameter timeLeft: The approximate time before the reservoir is empty
*/
private func updateReservoirVolume(_ units: Double, atDate date: Date, withTimeLeft timeLeft: TimeInterval?) {
private func updateReservoirVolume(_ units: Double, at date: Date, withTimeLeft timeLeft: TimeInterval?) {
doseStore.addReservoirValue(units, atDate: date) { (newValue, previousValue, areStoredValuesContinuous, error) -> Void in
if let error = error {
self.logger.addError(error, fromSource: "DoseStore")
Expand Down Expand Up @@ -347,7 +347,7 @@ final class DeviceDataManager: CarbStoreDelegate, DoseStoreDelegate, Transmitter
let nsPumpStatus: NightscoutUploadKit.PumpStatus?
switch result {
case .success(let (status, date)):
self.updateReservoirVolume(status.reservoir, atDate: date, withTimeLeft: nil)
self.updateReservoirVolume(status.reservoir, at: date, withTimeLeft: nil)
let battery = BatteryStatus(voltage: status.batteryVolts, status: BatteryIndicator(batteryStatus: status.batteryStatus))
nsPumpStatus = NightscoutUploadKit.PumpStatus(clock: date, pumpID: status.pumpID, iob: nil, battery: battery, suspended: status.suspended, bolusing: status.bolusing, reservoir: status.reservoir)
case .failure(let error):
Expand Down Expand Up @@ -388,7 +388,7 @@ final class DeviceDataManager: CarbStoreDelegate, DoseStoreDelegate, Transmitter
self.logger.addError(error, fromSource: "Bolus")
completion(LoopError.communicationError)
} else {
self.loopManager.recordBolus(units, atDate: Date())
self.loopManager.recordBolus(units, at: Date())
completion(nil)
}
}
Expand Down
4 changes: 3 additions & 1 deletion Loop/Managers/DoseMath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ struct DoseMath {
doseUnits -= max(0, remainingUnits)
}

return max(0, doseUnits)
doseUnits = round(doseUnits * 40) / 40

return min(maxBolus, max(0, doseUnits))
}
}
2 changes: 1 addition & 1 deletion Loop/Managers/LoopDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ final class LoopDataManager {
- parameter units: The amount of insulin
- parameter date: The date the bolus was set
*/
func recordBolus(_ units: Double, atDate date: Date) {
func recordBolus(_ units: Double, at date: Date) {
dataAccessQueue.async {
self.lastBolus = (units: units, date: date)
self.notify(forChange: .bolus)
Expand Down
2 changes: 1 addition & 1 deletion Loop/Managers/NotificationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct NotificationManager {

// MARK: - Notifications

static func sendBolusFailureNotificationForAmount(_ units: Double, atDate startDate: Date) {
static func sendBolusFailureNotificationForAmount(_ units: Double, atStartDate startDate: Date) {
let notification = UILocalNotification()

notification.alertTitle = NSLocalizedString("Bolus", comment: "The notification title for a bolus failure")
Expand Down
2 changes: 1 addition & 1 deletion Loop/Managers/WatchDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ final class WatchDataManager: NSObject, WCSessionDelegate {
if let bolus = SetBolusUserInfo(rawValue: message as SetBolusUserInfo.RawValue) {
self.deviceDataManager.enactBolus(bolus.value) { (error) in
if error != nil {
NotificationManager.sendBolusFailureNotificationForAmount(bolus.value, atDate: bolus.startDate)
NotificationManager.sendBolusFailureNotificationForAmount(bolus.value, atStartDate: bolus.startDate)
} else {
AnalyticsManager.sharedManager.didSetBolusFromWatch(bolus.value)
}
Expand Down
31 changes: 23 additions & 8 deletions Loop/View Controllers/BolusViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let spellOutFormatter = NumberFormatter()
spellOutFormatter.numberStyle = .spellOut

bolusAmountTextField.accessibilityHint = String(format: NSLocalizedString("Recommended Bolus: %@ Units", comment: "Accessibility hint describing recommended bolus units"), spellOutFormatter.string(from: NSNumber(value: recommendedBolus)) ?? "0")

bolusAmountTextField.becomeFirstResponder()

AnalyticsManager.sharedManager.didDisplayBolusScreen()
Expand All @@ -27,6 +32,8 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex
}
}

var maxBolus: Double = 25

private(set) var bolus: Double?

@IBOutlet weak var recommendedBolusAmountLabel: UILabel? {
Expand All @@ -42,27 +49,35 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex
@IBAction func authenticateBolus(_ sender: Any) {
bolusAmountTextField.resignFirstResponder()

guard let text = bolusAmountTextField?.text, let bolus = decimalFormatter.number(from: text)?.doubleValue,
let amountString = decimalFormatter.string(from: NSNumber(value: bolus)) else {
return
}

guard bolus <= maxBolus else {
presentAlertController(withTitle: NSLocalizedString("Exceeds Maximum Bolus", comment: "The title of the alert describing a maximum bolus validation error"), message: String(format: NSLocalizedString("The maximum bolus amount is %@ Units", comment: "Body of the alert describing a maximum bolus validation error. (1: The localized max bolus value)"), decimalFormatter.string(from: NSNumber(value: maxBolus)) ?? ""))
return
}

let context = LAContext()

if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) {
context.evaluatePolicy(.deviceOwnerAuthentication,
localizedReason: NSLocalizedString("Please authenticate to bolus", comment: "The message displayed during a device authentication prompt for bolus specification"),
localizedReason: String(format: NSLocalizedString("Authenticate to Bolus %@ Units", comment: "The message displayed during a device authentication prompt for bolus specification"), amountString),
reply: { (success, error) in
if success {
self.setBolusAndClose(sender)
self.setBolusAndClose(bolus)
}
})
} else {
setBolusAndClose(sender)
setBolusAndClose(bolus)
}
}

private func setBolusAndClose(_ sender: Any) {
if let text = bolusAmountTextField?.text, let bolus = decimalFormatter.number(from: text)?.doubleValue {
self.bolus = bolus
private func setBolusAndClose(_ bolus: Double) {
self.bolus = bolus

self.performSegue(withIdentifier: "close", sender: sender)
}
self.performSegue(withIdentifier: "close", sender: nil)
}

private lazy var decimalFormatter: NumberFormatter = {
Expand Down
Loading