Edit the default notification settings (#1468)
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */; };
|
||||
1772AFA97DDA51CF1B293A78 /* RoomAttachmentPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6A9B9DFEE964962C179DE3 /* RoomAttachmentPicker.swift */; };
|
||||
17780569FB41E9BAC60D4710 /* UNUserNotificationCenter+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E685274772980BDEFF6691E /* UNUserNotificationCenter+Settings.swift */; };
|
||||
1830E5431DB426E2F3660D58 /* NotificationSettingsEditScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F52419AEEDA2C006CB7181 /* NotificationSettingsEditScreenUITests.swift */; };
|
||||
18867F4F1C8991EEC56EA932 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
|
||||
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */; };
|
||||
19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC575D1895FA62591451A93 /* RoomMemberDetailsScreen.swift */; };
|
||||
@@ -133,6 +134,7 @@
|
||||
2E43A3D221BE9587BC19C3F1 /* MatrixEntityRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F31F59030205A6F65B057E1A /* MatrixEntityRegexTests.swift */; };
|
||||
2E8C6672D0EE7D5B1BEDB8E2 /* ServerConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */; };
|
||||
2F1CF90A3460C153154427F0 /* RoomScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086B997409328F091EBA43CE /* RoomScreenUITests.swift */; };
|
||||
2F623DA1122140A987B34D08 /* NotificationSettingsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */; };
|
||||
2F66701B15657A87B4AC3A0A /* WaitlistScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE2B7AD979BDEE09FEDB08 /* WaitlistScreenModels.swift */; };
|
||||
2F94054F50E312AF30BE07F3 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40B21E611DADDEF00307E7AC /* String.swift */; };
|
||||
308BD9343B95657FAA583FB7 /* SwiftState in Frameworks */ = {isa = PBXBuildFile; productRef = 19CD5B074D7DD44AF4C58BB6 /* SwiftState */; };
|
||||
@@ -211,6 +213,7 @@
|
||||
4E0D9E09B52CEC4C0E6211A8 /* MediaPickerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F49FB9EE2913234F06CE68 /* MediaPickerScreenCoordinator.swift */; };
|
||||
4E8F17EBA24FBBA6ABB62ECB /* MockBackgroundTaskService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3948D16F021DFDB2CD26EAA8 /* MockBackgroundTaskService.swift */; };
|
||||
4E945AD6862C403F74E57755 /* RoomTimelineItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */; };
|
||||
4EA1CE0E88EA68E862FF0EA2 /* NotificationSettingsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */; };
|
||||
4FC085B1E5D1EB804495E2F4 /* MockMediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD6E621CC5E6D4830D96D2D /* MockMediaProvider.swift */; };
|
||||
4FC1EFE4968A259CBBACFAFB /* RoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A65F140F9FE5E8D4DAEFF354 /* RoomProxy.swift */; };
|
||||
4FDC8A9764CFDA90CE035725 /* Duration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FB2253D36E81E045E1CB432 /* Duration.swift */; };
|
||||
@@ -225,6 +228,7 @@
|
||||
520EEDAFBC778AB0B41F2F53 /* ClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */; };
|
||||
5375902175B2FEA2949D7D74 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */; };
|
||||
53A55748D5F587C9061F98BF /* ServerConfigurationScreenViewStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277C20CDD5B64510401B6D0D /* ServerConfigurationScreenViewStateTests.swift */; };
|
||||
53A59720F4729D9BBFFB7CAB /* NotificationSettingsEditScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */; };
|
||||
53C1E7F6A7D6409D89F36ED7 /* AggregatedReactionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69CB8242D69B7E4D0B32E18D /* AggregatedReactionMock.swift */; };
|
||||
53DEF39F0C4DE02E3FC56D91 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 800631D7250B7F93195035F1 /* KeychainAccess */; };
|
||||
53F1196F9C69512306A2693F /* TextRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */; };
|
||||
@@ -500,6 +504,7 @@
|
||||
A9A5801D5EE3D4D91F6DDADB /* AnalyticsSettingsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58C2527813FDAE23E72A9063 /* AnalyticsSettingsScreenViewModelTests.swift */; };
|
||||
A9D349478F7D4A2B1E40CEF9 /* LegalInformationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8977176AB534AA41630395BC /* LegalInformationScreenViewModelProtocol.swift */; };
|
||||
AA050DF4AEE54A641BA7CA22 /* RoomSummaryProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10CC626F97AD70FF0420C115 /* RoomSummaryProviderProtocol.swift */; };
|
||||
AA93B3F9B5DD097DEF79F981 /* NotificationSettingsEditScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB0328F2887BF0A65BC5D49 /* NotificationSettingsEditScreen.swift */; };
|
||||
AAF0BBED840DF4A53EE85E77 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = C2C69B8BA5A9702E7A8BC08F /* MatrixRustSDK */; };
|
||||
ABF3FAB234AD3565B214309B /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BC588051E6572A1AF51D738 /* TimelineSenderAvatarView.swift */; };
|
||||
AC69B6DF15FC451AB2945036 /* UserSessionStoreProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */; };
|
||||
@@ -569,6 +574,7 @@
|
||||
BF675964C9159F718589C36A /* AnalyticsSettingsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */; };
|
||||
C051475DFF4C8EBDDF4DC8E4 /* StartChatScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99E13633862847D8B7E2815 /* StartChatScreenModels.swift */; };
|
||||
C08AAE7563E0722C9383F51C /* RoomMembersListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */; };
|
||||
C11939FDC40716C4387275A4 /* NotificationSettingsEditScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */; };
|
||||
C13128AAA787A4C2CBE4EE82 /* MessageForwardingScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */; };
|
||||
C1910A16BDF131FECA77BE22 /* EmojiPickerScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEA38B9851CFCC4D67F5587D /* EmojiPickerScreenCoordinator.swift */; };
|
||||
C1A5C386319835FB0C77736B /* ReportContentScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16CD2C62CB7DB78A4238485 /* ReportContentScreenCoordinator.swift */; };
|
||||
@@ -638,6 +644,7 @@
|
||||
D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */; };
|
||||
D5C805F49B2C75DC3793E780 /* EmojiItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */; };
|
||||
D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */; };
|
||||
D5FE90A6AF5FD5AE91BD37C7 /* NotificationSettingsEditScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780258F1B9D15E30549FF4BE /* NotificationSettingsEditScreenViewModel.swift */; };
|
||||
D63974A88CF2BC721F109C77 /* Compound in Frameworks */ = {isa = PBXBuildFile; productRef = DCA3C4A997AD28E6918D4CE5 /* Compound */; };
|
||||
D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */; };
|
||||
D7CDBAE82782BD0529DECB5F /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; };
|
||||
@@ -897,6 +904,7 @@
|
||||
1ABDE6F66532CBEB0E016F94 /* RoomProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyMock.swift; sourceTree = "<group>"; };
|
||||
1B1EE0908B2BF9212436AD3E /* SessionVerificationScreenStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenStateMachine.swift; sourceTree = "<group>"; };
|
||||
1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||
1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = "<group>"; };
|
||||
1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenModels.swift; sourceTree = "<group>"; };
|
||||
1B8E176484A89BAC389D4076 /* RoomMembersListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreen.swift; sourceTree = "<group>"; };
|
||||
1BC4437C107D52ED19357DFC /* OnboardingViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
@@ -1007,6 +1015,7 @@
|
||||
46B59EC4B0C93254089EAACB /* MigrationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
|
||||
46D560DDA3B20C82766ACFAD /* NotificationSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
46F52419AEEDA2C006CB7181 /* NotificationSettingsEditScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenUITests.swift; sourceTree = "<group>"; };
|
||||
47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = "<group>"; };
|
||||
471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenModels.swift; sourceTree = "<group>"; };
|
||||
@@ -1144,6 +1153,7 @@
|
||||
75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
780258F1B9D15E30549FF4BE /* NotificationSettingsEditScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
78910787F967CBC6042A101E /* StartChatScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSplitCoordinatorTests.swift; sourceTree = "<group>"; };
|
||||
7893780A1FD6E3F38B3E9049 /* UserIndicatorControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerMock.swift; sourceTree = "<group>"; };
|
||||
@@ -1175,6 +1185,7 @@
|
||||
84A87D0471D438A233C2CF4A /* RoomMemberDetailsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpiringTaskRunnerTests.swift; sourceTree = "<group>"; };
|
||||
851EF6258DF8B7EF129DC3AC /* WelcomeScreenScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreenScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||
8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||
854BCEAF2A832176FAACD2CB /* SplashScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaProviderProtocol.swift; sourceTree = "<group>"; };
|
||||
86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
@@ -1277,6 +1288,7 @@
|
||||
ACCC1874C122E2BBE648B8F5 /* LegalInformationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenUITests.swift; sourceTree = "<group>"; };
|
||||
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
AD6B522BD637845AB9570B10 /* RoomNotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxy.swift; sourceTree = "<group>"; };
|
||||
AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
ADB35E2DB4EFE8E6F3959629 /* InviteUsersScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenUITests.swift; sourceTree = "<group>"; };
|
||||
ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientMock.swift; sourceTree = "<group>"; };
|
||||
@@ -1499,8 +1511,10 @@
|
||||
F8CEB4634C0DD7779C4AB504 /* CreateRoomScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreenUITests.swift; sourceTree = "<group>"; };
|
||||
F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
F9ED8E731E21055F728E5FED /* TimelineStartRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStartRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
FB0D6CB491777E7FC6B5BA12 /* CreateRoomScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomScreen.swift; sourceTree = "<group>"; };
|
||||
FB7BAD55A4E2B8E5828CD64C /* SoftLogoutScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
FBB0328F2887BF0A65BC5D49 /* NotificationSettingsEditScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreen.swift; sourceTree = "<group>"; };
|
||||
FBC776F301D374A3298C69DA /* AppCoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinatorProtocol.swift; sourceTree = "<group>"; };
|
||||
FC2D505742FDA21FCDC4C18A /* AudioRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||
FD1275D9CE0FFBA6E8E85426 /* UserIndicatorController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorController.swift; sourceTree = "<group>"; };
|
||||
@@ -2110,6 +2124,18 @@
|
||||
path = Room;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
441115752CA2408F26A72D11 /* NotificationSettingsEditScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */,
|
||||
1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */,
|
||||
780258F1B9D15E30549FF4BE /* NotificationSettingsEditScreenViewModel.swift */,
|
||||
FA7BB497B2F539C17E88F6B7 /* NotificationSettingsEditScreenViewModelProtocol.swift */,
|
||||
8081F6F9AE11BB314A838EC9 /* View */,
|
||||
);
|
||||
path = NotificationSettingsEditScreen;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
448435400B561C40E514BE1C /* FilePreviewScreen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2452,6 +2478,7 @@
|
||||
09C599CB430ABF160C1EE55C /* AnalyticsSettingsScreen */,
|
||||
1CA6CD0DE6F0445156361B6D /* DeveloperOptionsScreen */,
|
||||
38A1C74493B816B8753F5BC2 /* LegalInformationScreen */,
|
||||
441115752CA2408F26A72D11 /* NotificationSettingsEditScreen */,
|
||||
7B91CB64534AD870924CCFEF /* NotificationSettingsScreen */,
|
||||
B364E08924AD15820350CDD9 /* SettingsScreen */,
|
||||
);
|
||||
@@ -2525,6 +2552,7 @@
|
||||
F875D71347DC81EAE7687446 /* NavigationRootCoordinatorTests.swift */,
|
||||
78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */,
|
||||
9C698E30698EC59302A8EEBD /* NavigationStackCoordinatorTests.swift */,
|
||||
8544F7058D31DBEB8DBFF0F5 /* NotificationSettingsEditScreenViewModelTests.swift */,
|
||||
514363244AE7D68080D44C6F /* NotificationSettingsScreenViewModelTests.swift */,
|
||||
00A941F289F6AB876BA3361A /* OnboardingViewModelTests.swift */,
|
||||
6FB31A32C93D94930B253FBF /* PermalinkBuilderTests.swift */,
|
||||
@@ -2706,6 +2734,14 @@
|
||||
path = Client;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8081F6F9AE11BB314A838EC9 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBB0328F2887BF0A65BC5D49 /* NotificationSettingsEditScreen.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
823ED0EC3F1B6CF47D284011 /* Tools */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2906,6 +2942,7 @@
|
||||
39B6C8690AEA1E49FF1BAF95 /* MediaUploadPreviewScreenUITests.swift */,
|
||||
59846FA04E1DBBFDD8829C2A /* MessageForwardingScreenUITests.swift */,
|
||||
75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */,
|
||||
46F52419AEEDA2C006CB7181 /* NotificationSettingsEditScreenUITests.swift */,
|
||||
B83BC0DC9A2DF2DD60F9B6E9 /* NotificationSettingsScreenUITests.swift */,
|
||||
0C88046D6A070D9827181C4D /* OnboardingUITests.swift */,
|
||||
4132F882A984ED971338EE9D /* ReportContentScreenUITests.swift */,
|
||||
@@ -4186,6 +4223,7 @@
|
||||
69C7B956B74BEC3DB88224EA /* NavigationSplitCoordinatorTests.swift in Sources */,
|
||||
4BB282209EA82015D0DF8F89 /* NavigationStackCoordinatorTests.swift in Sources */,
|
||||
1B2DADC008EE211AF1DA5292 /* NotificationManagerTests.swift in Sources */,
|
||||
C11939FDC40716C4387275A4 /* NotificationSettingsEditScreenViewModelTests.swift in Sources */,
|
||||
E3AC72E3E58F364EF15C1CC7 /* NotificationSettingsScreenViewModelTests.swift in Sources */,
|
||||
F9F6D2883BBEBB9A3789A137 /* OnboardingViewModelTests.swift in Sources */,
|
||||
27E9263DA75E266690A37EB1 /* PermalinkBuilderTests.swift in Sources */,
|
||||
@@ -4495,6 +4533,11 @@
|
||||
652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */,
|
||||
06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */,
|
||||
C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */,
|
||||
AA93B3F9B5DD097DEF79F981 /* NotificationSettingsEditScreen.swift in Sources */,
|
||||
53A59720F4729D9BBFFB7CAB /* NotificationSettingsEditScreenCoordinator.swift in Sources */,
|
||||
4EA1CE0E88EA68E862FF0EA2 /* NotificationSettingsEditScreenModels.swift in Sources */,
|
||||
D5FE90A6AF5FD5AE91BD37C7 /* NotificationSettingsEditScreenViewModel.swift in Sources */,
|
||||
2F623DA1122140A987B34D08 /* NotificationSettingsEditScreenViewModelProtocol.swift in Sources */,
|
||||
B93FA0DA1504B301CAEE141B /* NotificationSettingsProxy.swift in Sources */,
|
||||
4BAB8222DBA0B4207D1223E0 /* NotificationSettingsProxyMock.swift in Sources */,
|
||||
A1BA8D6BABAFA9BAAEAA3FFD /* NotificationSettingsProxyProtocol.swift in Sources */,
|
||||
@@ -4775,6 +4818,7 @@
|
||||
7FB0BDE26838F1A92782D5E1 /* MediaUploadPreviewScreenUITests.swift in Sources */,
|
||||
6713835120D94BAA8ED7E3E5 /* MessageForwardingScreenUITests.swift in Sources */,
|
||||
51C240F4660F7269203A9B3A /* MigrationScreenUITests.swift in Sources */,
|
||||
1830E5431DB426E2F3660D58 /* NotificationSettingsEditScreenUITests.swift in Sources */,
|
||||
AF4232E6F08C3DB86FFA9BBD /* NotificationSettingsScreenUITests.swift in Sources */,
|
||||
6B15FF984906AAFCF9DC4F58 /* OnboardingUITests.swift in Sources */,
|
||||
BA0D3DDCEDD97502DAC4B6E9 /* ReportContentScreenUITests.swift in Sources */,
|
||||
|
||||
@@ -266,6 +266,9 @@
|
||||
"screen_notification_settings_additional_settings_section_title" = "Additional settings";
|
||||
"screen_notification_settings_calls_label" = "Audio and video calls";
|
||||
"screen_notification_settings_direct_chats" = "Direct chats";
|
||||
"screen_notification_settings_edit_failed_updating_default_mode" = "An error occurred while updating the notification setting.";
|
||||
"screen_notification_settings_edit_screen_direct_section_header" = "On direct chats, notify me for";
|
||||
"screen_notification_settings_edit_screen_group_section_header" = "On group chats, notify me for";
|
||||
"screen_notification_settings_enable_notifications" = "Enable notifications on this device";
|
||||
"screen_notification_settings_group_chats" = "Group chats";
|
||||
"screen_notification_settings_mentions_section_title" = "Mentions";
|
||||
|
||||
@@ -640,7 +640,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private func presentNotificationSettingsScreen(animated: Bool) async {
|
||||
let navigationCoordinator = NavigationStackCoordinator()
|
||||
let parameters = await NotificationSettingsScreenCoordinatorParameters(userNotificationCenter: UNUserNotificationCenter.current(),
|
||||
let parameters = await NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationCoordinator,
|
||||
userNotificationCenter: UNUserNotificationCenter.current(),
|
||||
notificationSettings: userSession.clientProxy.notificationSettings(),
|
||||
isModallyPresented: true)
|
||||
let coordinator = NotificationSettingsScreenCoordinator(parameters: parameters)
|
||||
|
||||
@@ -688,6 +688,12 @@ public enum L10n {
|
||||
public static var screenNotificationSettingsCallsLabel: String { return L10n.tr("Localizable", "screen_notification_settings_calls_label") }
|
||||
/// Direct chats
|
||||
public static var screenNotificationSettingsDirectChats: String { return L10n.tr("Localizable", "screen_notification_settings_direct_chats") }
|
||||
/// An error occurred while updating the notification setting.
|
||||
public static var screenNotificationSettingsEditFailedUpdatingDefaultMode: String { return L10n.tr("Localizable", "screen_notification_settings_edit_failed_updating_default_mode") }
|
||||
/// On direct chats, notify me for
|
||||
public static var screenNotificationSettingsEditScreenDirectSectionHeader: String { return L10n.tr("Localizable", "screen_notification_settings_edit_screen_direct_section_header") }
|
||||
/// On group chats, notify me for
|
||||
public static var screenNotificationSettingsEditScreenGroupSectionHeader: String { return L10n.tr("Localizable", "screen_notification_settings_edit_screen_group_section_header") }
|
||||
/// Enable notifications on this device
|
||||
public static var screenNotificationSettingsEnableNotifications: String { return L10n.tr("Localizable", "screen_notification_settings_enable_notifications") }
|
||||
/// Group chats
|
||||
|
||||
@@ -365,27 +365,47 @@ class NotificationSettingsProxyMock: NotificationSettingsProxyProtocol {
|
||||
setNotificationModeRoomIdModeReceivedInvocations.append((roomId: roomId, mode: mode))
|
||||
try await setNotificationModeRoomIdModeClosure?(roomId, mode)
|
||||
}
|
||||
//MARK: - getDefaultNotificationRoomMode
|
||||
//MARK: - getDefaultRoomNotificationMode
|
||||
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneCallsCount = 0
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneCalled: Bool {
|
||||
return getDefaultNotificationRoomModeIsEncryptedIsOneToOneCallsCount > 0
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneCallsCount = 0
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneCalled: Bool {
|
||||
return getDefaultRoomNotificationModeIsEncryptedIsOneToOneCallsCount > 0
|
||||
}
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneReceivedArguments: (isEncrypted: Bool, isOneToOne: Bool)?
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneReceivedInvocations: [(isEncrypted: Bool, isOneToOne: Bool)] = []
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneReturnValue: RoomNotificationModeProxy!
|
||||
var getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure: ((Bool, Bool) async -> RoomNotificationModeProxy)?
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneReceivedArguments: (isEncrypted: Bool, isOneToOne: Bool)?
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneReceivedInvocations: [(isEncrypted: Bool, isOneToOne: Bool)] = []
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue: RoomNotificationModeProxy!
|
||||
var getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure: ((Bool, Bool) async -> RoomNotificationModeProxy)?
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy {
|
||||
getDefaultNotificationRoomModeIsEncryptedIsOneToOneCallsCount += 1
|
||||
getDefaultNotificationRoomModeIsEncryptedIsOneToOneReceivedArguments = (isEncrypted: isEncrypted, isOneToOne: isOneToOne)
|
||||
getDefaultNotificationRoomModeIsEncryptedIsOneToOneReceivedInvocations.append((isEncrypted: isEncrypted, isOneToOne: isOneToOne))
|
||||
if let getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure = getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure {
|
||||
return await getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure(isEncrypted, isOneToOne)
|
||||
func getDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy {
|
||||
getDefaultRoomNotificationModeIsEncryptedIsOneToOneCallsCount += 1
|
||||
getDefaultRoomNotificationModeIsEncryptedIsOneToOneReceivedArguments = (isEncrypted: isEncrypted, isOneToOne: isOneToOne)
|
||||
getDefaultRoomNotificationModeIsEncryptedIsOneToOneReceivedInvocations.append((isEncrypted: isEncrypted, isOneToOne: isOneToOne))
|
||||
if let getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure {
|
||||
return await getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure(isEncrypted, isOneToOne)
|
||||
} else {
|
||||
return getDefaultNotificationRoomModeIsEncryptedIsOneToOneReturnValue
|
||||
return getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - setDefaultRoomNotificationMode
|
||||
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeThrowableError: Error?
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount = 0
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCalled: Bool {
|
||||
return setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount > 0
|
||||
}
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedArguments: (isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy)?
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedInvocations: [(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy)] = []
|
||||
var setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeClosure: ((Bool, Bool, RoomNotificationModeProxy) async throws -> Void)?
|
||||
|
||||
func setDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy) async throws {
|
||||
if let error = setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeThrowableError {
|
||||
throw error
|
||||
}
|
||||
setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount += 1
|
||||
setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedArguments = (isEncrypted: isEncrypted, isOneToOne: isOneToOne, mode: mode)
|
||||
setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedInvocations.append((isEncrypted: isEncrypted, isOneToOne: isOneToOne, mode: mode))
|
||||
try await setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeClosure?(isEncrypted, isOneToOne, mode)
|
||||
}
|
||||
//MARK: - restoreDefaultNotificationMode
|
||||
|
||||
var restoreDefaultNotificationModeRoomIdThrowableError: Error?
|
||||
|
||||
@@ -35,7 +35,7 @@ extension NotificationSettingsProxyMock {
|
||||
|
||||
callbacks = configuration.callback
|
||||
getNotificationSettingsRoomIdIsEncryptedIsOneToOneReturnValue = configuration.roomMode
|
||||
getDefaultNotificationRoomModeIsEncryptedIsOneToOneReturnValue = configuration.defaultRoomMode
|
||||
getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = configuration.defaultRoomMode
|
||||
|
||||
setNotificationModeRoomIdModeClosure = { [weak self] _, mode in
|
||||
guard let self else { return }
|
||||
@@ -44,6 +44,15 @@ extension NotificationSettingsProxyMock {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeClosure = { [weak self] _, _, mode in
|
||||
guard let self else { return }
|
||||
self.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = mode
|
||||
Task {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
|
||||
restoreDefaultNotificationModeRoomIdClosure = { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.getNotificationSettingsRoomIdIsEncryptedIsOneToOneReturnValue = RoomNotificationSettingsProxyMock(with: .init(mode: configuration.defaultRoomMode, isDefault: true))
|
||||
@@ -51,6 +60,7 @@ extension NotificationSettingsProxyMock {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
|
||||
setRoomMentionEnabledEnabledClosure = { [weak self] enabled in
|
||||
guard let self else { return }
|
||||
self.isRoomMentionEnabledReturnValue = enabled
|
||||
@@ -58,6 +68,7 @@ extension NotificationSettingsProxyMock {
|
||||
self.callbacks.send(.settingsDidChange)
|
||||
}
|
||||
}
|
||||
|
||||
setCallEnabledEnabledClosure = { [weak self] enabled in
|
||||
guard let self else { return }
|
||||
self.isCallEnabledReturnValue = enabled
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Copyright 2022 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 Combine
|
||||
import SwiftUI
|
||||
|
||||
struct NotificationSettingsEditScreenCoordinatorParameters {
|
||||
let isDirect: Bool
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
}
|
||||
|
||||
enum NotificationSettingsEditScreenCoordinatorAction { }
|
||||
|
||||
final class NotificationSettingsEditScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: NotificationSettingsEditScreenCoordinatorParameters
|
||||
private var viewModel: NotificationSettingsEditScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<NotificationSettingsEditScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables: Set<AnyCancellable> = .init()
|
||||
|
||||
var actions: AnyPublisher<NotificationSettingsEditScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: NotificationSettingsEditScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: parameters.isDirect,
|
||||
notificationSettingsProxy: parameters.notificationSettings)
|
||||
}
|
||||
|
||||
func start() {
|
||||
viewModel.fetchInitialContent()
|
||||
}
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(NotificationSettingsEditScreen(context: viewModel.context))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2022 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
|
||||
|
||||
enum NotificationSettingsEditScreenViewModelAction { }
|
||||
|
||||
enum NotificationSettingsEditScreenDefaultMode {
|
||||
case allMessages
|
||||
case mentionsAndKeywordsOnly
|
||||
}
|
||||
|
||||
struct NotificationSettingsEditScreenViewState: BindableState {
|
||||
var bindings: NotificationSettingsEditScreenViewStateBindings
|
||||
var strings: NotificationSettingsEditScreenStrings
|
||||
var isDirect: Bool
|
||||
var availableDefaultModes: [NotificationSettingsEditScreenDefaultMode] = [.allMessages, .mentionsAndKeywordsOnly]
|
||||
var defaultMode: NotificationSettingsEditScreenDefaultMode?
|
||||
var pendingMode: NotificationSettingsEditScreenDefaultMode?
|
||||
|
||||
func isSelected(mode: NotificationSettingsEditScreenDefaultMode) -> Bool {
|
||||
pendingMode == nil && defaultMode == mode
|
||||
}
|
||||
}
|
||||
|
||||
struct NotificationSettingsEditScreenViewStateBindings {
|
||||
var alertInfo: AlertInfo<NotificationSettingsEditScreenErrorType>?
|
||||
}
|
||||
|
||||
enum NotificationSettingsEditScreenViewAction {
|
||||
case setMode(NotificationSettingsEditScreenDefaultMode)
|
||||
}
|
||||
|
||||
enum NotificationSettingsEditScreenErrorType: Hashable {
|
||||
case setModeFailed
|
||||
}
|
||||
|
||||
struct NotificationSettingsEditScreenStrings {
|
||||
let navigationTitle: String
|
||||
let modeSectionTitle: String
|
||||
|
||||
init(isDirect: Bool) {
|
||||
if isDirect {
|
||||
navigationTitle = L10n.screenNotificationSettingsDirectChats
|
||||
modeSectionTitle = L10n.screenNotificationSettingsEditScreenDirectSectionHeader
|
||||
} else {
|
||||
navigationTitle = L10n.screenNotificationSettingsGroupChats
|
||||
modeSectionTitle = L10n.screenNotificationSettingsEditScreenGroupSectionHeader
|
||||
}
|
||||
}
|
||||
|
||||
func string(for mode: NotificationSettingsEditScreenDefaultMode) -> String {
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
return L10n.screenNotificationSettingsModeAll
|
||||
case .mentionsAndKeywordsOnly:
|
||||
return L10n.screenNotificationSettingsModeMentions
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// Copyright 2022 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 Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias NotificationSettingsEditScreenViewModelType = StateStoreViewModel<NotificationSettingsEditScreenViewState, NotificationSettingsEditScreenViewAction>
|
||||
|
||||
class NotificationSettingsEditScreenViewModel: NotificationSettingsEditScreenViewModelType, NotificationSettingsEditScreenViewModelProtocol {
|
||||
private var actionsSubject: PassthroughSubject<NotificationSettingsEditScreenViewModelAction, Never> = .init()
|
||||
private let isDirect: Bool
|
||||
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
@CancellableTask private var fetchSettingsTask: Task<Void, Error>?
|
||||
|
||||
var actions: AnyPublisher<NotificationSettingsEditScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(isDirect: Bool, notificationSettingsProxy: NotificationSettingsProxyProtocol) {
|
||||
let bindings = NotificationSettingsEditScreenViewStateBindings()
|
||||
self.isDirect = isDirect
|
||||
self.notificationSettingsProxy = notificationSettingsProxy
|
||||
super.init(initialViewState: NotificationSettingsEditScreenViewState(bindings: bindings,
|
||||
strings: NotificationSettingsEditScreenStrings(isDirect: isDirect),
|
||||
isDirect: isDirect))
|
||||
|
||||
setupNotificationSettingsSubscription()
|
||||
}
|
||||
|
||||
func fetchInitialContent() {
|
||||
fetchSettings()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: NotificationSettingsEditScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .setMode(let mode):
|
||||
setMode(mode)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupNotificationSettingsSubscription() {
|
||||
notificationSettingsProxy.callbacks
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] callback in
|
||||
guard let self else { return }
|
||||
|
||||
switch callback {
|
||||
case .settingsDidChange:
|
||||
self.fetchSettings()
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func fetchSettings() {
|
||||
fetchSettingsTask = Task {
|
||||
var mode: RoomNotificationModeProxy?
|
||||
let encrypted_mode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: true, isOneToOne: isDirect)
|
||||
let unencrypted_mode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: false, isOneToOne: isDirect)
|
||||
if encrypted_mode == unencrypted_mode {
|
||||
mode = encrypted_mode
|
||||
}
|
||||
guard !Task.isCancelled else { return }
|
||||
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
state.defaultMode = .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
state.defaultMode = .mentionsAndKeywordsOnly
|
||||
default:
|
||||
state.defaultMode = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func setMode(_ mode: NotificationSettingsEditScreenDefaultMode) {
|
||||
guard state.pendingMode == nil, !state.isSelected(mode: mode) else { return }
|
||||
let roomNotificationModeProxy: RoomNotificationModeProxy
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
roomNotificationModeProxy = .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
roomNotificationModeProxy = .mentionsAndKeywordsOnly
|
||||
}
|
||||
state.pendingMode = mode
|
||||
Task {
|
||||
do {
|
||||
try await notificationSettingsProxy.setDefaultRoomNotificationMode(isEncrypted: true, isOneToOne: isDirect, mode: roomNotificationModeProxy)
|
||||
try await notificationSettingsProxy.setDefaultRoomNotificationMode(isEncrypted: false, isOneToOne: isDirect, mode: roomNotificationModeProxy)
|
||||
} catch {
|
||||
let retryAction: () -> Void = { [weak self] in
|
||||
self?.setMode(mode)
|
||||
}
|
||||
state.bindings.alertInfo = AlertInfo(id: .setModeFailed,
|
||||
title: L10n.commonError,
|
||||
message: L10n.screenNotificationSettingsEditFailedUpdatingDefaultMode,
|
||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.actionRetry, action: retryAction))
|
||||
}
|
||||
state.pendingMode = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2022 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 Combine
|
||||
|
||||
@MainActor
|
||||
protocol NotificationSettingsEditScreenViewModelProtocol {
|
||||
var actions: AnyPublisher<NotificationSettingsEditScreenViewModelAction, Never> { get }
|
||||
var context: NotificationSettingsEditScreenViewModelType.Context { get }
|
||||
|
||||
func fetchInitialContent()
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright 2022 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 SwiftUI
|
||||
|
||||
struct NotificationSettingsEditScreen: View {
|
||||
@ObservedObject var context: NotificationSettingsEditScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
notificationModeSection
|
||||
}
|
||||
.compoundForm()
|
||||
.navigationTitle(context.viewState.strings.navigationTitle)
|
||||
.alert(item: $context.alertInfo)
|
||||
.track(screen: .settingsDefaultNotifications)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private var notificationModeSection: some View {
|
||||
Section {
|
||||
ForEach(context.viewState.availableDefaultModes, id: \.self) { mode in
|
||||
Button {
|
||||
context.send(viewAction: .setMode(mode))
|
||||
} label: {
|
||||
LabeledContent {
|
||||
if context.viewState.pendingMode == mode {
|
||||
ProgressView()
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
} label: {
|
||||
Text(context.viewState.strings.string(for: mode))
|
||||
}
|
||||
}
|
||||
.buttonStyle(.compoundForm(accessory: .selected(context.viewState.isSelected(mode: mode))))
|
||||
.disabled(context.viewState.pendingMode != nil)
|
||||
}
|
||||
} header: {
|
||||
Text(context.viewState.strings.modeSectionTitle)
|
||||
.compoundFormSectionHeader()
|
||||
}
|
||||
.compoundFormSection()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct NotificationSettingsEditScreen_Previews: PreviewProvider {
|
||||
static let viewModelGroupChats: NotificationSettingsEditScreenViewModel = {
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .allMessages
|
||||
var viewModel = NotificationSettingsEditScreenViewModel(isDirect: false,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
viewModel.fetchInitialContent()
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static let viewModelDirectChats: NotificationSettingsEditScreenViewModel = {
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly
|
||||
var viewModel = NotificationSettingsEditScreenViewModel(isDirect: true,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
viewModel.fetchInitialContent()
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static let viewModelDirectApplyingChange: NotificationSettingsEditScreenViewModel = {
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly
|
||||
var viewModel = NotificationSettingsEditScreenViewModel(isDirect: true,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
viewModel.state.pendingMode = .mentionsAndKeywordsOnly
|
||||
viewModel.fetchInitialContent()
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
NotificationSettingsEditScreen(context: viewModelGroupChats.context)
|
||||
.previewDisplayName("Group Chats")
|
||||
NotificationSettingsEditScreen(context: viewModelDirectChats.context)
|
||||
.previewDisplayName("Direct Chats")
|
||||
NotificationSettingsEditScreen(context: viewModelDirectApplyingChange.context)
|
||||
.previewDisplayName("Applying change")
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct NotificationSettingsScreenCoordinatorParameters {
|
||||
weak var navigationStackCoordinator: NavigationStackCoordinator?
|
||||
let userNotificationCenter: UserNotificationCenterProtocol
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
let isModallyPresented: Bool
|
||||
@@ -32,7 +33,11 @@ final class NotificationSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
private var viewModel: NotificationSettingsScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<NotificationSettingsScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables: Set<AnyCancellable> = .init()
|
||||
|
||||
|
||||
private var navigationStackCoordinator: NavigationStackCoordinator? {
|
||||
parameters.navigationStackCoordinator
|
||||
}
|
||||
|
||||
var actions: AnyPublisher<NotificationSettingsScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
@@ -50,15 +55,27 @@ final class NotificationSettingsScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel.fetchInitialContent()
|
||||
|
||||
viewModel.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .close:
|
||||
self?.actionsSubject.send(.close)
|
||||
self.actionsSubject.send(.close)
|
||||
case .editDefaultMode(let isDirect):
|
||||
self.presentEditScreen(isDirect: isDirect)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(NotificationSettingsScreen(context: viewModel.context))
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func presentEditScreen(isDirect: Bool) {
|
||||
let editSettingsParameters = NotificationSettingsEditScreenCoordinatorParameters(isDirect: isDirect,
|
||||
notificationSettings: parameters.notificationSettings)
|
||||
let editSettingsCoordinator = NotificationSettingsEditScreenCoordinator(parameters: editSettingsParameters)
|
||||
navigationStackCoordinator?.push(editSettingsCoordinator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import UIKit
|
||||
|
||||
enum NotificationSettingsScreenViewModelAction {
|
||||
case close
|
||||
case editDefaultMode(isDirect: Bool)
|
||||
}
|
||||
|
||||
struct NotificationSettingsScreenViewState: BindableState {
|
||||
|
||||
@@ -60,9 +60,9 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
|
||||
case .changedEnableNotifications:
|
||||
toggleNotifications()
|
||||
case .groupChatsTapped:
|
||||
break
|
||||
actionsSubject.send(.editDefaultMode(isDirect: false))
|
||||
case .directChatsTapped:
|
||||
break
|
||||
actionsSubject.send(.editDefaultMode(isDirect: true))
|
||||
case .roomMentionChanged:
|
||||
guard let settings = state.settings, settings.roomMentionsEnabled != state.bindings.roomMentionsEnabled else {
|
||||
return
|
||||
@@ -120,14 +120,12 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
|
||||
private func fetchSettings() {
|
||||
fetchSettingsTask = Task {
|
||||
// Group chats
|
||||
// A group chat is a chat having more than 2 active members
|
||||
var groupChatsMode = await notificationSettingsProxy.getDefaultNotificationRoomMode(isEncrypted: false, isOneToOne: false)
|
||||
let encryptedGroupChatsMode = await notificationSettingsProxy.getDefaultNotificationRoomMode(isEncrypted: true, isOneToOne: false)
|
||||
var groupChatsMode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: false, isOneToOne: false)
|
||||
let encryptedGroupChatsMode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: true, isOneToOne: false)
|
||||
|
||||
// Direct chats
|
||||
// A direct chat is a chat having exactly 2 active members
|
||||
var directChatsMode = await notificationSettingsProxy.getDefaultNotificationRoomMode(isEncrypted: false, isOneToOne: true)
|
||||
let encryptedDirectChatsMode = await notificationSettingsProxy.getDefaultNotificationRoomMode(isEncrypted: true, isOneToOne: true)
|
||||
var directChatsMode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: false, isOneToOne: true)
|
||||
let encryptedDirectChatsMode = await notificationSettingsProxy.getDefaultRoomNotificationMode(isEncrypted: true, isOneToOne: true)
|
||||
|
||||
// Old clients were having specific settings for encrypted and unencrypted rooms,
|
||||
// so it's possible for `group chats` and `direct chats` settings to be inconsistent (e.g. encrypted `direct chats` can have a different mode that unencrypted `direct chats`)
|
||||
|
||||
@@ -183,7 +183,7 @@ struct NotificationSettingsScreen_Previews: PreviewProvider {
|
||||
let notificationCenter = UserNotificationCenterMock()
|
||||
notificationCenter.authorizationStatusReturnValue = .notDetermined
|
||||
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
|
||||
notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
switch (isEncrypted, isOneToOne) {
|
||||
case (_, true):
|
||||
return .allMessages
|
||||
|
||||
@@ -141,7 +141,8 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func presentNotificationSettings() {
|
||||
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(userNotificationCenter: UNUserNotificationCenter.current(),
|
||||
let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: parameters.navigationStackCoordinator,
|
||||
userNotificationCenter: UNUserNotificationCenter.current(),
|
||||
notificationSettings: parameters.notificationSettings,
|
||||
isModallyPresented: false)
|
||||
let coordinator = NotificationSettingsScreenCoordinator(parameters: notificationParameters)
|
||||
|
||||
@@ -55,23 +55,22 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
let roomNotificationMode: RoomNotificationMode
|
||||
switch mode {
|
||||
case .allMessages:
|
||||
roomNotificationMode = .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
roomNotificationMode = .mentionsAndKeywordsOnly
|
||||
case .mute:
|
||||
roomNotificationMode = .mute
|
||||
}
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: roomNotificationMode)
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: mode.roomNotificationMode)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy {
|
||||
func getDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy {
|
||||
let roomNotificationMode = await notificationSettings.getDefaultRoomNotificationMode(isEncrypted: isEncrypted, isOneToOne: isOneToOne)
|
||||
return RoomNotificationModeProxy.from(roomNotificationMode: roomNotificationMode)
|
||||
}
|
||||
|
||||
func setDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setDefaultRoomNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setDefaultRoomNotificationMode(isEncrypted: isEncrypted, isOneToOne: isOneToOne, mode: mode.roomNotificationMode)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "restoreDefaultNotificationMode")
|
||||
@@ -132,7 +131,11 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
// MARK: - Private
|
||||
|
||||
func updatedSettings() async {
|
||||
_ = await callbacks.values.first(where: { $0 == .settingsDidChange })
|
||||
// The timeout avoids having to wait indefinitely. This can happen when setting a mode that is already the current mode,
|
||||
// as in this case no API call is made by the RustSDK and the push rules are therefore not updated.
|
||||
_ = await callbacks
|
||||
.timeout(.seconds(2.0), scheduler: DispatchQueue.main, options: nil, customError: nil)
|
||||
.values.first(where: { $0 == .settingsDidChange })
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
||||
@@ -28,7 +28,8 @@ protocol NotificationSettingsProxyProtocol {
|
||||
|
||||
func getNotificationSettings(roomId: String, isEncrypted: Bool, isOneToOne: Bool) async throws -> RoomNotificationSettingsProxyProtocol
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws
|
||||
func getDefaultNotificationRoomMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy
|
||||
func getDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool) async -> RoomNotificationModeProxy
|
||||
func setDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy) async throws
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws
|
||||
func containsKeywordsRules() async -> Bool
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, isOneToOne: Bool) async throws
|
||||
|
||||
@@ -34,4 +34,15 @@ extension RoomNotificationModeProxy {
|
||||
return .mute
|
||||
}
|
||||
}
|
||||
|
||||
var roomNotificationMode: RoomNotificationMode {
|
||||
switch self {
|
||||
case .allMessages:
|
||||
return .allMessages
|
||||
case .mentionsAndKeywordsOnly:
|
||||
return .mentionsAndKeywordsOnly
|
||||
case .mute:
|
||||
return .mute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
UITests/Sources/NotificationSettingsEditScreenUITests.swift
Normal file
21
UITests/Sources/NotificationSettingsEditScreenUITests.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright 2022 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 ElementX
|
||||
import XCTest
|
||||
|
||||
@MainActor
|
||||
class NotificationSettingsEditScreenUITests: XCTestCase { }
|
||||
@@ -0,0 +1,203 @@
|
||||
//
|
||||
// Copyright 2022 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 MatrixRustSDK
|
||||
import XCTest
|
||||
|
||||
@testable import ElementX
|
||||
|
||||
@MainActor
|
||||
class NotificationSettingsEditScreenViewModelTests: XCTestCase {
|
||||
private var viewModel: NotificationSettingsEditScreenViewModelProtocol!
|
||||
private var notificationSettingsProxy: NotificationSettingsProxyMock!
|
||||
|
||||
private var context: NotificationSettingsEditScreenViewModelType.Context {
|
||||
viewModel.context
|
||||
}
|
||||
|
||||
@MainActor override func setUpWithError() throws {
|
||||
notificationSettingsProxy = NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration())
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .allMessages
|
||||
}
|
||||
|
||||
func testFetchSettings() async throws {
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
switch (isEncrypted, isOneToOne) {
|
||||
case (_, true):
|
||||
return .allMessages
|
||||
case (_, _):
|
||||
return .mentionsAndKeywordsOnly
|
||||
}
|
||||
}
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: false,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.map(\.defaultMode)
|
||||
.first(where: { !$0.isNil }))
|
||||
viewModel.fetchInitialContent()
|
||||
try await deferred.fulfill()
|
||||
|
||||
// `getDefaultRoomNotificationModeIsEncryptedIsOneToOne` must have been called twice (for encrypted and unencrypted group chats)
|
||||
let invocations = notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReceivedInvocations
|
||||
|
||||
XCTAssertEqual(invocations.count, 2)
|
||||
// First call for encrypted group chats
|
||||
XCTAssertEqual(invocations[0].isEncrypted, true)
|
||||
XCTAssertEqual(invocations[0].isOneToOne, false)
|
||||
// Second call for unencrypted group chats
|
||||
XCTAssertEqual(invocations[1].isEncrypted, false)
|
||||
XCTAssertEqual(invocations[1].isOneToOne, false)
|
||||
|
||||
XCTAssertEqual(context.viewState.defaultMode, .mentionsAndKeywordsOnly)
|
||||
XCTAssertNil(context.viewState.bindings.alertInfo)
|
||||
}
|
||||
|
||||
func testSetModeAllMessages() async throws {
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: false,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.map(\.defaultMode)
|
||||
.first(where: { !$0.isNil }))
|
||||
viewModel.fetchInitialContent()
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Set mode to .allMessages
|
||||
let deferredViewState = deferFulfillment(context.$viewState
|
||||
.map(\.pendingMode)
|
||||
.removeDuplicates()
|
||||
.collect(3).first())
|
||||
context.send(viewAction: .setMode(.allMessages))
|
||||
let pendingModes = try await deferredViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(pendingModes, [nil, .allMessages, nil])
|
||||
|
||||
// `setDefaultRoomNotificationModeIsEncryptedIsOneToOneMode` must have been called twice (for encrypted and unencrypted group chats)
|
||||
let invocations = notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedInvocations
|
||||
XCTAssertEqual(notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount, 2)
|
||||
// First call for encrypted group chats
|
||||
XCTAssertEqual(invocations[0].isEncrypted, true)
|
||||
XCTAssertEqual(invocations[0].isOneToOne, false)
|
||||
XCTAssertEqual(invocations[0].mode, .allMessages)
|
||||
// Second call for unencrypted group chats
|
||||
XCTAssertEqual(invocations[1].isEncrypted, false)
|
||||
XCTAssertEqual(invocations[1].isOneToOne, false)
|
||||
XCTAssertEqual(invocations[1].mode, .allMessages)
|
||||
|
||||
// The default mode should be updated
|
||||
let deferredNewViewState = deferFulfillment(context.$viewState
|
||||
.map(\.defaultMode)
|
||||
.first(where: { $0 == .allMessages }))
|
||||
try await deferredNewViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(context.viewState.defaultMode, .allMessages)
|
||||
XCTAssertNil(context.viewState.bindings.alertInfo)
|
||||
}
|
||||
|
||||
func testSetModeMentions() async throws {
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: false,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.map(\.defaultMode)
|
||||
.first(where: { !$0.isNil }))
|
||||
viewModel.fetchInitialContent()
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Set mode to .allMessages
|
||||
let deferredViewState = deferFulfillment(context.$viewState
|
||||
.map(\.pendingMode)
|
||||
.removeDuplicates()
|
||||
.collect(3).first())
|
||||
context.send(viewAction: .setMode(.mentionsAndKeywordsOnly))
|
||||
let pendingModes = try await deferredViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(pendingModes, [nil, .mentionsAndKeywordsOnly, nil])
|
||||
|
||||
// `setDefaultRoomNotificationModeIsEncryptedIsOneToOneMode` must have been called twice (for encrypted and unencrypted group chats)
|
||||
let invocations = notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedInvocations
|
||||
XCTAssertEqual(notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount, 2)
|
||||
// First call for encrypted group chats
|
||||
XCTAssertEqual(invocations[0].isEncrypted, true)
|
||||
XCTAssertEqual(invocations[0].isOneToOne, false)
|
||||
XCTAssertEqual(invocations[0].mode, .mentionsAndKeywordsOnly)
|
||||
// Second call for unencrypted group chats
|
||||
XCTAssertEqual(invocations[1].isEncrypted, false)
|
||||
XCTAssertEqual(invocations[1].isOneToOne, false)
|
||||
XCTAssertEqual(invocations[1].mode, .mentionsAndKeywordsOnly)
|
||||
|
||||
// The default mode should be updated
|
||||
let deferredNewViewState = deferFulfillment(context.$viewState
|
||||
.map(\.defaultMode)
|
||||
.first(where: { $0 == .mentionsAndKeywordsOnly }))
|
||||
try await deferredNewViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(context.viewState.defaultMode, .mentionsAndKeywordsOnly)
|
||||
XCTAssertNil(context.viewState.bindings.alertInfo)
|
||||
}
|
||||
|
||||
func testSetModeDirectChats() async throws {
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly
|
||||
// Initialize for direct chats
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: true,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.map(\.defaultMode)
|
||||
.first(where: { !$0.isNil }))
|
||||
viewModel.fetchInitialContent()
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Set mode to .allMessages
|
||||
let deferredViewState = deferFulfillment(context.$viewState
|
||||
.map(\.pendingMode)
|
||||
.removeDuplicates()
|
||||
.collect(3).first())
|
||||
context.send(viewAction: .setMode(.allMessages))
|
||||
let pendingModes = try await deferredViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(pendingModes, [nil, .allMessages, nil])
|
||||
|
||||
// `setDefaultRoomNotificationModeIsEncryptedIsOneToOneMode` must have been called twice (for encrypted and unencrypted direct chats)
|
||||
let invocations = notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeReceivedInvocations
|
||||
XCTAssertEqual(notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeCallsCount, 2)
|
||||
// First call for encrypted direct chats
|
||||
XCTAssertEqual(invocations[0].isEncrypted, true)
|
||||
XCTAssertEqual(invocations[0].isOneToOne, true)
|
||||
XCTAssertEqual(invocations[0].mode, .allMessages)
|
||||
// Second call for unencrypted direct chats
|
||||
XCTAssertEqual(invocations[1].isEncrypted, false)
|
||||
XCTAssertEqual(invocations[1].isOneToOne, true)
|
||||
XCTAssertEqual(invocations[1].mode, .allMessages)
|
||||
}
|
||||
|
||||
func testSetModeFailure() async throws {
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .mentionsAndKeywordsOnly
|
||||
notificationSettingsProxy.setDefaultRoomNotificationModeIsEncryptedIsOneToOneModeThrowableError = NotificationSettingsError.Generic(message: "error")
|
||||
viewModel = NotificationSettingsEditScreenViewModel(isDirect: true,
|
||||
notificationSettingsProxy: notificationSettingsProxy)
|
||||
let deferred = deferFulfillment(viewModel.context.$viewState.map(\.defaultMode)
|
||||
.first(where: { !$0.isNil }))
|
||||
viewModel.fetchInitialContent()
|
||||
try await deferred.fulfill()
|
||||
|
||||
// Set mode to .allMessages
|
||||
let deferredViewState = deferFulfillment(context.$viewState
|
||||
.map(\.pendingMode)
|
||||
.removeDuplicates()
|
||||
.collect(3).first())
|
||||
context.send(viewAction: .setMode(.allMessages))
|
||||
let pendingModes = try await deferredViewState.fulfill()
|
||||
|
||||
XCTAssertEqual(pendingModes, [nil, .allMessages, nil])
|
||||
XCTAssertNotNil(context.viewState.bindings.alertInfo)
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase {
|
||||
userNotificationCenter.authorizationStatusReturnValue = .authorized
|
||||
appSettings = AppSettings()
|
||||
notificationSettingsProxy = NotificationSettingsProxyMock(with: NotificationSettingsProxyMockConfiguration())
|
||||
notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneReturnValue = .allMessages
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneReturnValue = .allMessages
|
||||
notificationSettingsProxy.isRoomMentionEnabledReturnValue = true
|
||||
notificationSettingsProxy.isCallEnabledReturnValue = true
|
||||
|
||||
@@ -58,7 +58,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testFetchSettings() async throws {
|
||||
notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
switch (isEncrypted, isOneToOne) {
|
||||
case (_, true):
|
||||
return .allMessages
|
||||
@@ -71,7 +71,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase {
|
||||
notificationSettingsProxy.callbacks.send(.settingsDidChange)
|
||||
try await deferred.fulfill()
|
||||
|
||||
XCTAssertEqual(notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneCallsCount, 4)
|
||||
XCTAssertEqual(notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneCallsCount, 4)
|
||||
XCTAssert(notificationSettingsProxy.isRoomMentionEnabledCalled)
|
||||
XCTAssert(notificationSettingsProxy.isCallEnabledCalled)
|
||||
|
||||
@@ -82,7 +82,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testInconsistentGroupChatsSettings() async throws {
|
||||
notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
switch (isEncrypted, isOneToOne) {
|
||||
case (true, false):
|
||||
return .allMessages
|
||||
@@ -103,7 +103,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testInconsistentDirectChatsSettings() async throws {
|
||||
notificationSettingsProxy.getDefaultNotificationRoomModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
notificationSettingsProxy.getDefaultRoomNotificationModeIsEncryptedIsOneToOneClosure = { isEncrypted, isOneToOne in
|
||||
switch (isEncrypted, isOneToOne) {
|
||||
case (true, true):
|
||||
return .allMessages
|
||||
|
||||
@@ -426,6 +426,8 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
|
||||
notificationSettingsProxyMock.callbacks.send(.settingsDidChange)
|
||||
try await deferred.fulfill()
|
||||
|
||||
_ = await context.$viewState.debounce(for: .milliseconds(100), scheduler: DispatchQueue.main).values.first()
|
||||
|
||||
XCTAssertEqual(context.viewState.notificationShortcutButtonTitle, L10n.commonUnmute)
|
||||
XCTAssertEqual(context.viewState.notificationShortcutButtonImage, Image(systemName: "bell.slash.fill"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user