MESSENGER-3580 Several bugfixes to notification times

This commit is contained in:
Arnfried Griesert
2023-07-17 07:57:49 +00:00
parent 6a2101c858
commit fd7c694c8a
8 changed files with 143 additions and 64 deletions

View File

@@ -121,14 +121,6 @@ class NotificationService: UNNotificationServiceExtension {
return
}
// check if the event arrived outside the user defined working time for this room
guard !isRoomMuted(roomID: roomId) else {
// it's not a Matrix notification, do not change the content
MXLog.debug("[NotificationService] didReceiveRequest: This is not a Matrix notification.")
contentHandler(UNNotificationContent())
return
}
// save this content as fallback content
guard let content = request.content.mutableCopy() as? UNMutableNotificationContent else {
return
@@ -146,10 +138,12 @@ class NotificationService: UNNotificationServiceExtension {
// setup user account
setup(withRoomId: roomId, eventId: eventId) {
// preprocess the payload, will attempt to fetch room display name
self.preprocessPayload(forEventId: eventId, roomId: roomId)
// fetch the event first
self.fetchAndProcessEvent(withEventId: eventId, roomId: roomId)
do {
try self.preprocessPayload(forEventId: eventId, roomId: roomId) // fetch displayname and check against notification times
self.fetchAndProcessEvent(withEventId: eventId, roomId: roomId) // decrypt and parse
} catch {
contentHandler(UNNotificationContent())
}
}
}
@@ -192,20 +186,60 @@ class NotificationService: UNNotificationServiceExtension {
}
}
private func isGlobalSettingsNotificationTimesToggleOn() -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return false
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
}
return notificationTimes.isEnabled
}
private func isRoomMuted(roomID: String) -> Bool {
private func isRoomSettingsNotificationTimesToggleOn(roomId: String, isDirect: Bool) -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return false
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
}
if isDirect {
return notificationTimes.rooms[roomId] == true
} else {
return notificationTimes.rooms[roomId] != false
}
}
private func notificationTimeCheckPassed(roomId: String, isDirect: Bool) -> Bool {
guard isGlobalSettingsNotificationTimesToggleOn() else {
return true
}
guard isRoomSettingsNotificationTimesToggleOn(roomId: roomId, isDirect: isDirect) else {
return true
}
return isNotificationTimeEnabled(for: Date())
}
private func isNotificationTimeEnabled(for date: Date) -> Bool {
let sharedUserDefaults = MXKAppSettings.standard().sharedUserDefaults
if #available(iOSApplicationExtension 14.0, *) {
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey), let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return false
guard let data = sharedUserDefaults?.data(forKey: NotificationTimes.sharedUserDefaultsKey) else {
return true
}
guard let notificationTimes = try? JSONDecoder().decode(NotificationTimes.self, from: data) else {
return true
}
let now = Date()
let calendar = Calendar.current
let weekday: NotificationTimesWeekday
switch calendar.component(.weekday, from: now) {
switch calendar.component(.weekday, from: date) {
case 1: // sunday
weekday = notificationTimes.weekday(index: 6)
case 2: // monday
@@ -222,12 +256,18 @@ class NotificationService: UNNotificationServiceExtension {
weekday = notificationTimes.weekday(index: 5)
default:
MXLog.error("[NotificationService] isRoomMuted failed because of an invalid day component.")
return false
return true
}
return notificationTimes.isEnabled && weekday.isEnabled && weekday.startTime <= now && weekday.endTime >= now
let nowComponents = calendar.dateComponents([.hour, .minute], from: date)
if let hour = nowComponents.hour, let minute = nowComponents.minute {
let checkTime = Date.from(hour: hour, minute: minute)
return notificationTimes.isEnabled && weekday.isEnabled && weekday.startTime <= checkTime && weekday.endTime >= checkTime
} else {
return true
}
} else {
return false
return true
}
}
@@ -302,22 +342,49 @@ class NotificationService: UNNotificationServiceExtension {
return true
}
enum NSEError: Error, LocalizedError {
case isProtectionSet
case roomSummaryNotAvailable
case mutedBecauseOfNotificationTimes
case displayNameNotAvailable
public var errorDescription: String? {
switch self {
case .isProtectionSet:
return "isProtectionSet"
case .roomSummaryNotAvailable:
return "roomSummaryNotAvailable"
case .mutedBecauseOfNotificationTimes:
return "isProtectionSet"
case .displayNameNotAvailable:
return "isProtectionSet"
}
}
}
/// Attempts to preprocess payload and attach room display name to the best attempt content
/// - Parameters:
/// - eventId: Event identifier to mutate best attempt content
/// - roomId: Room identifier to fetch display name
private func preprocessPayload(forEventId eventId: String, roomId: String) {
if localAuthenticationService.isProtectionSet {
MXLog.debug("[NotificationService] preprocessPayload: Do not preprocess because app protection is set")
return
private func preprocessPayload(forEventId eventId: String, roomId: String) throws {
// If a room summary is available, use the displayname for the best attempt title.
guard let roomSummary = NotificationService.backgroundSyncService.roomSummary(forRoomId: roomId) else {
throw NSEError.roomSummaryNotAvailable
}
// If a room summary is available, use the displayname for the best attempt title.
guard let roomSummary = NotificationService.backgroundSyncService.roomSummary(forRoomId: roomId) else { return }
guard let roomDisplayName = roomSummary.displayName else { return }
bestAttemptContents[eventId]?.title = roomDisplayName
guard notificationTimeCheckPassed(roomId: roomId, isDirect: roomSummary.isDirect) else {
throw NSEError.mutedBecauseOfNotificationTimes
}
// At this stage we don't know the message type, so leave the body as set in didReceive.
if localAuthenticationService.isProtectionSet {
MXLog.debug("[NotificationService] preprocessPayload: Do not preprocess because app protection is set")
guard let roomDisplayName = roomSummary.displayName else {
throw NSEError.displayNameNotAvailable
}
bestAttemptContents[eventId]?.title = roomDisplayName
// At this stage we don't know the message type, so leave the body as set in didReceive.
}
}
private func fetchAndProcessEvent(withEventId eventId: String, roomId: String) {