Edit the default notification settings (#1468)

This commit is contained in:
Nicolas Mauri
2023-08-11 16:10:23 +02:00
committed by GitHub
parent 5256c5ae20
commit 2102ebc01e
23 changed files with 760 additions and 48 deletions

View File

@@ -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 */,

View File

@@ -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";

View File

@@ -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)

View File

@@ -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

View File

@@ -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?

View File

@@ -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

View File

@@ -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))
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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()
}

View File

@@ -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")
}
}

View File

@@ -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)
}
}

View File

@@ -19,6 +19,7 @@ import UIKit
enum NotificationSettingsScreenViewModelAction {
case close
case editDefaultMode(isDirect: Bool)
}
struct NotificationSettingsScreenViewState: BindableState {

View File

@@ -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`)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}
}

View 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 { }

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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"))
}