diff --git a/Cartfile.resolved b/Cartfile.resolved index ddbfd0d55e..66b850c60b 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,7 +1,7 @@ github "LoopKit/Amplitude-iOS" "2137d5fd44bf630ed33e1e72d7af6d8f8612f270" github "LoopKit/CGMBLEKit" "ea1267791c66e884f1013fffd36faf4555cc6eaf" github "LoopKit/G4ShareSpy" "fed5a389e3e47e3a1953878dd21852aa5f44b360" -github "LoopKit/LoopKit" "c6e9f9200deec9a401ab1725e888451b17dee98a" +github "LoopKit/LoopKit" "643026a2adbb1011f195c8d9bb5a16cd9fb576e4" github "LoopKit/dexcom-share-client-swift" "b0419edf55c7f389b36cb47dd5c376bbd3d03d69" github "i-schuetz/SwiftCharts" "0.6.2" github "ps2/rileylink_ios" "8418b57c1983bdefaec7ccb456c86d5efacf40e7" diff --git a/Common/Extensions/GlucoseRangeSchedule.swift b/Common/Extensions/GlucoseRangeSchedule.swift index 4cd1712a52..51ed6b48b3 100644 --- a/Common/Extensions/GlucoseRangeSchedule.swift +++ b/Common/Extensions/GlucoseRangeSchedule.swift @@ -35,16 +35,6 @@ extension GlucoseRangeSchedule { return activeOverride?.context } - var activeOverrideQuantityRange: Range? { - guard let activeOverride = activeOverride else { - return nil - } - - let lowerBound = HKQuantity(unit: unit, doubleValue: activeOverride.value.minValue) - let upperBound = HKQuantity(unit: unit, doubleValue: activeOverride.value.maxValue) - return lowerBound.. HKQuantity { - return HKQuantity(unit: unit, doubleValue: value(at: date).minValue) - } } -extension DoubleRange { - var averageValue: Double { +extension Range where Bound == HKQuantity { + func averageValue(for unit: HKUnit) -> Double { + let minValue = lowerBound.doubleValue(for: unit) + let maxValue = upperBound.doubleValue(for: unit) return (maxValue + minValue) / 2 } } diff --git a/Loop/Managers/DoseMath.swift b/Loop/Managers/DoseMath.swift index 61ba33ecf6..aa561e5108 100644 --- a/Loop/Managers/DoseMath.swift +++ b/Loop/Managers/DoseMath.swift @@ -257,7 +257,7 @@ extension Collection where Element == GlucoseValue { let targetValue = targetGlucoseValue( percentEffectDuration: time / model.effectDuration, minValue: suspendThresholdValue, - maxValue: correctionRange.value(at: prediction.startDate).averageValue + maxValue: correctionRange.quantityRange(at: prediction.startDate).averageValue(for: unit) ) // Compute the dose required to bring this prediction to target: @@ -287,23 +287,20 @@ extension Collection where Element == GlucoseValue { } // Choose either the minimum glucose or eventual glocse as the correction delta - let minGlucoseTargets = correctionRange.value(at: min.startDate) - let eventualGlucoseTargets = correctionRange.value(at: eventual.startDate) - - let minGlucoseValue = min.quantity.doubleValue(for: unit) - let eventualGlucoseValue = eventual.quantity.doubleValue(for: unit) + let minGlucoseTargets = correctionRange.quantityRange(at: min.startDate) + let eventualGlucoseTargets = correctionRange.quantityRange(at: eventual.startDate) // Treat the mininum glucose when both are below range - if minGlucoseValue < minGlucoseTargets.minValue && - eventual.quantity.doubleValue(for: unit) < eventualGlucoseTargets.minValue + if min.quantity < minGlucoseTargets.lowerBound && + eventual.quantity < eventualGlucoseTargets.lowerBound { let time = min.startDate.timeIntervalSince(date) // For time = 0, assume a small amount effected. This will result in large (negative) unit recommendation rather than no recommendation at all. let percentEffected = Swift.max(.ulpOfOne, 1 - model.percentEffectRemaining(at: time)) guard let units = insulinCorrectionUnits( - fromValue: minGlucoseValue, - toValue: minGlucoseTargets.averageValue, + fromValue: min.quantity.doubleValue(for: unit), + toValue: minGlucoseTargets.averageValue(for: unit), effectedSensitivity: sensitivityValue * percentEffected ) else { return nil @@ -311,16 +308,16 @@ extension Collection where Element == GlucoseValue { return .entirelyBelowRange( correcting: min, - minTarget: HKQuantity(unit: unit, doubleValue: minGlucoseTargets.minValue), + minTarget: minGlucoseTargets.lowerBound, units: units ) - } else if eventualGlucoseValue > eventualGlucoseTargets.maxValue, + } else if eventual.quantity > eventualGlucoseTargets.upperBound, let minCorrectionUnits = minCorrectionUnits, let correctingGlucose = correctingGlucose { return .aboveRange( min: min, correcting: correctingGlucose, - minTarget: HKQuantity(unit: unit, doubleValue: eventualGlucoseTargets.minValue), + minTarget: eventualGlucoseTargets.lowerBound, units: minCorrectionUnits ) } else { @@ -361,7 +358,7 @@ extension Collection where Element == GlucoseValue { let correction = self.insulinCorrection( to: correctionRange, at: date, - suspendThreshold: suspendThreshold ?? correctionRange.minQuantity(at: date), + suspendThreshold: suspendThreshold ?? correctionRange.quantityRange(at: date).lowerBound, sensitivity: sensitivity.quantity(at: date), model: model ) @@ -416,7 +413,7 @@ extension Collection where Element == GlucoseValue { guard let correction = self.insulinCorrection( to: correctionRange, at: date, - suspendThreshold: suspendThreshold ?? correctionRange.minQuantity(at: date), + suspendThreshold: suspendThreshold ?? correctionRange.quantityRange(at: date).lowerBound, sensitivity: sensitivity.quantity(at: date), model: model ) else { @@ -432,7 +429,7 @@ extension Collection where Element == GlucoseValue { // Handle the "current BG below target" notice here // TODO: Don't assume in the future that the first item in the array is current BG if case .predictedGlucoseBelowTarget? = bolus.notice, - let first = first, first.quantity < correctionRange.minQuantity(at: first.startDate) + let first = first, first.quantity < correctionRange.quantityRange(at: first.startDate).lowerBound { bolus.notice = .currentGlucoseBelowTarget(glucose: first) } diff --git a/LoopUI/Extensions/ChartPoint.swift b/LoopUI/Extensions/ChartPoint.swift index 032f934726..c9fce8efc9 100644 --- a/LoopUI/Extensions/ChartPoint.swift +++ b/LoopUI/Extensions/ChartPoint.swift @@ -13,8 +13,8 @@ import SwiftCharts extension ChartPoint { - static func pointsForGlucoseRangeSchedule(_ glucoseRangeSchedule: GlucoseRangeSchedule, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { - let targetRanges = glucoseRangeSchedule.between( + static func pointsForGlucoseRangeSchedule(_ glucoseRangeSchedule: GlucoseRangeSchedule, unit: HKUnit, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + let targetRanges = glucoseRangeSchedule.quantityBetween( start: ChartAxisValueDate.dateFromScalar(xAxisValues.first!.scalar), end: ChartAxisValueDate.dateFromScalar(xAxisValues.last!.scalar) ) @@ -38,7 +38,7 @@ extension ChartPoint { endDate = ChartAxisValueDate(date: targetRanges[index + 1].startDate, formatter: dateFormatter) } - let value = range.value.rangeWithMinimumIncremement(glucoseRangeSchedule.unit.chartableIncrement) + let value = range.value.doubleRangeWithMinimumIncrement(in: unit) let minValue = ChartAxisValueDouble(value.minValue) let maxValue = ChartAxisValueDouble(value.maxValue) @@ -56,8 +56,12 @@ extension ChartPoint { return maxPoints + minPoints.reversed() } - static func pointsForGlucoseRangeScheduleOverride(_ override: GlucoseRangeSchedule.Override, unit: HKUnit, xAxisValues: [ChartAxisValue], extendEndDateToChart: Bool = false) -> [ChartPoint] { - let range = override.value.rangeWithMinimumIncremement(unit.chartableIncrement) + static func pointsForGlucoseRangeScheduleOverride(_ glucoseRangeSchedule: GlucoseRangeSchedule, unit: HKUnit, xAxisValues: [ChartAxisValue], extendEndDateToChart: Bool = false) -> [ChartPoint] { + guard let override = glucoseRangeSchedule.override else { + return [] + } + + let range = override.quantityRange.doubleRangeWithMinimumIncrement(in: unit) let startDate = Date() let endDate = override.end @@ -96,10 +100,12 @@ extension ChartPoint: TimelineValue { } -private extension DoubleRange { - func rangeWithMinimumIncremement(_ increment: Double) -> DoubleRange { - var minValue = self.minValue - var maxValue = self.maxValue +private extension Range where Bound == HKQuantity { + func doubleRangeWithMinimumIncrement(in unit: HKUnit) -> DoubleRange { + let increment = unit.chartableIncrement + + var minValue = self.lowerBound.doubleValue(for: unit) + var maxValue = self.upperBound.doubleValue(for: unit) if (maxValue - minValue) < .ulpOfOne { minValue -= increment diff --git a/LoopUI/Managers/StatusChartsManager.swift b/LoopUI/Managers/StatusChartsManager.swift index 382115dfa6..5c3942e240 100644 --- a/LoopUI/Managers/StatusChartsManager.swift +++ b/LoopUI/Managers/StatusChartsManager.swift @@ -952,16 +952,9 @@ public final class StatusChartsManager { let xAxisValues = xAxisValues, xAxisValues.count > 1, let schedule = targetGlucoseSchedule { - targetGlucosePoints = ChartPoint.pointsForGlucoseRangeSchedule(schedule, xAxisValues: xAxisValues) - - if let override = schedule.override { - targetOverridePoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(override, unit: schedule.unit, xAxisValues: xAxisValues, extendEndDateToChart: true) - - targetOverrideDurationPoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(override, unit: schedule.unit, xAxisValues: xAxisValues) - } else { - targetOverridePoints = [] - targetOverrideDurationPoints = [] - } + targetGlucosePoints = ChartPoint.pointsForGlucoseRangeSchedule(schedule, unit: glucoseUnit, xAxisValues: xAxisValues) + targetOverridePoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(schedule, unit: glucoseUnit, xAxisValues: xAxisValues, extendEndDateToChart: true) + targetOverrideDurationPoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(schedule, unit: glucoseUnit, xAxisValues: xAxisValues) } } } diff --git a/WatchApp Extension/Models/GlucoseChartData.swift b/WatchApp Extension/Models/GlucoseChartData.swift index c45f24fa04..9b5e5485f8 100644 --- a/WatchApp Extension/Models/GlucoseChartData.swift +++ b/WatchApp Extension/Models/GlucoseChartData.swift @@ -53,7 +53,7 @@ struct GlucoseChartData { max = Swift.max(max, correction.value.upperBound.doubleValue(for: unit)) } - if let override = correctionRange?.activeOverrideQuantityRange { + if let override = correctionRange?.activeOverride?.quantityRange { min = Swift.min(min, override.lowerBound.doubleValue(for: unit)) max = Swift.max(max, override.upperBound.doubleValue(for: unit)) } diff --git a/WatchApp Extension/Scenes/GlucoseChartScene.swift b/WatchApp Extension/Scenes/GlucoseChartScene.swift index b233401623..363fc364dc 100644 --- a/WatchApp Extension/Scenes/GlucoseChartScene.swift +++ b/WatchApp Extension/Scenes/GlucoseChartScene.swift @@ -258,7 +258,7 @@ class GlucoseChartScene: SKScene { inactiveNodes.removeValue(forKey: range.chartHashValue) if range.end < spannedInterval.end { - let extendedRange = GlucoseRangeSchedule.Override(context: range.context, start: range.start, end: spannedInterval.end, value: range.value) + let extendedRange = GlucoseRangeSchedule.Override(context: range.context, start: range.start, end: spannedInterval.end, unit: range.unit, value: range.value) let (sprite2, created) = getSprite(forHash: extendedRange.chartHashValue) sprite2.color = UIColor.glucose.withAlphaComponent(0.25) sprite2.zPosition = NodePlane.overrideRanges.zPosition diff --git a/WatchApp Extension/Scenes/GlucoseChartValueHashable.swift b/WatchApp Extension/Scenes/GlucoseChartValueHashable.swift index 869a1a3d93..8b43c48987 100644 --- a/WatchApp Extension/Scenes/GlucoseChartValueHashable.swift +++ b/WatchApp Extension/Scenes/GlucoseChartValueHashable.swift @@ -78,10 +78,10 @@ extension AbsoluteScheduleValue: GlucoseChartValueHashable where T == Range