mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Removing Delivered Notifications (#1305)
* completed * changelog * tests * more tests * better naming * fix * a bit more waiting time * generated mocks * xcodegen
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; };
|
0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; };
|
||||||
020F7E70167FB2833266F2F0 /* AnalyticsSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39D7F513A36C9C1951DB44C /* AnalyticsSettingsScreen.swift */; };
|
020F7E70167FB2833266F2F0 /* AnalyticsSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39D7F513A36C9C1951DB44C /* AnalyticsSettingsScreen.swift */; };
|
||||||
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */; };
|
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */; };
|
||||||
|
02F4FAE40AF63A1941FD3BBA /* NotificationCenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */; };
|
||||||
037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDCAC6CAAD65A2C24EA9C4B /* Dictionary.swift */; };
|
037006FB6DF1374F94E4058D /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDCAC6CAAD65A2C24EA9C4B /* Dictionary.swift */; };
|
||||||
03D684A3AE85A23B3DA3B43F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26747B3154A5DBC3A7E24A5 /* Image.swift */; };
|
03D684A3AE85A23B3DA3B43F /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = E26747B3154A5DBC3A7E24A5 /* Image.swift */; };
|
||||||
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */; };
|
0437765FF480249486893CC7 /* ScreenTrackerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */; };
|
||||||
@@ -566,6 +567,7 @@
|
|||||||
C413D36D44F89DE63D3ADFA4 /* ReportContentScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */; };
|
C413D36D44F89DE63D3ADFA4 /* ReportContentScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */; };
|
||||||
C4180F418235DAD9DD173951 /* TemplateScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */; };
|
C4180F418235DAD9DD173951 /* TemplateScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */; };
|
||||||
C49FCC766673006B6D299F1C /* RoomDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */; };
|
C49FCC766673006B6D299F1C /* RoomDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */; };
|
||||||
|
C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4151163F666ED94FD959475A /* NotificationName.swift */; };
|
||||||
C4D2BCAA54E2C62B94B24AF4 /* InviteUsersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */; };
|
C4D2BCAA54E2C62B94B24AF4 /* InviteUsersScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */; };
|
||||||
C4E0D03DF88242697545A9B7 /* UserIndicatorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */; };
|
C4E0D03DF88242697545A9B7 /* UserIndicatorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */; };
|
||||||
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
|
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E508AB0EDEE017FF4F6F8D1 /* DTHTMLElement+AttributedStringBuilder.swift */; };
|
||||||
@@ -835,6 +837,7 @@
|
|||||||
0FB782CE6176A5D2C082EC5D /* WelcomeScreenScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreenScreenModels.swift; sourceTree = "<group>"; };
|
0FB782CE6176A5D2C082EC5D /* WelcomeScreenScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreenScreenModels.swift; sourceTree = "<group>"; };
|
||||||
1059E2AE7878CF7820592637 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
1059E2AE7878CF7820592637 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
|
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
|
||||||
|
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenterProtocol.swift; sourceTree = "<group>"; };
|
||||||
10CC626F97AD70FF0420C115 /* RoomSummaryProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProviderProtocol.swift; sourceTree = "<group>"; };
|
10CC626F97AD70FF0420C115 /* RoomSummaryProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProviderProtocol.swift; sourceTree = "<group>"; };
|
||||||
10F32E0B4B83D2A11EE8D011 /* InviteUsersScreenSelectedItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenSelectedItem.swift; sourceTree = "<group>"; };
|
10F32E0B4B83D2A11EE8D011 /* InviteUsersScreenSelectedItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenSelectedItem.swift; sourceTree = "<group>"; };
|
||||||
11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
11151E78D6BB2B04A8FBD389 /* EmojiPickerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -964,6 +967,7 @@
|
|||||||
3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = "<group>"; };
|
3FFDA99C98BE05F43A92343B /* test_pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = test_pdf.pdf; sourceTree = "<group>"; };
|
||||||
40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
40B21E611DADDEF00307E7AC /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||||
4132F882A984ED971338EE9D /* ReportContentScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenUITests.swift; sourceTree = "<group>"; };
|
4132F882A984ED971338EE9D /* ReportContentScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenUITests.swift; sourceTree = "<group>"; };
|
||||||
|
4151163F666ED94FD959475A /* NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName.swift; sourceTree = "<group>"; };
|
||||||
4176C3E20C772DE8D182863C /* LegalInformationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreen.swift; sourceTree = "<group>"; };
|
4176C3E20C772DE8D182863C /* LegalInformationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreen.swift; sourceTree = "<group>"; };
|
||||||
421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = "<group>"; };
|
421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -2052,6 +2056,7 @@
|
|||||||
C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */,
|
C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */,
|
||||||
2AFEF3AC64B1358083F76B8B /* List.swift */,
|
2AFEF3AC64B1358083F76B8B /* List.swift */,
|
||||||
23AA3F4B285570805CB0CCDD /* MapTiler.swift */,
|
23AA3F4B285570805CB0CCDD /* MapTiler.swift */,
|
||||||
|
4151163F666ED94FD959475A /* NotificationName.swift */,
|
||||||
F72EFC8C634469F9262659C7 /* NSItemProvider.swift */,
|
F72EFC8C634469F9262659C7 /* NSItemProvider.swift */,
|
||||||
95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */,
|
95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */,
|
||||||
7310D8DFE01AF45F0689C3AA /* Publisher.swift */,
|
7310D8DFE01AF45F0689C3AA /* Publisher.swift */,
|
||||||
@@ -3194,6 +3199,7 @@
|
|||||||
6A580295A56B55A856CC4084 /* InfoPlistReader.swift */,
|
6A580295A56B55A856CC4084 /* InfoPlistReader.swift */,
|
||||||
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
|
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
|
||||||
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
|
C789E7BFC066CF39B8AE0974 /* NetworkMonitor.swift */,
|
||||||
|
10B7F8EE25775DE2A305CBB5 /* NotificationCenterProtocol.swift */,
|
||||||
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
|
F754E66A8970963B15B2A41E /* PermalinkBuilder.swift */,
|
||||||
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
|
53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */,
|
||||||
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
|
DBA8DC95C079805B0B56E8A9 /* SharedUserDefaultsKeys.swift */,
|
||||||
@@ -4386,10 +4392,12 @@
|
|||||||
0C58A846F61949B1D545D661 /* NoticeRoomTimelineItem.swift in Sources */,
|
0C58A846F61949B1D545D661 /* NoticeRoomTimelineItem.swift in Sources */,
|
||||||
9408CE8B8865C0C8DD4C9869 /* NoticeRoomTimelineItemContent.swift in Sources */,
|
9408CE8B8865C0C8DD4C9869 /* NoticeRoomTimelineItemContent.swift in Sources */,
|
||||||
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */,
|
368C8758FCD079E6AAA18C2C /* NoticeRoomTimelineView.swift in Sources */,
|
||||||
|
02F4FAE40AF63A1941FD3BBA /* NotificationCenterProtocol.swift in Sources */,
|
||||||
3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */,
|
3F70E237CE4C3FAB02FC227F /* NotificationConstants.swift in Sources */,
|
||||||
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */,
|
CE9530A4CA661E090635C2F2 /* NotificationItemProxy.swift in Sources */,
|
||||||
652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */,
|
652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */,
|
||||||
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */,
|
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */,
|
||||||
|
C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */,
|
||||||
6786C4B0936AC84D993B20BF /* NotificationSettingsScreen.swift in Sources */,
|
6786C4B0936AC84D993B20BF /* NotificationSettingsScreen.swift in Sources */,
|
||||||
F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */,
|
F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */,
|
||||||
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */,
|
D12F440F7973F1489F61389D /* NotificationSettingsScreenModels.swift in Sources */,
|
||||||
|
|||||||
@@ -197,6 +197,25 @@ class BugReportServiceMock: BugReportServiceProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class NotificationCenterMock: NotificationCenterProtocol {
|
||||||
|
|
||||||
|
//MARK: - post
|
||||||
|
|
||||||
|
var postNameObjectCallsCount = 0
|
||||||
|
var postNameObjectCalled: Bool {
|
||||||
|
return postNameObjectCallsCount > 0
|
||||||
|
}
|
||||||
|
var postNameObjectReceivedArguments: (aName: NSNotification.Name, anObject: Any?)?
|
||||||
|
var postNameObjectReceivedInvocations: [(aName: NSNotification.Name, anObject: Any?)] = []
|
||||||
|
var postNameObjectClosure: ((NSNotification.Name, Any?) -> Void)?
|
||||||
|
|
||||||
|
func post(name aName: NSNotification.Name, object anObject: Any?) {
|
||||||
|
postNameObjectCallsCount += 1
|
||||||
|
postNameObjectReceivedArguments = (aName: aName, anObject: anObject)
|
||||||
|
postNameObjectReceivedInvocations.append((aName: aName, anObject: anObject))
|
||||||
|
postNameObjectClosure?(aName, anObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
class NotificationManagerMock: NotificationManagerProtocol {
|
class NotificationManagerMock: NotificationManagerProtocol {
|
||||||
var delegate: NotificationManagerDelegate?
|
var delegate: NotificationManagerDelegate?
|
||||||
|
|
||||||
@@ -1365,6 +1384,39 @@ class UserNotificationCenterMock: UserNotificationCenterProtocol {
|
|||||||
return requestAuthorizationOptionsReturnValue
|
return requestAuthorizationOptionsReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//MARK: - deliveredNotifications
|
||||||
|
|
||||||
|
var deliveredNotificationsCallsCount = 0
|
||||||
|
var deliveredNotificationsCalled: Bool {
|
||||||
|
return deliveredNotificationsCallsCount > 0
|
||||||
|
}
|
||||||
|
var deliveredNotificationsReturnValue: [UNNotification]!
|
||||||
|
var deliveredNotificationsClosure: (() async -> [UNNotification])?
|
||||||
|
|
||||||
|
func deliveredNotifications() async -> [UNNotification] {
|
||||||
|
deliveredNotificationsCallsCount += 1
|
||||||
|
if let deliveredNotificationsClosure = deliveredNotificationsClosure {
|
||||||
|
return await deliveredNotificationsClosure()
|
||||||
|
} else {
|
||||||
|
return deliveredNotificationsReturnValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//MARK: - removeDeliveredNotifications
|
||||||
|
|
||||||
|
var removeDeliveredNotificationsWithIdentifiersCallsCount = 0
|
||||||
|
var removeDeliveredNotificationsWithIdentifiersCalled: Bool {
|
||||||
|
return removeDeliveredNotificationsWithIdentifiersCallsCount > 0
|
||||||
|
}
|
||||||
|
var removeDeliveredNotificationsWithIdentifiersReceivedIdentifiers: [String]?
|
||||||
|
var removeDeliveredNotificationsWithIdentifiersReceivedInvocations: [[String]] = []
|
||||||
|
var removeDeliveredNotificationsWithIdentifiersClosure: (([String]) -> Void)?
|
||||||
|
|
||||||
|
func removeDeliveredNotifications(withIdentifiers identifiers: [String]) {
|
||||||
|
removeDeliveredNotificationsWithIdentifiersCallsCount += 1
|
||||||
|
removeDeliveredNotificationsWithIdentifiersReceivedIdentifiers = identifiers
|
||||||
|
removeDeliveredNotificationsWithIdentifiersReceivedInvocations.append(identifiers)
|
||||||
|
removeDeliveredNotificationsWithIdentifiersClosure?(identifiers)
|
||||||
|
}
|
||||||
//MARK: - setNotificationCategories
|
//MARK: - setNotificationCategories
|
||||||
|
|
||||||
var setNotificationCategoriesCallsCount = 0
|
var setNotificationCategoriesCallsCount = 0
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// sourcery: AutoMockable
|
||||||
|
protocol NotificationCenterProtocol: AnyObject {
|
||||||
|
func post(name aName: NSNotification.Name, object anObject: Any?)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NotificationCenter: NotificationCenterProtocol { }
|
||||||
@@ -48,4 +48,5 @@ struct InvitesScreenRoomDetails: Identifiable {
|
|||||||
enum InvitesScreenViewAction {
|
enum InvitesScreenViewAction {
|
||||||
case accept(InvitesScreenRoomDetails)
|
case accept(InvitesScreenRoomDetails)
|
||||||
case decline(InvitesScreenRoomDetails)
|
case decline(InvitesScreenRoomDetails)
|
||||||
|
case appeared
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
|
|||||||
private let appSettings: AppSettings
|
private let appSettings: AppSettings
|
||||||
private let analytics: AnalyticsService
|
private let analytics: AnalyticsService
|
||||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
private let notificationCenterProtocol: NotificationCenterProtocol
|
||||||
|
|
||||||
private let previouslySeenInvites: Set<String>
|
private let previouslySeenInvites: Set<String>
|
||||||
private let actionsSubject: PassthroughSubject<InvitesScreenViewModelAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<InvitesScreenViewModelAction, Never> = .init()
|
||||||
@@ -36,11 +37,13 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
|
|||||||
init(userSession: UserSessionProtocol,
|
init(userSession: UserSessionProtocol,
|
||||||
appSettings: AppSettings,
|
appSettings: AppSettings,
|
||||||
analytics: AnalyticsService,
|
analytics: AnalyticsService,
|
||||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
|
notificationCenterProtocol: NotificationCenterProtocol = NotificationCenter.default) {
|
||||||
self.userSession = userSession
|
self.userSession = userSession
|
||||||
self.appSettings = appSettings
|
self.appSettings = appSettings
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
|
self.notificationCenterProtocol = notificationCenterProtocol
|
||||||
|
|
||||||
previouslySeenInvites = appSettings.seenInvites
|
previouslySeenInvites = appSettings.seenInvites
|
||||||
super.init(initialViewState: InvitesScreenViewState(), imageProvider: userSession.mediaProvider)
|
super.init(initialViewState: InvitesScreenViewState(), imageProvider: userSession.mediaProvider)
|
||||||
@@ -55,6 +58,8 @@ class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModel
|
|||||||
accept(invite: invite)
|
accept(invite: invite)
|
||||||
case .decline(let invite):
|
case .decline(let invite):
|
||||||
startDeclineFlow(invite: invite)
|
startDeclineFlow(invite: invite)
|
||||||
|
case .appeared:
|
||||||
|
notificationCenterProtocol.post(name: .invitesScreenAppeared, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ struct InvitesScreen: View {
|
|||||||
noInvitesContent
|
noInvitesContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onAppear {
|
||||||
|
context.send(viewAction: .appeared)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var noInvitesContent: some View {
|
private var noInvitesContent: some View {
|
||||||
|
|||||||
@@ -33,18 +33,21 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
private let appSettings: AppSettings
|
private let appSettings: AppSettings
|
||||||
private let analytics: AnalyticsService
|
private let analytics: AnalyticsService
|
||||||
private unowned let userIndicatorController: UserIndicatorControllerProtocol
|
private unowned let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
private let notificationCenterProtocol: NotificationCenterProtocol
|
||||||
|
|
||||||
init(timelineController: RoomTimelineControllerProtocol,
|
init(timelineController: RoomTimelineControllerProtocol,
|
||||||
mediaProvider: MediaProviderProtocol,
|
mediaProvider: MediaProviderProtocol,
|
||||||
roomProxy: RoomProxyProtocol,
|
roomProxy: RoomProxyProtocol,
|
||||||
appSettings: AppSettings,
|
appSettings: AppSettings,
|
||||||
analytics: AnalyticsService,
|
analytics: AnalyticsService,
|
||||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
userIndicatorController: UserIndicatorControllerProtocol,
|
||||||
|
notificationCenterProtocol: NotificationCenterProtocol = NotificationCenter.default) {
|
||||||
self.roomProxy = roomProxy
|
self.roomProxy = roomProxy
|
||||||
self.timelineController = timelineController
|
self.timelineController = timelineController
|
||||||
self.appSettings = appSettings
|
self.appSettings = appSettings
|
||||||
self.analytics = analytics
|
self.analytics = analytics
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
|
self.notificationCenterProtocol = notificationCenterProtocol
|
||||||
|
|
||||||
super.init(initialViewState: RoomScreenViewState(roomId: timelineController.roomID,
|
super.init(initialViewState: RoomScreenViewState(roomId: timelineController.roomID,
|
||||||
roomTitle: roomProxy.roomTitle,
|
roomTitle: roomProxy.roomTitle,
|
||||||
@@ -214,6 +217,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func markRoomAsRead() async {
|
private func markRoomAsRead() async {
|
||||||
|
notificationCenterProtocol.post(name: .roomMarkedAsRead, object: roomProxy.id)
|
||||||
_ = await timelineController.markRoomAsRead()
|
_ = await timelineController.markRoomAsRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
class NotificationManager: NSObject, NotificationManagerProtocol {
|
final class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||||
private let notificationCenter: UserNotificationCenterProtocol
|
private let notificationCenter: UserNotificationCenterProtocol
|
||||||
private let appSettings: AppSettings
|
private let appSettings: AppSettings
|
||||||
|
|
||||||
@@ -31,6 +31,8 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
|||||||
appSettings: AppSettings) {
|
appSettings: AppSettings) {
|
||||||
self.notificationCenter = notificationCenter
|
self.notificationCenter = notificationCenter
|
||||||
self.appSettings = appSettings
|
self.appSettings = appSettings
|
||||||
|
super.init()
|
||||||
|
addObservers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: NotificationManagerProtocol
|
// MARK: NotificationManagerProtocol
|
||||||
@@ -169,6 +171,47 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
|||||||
delegate?.unregisterForRemoteNotifications()
|
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
|
// MARK: - UNUserNotificationCenterDelegate
|
||||||
|
|||||||
@@ -17,10 +17,14 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
|
// Sadly we can't mock this because the delegate needs to be weak
|
||||||
|
// Use UserNotificationCenterSpy
|
||||||
protocol UserNotificationCenterProtocol: AnyObject {
|
protocol UserNotificationCenterProtocol: AnyObject {
|
||||||
var delegate: UNUserNotificationCenterDelegate? { get set }
|
var delegate: UNUserNotificationCenterDelegate? { get set }
|
||||||
func add(_ request: UNNotificationRequest) async throws
|
func add(_ request: UNNotificationRequest) async throws
|
||||||
func requestAuthorization(options: UNAuthorizationOptions) async throws -> Bool
|
func requestAuthorization(options: UNAuthorizationOptions) async throws -> Bool
|
||||||
|
func deliveredNotifications() async -> [UNNotification]
|
||||||
|
func removeDeliveredNotifications(withIdentifiers identifiers: [String])
|
||||||
func setNotificationCategories(_ categories: Set<UNNotificationCategory>)
|
func setNotificationCategories(_ categories: Set<UNNotificationCategory>)
|
||||||
func authorizationStatus() async -> UNAuthorizationStatus
|
func authorizationStatus() async -> UNAuthorizationStatus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class InvitesScreenViewModelTests: XCTestCase {
|
|||||||
var viewModel: InvitesScreenViewModelProtocol!
|
var viewModel: InvitesScreenViewModelProtocol!
|
||||||
var clientProxy: MockClientProxy!
|
var clientProxy: MockClientProxy!
|
||||||
var userSession: MockUserSession!
|
var userSession: MockUserSession!
|
||||||
|
var mockNotificationCenter: NotificationCenterMock!
|
||||||
|
|
||||||
var context: InvitesScreenViewModelType.Context {
|
var context: InvitesScreenViewModelType.Context {
|
||||||
viewModel.context
|
viewModel.context
|
||||||
@@ -30,6 +31,7 @@ class InvitesScreenViewModelTests: XCTestCase {
|
|||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
clientProxy = MockClientProxy(userID: "@a:b.com")
|
clientProxy = MockClientProxy(userID: "@a:b.com")
|
||||||
userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
|
userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
|
||||||
|
mockNotificationCenter = NotificationCenterMock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEmptyState() async throws {
|
func testEmptyState() async throws {
|
||||||
@@ -73,6 +75,14 @@ class InvitesScreenViewModelTests: XCTestCase {
|
|||||||
XCTAssertNotNil(context.alertInfo)
|
XCTAssertNotNil(context.alertInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testHasAppeared() async {
|
||||||
|
setupViewModel()
|
||||||
|
context.send(viewAction: .appeared)
|
||||||
|
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssertEqual(mockNotificationCenter.postNameObjectReceivedArguments?.aName, .invitesScreenAppeared)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func setupViewModel(roomSummaries: [RoomSummary]? = nil) {
|
private func setupViewModel(roomSummaries: [RoomSummary]? = nil) {
|
||||||
@@ -85,6 +95,7 @@ class InvitesScreenViewModelTests: XCTestCase {
|
|||||||
viewModel = InvitesScreenViewModel(userSession: userSession,
|
viewModel = InvitesScreenViewModel(userSession: userSession,
|
||||||
appSettings: ServiceLocator.shared.settings,
|
appSettings: ServiceLocator.shared.settings,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||||
|
notificationCenterProtocol: mockNotificationCenter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import NotificationCenter
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
import Combine
|
|
||||||
@testable import ElementX
|
@testable import ElementX
|
||||||
|
|
||||||
final class NotificationManagerTests: XCTestCase {
|
final class NotificationManagerTests: XCTestCase {
|
||||||
@@ -176,6 +177,32 @@ final class NotificationManagerTests: XCTestCase {
|
|||||||
await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response)
|
await notificationManager.userNotificationCenter(UNUserNotificationCenter.current(), didReceive: response)
|
||||||
XCTAssertTrue(notificationTappedDelegateCalled)
|
XCTAssertTrue(notificationTappedDelegateCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func test_MessageNotificationsRemoval() async throws {
|
||||||
|
// No interaction if the object is nil or of the wrong type
|
||||||
|
NotificationCenter.default.post(name: .roomMarkedAsRead, object: nil)
|
||||||
|
try await Task.sleep(for: .microseconds(200))
|
||||||
|
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0)
|
||||||
|
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0)
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .roomMarkedAsRead, object: 1)
|
||||||
|
try await Task.sleep(for: .microseconds(200))
|
||||||
|
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 0)
|
||||||
|
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 0)
|
||||||
|
|
||||||
|
// The center calls the delivered and the removal functions when an id is passed
|
||||||
|
NotificationCenter.default.post(name: .roomMarkedAsRead, object: "RoomID")
|
||||||
|
try await Task.sleep(for: .microseconds(200))
|
||||||
|
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1)
|
||||||
|
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_InvitesNotificationsRemoval() async throws {
|
||||||
|
NotificationCenter.default.post(name: .invitesScreenAppeared, object: nil)
|
||||||
|
try await Task.sleep(for: .microseconds(200))
|
||||||
|
XCTAssertEqual(notificationCenter.deliveredNotificationsCallsCount, 1)
|
||||||
|
XCTAssertEqual(notificationCenter.removeDeliveredNotificationsCallsCount, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationManagerTests: NotificationManagerDelegate {
|
extension NotificationManagerTests: NotificationManagerDelegate {
|
||||||
|
|||||||
@@ -17,9 +17,20 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
class UserNotificationCenterSpy: UserNotificationCenterProtocol {
|
final class UserNotificationCenterSpy: UserNotificationCenterProtocol {
|
||||||
weak var delegate: UNUserNotificationCenterDelegate?
|
weak var delegate: UNUserNotificationCenterDelegate?
|
||||||
|
|
||||||
|
var deliveredNotificationsCallsCount = 0
|
||||||
|
func deliveredNotifications() async -> [UNNotification] {
|
||||||
|
deliveredNotificationsCallsCount += 1
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
var removeDeliveredNotificationsCallsCount = 0
|
||||||
|
func removeDeliveredNotifications(withIdentifiers identifiers: [String]) {
|
||||||
|
removeDeliveredNotificationsCallsCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
var addRequest: UNNotificationRequest?
|
var addRequest: UNNotificationRequest?
|
||||||
func add(_ request: UNNotificationRequest) async throws {
|
func add(_ request: UNNotificationRequest) async throws {
|
||||||
addRequest = request
|
addRequest = request
|
||||||
|
|||||||
@@ -349,6 +349,27 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
await Task.yield()
|
await Task.yield()
|
||||||
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
|
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testMarkAsRead() async {
|
||||||
|
// Setup
|
||||||
|
let notificationCenterMock = NotificationCenterMock()
|
||||||
|
let timelineController = MockRoomTimelineController()
|
||||||
|
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
|
||||||
|
|
||||||
|
let viewModel = RoomScreenViewModel(timelineController: timelineController,
|
||||||
|
mediaProvider: MockMediaProvider(),
|
||||||
|
roomProxy: roomProxyMock,
|
||||||
|
appSettings: ServiceLocator.shared.settings,
|
||||||
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
userIndicatorController: userIndicatorControllerMock,
|
||||||
|
notificationCenterProtocol: notificationCenterMock)
|
||||||
|
|
||||||
|
viewModel.context.send(viewAction: .markRoomAsRead)
|
||||||
|
await Task.yield()
|
||||||
|
XCTAssertEqual(notificationCenterMock.postNameObjectReceivedArguments?.aName, .roomMarkedAsRead)
|
||||||
|
let roomID = notificationCenterMock.postNameObjectReceivedArguments?.anObject as? String
|
||||||
|
XCTAssertEqual(roomID, roomProxyMock.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Push notifications for a room are cleared from the notification centre when opening its timeline. Same for invitations when opening the invite screen.
|
||||||
Reference in New Issue
Block a user