Add boot detection in the NSE and use this to inform the user that there may be more notifications. (#5054)

* Add an initial implementation of the receivedWhileOfflineNotification.

* Only deliver a single receivedWhileOffline notification per boot and clarify the API.

* Add a 15-minute threshold for the receiveWhileOfflineNotification.
This commit is contained in:
Doug
2026-02-06 15:18:09 +00:00
committed by GitHub
parent bff328554a
commit 7532a792b7
11 changed files with 157 additions and 21 deletions
@@ -14,7 +14,9 @@ import Foundation
import SwiftUI
/// Common settings between app and NSE
protocol CommonSettingsProtocol {
protocol CommonSettingsProtocol: AnyObject {
var lastNotificationBootTime: TimeInterval? { get set }
var logLevel: LogLevel { get }
var traceLogPacks: Set<TraceLogPack> { get }
var bugReportRageshakeURL: RemotePreference<RageshakeConfiguration> { get }
@@ -51,6 +53,7 @@ final class AppSettings {
case enableNotifications
case enableInAppNotifications
case pusherProfileTag
case lastNotificationBootTime
case logLevel
case traceLogPacks
case viewSourceEnabled
@@ -291,6 +294,10 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.pusherProfileTag, storageType: .userDefaults(store))
var pusherProfileTag: String?
/// The device's last boot time as recorded by the NSE.
@UserPreference(key: UserDefaultsKeys.lastNotificationBootTime, storageType: .userDefaults(store))
var lastNotificationBootTime: TimeInterval?
// MARK: - Logging
@UserPreference(key: UserDefaultsKeys.logLevel, defaultValue: LogLevel.info, storageType: .userDefaults(store))
+2
View File
@@ -1060,6 +1060,8 @@ internal enum L10n {
internal static func notificationReactionBody(_ p1: Any) -> String {
return L10n.tr("Localizable", "notification_reaction_body", String(describing: p1))
}
/// You received one or more notifications while offline.
internal static var notificationReceivedWhileOfflineIos: String { return L10n.tr("Localizable", "notification_received_while_offline_ios") }
/// Mark as read
internal static var notificationRoomActionMarkAsRead: String { return L10n.tr("Localizable", "notification_room_action_mark_as_read") }
/// Quick reply
@@ -29,6 +29,10 @@ extension UNNotificationContent {
@objc var threadRootEventID: String? {
userInfo[NotificationConstants.UserInfoKey.threadRootEventIdentifier] as? String
}
var unreadCount: Int? {
userInfo[NotificationConstants.UserInfoKey.unreadCount] as? Int
}
}
extension UNMutableNotificationContent {
@@ -40,7 +44,7 @@ extension UNMutableNotificationContent {
userInfo[NotificationConstants.UserInfoKey.receiverIdentifier] = newValue
}
}
override var roomID: String? {
get {
userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String
@@ -67,8 +71,4 @@ extension UNMutableNotificationContent {
userInfo[NotificationConstants.UserInfoKey.threadRootEventIdentifier] = newValue
}
}
var unreadCount: Int? {
userInfo[NotificationConstants.UserInfoKey.unreadCount] as? Int
}
}
@@ -56,8 +56,14 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
self?.enableNotifications(newValue)
}
.store(in: &cancellables)
}
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
.sink { [weak self] _ in
self?.removeReceivedWhileOfflineNotification()
}
.store(in: &cancellables)
}
func requestAuthorization() {
guard appSettings.enableNotifications, !userSession.isNil else { return }
Task {
@@ -151,6 +157,10 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
}
private func removeReceivedWhileOfflineNotification() {
notificationCenter.removeDeliveredNotifications(withIdentifiers: [NotificationServiceExtension.receivedWhileOfflineNotificationID])
}
private func setPusher(with deviceToken: Data, clientProxy: ClientProxyProtocol) async -> Bool {
do {