From e74c2c7c6c254b95cb413e5d3f7666538520ede1 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 30 Aug 2017 23:18:01 -0500 Subject: [PATCH] Adding pre-meal targets --- DoseMathTests/DoseMathTests.swift | 4 +- .../Pre-Meal Selected.imageset/Contents.json | 12 ++++ .../Pre-Meal Selected.pdf | Bin 0 -> 4645 bytes .../Pre-Meal.imageset/Contents.json | 12 ++++ .../Pre-Meal.imageset/Pre-Meal.pdf | Bin 0 -> 4506 bytes .../carbs.imageset/Contents.json | 2 +- Loop/Assets.xcassets/carbs.imageset/Meal.pdf | Bin 0 -> 4523 bytes Loop/Assets.xcassets/carbs.imageset/carbs.pdf | Bin 6759 -> 0 bytes Loop/Base.lproj/Main.storyboard | 17 +++-- Loop/Extensions/ChartPoint+Loop.swift | 8 +-- Loop/Extensions/GlucoseRangeSchedule.swift | 11 +++- Loop/Extensions/UIImage.swift | 4 ++ .../GlucoseRangeScheduleCalculator.swift | 2 +- Loop/Managers/LoopDataManager.swift | 49 ++++---------- .../Managers/StatusExtensionDataManager.swift | 9 +-- .../SettingsTableViewController.swift | 4 +- .../StatusTableViewController.swift | 61 ++++++++++++++---- 17 files changed, 122 insertions(+), 73 deletions(-) create mode 100644 Loop/Assets.xcassets/Pre-Meal Selected.imageset/Contents.json create mode 100644 Loop/Assets.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf create mode 100644 Loop/Assets.xcassets/Pre-Meal.imageset/Contents.json create mode 100644 Loop/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf create mode 100644 Loop/Assets.xcassets/carbs.imageset/Meal.pdf delete mode 100644 Loop/Assets.xcassets/carbs.imageset/carbs.pdf diff --git a/DoseMathTests/DoseMathTests.swift b/DoseMathTests/DoseMathTests.swift index 538e4416bf..5752a5501f 100644 --- a/DoseMathTests/DoseMathTests.swift +++ b/DoseMathTests/DoseMathTests.swift @@ -82,7 +82,7 @@ class RecommendTempBasalTests: XCTestCase { } var glucoseTargetRange: GlucoseRangeSchedule { - return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], workoutRange: nil)! + return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! } var insulinSensitivitySchedule: InsulinSensitivitySchedule { @@ -486,7 +486,7 @@ class RecommendBolusTests: XCTestCase { } var glucoseTargetRange: GlucoseRangeSchedule { - return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], workoutRange: nil)! + return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! } var insulinSensitivitySchedule: InsulinSensitivitySchedule { diff --git a/Loop/Assets.xcassets/Pre-Meal Selected.imageset/Contents.json b/Loop/Assets.xcassets/Pre-Meal Selected.imageset/Contents.json new file mode 100644 index 0000000000..e4a31838d0 --- /dev/null +++ b/Loop/Assets.xcassets/Pre-Meal Selected.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Pre-Meal Selected.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Loop/Assets.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf b/Loop/Assets.xcassets/Pre-Meal Selected.imageset/Pre-Meal Selected.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8c285da0df0a223013d124f21467d9c3aefef557 GIT binary patch literal 4645 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 UL*vJShzJWy0C{*+V5-3X0|Xijxc~qF literal 0 HcmV?d00001 diff --git a/Loop/Assets.xcassets/Pre-Meal.imageset/Contents.json b/Loop/Assets.xcassets/Pre-Meal.imageset/Contents.json new file mode 100644 index 0000000000..261ace122b --- /dev/null +++ b/Loop/Assets.xcassets/Pre-Meal.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Pre-Meal.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Loop/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf b/Loop/Assets.xcassets/Pre-Meal.imageset/Pre-Meal.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0992a4a2860b615d49418e1a454975c881f1b844 GIT binary patch literal 4506 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 literal 0 HcmV?d00001 diff --git a/Loop/Assets.xcassets/carbs.imageset/Contents.json b/Loop/Assets.xcassets/carbs.imageset/Contents.json index 1e4fc587fc..616f863b2d 100644 --- a/Loop/Assets.xcassets/carbs.imageset/Contents.json +++ b/Loop/Assets.xcassets/carbs.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "carbs.pdf" + "filename" : "Meal.pdf" } ], "info" : { diff --git a/Loop/Assets.xcassets/carbs.imageset/Meal.pdf b/Loop/Assets.xcassets/carbs.imageset/Meal.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5e1c948daddf721ee3dd86e653fbe87d78ad98be GIT binary patch literal 4523 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 diff --git a/Loop/Base.lproj/Main.storyboard b/Loop/Base.lproj/Main.storyboard index 24f48a7c71..d05f6ca240 100644 --- a/Loop/Base.lproj/Main.storyboard +++ b/Loop/Base.lproj/Main.storyboard @@ -697,18 +697,16 @@ + + - - - - - - + + @@ -1020,15 +1018,16 @@ + - + + + - - diff --git a/Loop/Extensions/ChartPoint+Loop.swift b/Loop/Extensions/ChartPoint+Loop.swift index 26a3190efa..3432cc5925 100644 --- a/Loop/Extensions/ChartPoint+Loop.swift +++ b/Loop/Extensions/ChartPoint+Loop.swift @@ -26,15 +26,15 @@ extension ChartPoint { return ChartPoint.pointsForDatedRanges(targetRanges, xAxisValues: xAxisValues) } - static func pointsForGlucoseRangeScheduleOverrideDuration(_ override: AbsoluteScheduleValue, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + static func pointsForGlucoseRangeScheduleOverrideDuration(_ override: GlucoseRangeSchedule.Override, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { return ChartPoint.pointsForDatedRangeOverrideDuration( - DatedRangeContext(startDate: override.startDate, endDate: override.endDate, minValue: override.value.minValue, maxValue: override.value.maxValue), + DatedRangeContext(startDate: override.start, endDate: override.end ?? .distantFuture, minValue: override.value.minValue, maxValue: override.value.maxValue), xAxisValues: xAxisValues) } - static func pointsForGlucoseRangeScheduleOverride(_ override: AbsoluteScheduleValue, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + static func pointsForGlucoseRangeScheduleOverride(_ override: GlucoseRangeSchedule.Override, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { return ChartPoint.pointsForDatedRangeOverride( - DatedRangeContext(startDate: override.startDate, endDate: override.endDate, minValue: override.value.minValue, maxValue: override.value.maxValue), + DatedRangeContext(startDate: override.start, endDate: override.end ?? .distantFuture, minValue: override.value.minValue, maxValue: override.value.maxValue), xAxisValues: xAxisValues) } } diff --git a/Loop/Extensions/GlucoseRangeSchedule.swift b/Loop/Extensions/GlucoseRangeSchedule.swift index 11a276dba8..6c0805735f 100644 --- a/Loop/Extensions/GlucoseRangeSchedule.swift +++ b/Loop/Extensions/GlucoseRangeSchedule.swift @@ -9,11 +9,16 @@ import LoopKit extension GlucoseRangeSchedule { - var workoutModeEnabled: Bool? { - guard let override = temporaryOverride else { + func overrideEnabledForContext(_ context: Override.Context) -> Bool? { + guard let override = override, override.context == context else { + guard let value = overrideRanges[context], !value.isZero else { + // Unavailable to set + return nil + } + return false } - return override.endDate.timeIntervalSinceNow > 0 + return override.isActive() } } diff --git a/Loop/Extensions/UIImage.swift b/Loop/Extensions/UIImage.swift index d5a572afd8..74103bfea5 100644 --- a/Loop/Extensions/UIImage.swift +++ b/Loop/Extensions/UIImage.swift @@ -39,6 +39,10 @@ extension UIImage { return UIImage(named: "reservoir_\(imageSuffixForLevel(level))") } + static func preMealImage(selected: Bool) -> UIImage? { + return UIImage(named: selected ? "Pre-Meal Selected" : "Pre-Meal") + } + static func workoutImage(selected: Bool) -> UIImage? { return UIImage(named: selected ? "workout-selected" : "workout") } diff --git a/Loop/Managers/GlucoseRangeScheduleCalculator.swift b/Loop/Managers/GlucoseRangeScheduleCalculator.swift index d1efe6d2a7..01379474f6 100644 --- a/Loop/Managers/GlucoseRangeScheduleCalculator.swift +++ b/Loop/Managers/GlucoseRangeScheduleCalculator.swift @@ -29,7 +29,7 @@ class GlucoseRangeScheduleCalculator: TargetPointsCalculator { { glucosePoints = ChartPoint.pointsForGlucoseRangeSchedule(schedule, xAxisValues: xAxisValues) - if let override = schedule.temporaryOverride { + if let override = schedule.override { overridePoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(override, xAxisValues: xAxisValues) overrideDurationPoints = ChartPoint.pointsForGlucoseRangeScheduleOverrideDuration(override, xAxisValues: xAxisValues) diff --git a/Loop/Managers/LoopDataManager.swift b/Loop/Managers/LoopDataManager.swift index a615109455..f75b1ee838 100644 --- a/Loop/Managers/LoopDataManager.swift +++ b/Loop/Managers/LoopDataManager.swift @@ -33,7 +33,7 @@ final class LoopDataManager { let doseStore: DoseStore - let glucoseStore: GlucoseStore! = GlucoseStore() + let glucoseStore: GlucoseStore! unowned let delegate: LoopDataManagerDelegate @@ -57,7 +57,10 @@ final class LoopDataManager { self.lastTempBasal = lastTempBasal self.settings = settings + let healthStore = HKHealthStore() + carbStore = CarbStore( + healthStore: healthStore, defaultAbsorptionTimes: ( fast: TimeInterval(hours: 2), medium: TimeInterval(hours: 3), @@ -73,6 +76,8 @@ final class LoopDataManager { insulinSensitivitySchedule: insulinSensitivitySchedule ) + glucoseStore = GlucoseStore(healthStore: healthStore) + // Observe changes carbUpdateObserver = NotificationCenter.default.addObserver( forName: .CarbEntriesDidUpdate, @@ -130,24 +135,6 @@ final class LoopDataManager { } } - /// Enable workout glucose targets until the given date - /// - /// TODO: When schedule settings are migrated to structs, this can be simplified - /// - /// - Parameter endDate: The date the workout targets should end - /// - Returns: True if the override was set - @discardableResult - func enableWorkoutMode(until endDate: Date) -> Bool { - if settings.glucoseTargetRangeSchedule != nil { - _ = settings.glucoseTargetRangeSchedule!.setWorkoutOverride(until: endDate) - } - - - notify(forChange: .preferences) - - return true - } - /// Disable any active workout glucose targets func disableWorkoutMode() { settings.glucoseTargetRangeSchedule?.clearOverride() @@ -212,23 +199,10 @@ final class LoopDataManager { /// /// - Parameter timeZone: The time zone func setScheduleTimeZone(_ timeZone: TimeZone) { - // Recreate each schedule to force a change notification - // TODO: When schedule settings are migrated to structs, this can be simplified - if let basalRateSchedule = basalRateSchedule { - self.basalRateSchedule = BasalRateSchedule(dailyItems: basalRateSchedule.items, timeZone: timeZone) - } - - if let carbRatioSchedule = carbRatioSchedule { - self.carbRatioSchedule = CarbRatioSchedule(unit: carbRatioSchedule.unit, dailyItems: carbRatioSchedule.items, timeZone: timeZone) - } - - if let insulinSensitivitySchedule = insulinSensitivitySchedule { - self.insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: insulinSensitivitySchedule.unit, dailyItems: insulinSensitivitySchedule.items, timeZone: timeZone) - } - - if let glucoseTargetRangeSchedule = settings.glucoseTargetRangeSchedule { - settings.glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: glucoseTargetRangeSchedule.unit, dailyItems: glucoseTargetRangeSchedule.items, workoutRange: glucoseTargetRangeSchedule.workoutRange, timeZone: timeZone) - } + self.basalRateSchedule?.timeZone = timeZone + self.carbRatioSchedule?.timeZone = timeZone + self.insulinSensitivitySchedule?.timeZone = timeZone + settings.glucoseTargetRangeSchedule?.timeZone = timeZone } // MARK: - Intake @@ -273,6 +247,9 @@ final class LoopDataManager { let addCompletion: (Bool, CarbEntry?, CarbStore.CarbStoreError?) -> Void = { (success, _, error) in self.dataAccessQueue.async { if success { + // Remove the active pre-meal target override + self.settings.glucoseTargetRangeSchedule?.clearOverride(matching: .preMeal) + self.carbEffect = nil self.carbsOnBoard = nil diff --git a/Loop/Managers/StatusExtensionDataManager.swift b/Loop/Managers/StatusExtensionDataManager.swift index 1ec54a2c95..91a0594480 100644 --- a/Loop/Managers/StatusExtensionDataManager.swift +++ b/Loop/Managers/StatusExtensionDataManager.swift @@ -148,12 +148,13 @@ final class StatusExtensionDataManager { ) } - if let override = targetRanges.temporaryOverride { + if let override = targetRanges.override { context.temporaryOverride = DatedRangeContext( - startDate: override.startDate, - endDate: override.endDate, + startDate: override.start, + endDate: override.end ?? .distantFuture, minValue: override.value.minValue, - maxValue: override.value.maxValue) + maxValue: override.value.maxValue + ) } } diff --git a/Loop/View Controllers/SettingsTableViewController.swift b/Loop/View Controllers/SettingsTableViewController.swift index a594208f98..721d20e665 100644 --- a/Loop/View Controllers/SettingsTableViewController.swift +++ b/Loop/View Controllers/SettingsTableViewController.swift @@ -558,7 +558,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu scheduleVC.timeZone = schedule.timeZone scheduleVC.scheduleItems = schedule.items scheduleVC.unit = schedule.unit - scheduleVC.workoutRange = schedule.workoutRange + scheduleVC.overrideRanges = schedule.overrideRanges show(scheduleVC, sender: sender) } else { @@ -802,7 +802,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu } case .glucoseTargetRange: if let controller = controller as? GlucoseRangeScheduleTableViewController { - dataManager.loopManager.settings.glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: controller.unit, dailyItems: controller.scheduleItems, workoutRange: controller.workoutRange, timeZone: controller.timeZone) + dataManager.loopManager.settings.glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: controller.unit, dailyItems: controller.scheduleItems, timeZone: controller.timeZone, overrideRanges: controller.overrideRanges, override: dataManager.loopManager.settings.glucoseTargetRangeSchedule?.override) AnalyticsManager.shared.didChangeGlucoseTargetRangeSchedule() } case let row: diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 682966ee95..ee9758129d 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -78,10 +78,10 @@ final class StatusTableViewController: ChartsTableViewController { // Toolbar toolbarItems![0].accessibilityLabel = NSLocalizedString("Add Meal", comment: "The label of the carb entry button") toolbarItems![0].tintColor = UIColor.COBTintColor - toolbarItems![2].accessibilityLabel = NSLocalizedString("Bolus", comment: "The label of the bolus entry button") - toolbarItems![2].tintColor = UIColor.doseTintColor - toolbarItems![6].accessibilityLabel = NSLocalizedString("Settings", comment: "The label of the settings button") - toolbarItems![6].tintColor = UIColor.secondaryLabelColor + toolbarItems![4].accessibilityLabel = NSLocalizedString("Bolus", comment: "The label of the bolus entry button") + toolbarItems![4].tintColor = UIColor.doseTintColor + toolbarItems![8].accessibilityLabel = NSLocalizedString("Settings", comment: "The label of the settings button") + toolbarItems![8].tintColor = UIColor.secondaryLabelColor } override func didReceiveMemoryWarning() { @@ -297,7 +297,8 @@ final class StatusTableViewController: ChartsTableViewController { hudView.loopCompletionHUD.dosingEnabled = deviceManager.loopManager.settings.dosingEnabled - workoutMode = deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.workoutModeEnabled + workoutMode = deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.overrideEnabledForContext(.workout) + preMealMode = deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.overrideEnabledForContext(.preMeal) reloadGroup.notify(queue: .main) { if let glucose = self.deviceManager.loopManager.glucoseStore.latestGlucose { @@ -432,6 +433,20 @@ final class StatusTableViewController: ChartsTableViewController { // MARK: - Toolbar data + private var preMealMode: Bool? = nil { + didSet { + guard oldValue != preMealMode else { + return + } + + if let preMealMode = preMealMode { + toolbarItems![2] = createPreMealButtonItem(selected: preMealMode) + } else { + toolbarItems![2].isEnabled = false + } + } + } + private var workoutMode: Bool? = nil { didSet { guard oldValue != workoutMode else { @@ -439,9 +454,9 @@ final class StatusTableViewController: ChartsTableViewController { } if let workoutMode = workoutMode { - toolbarItems![4] = createWorkoutButtonItem(selected: workoutMode) + toolbarItems![6] = createWorkoutButtonItem(selected: workoutMode) } else { - toolbarItems![4].isEnabled = false + toolbarItems![6].isEnabled = false } } } @@ -722,9 +737,25 @@ final class StatusTableViewController: ChartsTableViewController { @IBAction func unwindFromSettings(_ segue: UIStoryboardSegue) { } + private func createPreMealButtonItem(selected: Bool) -> UIBarButtonItem { + let item = UIBarButtonItem(image: UIImage.preMealImage(selected: selected), style: .plain, target: self, action: #selector(togglePreMealMode(_:))) + item.accessibilityLabel = NSLocalizedString("Pre-Meal Targets", comment: "The label of the pre-meal mode toggle button") + + if selected { + item.accessibilityTraits = item.accessibilityTraits | UIAccessibilityTraitSelected + item.accessibilityHint = NSLocalizedString("Disables", comment: "The action hint of the workout mode toggle button when enabled") + } else { + item.accessibilityHint = NSLocalizedString("Enables", comment: "The action hint of the workout mode toggle button when disabled") + } + + item.tintColor = UIColor.COBTintColor + + return item + } + private func createWorkoutButtonItem(selected: Bool) -> UIBarButtonItem { let item = UIBarButtonItem(image: UIImage.workoutImage(selected: selected), style: .plain, target: self, action: #selector(toggleWorkoutMode(_:))) - item.accessibilityLabel = NSLocalizedString("Workout Mode", comment: "The label of the workout mode toggle button") + item.accessibilityLabel = NSLocalizedString("Workout Targets", comment: "The label of the workout mode toggle button") if selected { item.accessibilityTraits = item.accessibilityTraits | UIAccessibilityTraitSelected @@ -738,12 +769,20 @@ final class StatusTableViewController: ChartsTableViewController { return item } + @IBAction func togglePreMealMode(_ sender: UIBarButtonItem) { + if preMealMode == true { + deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.clearOverride(matching: .preMeal) + } else { + _ = self.deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.setOverride(.preMeal, until: Date(timeIntervalSinceNow: .hours(1))) + } + } + @IBAction func toggleWorkoutMode(_ sender: UIBarButtonItem) { - if let workoutModeEnabled = workoutMode, workoutModeEnabled { - deviceManager.loopManager.disableWorkoutMode() + if workoutMode == true { + deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.clearOverride(matching: .workout) } else { let vc = UIAlertController(workoutDurationSelectionHandler: { (endDate) in - self.deviceManager.loopManager.enableWorkoutMode(until: endDate) + _ = self.deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.setOverride(.workout, until: endDate) }) present(vc, animated: true, completion: nil)