Jon Fawcett před 6 roky
rodič
revize
fa6bffc13d

+ 0 - 1
LoopFollow/Controllers/AlarmSound.swift

@@ -116,7 +116,6 @@ class AlarmSound {
     
     
     static func play(overrideVolume: Bool, numLoops: Int) {
-        
         guard !self.isPlaying else {
             return
         }

+ 263 - 207
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)))

+ 123 - 98
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
+        }
        }
 
 }

+ 0 - 41
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

+ 41 - 0
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 {

+ 12 - 14
LoopFollow/repository/UserDefaults.swift

@@ -78,6 +78,9 @@ class UserDefaultsRepository {
     
     // Alerts
     
+    static let quietHourStart = UserDefaultsValue<Date?>(key: "quietHourStart", default: nil)
+    static let quietHourEnd = UserDefaultsValue<Date?>(key: "quietHourEnd", default: nil)
+    
     static let snoozedBGReadingTime = UserDefaultsValue<TimeInterval?>(key: "snoozedBGReadingTime", default: 0)
     
     static let alertCageInsertTime = UserDefaultsValue<TimeInterval>(key: "alertCageInsertTime", default: 0)
@@ -92,7 +95,6 @@ class UserDefaultsRepository {
     static let alertUrgentLowSnooze = UserDefaultsValue<Int>(key: "alertUrgentLowSnooze", default: 5)
     static let alertUrgentLowSnoozedTime = UserDefaultsValue<Date?>(key: "alertUrgentLowSnoozedTime", default: nil)
     static let alertUrgentLowIsSnoozed = UserDefaultsValue<Bool>(key: "alertUrgentLowIsSnoozed", default: false)
-    static let alertUrgentLowDND = UserDefaultsValue<Bool>(key: "alertUrgentLowDND", default: true)
     static let alertUrgentLowRepeat = UserDefaultsValue<Bool>(key: "alertUrgentLowRepeat", default: true)
     static let alertUrgentLowSound = UserDefaultsValue<String>(key: "alertUrgentLowSound", default: "Indeed")
     
@@ -101,7 +103,6 @@ class UserDefaultsRepository {
     static let alertLowSnooze = UserDefaultsValue<Int>(key: "alertLowSnooze", default: 5)
     static let alertLowSnoozedTime = UserDefaultsValue<Date?>(key: "alertLowSnoozedTime", default: nil)
     static let alertLowIsSnoozed = UserDefaultsValue<Bool>(key: "alertLowIsSnoozed", default: false)
-    static let alertLowDND = UserDefaultsValue<Bool>(key: "alertLowDND", default: true)
     static let alertLowRepeat = UserDefaultsValue<Bool>(key: "alertLowRepeat", default: true)
     static let alertLowSound = UserDefaultsValue<String>(key: "alertLowSound", default: "Indeed")
     
@@ -111,7 +112,6 @@ class UserDefaultsRepository {
     static let alertHighSnooze = UserDefaultsValue<Int>(key: "alertHighSnooze", default: 60)
     static let alertHighSnoozedTime = UserDefaultsValue<Date?>(key: "alertHighSnoozedTime", default: nil)
     static let alertHighIsSnoozed = UserDefaultsValue<Bool>(key: "alertHighIsSnoozed", default: false)
-    static let alertHighDND = UserDefaultsValue<Bool>(key: "alertHighDND", default: true)
     static let alertHighRepeat = UserDefaultsValue<Bool>(key: "alertHighRepeat", default: true)
     static let alertHighSound = UserDefaultsValue<String>(key: "alertHighSound", default: "Indeed")
     
@@ -120,7 +120,6 @@ class UserDefaultsRepository {
     static let alertUrgentHighSnooze = UserDefaultsValue<Int>(key: "alertUrgentHighSnooze", default: 30)
     static let alertUrgentHighSnoozedTime = UserDefaultsValue<Date?>(key: "alertUrgentHighSnoozedTime", default: nil)
     static let alertUrgentHighIsSnoozed = UserDefaultsValue<Bool>(key: "alertUrgentHighIsSnoozed", default: false)
-    static let alertUrgentHighDND = UserDefaultsValue<Bool>(key: "alertUrgentHighDND", default: true)
     static let alertUrgentHighRepeat = UserDefaultsValue<Bool>(key: "alertUrgentHighRepeat", default: true)
     static let alertUrgentHighSound = UserDefaultsValue<String>(key: "alertUrgentHighSound", default: "Indeed")
 
@@ -133,7 +132,6 @@ class UserDefaultsRepository {
     static let alertFastDropBelowBG = UserDefaultsValue<Float>(key: "alertFastDropBelowBG", default: 120.0)
     static let alertFastDropSnoozedTime = UserDefaultsValue<Date?>(key: "alertFastDropSnoozedTime", default: nil)
     static let alertFastDropIsSnoozed = UserDefaultsValue<Bool>(key: "alertFastDropIsSnoozed", default: false)
-    static let alertFastDropDND = UserDefaultsValue<Bool>(key: "alertFastDropDND", default: true)
     static let alertFastDropRepeat = UserDefaultsValue<Bool>(key: "alertFastDropRepeat", default: true)
     static let alertFastDropSound = UserDefaultsValue<String>(key: "alertFastDropSound", default: "Indeed")
     
@@ -145,7 +143,6 @@ class UserDefaultsRepository {
     static let alertFastRiseAboveBG = UserDefaultsValue<Float>(key: "alertFastRiseAboveBG", default: 200.0)
     static let alertFastRiseSnoozedTime = UserDefaultsValue<Date?>(key: "alertFastRiseSnoozedTime", default: nil)
     static let alertFastRiseIsSnoozed = UserDefaultsValue<Bool>(key: "alertFastRiseIsSnoozed", default: false)
-    static let alertFastRiseDND = UserDefaultsValue<Bool>(key: "alertFastRiseDND", default: true)
     static let alertFastRiseRepeat = UserDefaultsValue<Bool>(key: "alertFastRiseRepeat", default: true)
     static let alertFastRiseSound = UserDefaultsValue<String>(key: "alertFastRiseSound", default: "Indeed")
     
@@ -155,7 +152,6 @@ class UserDefaultsRepository {
     static let alertMissedReadingSnooze = UserDefaultsValue<Int>(key: "alertMissedReadingSnooze", default: 30)
     static let alertMissedReadingSnoozedTime = UserDefaultsValue<Date?>(key: "alertMissedReadingSnoozedTime", default: nil)
     static let alertMissedReadingIsSnoozed = UserDefaultsValue<Bool>(key: "alertMissedReadingIsSnoozed", default: false)
-    static let alertMissedReadingDND = UserDefaultsValue<Bool>(key: "alertMissedReadingDND", default: true)
     static let alertMissedReadingRepeat = UserDefaultsValue<Bool>(key: "alertMissedReadingRepeat", default: true)
     static let alertMissedReadingSound = UserDefaultsValue<String>(key: "alertMissedReadingSound", default: "Indeed")
     
@@ -168,7 +164,6 @@ class UserDefaultsRepository {
     static let alertNotLoopingUpperLimit = UserDefaultsValue<Float>(key: "alertNotLoopingAboveBG", default: 160.0)
     static let alertNotLoopingSnoozedTime = UserDefaultsValue<Date?>(key: "alertNotLoopingSnoozedTime", default: nil)
     static let alertNotLoopingIsSnoozed = UserDefaultsValue<Bool>(key: "alertNotLoopingIsSnoozed", default: false)
-    static let alertNotLoopingDND = UserDefaultsValue<Bool>(key: "alertNotLoopingDND", default: true)
     static let alertNotLoopingRepeat = UserDefaultsValue<Bool>(key: "alertNotLoopingRepeat", default: true)
     static let alertNotLoopingSound = UserDefaultsValue<String>(key: "alertNotLoopingSound", default: "Indeed")
     static let alertLastLoopTime = UserDefaultsValue<TimeInterval>(key: "alertLastLoopTime", default: 0)
@@ -182,13 +177,13 @@ class UserDefaultsRepository {
     static let alertMissedBolusLowGramsBG = UserDefaultsValue<Float>(key: "alertMissedBolusLowGramsBG", default: 70.0)
     static let alertMissedBolusSnoozedTime = UserDefaultsValue<Date?>(key: "alertMissedBolusSnoozedTime", default: nil)
     static let alertMissedBolusIsSnoozed = UserDefaultsValue<Bool>(key: "alertMissedBolusIsSnoozed", default: false)
-    static let alertMissedBolusDND = UserDefaultsValue<Bool>(key: "alertMissedBolusDND", default: false)
+    static let alertMissedBolusQuiet = UserDefaultsValue<Bool>(key: "alertMissedBolusQuiet", default: false)
     static let alertMissedBolusRepeat = UserDefaultsValue<Bool>(key: "alertMissedBolusRepeat", default: false)
     static let alertMissedBolusSound = UserDefaultsValue<String>(key: "alertMissedBolusSound", default: "Indeed")
     
     static let alertSAGEActive = UserDefaultsValue<Bool>(key: "alertSAGEActive", default: false)
     static let alertSAGE = UserDefaultsValue<Int>(key: "alertSAGE", default: 8) //Hours
-    static let alertSAGEDND = UserDefaultsValue<Bool>(key: "alertSAGEDND", default: false)
+    static let alertSAGEQuiet = UserDefaultsValue<Bool>(key: "alertSAGEQuiet", default: false)
     static let alertSAGERepeat = UserDefaultsValue<Bool>(key: "alertSAGERepeat", default: false)
     static let alertSAGESnooze = UserDefaultsValue<Int>(key: "alertSAGESnooze", default: 2) //Hours
     static let alertSAGESnoozedTime = UserDefaultsValue<Date?>(key: "alertSAGESnoozedTime", default: nil)
@@ -197,7 +192,7 @@ class UserDefaultsRepository {
     
     static let alertCAGEActive = UserDefaultsValue<Bool>(key: "alertCAGEActive", default: false)
     static let alertCAGE = UserDefaultsValue<Int>(key: "alertCAGE", default: 4) //Hours
-    static let alertCAGEDND = UserDefaultsValue<Bool>(key: "alertCAGEDND", default: false)
+    static let alertCAGEQuiet = UserDefaultsValue<Bool>(key: "alertCAGEQuiet", default: false)
     static let alertCAGERepeat = UserDefaultsValue<Bool>(key: "alertCAGERepeat", default: false)
     static let alertCAGESnooze = UserDefaultsValue<Int>(key: "alertCAGESnooze", default: 2) //Hours
     static let alertCAGESnoozedTime = UserDefaultsValue<Date?>(key: "alertCAGESnoozedTime", default: nil)
@@ -209,18 +204,21 @@ class UserDefaultsRepository {
     static let alertTemporaryActive = UserDefaultsValue<Bool>(key: "alertTemporaryActive", default: false)
     static let alertTemporaryBelow = UserDefaultsValue<Bool>(key: "alertTemporaryBelow", default: true)
     static let alertTemporaryBG = UserDefaultsValue<Float>(key: "alertTemporaryBG", default: 90.0)
-    static let alertTemporaryBGDND = UserDefaultsValue<Bool>(key: "alertTemporaryBGDND", default: true)
     static let alertTemporaryBGRepeat = UserDefaultsValue<Bool>(key: "alertTemporaryBGRepeat", default: true)
     static let alertTemporarySound = UserDefaultsValue<String>(key: "alertTemporarySound", default: "Indeed")
     
     static let alertOverrideStart = UserDefaultsValue<Bool>(key: "alertOverrideStart", default: false)
-    static let alertOverrideStartDND = UserDefaultsValue<Bool>(key: "alertOverrideStartDND", default: false)
+    static let alertOverrideStartQuiet = UserDefaultsValue<Bool>(key: "alertOverrideStartQuiet", default: false)
     static let alertOverrideStartRepeat = UserDefaultsValue<Bool>(key: "alertOverrideStartRepeat", default: false)
     static let alertOverrideStartSound = UserDefaultsValue<String>(key: "alertOverrideStartSound", default: "Alert_Tone_Busy")
+    static let alertOverrideStartSnoozedTime = UserDefaultsValue<Date?>(key: "alertOverrideStartSnoozedTime", default: nil)
+    static let alertOverrideStartIsSnoozed = UserDefaultsValue<Bool>(key: "alertOverrideStartIsSnoozed", default: false)
     
     static let alertOverrideEnd = UserDefaultsValue<Bool>(key: "alertOverrideEnd", default: false)
-    static let alertOverrideEndDND = UserDefaultsValue<Bool>(key: "alertOverrideEndDND", default: false)
+    static let alertOverrideEndQuiet = UserDefaultsValue<Bool>(key: "alertOverrideEndQuiet", default: false)
     static let alertOverrideEndRepeat = UserDefaultsValue<Bool>(key: "alertOverrideEndRepeat", default: false)
     static let alertOverrideEndSound = UserDefaultsValue<String>(key: "alertOverrideEndSound", default: "Ending_Reached")
+    static let alertOverrideEndSnoozedTime = UserDefaultsValue<Date?>(key: "alertOverrideEndSnoozedTime", default: nil)
+    static let alertOverrideEndIsSnoozed = UserDefaultsValue<Bool>(key: "alertOverrideEndIsSnoozed", default: false)
     
 }