Browse Source

Persistent Notification

Jonas Björkert 1 year ago
parent
commit
2367c2e96b

+ 1 - 20
LoopFollow/Alarm/Alarm.swift

@@ -177,26 +177,7 @@ struct Alarm: Identifiable, Codable, Equatable {
             }
         }()
 
-        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
-
-        let content = UNMutableNotificationContent()
-        content.title = type.rawValue
-        content.subtitle += Observable.shared.bgText.value + " "
-        content.subtitle += Observable.shared.directionText.value + " "
-        content.subtitle += Observable.shared.deltaText.value
-        content.categoryIdentifier = "category"
-        // This is needed to trigger vibrate on watch and phone
-        // See if we can use .Critcal
-        // See if we should use this method instead of direct sound player
-        content.sound = .default
-
-        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
-        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
-        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
-
-        let action = UNNotificationAction(identifier: "snooze", title: snoozeDuration == 0 ? "Acknowledge" : "Snooze", options: [])
-        let category = UNNotificationCategory(identifier: "category", actions: [action], intentIdentifiers: [], options: [])
-        UNUserNotificationCenter.current().setNotificationCategories([category])
+        AlarmManager.shared.sendNotification(title: type.rawValue, actionTitle: snoozeDuration == 0 ? "Acknowledge" : "Snooze")
 
         if playSound {
             AlarmSound.setSoundFile(str: soundFile.rawValue)

+ 30 - 0
LoopFollow/Alarm/AlarmManager.swift

@@ -42,6 +42,7 @@ class AlarmManager {
 
     func checkAlarms(data: AlarmData) {
         let now = Date()
+        var alarmTriggered = false
         let alarms = Storage.shared.alarms.value
 
         let sorted = alarms.sorted { lhs, rhs in
@@ -149,8 +150,15 @@ class AlarmManager {
                     Storage.shared.alarms.value = list
                 }
             }
+
+            alarmTriggered = true
             break
         }
+
+        if isLatestReadingRecent, Storage.shared.persistentNotification.value, !alarmTriggered, let latestDate = data.bgReadings.last?.date, latestDate > Storage.shared.persistentNotificationLastBGTime.value {
+            sendNotification(title: "Latest BG")
+            Storage.shared.persistentNotificationLastBGTime.value = now
+        }
     }
 
     func performSnooze(_ snoozeUnits: Int? = nil) {
@@ -173,4 +181,26 @@ class AlarmManager {
         Observable.shared.currentAlarm.value = nil
         UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
     }
+
+    func sendNotification(title: String, actionTitle: String? = nil) {
+        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
+
+        let content = UNMutableNotificationContent()
+        content.title = title
+        content.subtitle += Observable.shared.bgText.value + " "
+        content.subtitle += Observable.shared.directionText.value + " "
+        content.subtitle += Observable.shared.deltaText.value
+        content.categoryIdentifier = "category"
+        content.sound = .default
+
+        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
+        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
+        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
+
+        if let actionTitle = actionTitle {
+            let action = UNNotificationAction(identifier: "snooze", title: actionTitle, options: [])
+            let category = UNNotificationCategory(identifier: "category", actions: [action], intentIdentifiers: [], options: [])
+            UNUserNotificationCenter.current().setNotificationCategories([category])
+        }
+    }
 }

+ 1 - 1
LoopFollow/Settings/ContactSettingsViewModel.swift

@@ -1,6 +1,6 @@
 // LoopFollow
 // ContactSettingsViewModel.swift
-// Created by Jonas Björkert on 2025-05-23.
+// Created by Jonas Björkert on 2024-12-10.
 
 import Combine
 import Foundation

+ 1 - 1
LoopFollow/Settings/DexcomSettingsView.swift

@@ -1,6 +1,6 @@
 // LoopFollow
 // DexcomSettingsView.swift
-// Created by Jonas Björkert on 2025-05-23.
+// Created by Jonas Björkert on 2025-01-18.
 
 import SwiftUI
 

+ 2 - 0
LoopFollow/Settings/GeneralSettingsView.swift

@@ -14,6 +14,7 @@ struct GeneralSettingsView: View {
     @ObservedObject var screenlockSwitchState = Storage.shared.screenlockSwitchState
     @ObservedObject var showDisplayName = Storage.shared.showDisplayName
     @ObservedObject var snoozerEmoji = Storage.shared.snoozerEmoji
+    @ObservedObject var persistentNotification = Storage.shared.persistentNotification
 
     // Speak-BG settings
     @ObservedObject var speakBG = Storage.shared.speakBG
@@ -31,6 +32,7 @@ struct GeneralSettingsView: View {
             Form {
                 Section("App Settings") {
                     Toggle("Display App Badge", isOn: $appBadge.value)
+                    Toggle("Persistent Notification", isOn: $persistentNotification.value)
                 }
 
                 Section("Display") {

+ 2 - 0
LoopFollow/Storage/Storage+Migrate.swift

@@ -136,6 +136,8 @@ extension Storage {
             legacySpeakLanguage.setNil(key: "speakLanguage")
         }
 
+        move(UserDefaultsValue<Bool>(key: "persistentNotification", default: true), into: Storage.shared.persistentNotification)
+
         // ── General (done earlier, but safe to repeat) ──
         move(UserDefaultsValue<Bool>(key: "colorBGText", default: true), into: Storage.shared.colorBGText)
         move(UserDefaultsValue<Bool>(key: "appBadge", default: true), into: appBadge)

+ 3 - 0
LoopFollow/Storage/Storage.swift

@@ -156,6 +156,9 @@ class Storage {
 
     var migrationStep = StorageValue<Int>(key: "migrationStep", defaultValue: 0)
 
+    var persistentNotification = StorageValue<Bool>(key: "persistentNotification", defaultValue: false)
+    var persistentNotificationLastBGTime = StorageValue<Date>(key: "persistentNotificationLastBGTime", defaultValue: .distantPast)
+
     static let shared = Storage()
     private init() {}
 }

+ 0 - 13
LoopFollow/ViewControllers/MainViewController.swift

@@ -648,19 +648,6 @@ class MainViewController: UIViewController, UITableViewDataSource, ChartViewDele
         }
     }
 
-    func sendGeneralNotification(_: Any, title: String, subtitle: String, body: String, timer: TimeInterval) {
-        let content = UNMutableNotificationContent()
-        content.title = title
-        content.subtitle = subtitle
-        content.body = body
-        content.categoryIdentifier = "noAction"
-        content.sound = .default
-
-        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timer, repeats: false)
-        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
-        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
-    }
-
     func userNotificationCenter(_: UNUserNotificationCenter, didReceive _: UNNotificationResponse, withCompletionHandler _: @escaping () -> Void) {}
 
     // User has scrolled the chart