Skip to content

Commit bc14ebb

Browse files
author
Rick Pasetto
authored
LOOP-3871: Make all alerts/notifications "Time Sensitive" (#473)
* checkpoint * LOOP-3871: Make all alerts/notifications "Time Sensitive" Also fixes what appears to be a crash introduced into `StatusTableViewController` where there appears to be an extra call to `redrawCharts`. I'm hoping it fixes the crash. * We don't quite want this yet not until LOOP-3938
1 parent 98fcc84 commit bc14ebb

File tree

5 files changed

+44
-36
lines changed

5 files changed

+44
-36
lines changed

Loop/Managers/Alerts/UserNotificationAlertIssuer.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ fileprivate extension Alert {
6868
let userNotificationContent = UNMutableNotificationContent()
6969
userNotificationContent.title = content.title
7070
userNotificationContent.body = content.body
71-
userNotificationContent.sound = getUserNotificationSound()
71+
userNotificationContent.sound = userNotificationSound
72+
if #available(iOS 15.0, *) {
73+
userNotificationContent.interruptionLevel = backgroundContent?.isCritical == true ? .critical : .timeSensitive
74+
}
7275
// TODO: Once we have a final design and approval for custom UserNotification buttons, we'll need to set categoryIdentifier
7376
// userNotificationContent.categoryIdentifier = LoopNotificationCategory.alert.rawValue
7477
userNotificationContent.threadIdentifier = identifier.value // Used to match categoryIdentifier, but I /think/ we want multiple threads for multiple alert types, no?
@@ -78,8 +81,8 @@ fileprivate extension Alert {
7881
]
7982
return userNotificationContent
8083
}
81-
82-
private func getUserNotificationSound() -> UNNotificationSound? {
84+
85+
private var userNotificationSound: UNNotificationSound? {
8386
guard let content = backgroundContent else {
8487
return nil
8588
}

Loop/Managers/NotificationManager.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ extension NotificationManager {
9898

9999
notification.body = body
100100
notification.sound = .default
101+
if #available(iOS 15.0, *) {
102+
notification.interruptionLevel = .timeSensitive
103+
}
101104

102105
if startDate.timeIntervalSinceNow >= TimeInterval(minutes: -5) {
103106
notification.categoryIdentifier = LoopNotificationCategory.bolusFailure.rawValue
@@ -131,14 +134,20 @@ extension NotificationManager {
131134
formatter.allowedUnits = [.hour, .minute]
132135
formatter.unitsStyle = .full
133136

134-
if let failueIntervalString = formatter.string(from: failureInterval)?.localizedLowercase {
135-
notification.body = String(format: NSLocalizedString("Loop has not completed successfully in %@", comment: "The notification alert describing a long-lasting loop failure. The substitution parameter is the time interval since the last loop"), failueIntervalString)
137+
if let failureIntervalString = formatter.string(from: failureInterval)?.localizedLowercase {
138+
notification.body = String(format: NSLocalizedString("Loop has not completed successfully in %@", comment: "The notification alert describing a long-lasting loop failure. The substitution parameter is the time interval since the last loop"), failureIntervalString)
136139
}
137140

138141
notification.title = NSLocalizedString("Loop Failure", comment: "The notification title for a loop failure")
139142
if isCritical, FeatureFlags.criticalAlertsEnabled {
143+
if #available(iOS 15.0, *) {
144+
notification.interruptionLevel = .critical
145+
}
140146
notification.sound = .defaultCritical
141147
} else {
148+
if #available(iOS 15.0, *) {
149+
notification.interruptionLevel = .timeSensitive
150+
}
142151
notification.sound = .default
143152
}
144153
notification.categoryIdentifier = LoopNotificationCategory.loopNotRunning.rawValue

Loop/View Controllers/StatusTableViewController.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,6 @@ final class StatusTableViewController: LoopChartsTableViewController {
131131
tableView.backgroundColor = .secondarySystemBackground
132132

133133
tableView.register(AlertPermissionsDisabledWarningCell.self, forCellReuseIdentifier: AlertPermissionsDisabledWarningCell.className)
134-
notificationsCriticalAlertPermissionsViewModel.$showWarning
135-
.receive(on: RunLoop.main)
136-
.sink { [weak self] showWarning in
137-
guard let self = self else { return }
138-
let isWarningVisible = self.tableView.numberOfRows(inSection: Section.alertPermissionsDisabledWarning.rawValue) != 0
139-
if !showWarning && isWarningVisible {
140-
self.tableView.deleteRows(at: [IndexPath(row: 0, section: Section.alertPermissionsDisabledWarning.rawValue)], with: .top)
141-
} else if showWarning && !isWarningVisible {
142-
self.tableView.insertRows(at: [IndexPath(row: 0, section: Section.alertPermissionsDisabledWarning.rawValue)], with: .top)
143-
}
144-
}
145-
.store(in: &cancellables)
146134
}
147135

148136
override func didReceiveMemoryWarning() {
@@ -337,7 +325,6 @@ final class StatusTableViewController: LoopChartsTableViewController {
337325
}
338326

339327
updateChartDateRange()
340-
redrawCharts()
341328

342329
if case .bolusing = statusRowMode, bolusProgressReporter?.progress.isComplete == true {
343330
refreshContext.update(with: .status)
@@ -350,6 +337,7 @@ final class StatusTableViewController: LoopChartsTableViewController {
350337
}
351338

352339
guard active && visible && !refreshContext.isEmpty else {
340+
redrawCharts()
353341
return
354342
}
355343

@@ -582,7 +570,7 @@ final class StatusTableViewController: LoopChartsTableViewController {
582570
// Show/hide the table view rows
583571
let statusRowMode = self.determineStatusRowMode()
584572

585-
self.updateHUDandStatusRows(statusRowMode: statusRowMode, newSize: currentContext.newSize, animated: animated)
573+
self.updateBannerAndHUDandStatusRows(statusRowMode: statusRowMode, newSize: currentContext.newSize, animated: animated)
586574

587575
self.redrawCharts()
588576

@@ -691,8 +679,18 @@ final class StatusTableViewController: LoopChartsTableViewController {
691679

692680
return statusRowMode
693681
}
682+
683+
private func updateBannerRow(animated: Bool) {
684+
let warningWasVisible = tableView.numberOfRows(inSection: Section.alertPermissionsDisabledWarning.rawValue) != 0
685+
let showWarning = notificationsCriticalAlertPermissionsViewModel.showWarning
686+
if !showWarning && warningWasVisible {
687+
tableView.deleteRows(at: [IndexPath(row: 0, section: Section.alertPermissionsDisabledWarning.rawValue)], with: animated ? .top : .none)
688+
} else if showWarning && !warningWasVisible {
689+
tableView.insertRows(at: [IndexPath(row: 0, section: Section.alertPermissionsDisabledWarning.rawValue)], with: animated ? .top : .none)
690+
}
691+
}
694692

695-
private func updateHUDandStatusRows(statusRowMode: StatusRowMode, newSize: CGSize?, animated: Bool) {
693+
private func updateBannerAndHUDandStatusRows(statusRowMode: StatusRowMode, newSize: CGSize?, animated: Bool) {
696694
let hudWasVisible = self.shouldShowHUD
697695
let statusWasVisible = self.shouldShowStatus
698696

@@ -701,7 +699,7 @@ final class StatusTableViewController: LoopChartsTableViewController {
701699
self.statusRowMode = statusRowMode
702700

703701
if let newSize = newSize {
704-
self.landscapeMode = newSize.width > newSize.height
702+
landscapeMode = newSize.width > newSize.height
705703
}
706704

707705
let hudIsVisible = self.shouldShowHUD
@@ -710,12 +708,14 @@ final class StatusTableViewController: LoopChartsTableViewController {
710708
hudView?.cgmStatusHUD?.isVisible = hudIsVisible
711709

712710
tableView.beginUpdates()
711+
712+
updateBannerRow(animated: animated)
713713

714714
switch (hudWasVisible, hudIsVisible) {
715715
case (false, true):
716-
self.tableView.insertRows(at: [IndexPath(row: 0, section: Section.hud.rawValue)], with: animated ? .top : .none)
716+
tableView.insertRows(at: [IndexPath(row: 0, section: Section.hud.rawValue)], with: animated ? .top : .none)
717717
case (true, false):
718-
self.tableView.deleteRows(at: [IndexPath(row: 0, section: Section.hud.rawValue)], with: animated ? .top : .none)
718+
tableView.deleteRows(at: [IndexPath(row: 0, section: Section.hud.rawValue)], with: animated ? .top : .none)
719719
default:
720720
break
721721
}
@@ -1069,17 +1069,17 @@ final class StatusTableViewController: LoopChartsTableViewController {
10691069

10701070
switch statusRowMode {
10711071
case .pumpSuspended(let resuming) where !resuming:
1072-
updateHUDandStatusRows(statusRowMode: .pumpSuspended(resuming: true) , newSize: nil, animated: true)
1072+
updateBannerAndHUDandStatusRows(statusRowMode: .pumpSuspended(resuming: true) , newSize: nil, animated: true)
10731073
deviceManager.pumpManager?.resumeDelivery() { (error) in
10741074
DispatchQueue.main.async {
10751075
if let error = error {
10761076
let alert = UIAlertController(with: error, title: NSLocalizedString("Failed to Resume Insulin Delivery", comment: "The alert title for a resume error"))
10771077
self.present(alert, animated: true, completion: nil)
10781078
if case .suspended = self.basalDeliveryState {
1079-
self.updateHUDandStatusRows(statusRowMode: .pumpSuspended(resuming: false), newSize: nil, animated: true)
1079+
self.updateBannerAndHUDandStatusRows(statusRowMode: .pumpSuspended(resuming: false), newSize: nil, animated: true)
10801080
}
10811081
} else {
1082-
self.updateHUDandStatusRows(statusRowMode: self.determineStatusRowMode(), newSize: nil, animated: true)
1082+
self.updateBannerAndHUDandStatusRows(statusRowMode: self.determineStatusRowMode(), newSize: nil, animated: true)
10831083
self.refreshContext.update(with: .insulin)
10841084
self.log.debug("[reloadData] after manually resuming suspend")
10851085
self.reloadData()
@@ -1097,7 +1097,7 @@ final class StatusTableViewController: LoopChartsTableViewController {
10971097
show(vc, sender: tableView.cellForRow(at: indexPath))
10981098
}
10991099
case .bolusing:
1100-
updateHUDandStatusRows(statusRowMode: .cancelingBolus, newSize: nil, animated: true)
1100+
updateBannerAndHUDandStatusRows(statusRowMode: .cancelingBolus, newSize: nil, animated: true)
11011101
deviceManager.pumpManager?.cancelBolus() { (result) in
11021102
DispatchQueue.main.async {
11031103
switch result {
@@ -1107,9 +1107,9 @@ final class StatusTableViewController: LoopChartsTableViewController {
11071107
case .failure(let error):
11081108
self.presentErrorCancelingBolus(error)
11091109
if case .inProgress(let dose) = self.bolusState {
1110-
self.updateHUDandStatusRows(statusRowMode: .bolusing(dose: dose), newSize: nil, animated: true)
1110+
self.updateBannerAndHUDandStatusRows(statusRowMode: .bolusing(dose: dose), newSize: nil, animated: true)
11111111
} else {
1112-
self.updateHUDandStatusRows(statusRowMode: .hidden, newSize: nil, animated: true)
1112+
self.updateBannerAndHUDandStatusRows(statusRowMode: .hidden, newSize: nil, animated: true)
11131113
}
11141114
}
11151115
}

Loop/View Models/SettingsViewModel.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,7 @@ public class SettingsViewModel: ObservableObject {
6262
let versionUpdateViewModel: VersionUpdateViewModel
6363

6464
private weak var delegate: SettingsViewModelDelegate?
65-
66-
var showWarning: Bool {
67-
notificationsCriticalAlertPermissionsViewModel.showWarning
68-
}
69-
65+
7066
var didTapIssueReport: ((String) -> Void)? {
7167
delegate?.didTapIssueReport
7268
}

Loop/Views/SettingsView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public struct SettingsView: View {
4646
if FeatureFlags.automaticBolusEnabled {
4747
dosingStrategySection
4848
}
49-
if viewModel.showWarning {
49+
if viewModel.notificationsCriticalAlertPermissionsViewModel.showWarning {
5050
alertPermissionsSection
5151
}
5252
if viewModel.pumpManagerSettingsViewModel.isSetUp() {
@@ -129,7 +129,7 @@ extension SettingsView {
129129
{
130130
HStack {
131131
Text(NSLocalizedString("Alert Permissions", comment: "Alert Permissions button text"))
132-
if viewModel.showWarning {
132+
if viewModel.notificationsCriticalAlertPermissionsViewModel.showWarning {
133133
Spacer()
134134
Image(systemName: "exclamationmark.triangle.fill")
135135
.foregroundColor(.critical)

0 commit comments

Comments
 (0)