mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Stop relying on the NotificationCenter for removing delivered push notifications:
- this will improve the architecture but more importantly will remove some very flakey unit tests
This commit is contained in:
committed by
Stefan Ceriu
parent
891315ef04
commit
4d513f9ed1
@@ -32,6 +32,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let bugReportService: BugReportServiceProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
private let notificationManager: NotificationManagerProtocol
|
||||
|
||||
private let stateMachine: UserSessionFlowCoordinatorStateMachine
|
||||
|
||||
@@ -82,6 +83,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.roomTimelineControllerFactory = roomTimelineControllerFactory
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
self.notificationManager = notificationManager
|
||||
|
||||
navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
|
||||
|
||||
@@ -467,7 +469,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
|
||||
Task {
|
||||
await userSession.clientProxy.trackRecentlyVisitedRoom(roomID)
|
||||
let _ = await userSession.clientProxy.trackRecentlyVisitedRoom(roomID)
|
||||
|
||||
await notificationManager.removeDeliveredMessageNotifications(for: roomID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +531,10 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
sidebarNavigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.processEvent(.dismissedInvitesScreen)
|
||||
}
|
||||
|
||||
Task {
|
||||
await notificationManager.removeDeliveredInviteNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissInvitesList(animated: Bool) {
|
||||
|
||||
@@ -5329,6 +5329,80 @@ class NotificationManagerMock: NotificationManagerProtocol {
|
||||
requestAuthorizationCallsCount += 1
|
||||
requestAuthorizationClosure?()
|
||||
}
|
||||
//MARK: - removeDeliveredMessageNotifications
|
||||
|
||||
var removeDeliveredMessageNotificationsForUnderlyingCallsCount = 0
|
||||
var removeDeliveredMessageNotificationsForCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return removeDeliveredMessageNotificationsForUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = removeDeliveredMessageNotificationsForUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
removeDeliveredMessageNotificationsForUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
removeDeliveredMessageNotificationsForUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var removeDeliveredMessageNotificationsForCalled: Bool {
|
||||
return removeDeliveredMessageNotificationsForCallsCount > 0
|
||||
}
|
||||
var removeDeliveredMessageNotificationsForReceivedRoomID: String?
|
||||
var removeDeliveredMessageNotificationsForReceivedInvocations: [String] = []
|
||||
var removeDeliveredMessageNotificationsForClosure: ((String) async -> Void)?
|
||||
|
||||
func removeDeliveredMessageNotifications(for roomID: String) async {
|
||||
removeDeliveredMessageNotificationsForCallsCount += 1
|
||||
removeDeliveredMessageNotificationsForReceivedRoomID = roomID
|
||||
removeDeliveredMessageNotificationsForReceivedInvocations.append(roomID)
|
||||
await removeDeliveredMessageNotificationsForClosure?(roomID)
|
||||
}
|
||||
//MARK: - removeDeliveredInviteNotifications
|
||||
|
||||
var removeDeliveredInviteNotificationsUnderlyingCallsCount = 0
|
||||
var removeDeliveredInviteNotificationsCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return removeDeliveredInviteNotificationsUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = removeDeliveredInviteNotificationsUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
removeDeliveredInviteNotificationsUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
removeDeliveredInviteNotificationsUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var removeDeliveredInviteNotificationsCalled: Bool {
|
||||
return removeDeliveredInviteNotificationsCallsCount > 0
|
||||
}
|
||||
var removeDeliveredInviteNotificationsClosure: (() async -> Void)?
|
||||
|
||||
func removeDeliveredInviteNotifications() async {
|
||||
removeDeliveredInviteNotificationsCallsCount += 1
|
||||
await removeDeliveredInviteNotificationsClosure?()
|
||||
}
|
||||
}
|
||||
class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol {
|
||||
var callbacks: PassthroughSubject<NotificationSettingsProxyCallback, Never> {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Notification.Name {
|
||||
static let roomMarkedAsRead = Notification.Name("roomMarkedAsRead")
|
||||
static let invitesScreenAppeared = Notification.Name("invitesScreenAppeared")
|
||||
}
|
||||
@@ -43,5 +43,4 @@ struct InvitesScreenRoomDetails: Identifiable {
|
||||
enum InvitesScreenViewAction {
|
||||
case accept(InvitesScreenRoomDetails)
|
||||
case decline(InvitesScreenRoomDetails)
|
||||
case appeared
|
||||
}
|
||||
|
||||
@@ -57,8 +57,6 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
|
||||
accept(invite: invite)
|
||||
case .decline(let invite):
|
||||
startDeclineFlow(invite: invite)
|
||||
case .appeared:
|
||||
notificationCenterProtocol.post(name: .invitesScreenAppeared, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@ struct InvitesScreen: View {
|
||||
noInvitesContent
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
context.send(viewAction: .appeared)
|
||||
}
|
||||
}
|
||||
|
||||
private var noInvitesContent: some View {
|
||||
|
||||
@@ -60,7 +60,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
|
||||
switch await clientProxy.joinRoom(state.roomID) {
|
||||
case .success:
|
||||
actionsSubject.send(.joined)
|
||||
case .failure(let error):
|
||||
case .failure:
|
||||
state.bindings.alertInfo = .init(id: .joinFailed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,12 +415,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
private func sendReadReceiptIfNeeded(for lastVisibleItemID: TimelineItemIdentifier) async {
|
||||
guard application.applicationState == .active else { return }
|
||||
|
||||
// Clear any notifications from notification center.
|
||||
if lastVisibleItemID.timelineID == state.timelineViewState.timelineIDs.last {
|
||||
notificationCenter.post(name: .roomMarkedAsRead, object: roomProxy.id)
|
||||
}
|
||||
|
||||
|
||||
await timelineController.sendReadReceipt(for: lastVisibleItemID)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
self.notificationCenter = notificationCenter
|
||||
self.appSettings = appSettings
|
||||
super.init()
|
||||
addObservers()
|
||||
}
|
||||
|
||||
// MARK: NotificationManagerProtocol
|
||||
@@ -100,8 +99,8 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
guard let self else { return }
|
||||
|
||||
if await notificationCenter.authorizationStatus() == .authorized {
|
||||
await MainActor.run {
|
||||
delegate?.registerForRemoteNotifications()
|
||||
await MainActor.run { [weak self] in
|
||||
self?.delegate?.registerForRemoteNotifications()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +127,22 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func removeDeliveredMessageNotifications(for roomID: String) async {
|
||||
let notificationsIdentifiers = await notificationCenter
|
||||
.deliveredNotifications()
|
||||
.filter { $0.request.content.roomID == roomID }
|
||||
.map(\.request.identifier)
|
||||
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
|
||||
}
|
||||
|
||||
func removeDeliveredInviteNotifications() async {
|
||||
let notificationsIdentifiers = await notificationCenter
|
||||
.deliveredNotifications()
|
||||
.filter { $0.request.content.categoryIdentifier == NotificationConstants.Category.invite }
|
||||
.map(\.request.identifier)
|
||||
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
|
||||
}
|
||||
|
||||
private func setPusher(with deviceToken: Data, clientProxy: ClientProxyProtocol) async -> Bool {
|
||||
do {
|
||||
let defaultPayload = APNSPayload(aps: APSInfo(mutableContent: 1,
|
||||
@@ -177,47 +192,6 @@ final class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
delegate?.unregisterForRemoteNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
private func addObservers() {
|
||||
NotificationCenter
|
||||
.default
|
||||
.publisher(for: .roomMarkedAsRead)
|
||||
.sink { [weak self] notification in
|
||||
guard let roomID = notification.object as? String else {
|
||||
return
|
||||
}
|
||||
self?.removeMessageNotifications(for: roomID)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
NotificationCenter
|
||||
.default
|
||||
.publisher(for: .invitesScreenAppeared)
|
||||
.sink { [weak self] _ in
|
||||
self?.removeInviteNotifications()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func removeMessageNotifications(for roomID: String) {
|
||||
Task {
|
||||
let notificationsIdentifiers = await notificationCenter
|
||||
.deliveredNotifications()
|
||||
.filter { $0.request.content.roomID == roomID }
|
||||
.map(\.request.identifier)
|
||||
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
|
||||
}
|
||||
}
|
||||
|
||||
private func removeInviteNotifications() {
|
||||
Task {
|
||||
let notificationsIdentifiers = await notificationCenter
|
||||
.deliveredNotifications()
|
||||
.filter { $0.request.content.categoryIdentifier == NotificationConstants.Category.invite }
|
||||
.map(\.request.identifier)
|
||||
notificationCenter.removeDeliveredNotifications(withIdentifiers: notificationsIdentifiers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UNUserNotificationCenterDelegate
|
||||
|
||||
@@ -40,4 +40,7 @@ protocol NotificationManagerProtocol: AnyObject {
|
||||
func setUserSession(_ userSession: UserSessionProtocol?)
|
||||
|
||||
func requestAuthorization()
|
||||
|
||||
func removeDeliveredMessageNotifications(for roomID: String) async
|
||||
func removeDeliveredInviteNotifications() async
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user