From fa6bffc13d5779243369fc06509f9a501b8f8fb7 Mon Sep 17 00:00:00 2001 From: Jon Fawcett Date: Thu, 9 Jul 2020 18:51:37 -0400 Subject: [PATCH 01/37] Quiet Hours --- LoopFollow/Controllers/AlarmSound.swift | 1 - LoopFollow/Controllers/Alarms.swift | 470 ++++++++++-------- .../ViewControllers/AlarmViewController.swift | 221 ++++---- .../SettingsViewController.swift | 41 -- .../SnoozeViewController.swift | 41 ++ LoopFollow/repository/UserDefaults.swift | 26 +- 6 files changed, 439 insertions(+), 361 deletions(-) diff --git a/LoopFollow/Controllers/AlarmSound.swift b/LoopFollow/Controllers/AlarmSound.swift index 11f94a1dc..5c65f3f3b 100644 --- a/LoopFollow/Controllers/AlarmSound.swift +++ b/LoopFollow/Controllers/AlarmSound.swift @@ -116,7 +116,6 @@ class AlarmSound { static func play(overrideVolume: Bool, numLoops: Int) { - guard !self.isPlaying else { return } diff --git a/LoopFollow/Controllers/Alarms.swift b/LoopFollow/Controllers/Alarms.swift index f5757fc11..806c6bd12 100644 --- a/LoopFollow/Controllers/Alarms.swift +++ b/LoopFollow/Controllers/Alarms.swift @@ -13,179 +13,180 @@ extension MainViewController { func checkAlarms(bgs: [DataStructs.sgvData]) { - if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Checking Alarms") } - // Don't check or fire alarms within 1 minute of prior alarm - if checkAlarmTimer.isValid { return } - - let date = Date() - let now = date.timeIntervalSince1970 - let currentBG = bgs[bgs.count - 1].sgv - let lastBG = bgs[bgs.count - 2].sgv - guard let deltas: [Int] = [ - bgs[bgs.count - 1].sgv - bgs[bgs.count - 2].sgv, - bgs[bgs.count - 2].sgv - bgs[bgs.count - 3].sgv, - bgs[bgs.count - 3].sgv - bgs[bgs.count - 4].sgv - ] else {} - let currentBGTime = bgs[bgs.count - 1].date - var alarmTriggered = false - var numLoops = 0 - clearOldSnoozes() - - // Exit if all is snoozed - // still send persistent notification with all snoozed - if UserDefaultsRepository.alertSnoozeAllIsSnoozed.value { - persistentNotification(bgTime: currentBGTime) - return - } - - - // BG Based Alarms - // Check to make sure it is a current reading and has not already triggered alarm from this reading - if now - currentBGTime <= (5*60) && currentBGTime > UserDefaultsRepository.snoozedBGReadingTime.value as! TimeInterval { - - // trigger temporary alert first - if UserDefaultsRepository.alertTemporaryActive.value { - if UserDefaultsRepository.alertTemporaryBelow.value { - if Float(currentBG) < UserDefaultsRepository.alertTemporaryBG.value { - UserDefaultsRepository.alertTemporaryActive.value = false - AlarmSound.whichAlarm = "Temporary Alert" + if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Checking Alarms") } + // Don't check or fire alarms within 1 minute of prior alarm + if checkAlarmTimer.isValid { return } + + let date = Date() + let now = date.timeIntervalSince1970 + let currentBG = bgs[bgs.count - 1].sgv + let lastBG = bgs[bgs.count - 2].sgv + guard let deltas: [Int] = [ + bgs[bgs.count - 1].sgv - bgs[bgs.count - 2].sgv, + bgs[bgs.count - 2].sgv - bgs[bgs.count - 3].sgv, + bgs[bgs.count - 3].sgv - bgs[bgs.count - 4].sgv + ] else {} + let currentBGTime = bgs[bgs.count - 1].date + var alarmTriggered = false + var numLoops = 0 + checkQuietHours() + clearOldSnoozes() + + // Exit if all is snoozed + // still send persistent notification with all snoozed + if UserDefaultsRepository.alertSnoozeAllIsSnoozed.value { + persistentNotification(bgTime: currentBGTime) + return + } + + + // BG Based Alarms + // Check to make sure it is a current reading and has not already triggered alarm from this reading + if now - currentBGTime <= (5*60) && currentBGTime > UserDefaultsRepository.snoozedBGReadingTime.value as! TimeInterval { + + // trigger temporary alert first + if UserDefaultsRepository.alertTemporaryActive.value { + if UserDefaultsRepository.alertTemporaryBelow.value { + if Float(currentBG) < UserDefaultsRepository.alertTemporaryBG.value { + UserDefaultsRepository.alertTemporaryActive.value = false + AlarmSound.whichAlarm = "Temporary Alert" if UserDefaultsRepository.alertTemporaryBGRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertTemporarySound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertTemporaryBGDND.value, numLoops: numLoops) - return - } - } else{ - if Float(currentBG) > UserDefaultsRepository.alertTemporaryBG.value { - tabBarController?.selectedIndex = 2 - AlarmSound.whichAlarm = "Temporary Alert" + triggerAlarm(sound: UserDefaultsRepository.alertTemporarySound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } else{ + if Float(currentBG) > UserDefaultsRepository.alertTemporaryBG.value { + tabBarController?.selectedIndex = 2 + AlarmSound.whichAlarm = "Temporary Alert" if UserDefaultsRepository.alertTemporaryBGRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertTemporarySound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertTemporaryBGDND.value, numLoops: numLoops) - return - } - } - } - - // Check Urgent Low - if UserDefaultsRepository.alertUrgentLowActive.value && !UserDefaultsRepository.alertUrgentLowIsSnoozed.value && - Float(currentBG) <= UserDefaultsRepository.alertUrgentLowBG.value { - // Separating this makes it so the low or drop alerts won't trigger if they already snoozed the urgent low - if !UserDefaultsRepository.alertUrgentLowIsSnoozed.value { - AlarmSound.whichAlarm = "Urgent Low Alert" + triggerAlarm(sound: UserDefaultsRepository.alertTemporarySound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } + } + + // Check Urgent Low + if UserDefaultsRepository.alertUrgentLowActive.value && !UserDefaultsRepository.alertUrgentLowIsSnoozed.value && + Float(currentBG) <= UserDefaultsRepository.alertUrgentLowBG.value { + // Separating this makes it so the low or drop alerts won't trigger if they already snoozed the urgent low + if !UserDefaultsRepository.alertUrgentLowIsSnoozed.value { + AlarmSound.whichAlarm = "Urgent Low Alert" if UserDefaultsRepository.alertUrgentLowRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertUrgentLowSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertUrgentLowDND.value, numLoops: numLoops) - return - } else { - return - } - } - - // Check Low - if UserDefaultsRepository.alertLowActive.value && !UserDefaultsRepository.alertUrgentLowIsSnoozed.value && - Float(currentBG) <= UserDefaultsRepository.alertLowBG.value && !UserDefaultsRepository.alertLowIsSnoozed.value { - AlarmSound.whichAlarm = "Low Alert" + triggerAlarm(sound: UserDefaultsRepository.alertUrgentLowSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } else { + return + } + } + + // Check Low + if UserDefaultsRepository.alertLowActive.value && !UserDefaultsRepository.alertUrgentLowIsSnoozed.value && + Float(currentBG) <= UserDefaultsRepository.alertLowBG.value && !UserDefaultsRepository.alertLowIsSnoozed.value { + AlarmSound.whichAlarm = "Low Alert" if UserDefaultsRepository.alertLowRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertLowSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertLowDND.value, numLoops: numLoops) - return - } - - // Check Urgent High - if UserDefaultsRepository.alertUrgentHighActive.value && !UserDefaultsRepository.alertUrgentHighIsSnoozed.value && - Float(currentBG) >= UserDefaultsRepository.alertUrgentHighBG.value { - // Separating this makes it so the high or rise alerts won't trigger if they already snoozed the urgent high - if !UserDefaultsRepository.alertUrgentHighIsSnoozed.value { - AlarmSound.whichAlarm = "Urgent High Alert" + triggerAlarm(sound: UserDefaultsRepository.alertLowSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + + // Check Urgent High + if UserDefaultsRepository.alertUrgentHighActive.value && !UserDefaultsRepository.alertUrgentHighIsSnoozed.value && + Float(currentBG) >= UserDefaultsRepository.alertUrgentHighBG.value { + // Separating this makes it so the high or rise alerts won't trigger if they already snoozed the urgent high + if !UserDefaultsRepository.alertUrgentHighIsSnoozed.value { + AlarmSound.whichAlarm = "Urgent High Alert" if UserDefaultsRepository.alertUrgentHighRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertUrgentHighSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertUrgentHighDND.value, numLoops: numLoops) - return - } else { - return - } - - } - - // Check High - let persistentReadings = Int(UserDefaultsRepository.alertHighPersistent.value / 5) - let persistentBG = bgData[bgData.count - 1 - persistentReadings].sgv - if UserDefaultsRepository.alertHighActive.value && - !UserDefaultsRepository.alertHighIsSnoozed.value && - Float(currentBG) >= UserDefaultsRepository.alertHighBG.value && - Float(persistentBG) >= UserDefaultsRepository.alertHighBG.value && - !UserDefaultsRepository.alertHighIsSnoozed.value { - AlarmSound.whichAlarm = "High Alert" + triggerAlarm(sound: UserDefaultsRepository.alertUrgentHighSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } else { + return + } + + } + + // Check High + let persistentReadings = Int(UserDefaultsRepository.alertHighPersistent.value / 5) + let persistentBG = bgData[bgData.count - 1 - persistentReadings].sgv + if UserDefaultsRepository.alertHighActive.value && + !UserDefaultsRepository.alertHighIsSnoozed.value && + Float(currentBG) >= UserDefaultsRepository.alertHighBG.value && + Float(persistentBG) >= UserDefaultsRepository.alertHighBG.value && + !UserDefaultsRepository.alertHighIsSnoozed.value { + AlarmSound.whichAlarm = "High Alert" if UserDefaultsRepository.alertHighRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertHighSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertHighDND.value, numLoops: numLoops) - return - } - - - - // Check Fast Drop - if UserDefaultsRepository.alertFastDropActive.value && !UserDefaultsRepository.alertFastDropIsSnoozed.value { - // make sure limit is off or BG is below value - if (!UserDefaultsRepository.alertFastDropUseLimit.value) || (UserDefaultsRepository.alertFastDropUseLimit.value && Float(currentBG) < UserDefaultsRepository.alertFastDropBelowBG.value) { - let compare = 0 - UserDefaultsRepository.alertFastDropDelta.value - - //check last 2/3/4 readings - if (UserDefaultsRepository.alertFastDropReadings.value == 2 && Float(deltas[0]) <= compare) - || (UserDefaultsRepository.alertFastDropReadings.value == 3 && Float(deltas[0]) <= compare && Float(deltas[1]) <= compare) - || (UserDefaultsRepository.alertFastDropReadings.value == 4 && Float(deltas[0]) <= compare && Float(deltas[1]) <= compare && Float(deltas[2]) <= compare) { - AlarmSound.whichAlarm = "Fast Drop Alert" + triggerAlarm(sound: UserDefaultsRepository.alertHighSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + + + + // Check Fast Drop + if UserDefaultsRepository.alertFastDropActive.value && !UserDefaultsRepository.alertFastDropIsSnoozed.value { + // make sure limit is off or BG is below value + if (!UserDefaultsRepository.alertFastDropUseLimit.value) || (UserDefaultsRepository.alertFastDropUseLimit.value && Float(currentBG) < UserDefaultsRepository.alertFastDropBelowBG.value) { + let compare = 0 - UserDefaultsRepository.alertFastDropDelta.value + + //check last 2/3/4 readings + if (UserDefaultsRepository.alertFastDropReadings.value == 2 && Float(deltas[0]) <= compare) + || (UserDefaultsRepository.alertFastDropReadings.value == 3 && Float(deltas[0]) <= compare && Float(deltas[1]) <= compare) + || (UserDefaultsRepository.alertFastDropReadings.value == 4 && Float(deltas[0]) <= compare && Float(deltas[1]) <= compare && Float(deltas[2]) <= compare) { + AlarmSound.whichAlarm = "Fast Drop Alert" if UserDefaultsRepository.alertFastDropRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertFastDropSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertFastDropDND.value, numLoops: numLoops) - return - } - } - } - - // Check Fast Rise - if UserDefaultsRepository.alertFastRiseActive.value && !UserDefaultsRepository.alertFastRiseIsSnoozed.value { - // make sure limit is off or BG is above value - if (!UserDefaultsRepository.alertFastRiseUseLimit.value) || (UserDefaultsRepository.alertFastRiseUseLimit.value && Float(currentBG) > UserDefaultsRepository.alertFastRiseAboveBG.value) { - let compare = UserDefaultsRepository.alertFastDropDelta.value - - //check last 2/3/4 readings - if (UserDefaultsRepository.alertFastRiseReadings.value == 2 && Float(deltas[0]) >= compare) - || (UserDefaultsRepository.alertFastRiseReadings.value == 3 && Float(deltas[0]) >= compare && Float(deltas[1]) >= compare) - || (UserDefaultsRepository.alertFastRiseReadings.value == 4 && Float(deltas[0]) >= compare && Float(deltas[1]) >= compare && Float(deltas[2]) >= compare) { - AlarmSound.whichAlarm = "Fast Rise Alert" + triggerAlarm(sound: UserDefaultsRepository.alertFastDropSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } + } + + // Check Fast Rise + if UserDefaultsRepository.alertFastRiseActive.value && !UserDefaultsRepository.alertFastRiseIsSnoozed.value { + // make sure limit is off or BG is above value + if (!UserDefaultsRepository.alertFastRiseUseLimit.value) || (UserDefaultsRepository.alertFastRiseUseLimit.value && Float(currentBG) > UserDefaultsRepository.alertFastRiseAboveBG.value) { + let compare = UserDefaultsRepository.alertFastDropDelta.value + + //check last 2/3/4 readings + if (UserDefaultsRepository.alertFastRiseReadings.value == 2 && Float(deltas[0]) >= compare) + || (UserDefaultsRepository.alertFastRiseReadings.value == 3 && Float(deltas[0]) >= compare && Float(deltas[1]) >= compare) + || (UserDefaultsRepository.alertFastRiseReadings.value == 4 && Float(deltas[0]) >= compare && Float(deltas[1]) >= compare && Float(deltas[2]) >= compare) { + AlarmSound.whichAlarm = "Fast Rise Alert" if UserDefaultsRepository.alertFastRiseRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertFastRiseSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.alertFastRiseDND.value, numLoops: numLoops) - return - } - } - } - - - - } - - // These only get checked and fire if a BG reading doesn't fire - if UserDefaultsRepository.alertNotLoopingActive.value - && !UserDefaultsRepository.alertNotLoopingIsSnoozed.value + triggerAlarm(sound: UserDefaultsRepository.alertFastRiseSound.value, snooozedBGReadingTime: currentBGTime, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } + } + + + + } + + // These only get checked and fire if a BG reading doesn't fire + if UserDefaultsRepository.alertNotLoopingActive.value + && !UserDefaultsRepository.alertNotLoopingIsSnoozed.value && (Double(dateTimeUtils.getNowTimeIntervalUTC() - UserDefaultsRepository.alertLastLoopTime.value) >= Double(UserDefaultsRepository.alertNotLooping.value * 60)) - && UserDefaultsRepository.alertLastLoopTime.value > 0 { - - var trigger = true - if (UserDefaultsRepository.alertNotLoopingUseLimits.value - && ( - (Float(currentBG) <= UserDefaultsRepository.alertNotLoopingUpperLimit.value - && Float(currentBG) >= UserDefaultsRepository.alertNotLoopingLowerLimit.value) || - // Ignore Limits if BG reading is older than non looping time - (Double(now - currentBGTime) >= Double(UserDefaultsRepository.alertNotLooping.value * 60)) - ) || - !UserDefaultsRepository.alertNotLoopingUseLimits.value) { - AlarmSound.whichAlarm = "Not Looping Alert" + && UserDefaultsRepository.alertLastLoopTime.value > 0 { + + var trigger = true + if (UserDefaultsRepository.alertNotLoopingUseLimits.value + && ( + (Float(currentBG) <= UserDefaultsRepository.alertNotLoopingUpperLimit.value + && Float(currentBG) >= UserDefaultsRepository.alertNotLoopingLowerLimit.value) || + // Ignore Limits if BG reading is older than non looping time + (Double(now - currentBGTime) >= Double(UserDefaultsRepository.alertNotLooping.value * 60)) + ) || + !UserDefaultsRepository.alertNotLoopingUseLimits.value) { + AlarmSound.whichAlarm = "Not Looping Alert" if UserDefaultsRepository.alertNotLoopingRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertNotLoopingSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertNotLoopingDND.value, numLoops: numLoops) - return - } - } + triggerAlarm(sound: UserDefaultsRepository.alertNotLoopingSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } // check for missed bolus - Only checks within 1 hour of carb entry // Only continue if alert is active, not snooozed, we have carb data, and bg is over the ignore limit if UserDefaultsRepository.alertMissedBolusActive.value - && !UserDefaultsRepository.alertMissedBolusIsSnoozed.value - && carbData.count > 0 - && Float(currentBG) > UserDefaultsRepository.alertMissedBolusLowGramsBG.value { + && !UserDefaultsRepository.alertMissedBolusIsSnoozed.value + && carbData.count > 0 + && Float(currentBG) > UserDefaultsRepository.alertMissedBolusLowGramsBG.value { // Grab the latest carb entry let lastCarb = carbData[carbData.count - 1].value @@ -194,14 +195,14 @@ extension MainViewController { //Make sure carb entry is newer than 1 hour, has reached the time length, and is over the ignore limit if lastCarbTime > (now - (60 * 60)) - && lastCarbTime < (now - Double((UserDefaultsRepository.alertMissedBolus.value * 60))) - && lastCarb > Double(UserDefaultsRepository.alertMissedBolusLowGrams.value) { + && lastCarbTime < (now - Double((UserDefaultsRepository.alertMissedBolus.value * 60))) + && lastCarb > Double(UserDefaultsRepository.alertMissedBolusLowGrams.value) { // There is a current carb but no boluses data at all if bolusData.count < 1 { AlarmSound.whichAlarm = "Missed Bolus Alert" if UserDefaultsRepository.alertMissedBolusRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertMissedBolusSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertMissedBolusDND.value, numLoops: numLoops) + triggerAlarm(sound: UserDefaultsRepository.alertMissedBolusSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) return } @@ -225,54 +226,54 @@ extension MainViewController { if (lastBolus == 0.0) { AlarmSound.whichAlarm = "Missed Bolus Alert" if UserDefaultsRepository.alertMissedBolusRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertMissedBolusSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertMissedBolusDND.value, numLoops: numLoops) + triggerAlarm(sound: UserDefaultsRepository.alertMissedBolusSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) return } - - } + } + } - - //check for missed reading alert - if UserDefaultsRepository.alertMissedReadingActive.value && !UserDefaultsRepository.alertMissedReadingIsSnoozed.value && (Double(now - currentBGTime) >= Double(UserDefaultsRepository.alertMissedReading.value * 60)) { - AlarmSound.whichAlarm = "Missed Reading Alert" + + //check for missed reading alert + if UserDefaultsRepository.alertMissedReadingActive.value && !UserDefaultsRepository.alertMissedReadingIsSnoozed.value && (Double(now - currentBGTime) >= Double(UserDefaultsRepository.alertMissedReading.value * 60)) { + AlarmSound.whichAlarm = "Missed Reading Alert" if UserDefaultsRepository.alertMissedReadingRepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertMissedReadingSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertMissedReadingDND.value, numLoops: numLoops) - return - } - - // Check Sage - if UserDefaultsRepository.alertSAGEActive.value && !UserDefaultsRepository.alertSAGEIsSnoozed.value { - let insertTime = Double(UserDefaultsRepository.alertSageInsertTime.value) - let alertDistance = Double(UserDefaultsRepository.alertSAGE.value * 60 * 60) - let delta = now - insertTime - let tenDays = 10 * 24 * 60 * 60 - if Double(tenDays) - Double(delta) <= alertDistance { - AlarmSound.whichAlarm = "Sensor Change Alert" + triggerAlarm(sound: UserDefaultsRepository.alertMissedReadingSound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + + // Check Sage + if UserDefaultsRepository.alertSAGEActive.value && !UserDefaultsRepository.alertSAGEIsSnoozed.value { + let insertTime = Double(UserDefaultsRepository.alertSageInsertTime.value) + let alertDistance = Double(UserDefaultsRepository.alertSAGE.value * 60 * 60) + let delta = now - insertTime + let tenDays = 10 * 24 * 60 * 60 + if Double(tenDays) - Double(delta) <= alertDistance { + AlarmSound.whichAlarm = "Sensor Change Alert" if UserDefaultsRepository.alertSAGERepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertSAGESound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertSAGEDND.value, numLoops: numLoops) - return - } - } - - // Check Cage - if UserDefaultsRepository.alertCAGEActive.value && !UserDefaultsRepository.alertCAGEIsSnoozed.value { - let insertTime = Double(UserDefaultsRepository.alertCageInsertTime.value) - let alertDistance = Double(UserDefaultsRepository.alertCAGE.value * 60 * 60) - let delta = now - insertTime - let tenDays = 3 * 24 * 60 * 60 - if Double(tenDays) - Double(delta) <= alertDistance { - AlarmSound.whichAlarm = "Pump Change Alert" + triggerAlarm(sound: UserDefaultsRepository.alertSAGESound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } + + // Check Cage + if UserDefaultsRepository.alertCAGEActive.value && !UserDefaultsRepository.alertCAGEIsSnoozed.value { + let insertTime = Double(UserDefaultsRepository.alertCageInsertTime.value) + let alertDistance = Double(UserDefaultsRepository.alertCAGE.value * 60 * 60) + let delta = now - insertTime + let tenDays = 3 * 24 * 60 * 60 + if Double(tenDays) - Double(delta) <= alertDistance { + AlarmSound.whichAlarm = "Pump Change Alert" if UserDefaultsRepository.alertCAGERepeat.value { numLoops = -1 } - triggerAlarm(sound: UserDefaultsRepository.alertCAGESound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.alertCAGEDND.value, numLoops: numLoops) - return - } - } - - // still send persistent notification if no alarms trigger and persistent notification is on - persistentNotification(bgTime: currentBGTime) - - } + triggerAlarm(sound: UserDefaultsRepository.alertCAGESound.value, snooozedBGReadingTime: nil, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) + return + } + } + + // still send persistent notification if no alarms trigger and persistent notification is on + persistentNotification(bgTime: currentBGTime) + + } func checkOverrideAlarms() { @@ -295,18 +296,18 @@ extension MainViewController { if latest.value == prior.value { return } var numLoops = 0 - if UserDefaultsRepository.alertOverrideStart.value { + if UserDefaultsRepository.alertOverrideStart.value && !UserDefaultsRepository.alertOverrideStartIsSnoozed.value { if latest.value != 1.0 && lastOverrideStartTime != latest.date { AlarmSound.whichAlarm = String(format: "%.0f%%", (latest.value * 100)) + " Override Started" if UserDefaultsRepository.alertOverrideStartRepeat.value { numLoops = -1 } - triggerOneTimeAlarm(sound: UserDefaultsRepository.alertOverrideEndSound.value, overrideVolume: UserDefaultsRepository.alertOverrideStartDND.value, numLoops: numLoops) + triggerOneTimeAlarm(sound: UserDefaultsRepository.alertOverrideEndSound.value, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) lastOverrideStartTime = latest.date } - } else if UserDefaultsRepository.alertOverrideEnd.value { + } else if UserDefaultsRepository.alertOverrideEnd.value && !UserDefaultsRepository.alertOverrideEndIsSnoozed.value { if latest.value == 1.0 && lastOverrideEndTime != latest.date { AlarmSound.whichAlarm = "Override Ended" if UserDefaultsRepository.alertOverrideEndRepeat.value { numLoops = -1 } - triggerOneTimeAlarm(sound: UserDefaultsRepository.alertOverrideEndSound.value, overrideVolume: UserDefaultsRepository.alertOverrideEndDND.value, numLoops: numLoops) + triggerOneTimeAlarm(sound: UserDefaultsRepository.alertOverrideEndSound.value, overrideVolume: UserDefaultsRepository.overrideSystemOutputVolume.value, numLoops: numLoops) lastOverrideEndTime = latest.date } } @@ -427,9 +428,64 @@ extension MainViewController { alarms.reloadIsSnoozed(key: "alertCAGEIsSnoozed", value: false) } + if date > UserDefaultsRepository.alertOverrideStartSnoozedTime.value ?? date { + UserDefaultsRepository.alertOverrideStartSnoozedTime.setNil(key: "alertOverrideStartSnoozedTime") + UserDefaultsRepository.alertOverrideStartIsSnoozed.value = false + alarms.reloadSnoozeTime(key: "alertOverrideStartSnoozedTime", setNil: true) + alarms.reloadIsSnoozed(key: "alertOverrideStartIsSnoozed", value: false) + } + if date > UserDefaultsRepository.alertOverrideEndSnoozedTime.value ?? date { + UserDefaultsRepository.alertOverrideEndSnoozedTime.setNil(key: "alertOverrideEndSnoozedTime") + UserDefaultsRepository.alertOverrideEndIsSnoozed.value = false + alarms.reloadSnoozeTime(key: "alertOverrideEndSnoozedTime", setNil: true) + alarms.reloadIsSnoozed(key: "alertOverrideEndIsSnoozed", value: false) + + } } + func checkQuietHours() { + if UserDefaultsRepository.quietHourStart.value == nil || UserDefaultsRepository.quietHourEnd.value == nil { return } + + var startDateComponents = DateComponents() + + let today = Date() + let todayCalendar = Calendar.current + let month = todayCalendar.component(.month, from: today) + let day = todayCalendar.component(.day, from: today) + let year = todayCalendar.component(.year, from: today) + let hour = todayCalendar.component(.hour, from: today) + let minute = todayCalendar.component(.minute, from: today) + let todayMinutes = (60 * hour) + minute + + let start = UserDefaultsRepository.quietHourStart.value + let startCalendar = Calendar.current + let startHour = startCalendar.component(.hour, from: start!) + let startMinute = startCalendar.component(.minute, from: start!) + let startMinutes = (60 * startHour) + startMinute + + if todayMinutes >= startMinutes { + let tomorrow = Date().addingTimeInterval(86400) + let tomorrowCalendar = Calendar.current + let end = UserDefaultsRepository.quietHourEnd.value + let endCalendar = Calendar.current + + var components = DateComponents() + components.month = tomorrowCalendar.component(.month, from: tomorrow) + components.day = tomorrowCalendar.component(.day, from: tomorrow) + components.year = tomorrowCalendar.component(.year, from: tomorrow) + components.hour = endCalendar.component(.hour, from: end!) + components.minute = endCalendar.component(.minute, from: end!) + components.second = endCalendar.component(.second, from: end!) + let snoozeCalendar = Calendar.current + let snoozeTime = snoozeCalendar.date(from: components) + + guard let snoozer = self.tabBarController!.viewControllers?[2] as? SnoozeViewController else { return } + snoozer.setQuietHours(snoozeTime: snoozeTime!) + } + + } + func speakBG(sgv: Int) { var speechSynthesizer = AVSpeechSynthesizer() var speechUtterance: AVSpeechUtterance = AVSpeechUtterance(string: "Current BG is " + bgUnits.toDisplayUnits(String(sgv))) diff --git a/LoopFollow/ViewControllers/AlarmViewController.swift b/LoopFollow/ViewControllers/AlarmViewController.swift index 3613a9609..33f9cf3fb 100644 --- a/LoopFollow/ViewControllers/AlarmViewController.swift +++ b/LoopFollow/ViewControllers/AlarmViewController.swift @@ -356,13 +356,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertTempoaryDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertTemporaryBGDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertTemporaryBGDND.value = value - } <<< SwitchRow("alertTemporaryRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertTemporaryBGRepeat.value @@ -427,13 +420,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertUrgentLowDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertUrgentLowDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertUrgentLowDND.value = value - } <<< SwitchRow("alertUrgentLowRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertUrgentLowRepeat.value @@ -540,13 +526,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertLowDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertLowDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertLowDND.value = value - } <<< SwitchRow("alertLowRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertLowRepeat.value @@ -667,13 +646,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertHighDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertHighDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertHighDND.value = value - } <<< SwitchRow("alertHighRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertHighRepeat.value @@ -778,13 +750,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertUrgentHighDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertUrgentHighDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertUrgentHighDND.value = value - } <<< SwitchRow("alertUrgentHighRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertUrgentHighRepeat.value @@ -926,13 +891,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertFastDropDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertFastDropDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertFastDropDND.value = value - } <<< SwitchRow("alertFastDropRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertFastDropRepeat.value @@ -1074,13 +1032,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertFastRiseDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertFastRiseDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertFastRiseDND.value = value - } <<< SwitchRow("alertFastRiseRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertFastRiseRepeat.value @@ -1187,13 +1138,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertMissedReadingDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertMissedReadingDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertMissedReadingDND.value = value - } <<< SwitchRow("alertMissedReadingRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertMissedReadingRepeat.value @@ -1336,13 +1280,6 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertNotLoopingDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertNotLoopingDND.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.alertNotLoopingDND.value = value - } <<< SwitchRow("alertNotLoopingRepeat"){ row in row.title = "Repeat Sound" row.value = UserDefaultsRepository.alertNotLoopingRepeat.value @@ -1504,12 +1441,12 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertMissedBolusDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertMissedBolusDND.value + <<< SwitchRow("alertMissedBolusQuiet"){ row in + row.title = "Use Quiet Hours" + row.value = UserDefaultsRepository.alertMissedBolusQuiet.value }.onChange { [weak self] row in guard let value = row.value else { return } - UserDefaultsRepository.alertMissedBolusDND.value = value + UserDefaultsRepository.alertMissedBolusQuiet.value = value } <<< SwitchRow("alertMissedBolusRepeat"){ row in row.title = "Repeat Sound" @@ -1630,12 +1567,12 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertSAGEDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertSAGEDND.value + <<< SwitchRow("alertSAGEQuiet"){ row in + row.title = "Use Quiet Hours" + row.value = UserDefaultsRepository.alertSAGEQuiet.value }.onChange { [weak self] row in guard let value = row.value else { return } - UserDefaultsRepository.alertSAGEDND.value = value + UserDefaultsRepository.alertSAGEQuiet.value = value } <<< SwitchRow("alertSAGERepeat"){ row in row.title = "Repeat Sound" @@ -1742,12 +1679,12 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertCAGEDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertCAGEDND.value + <<< SwitchRow("alertCAGEQuiet"){ row in + row.title = "Use Quiet Hours" + row.value = UserDefaultsRepository.alertCAGEQuiet.value }.onChange { [weak self] row in guard let value = row.value else { return } - UserDefaultsRepository.alertCAGEDND.value = value + UserDefaultsRepository.alertCAGEQuiet.value = value } <<< SwitchRow("alertCAGERepeat"){ row in row.title = "Repeat Sound" @@ -1826,12 +1763,12 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertOverrideStartDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertOverrideStartDND.value + <<< SwitchRow("alertOverrideStartQuiet"){ row in + row.title = "Use Quiet Hours" + row.value = UserDefaultsRepository.alertOverrideStartQuiet.value }.onChange { [weak self] row in guard let value = row.value else { return } - UserDefaultsRepository.alertOverrideStartDND.value = value + UserDefaultsRepository.alertOverrideStartQuiet.value = value } <<< SwitchRow("alertOverrideStartRepeat"){ row in row.title = "Repeat Sound" @@ -1840,6 +1777,46 @@ class AlarmViewController: FormViewController { guard let value = row.value else { return } UserDefaultsRepository.alertOverrideStartRepeat.value = value } + <<< DateTimeInlineRow("alertOverrideStartSnoozedTime") { row in + row.title = "Snoozed Until" + if (UserDefaultsRepository.alertOverrideStartSnoozedTime.value != nil) { + row.value = UserDefaultsRepository.alertOverrideStartSnoozedTime.value + } + row.minuteInterval = 5 + row.noValueDisplayText = "Not Snoozed" + } + .onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.alertOverrideStartSnoozedTime.value = value + UserDefaultsRepository.alertOverrideStartIsSnoozed.value = true + let otherRow = self?.form.rowBy(tag: "alertOverrideStartIsSnoozed") as! SwitchRow + otherRow.value = true + otherRow.reload() + } + .onExpandInlineRow { [weak self] cell, row, inlineRow in + inlineRow.cellUpdate() { cell, row in + cell.datePicker.datePickerMode = .dateAndTime + } + let color = cell.detailTextLabel?.textColor + row.onCollapseInlineRow { cell, _, _ in + cell.detailTextLabel?.textColor = color + } + cell.detailTextLabel?.textColor = cell.tintColor + } + <<< SwitchRow("alertOverrideStartIsSnoozed"){ row in + row.title = "Is Snoozed" + row.value = UserDefaultsRepository.alertOverrideStartIsSnoozed.value + row.hidden = "$alertOverrideStartSnoozedTime == nil" + }.onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.alertOverrideStartIsSnoozed.value = value + if !value { + UserDefaultsRepository.alertOverrideStartSnoozedTime.setNil(key: "alertOverrideStartSnoozedTime") + let otherRow = self?.form.rowBy(tag: "alertOverrideStartSnoozedTime") as! DateTimeInlineRow + otherRow.value = nil + otherRow.reload() + } + } } @@ -1871,12 +1848,12 @@ class AlarmViewController: FormViewController { AlarmSound.stop() AlarmSound.playTest() } - <<< SwitchRow("alertOverrideEndDND"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.alertOverrideEndDND.value + <<< SwitchRow("alertOverrideEndQuiet"){ row in + row.title = "Use Quiet Hours" + row.value = UserDefaultsRepository.alertOverrideEndQuiet.value }.onChange { [weak self] row in guard let value = row.value else { return } - UserDefaultsRepository.alertOverrideEndDND.value = value + UserDefaultsRepository.alertOverrideEndQuiet.value = value } <<< SwitchRow("alertOverrideEndRepeat"){ row in row.title = "Repeat Sound" @@ -1885,19 +1862,67 @@ class AlarmViewController: FormViewController { guard let value = row.value else { return } UserDefaultsRepository.alertOverrideEndRepeat.value = value } + <<< DateTimeInlineRow("alertOverrideEndSnoozedTime") { row in + row.title = "Snoozed Until" + if (UserDefaultsRepository.alertOverrideEndSnoozedTime.value != nil) { + row.value = UserDefaultsRepository.alertOverrideEndSnoozedTime.value + } + row.minuteInterval = 5 + row.noValueDisplayText = "Not Snoozed" + } + .onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.alertOverrideEndSnoozedTime.value = value + UserDefaultsRepository.alertOverrideEndIsSnoozed.value = true + let otherRow = self?.form.rowBy(tag: "alertOverrideEndIsSnoozed") as! SwitchRow + otherRow.value = true + otherRow.reload() + } + .onExpandInlineRow { [weak self] cell, row, inlineRow in + inlineRow.cellUpdate() { cell, row in + cell.datePicker.datePickerMode = .dateAndTime + } + let color = cell.detailTextLabel?.textColor + row.onCollapseInlineRow { cell, _, _ in + cell.detailTextLabel?.textColor = color + } + cell.detailTextLabel?.textColor = cell.tintColor + } + <<< SwitchRow("alertOverrideEndIsSnoozed"){ row in + row.title = "Is Snoozed" + row.value = UserDefaultsRepository.alertOverrideEndIsSnoozed.value + row.hidden = "$alertOverrideEndSnoozedTime == nil" + }.onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.alertOverrideEndIsSnoozed.value = value + if !value { + UserDefaultsRepository.alertOverrideEndSnoozedTime.setNil(key: "alertOverrideEndSnoozedTime") + let otherRow = self?.form.rowBy(tag: "alertOverrideEndSnoozedTime") as! DateTimeInlineRow + otherRow.value = nil + otherRow.reload() + } + } } func buildAlarmSettings() { form - +++ Section(header: "Alarm Sound Settings", footer: "Use this volume level for alarms that override system volume") + +++ Section(header: "Alarm Sound Settings", footer: "Quiet hours can be used to automatically snooze non-critical alerts that you do not wish to be awakened for such as a sensor change pre-alert that may happen during the night.") + <<< SwitchRow("overrideSystemOutputVolume"){ row in + row.title = "Override System Volume" + row.value = UserDefaultsRepository.overrideSystemOutputVolume.value + }.onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.overrideSystemOutputVolume.value = value + } <<< StepperRow("forcedOutputVolume") { row in row.title = "Volume Level" row.cell.stepper.stepValue = 0.05 row.cell.stepper.minimumValue = 0 row.cell.stepper.maximumValue = 1 row.value = Double(UserDefaultsRepository.forcedOutputVolume.value) + row.hidden = "$overrideSystemOutputVolume == false" row.displayValueFor = { value in guard let value = value else { return nil } return "\(Int(value*100))%" @@ -1906,20 +1931,20 @@ class AlarmViewController: FormViewController { guard let value = row.value else { return } UserDefaultsRepository.forcedOutputVolume.value = Float(value) } - /* <<< StepperRow("fadeInTimeInterval") { row in - row.title = "Fade-in Seconds" - row.cell.stepper.stepValue = 5 - row.cell.stepper.minimumValue = 0 - row.cell.stepper.maximumValue = 60 - row.value = Double(UserDefaultsRepository.fadeInTimeInterval.value) - row.displayValueFor = { value in - guard let value = value else { return nil } - return "\(Int(value))" - } - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.fadeInTimeInterval.value = TimeInterval(value) - }*/ + <<< TimeInlineRow("quietHourStart") { row in + row.title = "Quiet Hours Start Today" + row.value = UserDefaultsRepository.quietHourStart.value + }.onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.quietHourStart.value = value + } + <<< TimeInlineRow("quietHourEnd") { row in + row.title = "Quiet Hours End Tomorrow" + row.value = UserDefaultsRepository.quietHourEnd.value + }.onChange { [weak self] row in + guard let value = row.value else { return } + UserDefaultsRepository.quietHourEnd.value = value + } } } diff --git a/LoopFollow/ViewControllers/SettingsViewController.swift b/LoopFollow/ViewControllers/SettingsViewController.swift index b01a0df45..8da99531d 100644 --- a/LoopFollow/ViewControllers/SettingsViewController.swift +++ b/LoopFollow/ViewControllers/SettingsViewController.swift @@ -70,7 +70,6 @@ class SettingsViewController: FormViewController { buildGeneralSettings() - // buildAlarmSettings() buildGraphSettings() buildWatchSettings() buildDebugSettings() @@ -159,46 +158,6 @@ class SettingsViewController: FormViewController { } } - func buildAlarmSettings() { - form - +++ Section("Alarm Settings") - <<< SwitchRow("overrideSystemOutputVolume"){ row in - row.title = "Override System Volume" - row.value = UserDefaultsRepository.overrideSystemOutputVolume.value - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.overrideSystemOutputVolume.value = value - } - <<< StepperRow("forcedOutputVolume") { row in - row.title = "Volume Level" - row.cell.stepper.stepValue = 0.05 - row.cell.stepper.minimumValue = 0 - row.cell.stepper.maximumValue = 1 - row.value = Double(UserDefaultsRepository.forcedOutputVolume.value) - row.hidden = "$overrideSystemOutputVolume == false" - row.displayValueFor = { value in - guard let value = value else { return nil } - return "\(Int(value*100))%" - } - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.forcedOutputVolume.value = Float(value) - } - /* <<< StepperRow("fadeInTimeInterval") { row in - row.title = "Fade-in Seconds" - row.cell.stepper.stepValue = 5 - row.cell.stepper.minimumValue = 0 - row.cell.stepper.maximumValue = 60 - row.value = Double(UserDefaultsRepository.fadeInTimeInterval.value) - row.displayValueFor = { value in - guard let value = value else { return nil } - return "\(Int(value))" - } - }.onChange { [weak self] row in - guard let value = row.value else { return } - UserDefaultsRepository.fadeInTimeInterval.value = TimeInterval(value) - }*/ - } func buildGraphSettings() { form diff --git a/LoopFollow/ViewControllers/SnoozeViewController.swift b/LoopFollow/ViewControllers/SnoozeViewController.swift index fbc931364..fa9e9d872 100644 --- a/LoopFollow/ViewControllers/SnoozeViewController.swift +++ b/LoopFollow/ViewControllers/SnoozeViewController.swift @@ -156,6 +156,47 @@ class SnoozeViewController: UIViewController, UNUserNotificationCenterDelegate { } } + func setQuietHours(snoozeTime: Date) + { + + if UserDefaultsRepository.alertMissedBolusQuiet.value { + UserDefaultsRepository.alertMissedBolusIsSnoozed.value = true + UserDefaultsRepository.alertMissedBolusSnoozedTime.value = snoozeTime + guard let alarms = self.tabBarController!.viewControllers?[1] as? AlarmViewController else { return } + alarms.reloadIsSnoozed(key: "alertMissedBolusIsSnoozed", value: true) + alarms.reloadSnoozeTime(key: "alertMissedBolusSnoozedTime", setNil: false, value: snoozeTime) + } + if UserDefaultsRepository.alertOverrideStartQuiet.value { + UserDefaultsRepository.alertOverrideStartIsSnoozed.value = true + UserDefaultsRepository.alertOverrideStartSnoozedTime.value = snoozeTime + guard let alarms = self.tabBarController!.viewControllers?[1] as? AlarmViewController else { return } + alarms.reloadIsSnoozed(key: "alertOverrideStartIsSnoozed", value: true) + alarms.reloadSnoozeTime(key: "alertOverrideStartSnoozedTime", setNil: false, value: snoozeTime) + } + if UserDefaultsRepository.alertOverrideEndQuiet.value { + UserDefaultsRepository.alertOverrideEndIsSnoozed.value = true + UserDefaultsRepository.alertOverrideEndSnoozedTime.value = snoozeTime + guard let alarms = self.tabBarController!.viewControllers?[1] as? AlarmViewController else { return } + alarms.reloadIsSnoozed(key: "alertOverrideEndIsSnoozed", value: true) + alarms.reloadSnoozeTime(key: "alertOverrideEndSnoozedTime", setNil: false, value: snoozeTime) + } + if UserDefaultsRepository.alertCAGEQuiet.value { + UserDefaultsRepository.alertCAGEIsSnoozed.value = true + UserDefaultsRepository.alertCAGESnoozedTime.value = snoozeTime + guard let alarms = self.tabBarController!.viewControllers?[1] as? AlarmViewController else { return } + alarms.reloadIsSnoozed(key: "alertCAGEIsSnoozed", value: true) + alarms.reloadSnoozeTime(key: "alertCAGESnoozedTime", setNil: false, value: snoozeTime) + } + if UserDefaultsRepository.alertSAGEQuiet.value { + UserDefaultsRepository.alertSAGEIsSnoozed.value = true + UserDefaultsRepository.alertSAGESnoozedTime.value = snoozeTime + guard let alarms = self.tabBarController!.viewControllers?[1] as? AlarmViewController else { return } + alarms.reloadIsSnoozed(key: "alertSAGEIsSnoozed", value: true) + alarms.reloadSnoozeTime(key: "alertSAGESnoozedTime", setNil: false, value: snoozeTime) + } + + } + override func viewDidLoad() { super.viewDidLoad() if UserDefaultsRepository.forceDarkMode.value { diff --git a/LoopFollow/repository/UserDefaults.swift b/LoopFollow/repository/UserDefaults.swift index 790229d8c..422b4760b 100644 --- a/LoopFollow/repository/UserDefaults.swift +++ b/LoopFollow/repository/UserDefaults.swift @@ -78,6 +78,9 @@ class UserDefaultsRepository { // Alerts + static let quietHourStart = UserDefaultsValue(key: "quietHourStart", default: nil) + static let quietHourEnd = UserDefaultsValue(key: "quietHourEnd", default: nil) + static let snoozedBGReadingTime = UserDefaultsValue(key: "snoozedBGReadingTime", default: 0) static let alertCageInsertTime = UserDefaultsValue(key: "alertCageInsertTime", default: 0) @@ -92,7 +95,6 @@ class UserDefaultsRepository { static let alertUrgentLowSnooze = UserDefaultsValue(key: "alertUrgentLowSnooze", default: 5) static let alertUrgentLowSnoozedTime = UserDefaultsValue(key: "alertUrgentLowSnoozedTime", default: nil) static let alertUrgentLowIsSnoozed = UserDefaultsValue(key: "alertUrgentLowIsSnoozed", default: false) - static let alertUrgentLowDND = UserDefaultsValue(key: "alertUrgentLowDND", default: true) static let alertUrgentLowRepeat = UserDefaultsValue(key: "alertUrgentLowRepeat", default: true) static let alertUrgentLowSound = UserDefaultsValue(key: "alertUrgentLowSound", default: "Indeed") @@ -101,7 +103,6 @@ class UserDefaultsRepository { static let alertLowSnooze = UserDefaultsValue(key: "alertLowSnooze", default: 5) static let alertLowSnoozedTime = UserDefaultsValue(key: "alertLowSnoozedTime", default: nil) static let alertLowIsSnoozed = UserDefaultsValue(key: "alertLowIsSnoozed", default: false) - static let alertLowDND = UserDefaultsValue(key: "alertLowDND", default: true) static let alertLowRepeat = UserDefaultsValue(key: "alertLowRepeat", default: true) static let alertLowSound = UserDefaultsValue(key: "alertLowSound", default: "Indeed") @@ -111,7 +112,6 @@ class UserDefaultsRepository { static let alertHighSnooze = UserDefaultsValue(key: "alertHighSnooze", default: 60) static let alertHighSnoozedTime = UserDefaultsValue(key: "alertHighSnoozedTime", default: nil) static let alertHighIsSnoozed = UserDefaultsValue(key: "alertHighIsSnoozed", default: false) - static let alertHighDND = UserDefaultsValue(key: "alertHighDND", default: true) static let alertHighRepeat = UserDefaultsValue(key: "alertHighRepeat", default: true) static let alertHighSound = UserDefaultsValue(key: "alertHighSound", default: "Indeed") @@ -120,7 +120,6 @@ class UserDefaultsRepository { static let alertUrgentHighSnooze = UserDefaultsValue(key: "alertUrgentHighSnooze", default: 30) static let alertUrgentHighSnoozedTime = UserDefaultsValue(key: "alertUrgentHighSnoozedTime", default: nil) static let alertUrgentHighIsSnoozed = UserDefaultsValue(key: "alertUrgentHighIsSnoozed", default: false) - static let alertUrgentHighDND = UserDefaultsValue(key: "alertUrgentHighDND", default: true) static let alertUrgentHighRepeat = UserDefaultsValue(key: "alertUrgentHighRepeat", default: true) static let alertUrgentHighSound = UserDefaultsValue(key: "alertUrgentHighSound", default: "Indeed") @@ -133,7 +132,6 @@ class UserDefaultsRepository { static let alertFastDropBelowBG = UserDefaultsValue(key: "alertFastDropBelowBG", default: 120.0) static let alertFastDropSnoozedTime = UserDefaultsValue(key: "alertFastDropSnoozedTime", default: nil) static let alertFastDropIsSnoozed = UserDefaultsValue(key: "alertFastDropIsSnoozed", default: false) - static let alertFastDropDND = UserDefaultsValue(key: "alertFastDropDND", default: true) static let alertFastDropRepeat = UserDefaultsValue(key: "alertFastDropRepeat", default: true) static let alertFastDropSound = UserDefaultsValue(key: "alertFastDropSound", default: "Indeed") @@ -145,7 +143,6 @@ class UserDefaultsRepository { static let alertFastRiseAboveBG = UserDefaultsValue(key: "alertFastRiseAboveBG", default: 200.0) static let alertFastRiseSnoozedTime = UserDefaultsValue(key: "alertFastRiseSnoozedTime", default: nil) static let alertFastRiseIsSnoozed = UserDefaultsValue(key: "alertFastRiseIsSnoozed", default: false) - static let alertFastRiseDND = UserDefaultsValue(key: "alertFastRiseDND", default: true) static let alertFastRiseRepeat = UserDefaultsValue(key: "alertFastRiseRepeat", default: true) static let alertFastRiseSound = UserDefaultsValue(key: "alertFastRiseSound", default: "Indeed") @@ -155,7 +152,6 @@ class UserDefaultsRepository { static let alertMissedReadingSnooze = UserDefaultsValue(key: "alertMissedReadingSnooze", default: 30) static let alertMissedReadingSnoozedTime = UserDefaultsValue(key: "alertMissedReadingSnoozedTime", default: nil) static let alertMissedReadingIsSnoozed = UserDefaultsValue(key: "alertMissedReadingIsSnoozed", default: false) - static let alertMissedReadingDND = UserDefaultsValue(key: "alertMissedReadingDND", default: true) static let alertMissedReadingRepeat = UserDefaultsValue(key: "alertMissedReadingRepeat", default: true) static let alertMissedReadingSound = UserDefaultsValue(key: "alertMissedReadingSound", default: "Indeed") @@ -168,7 +164,6 @@ class UserDefaultsRepository { static let alertNotLoopingUpperLimit = UserDefaultsValue(key: "alertNotLoopingAboveBG", default: 160.0) static let alertNotLoopingSnoozedTime = UserDefaultsValue(key: "alertNotLoopingSnoozedTime", default: nil) static let alertNotLoopingIsSnoozed = UserDefaultsValue(key: "alertNotLoopingIsSnoozed", default: false) - static let alertNotLoopingDND = UserDefaultsValue(key: "alertNotLoopingDND", default: true) static let alertNotLoopingRepeat = UserDefaultsValue(key: "alertNotLoopingRepeat", default: true) static let alertNotLoopingSound = UserDefaultsValue(key: "alertNotLoopingSound", default: "Indeed") static let alertLastLoopTime = UserDefaultsValue(key: "alertLastLoopTime", default: 0) @@ -182,13 +177,13 @@ class UserDefaultsRepository { static let alertMissedBolusLowGramsBG = UserDefaultsValue(key: "alertMissedBolusLowGramsBG", default: 70.0) static let alertMissedBolusSnoozedTime = UserDefaultsValue(key: "alertMissedBolusSnoozedTime", default: nil) static let alertMissedBolusIsSnoozed = UserDefaultsValue(key: "alertMissedBolusIsSnoozed", default: false) - static let alertMissedBolusDND = UserDefaultsValue(key: "alertMissedBolusDND", default: false) + static let alertMissedBolusQuiet = UserDefaultsValue(key: "alertMissedBolusQuiet", default: false) static let alertMissedBolusRepeat = UserDefaultsValue(key: "alertMissedBolusRepeat", default: false) static let alertMissedBolusSound = UserDefaultsValue(key: "alertMissedBolusSound", default: "Indeed") static let alertSAGEActive = UserDefaultsValue(key: "alertSAGEActive", default: false) static let alertSAGE = UserDefaultsValue(key: "alertSAGE", default: 8) //Hours - static let alertSAGEDND = UserDefaultsValue(key: "alertSAGEDND", default: false) + static let alertSAGEQuiet = UserDefaultsValue(key: "alertSAGEQuiet", default: false) static let alertSAGERepeat = UserDefaultsValue(key: "alertSAGERepeat", default: false) static let alertSAGESnooze = UserDefaultsValue(key: "alertSAGESnooze", default: 2) //Hours static let alertSAGESnoozedTime = UserDefaultsValue(key: "alertSAGESnoozedTime", default: nil) @@ -197,7 +192,7 @@ class UserDefaultsRepository { static let alertCAGEActive = UserDefaultsValue(key: "alertCAGEActive", default: false) static let alertCAGE = UserDefaultsValue(key: "alertCAGE", default: 4) //Hours - static let alertCAGEDND = UserDefaultsValue(key: "alertCAGEDND", default: false) + static let alertCAGEQuiet = UserDefaultsValue(key: "alertCAGEQuiet", default: false) static let alertCAGERepeat = UserDefaultsValue(key: "alertCAGERepeat", default: false) static let alertCAGESnooze = UserDefaultsValue(key: "alertCAGESnooze", default: 2) //Hours static let alertCAGESnoozedTime = UserDefaultsValue(key: "alertCAGESnoozedTime", default: nil) @@ -209,18 +204,21 @@ class UserDefaultsRepository { static let alertTemporaryActive = UserDefaultsValue(key: "alertTemporaryActive", default: false) static let alertTemporaryBelow = UserDefaultsValue(key: "alertTemporaryBelow", default: true) static let alertTemporaryBG = UserDefaultsValue(key: "alertTemporaryBG", default: 90.0) - static let alertTemporaryBGDND = UserDefaultsValue(key: "alertTemporaryBGDND", default: true) static let alertTemporaryBGRepeat = UserDefaultsValue(key: "alertTemporaryBGRepeat", default: true) static let alertTemporarySound = UserDefaultsValue(key: "alertTemporarySound", default: "Indeed") static let alertOverrideStart = UserDefaultsValue(key: "alertOverrideStart", default: false) - static let alertOverrideStartDND = UserDefaultsValue(key: "alertOverrideStartDND", default: false) + static let alertOverrideStartQuiet = UserDefaultsValue(key: "alertOverrideStartQuiet", default: false) static let alertOverrideStartRepeat = UserDefaultsValue(key: "alertOverrideStartRepeat", default: false) static let alertOverrideStartSound = UserDefaultsValue(key: "alertOverrideStartSound", default: "Alert_Tone_Busy") + static let alertOverrideStartSnoozedTime = UserDefaultsValue(key: "alertOverrideStartSnoozedTime", default: nil) + static let alertOverrideStartIsSnoozed = UserDefaultsValue(key: "alertOverrideStartIsSnoozed", default: false) static let alertOverrideEnd = UserDefaultsValue(key: "alertOverrideEnd", default: false) - static let alertOverrideEndDND = UserDefaultsValue(key: "alertOverrideEndDND", default: false) + static let alertOverrideEndQuiet = UserDefaultsValue(key: "alertOverrideEndQuiet", default: false) static let alertOverrideEndRepeat = UserDefaultsValue(key: "alertOverrideEndRepeat", default: false) static let alertOverrideEndSound = UserDefaultsValue(key: "alertOverrideEndSound", default: "Ending_Reached") + static let alertOverrideEndSnoozedTime = UserDefaultsValue(key: "alertOverrideEndSnoozedTime", default: nil) + static let alertOverrideEndIsSnoozed = UserDefaultsValue(key: "alertOverrideEndIsSnoozed", default: false) } From ceb9dcd8d8edf3815c0dc722049eb23f287662fc Mon Sep 17 00:00:00 2001 From: Jon Fawcett Date: Thu, 9 Jul 2020 23:12:37 -0400 Subject: [PATCH 02/37] Prediction fix when using max hours and there aren't enough downloaded --- LoopFollow/Controllers/NightScout.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/LoopFollow/Controllers/NightScout.swift b/LoopFollow/Controllers/NightScout.swift index ab80860fd..322307a08 100644 --- a/LoopFollow/Controllers/NightScout.swift +++ b/LoopFollow/Controllers/NightScout.swift @@ -373,9 +373,11 @@ extension MainViewController { let toLoad = Int(UserDefaultsRepository.predictionToLoad.value * 12) var i = 1 while i <= toLoad { - let prediction = DataStructs.sgvData(sgv: prediction[i], date: predictionTime, direction: "flat") - predictionData.append(prediction) - predictionTime += 300 + if i < prediction.count { + let prediction = DataStructs.sgvData(sgv: prediction[i], date: predictionTime, direction: "flat") + predictionData.append(prediction) + predictionTime += 300 + } i += 1 } } From 6b8eb5ef68778e2ead41d10df64abbdcceae40a3 Mon Sep 17 00:00:00 2001 From: Jose Paredes Date: Fri, 10 Jul 2020 18:21:13 -0500 Subject: [PATCH 03/37] Added: 1) Share Client Pod & some testing 2) Add share id and password 3) Std Dev. --- LoopFollow.xcodeproj/project.pbxproj | 4 +- .../Application/Base.lproj/Main.storyboard | 51 +- LoopFollow/Controllers/Stats.swift | 10 +- LoopFollow/Controllers/StatsView.swift | 3 +- .../ViewControllers/MainViewController.swift | 23 +- .../SettingsViewController.swift | 34 + LoopFollow/repository/UserDefaults.swift | 6 + Podfile | 5 +- Podfile.lock | 15 +- Pods/Manifest.lock | 15 +- Pods/Pods.xcodeproj/project.pbxproj | 1739 +++++++++-------- .../Pods-LoopFollow-acknowledgements.markdown | 25 + .../Pods-LoopFollow-acknowledgements.plist | 31 + ...ow-frameworks-Debug-input-files.xcfilelist | 3 +- ...w-frameworks-Debug-output-files.xcfilelist | 3 +- ...-frameworks-Release-input-files.xcfilelist | 3 +- ...frameworks-Release-output-files.xcfilelist | 3 +- .../Pods-LoopFollow-frameworks.sh | 2 + .../Pods-LoopFollow.debug.xcconfig | 6 +- .../Pods-LoopFollow.release.xcconfig | 6 +- 20 files changed, 1171 insertions(+), 816 deletions(-) diff --git a/LoopFollow.xcodeproj/project.pbxproj b/LoopFollow.xcodeproj/project.pbxproj index 9d1133389..c4de9a730 100644 --- a/LoopFollow.xcodeproj/project.pbxproj +++ b/LoopFollow.xcodeproj/project.pbxproj @@ -998,7 +998,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "LoopFollow/Loop Follow.entitlements"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 9W476TGJ4S; INFOPLIST_FILE = LoopFollow/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1019,7 +1019,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "LoopFollow/Loop Follow.entitlements"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 9W476TGJ4S; INFOPLIST_FILE = LoopFollow/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/LoopFollow/Application/Base.lproj/Main.storyboard b/LoopFollow/Application/Base.lproj/Main.storyboard index 1cbee5750..20df834da 100644 --- a/LoopFollow/Application/Base.lproj/Main.storyboard +++ b/LoopFollow/Application/Base.lproj/Main.storyboard @@ -139,7 +139,7 @@