diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index adcacb14c..84234c28d 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ 0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */; }; 0CF81807BE5FBFC9E2BBCECF /* PollFormScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3368395F06AA180138E185B6 /* PollFormScreenUITests.swift */; }; 0D4EB2ABAA5FE8CB10FDBCB8 /* TimelineItemFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */; }; + 0D617A152D099D94271D3BA8 /* SecurityAndPrivacyScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D046ABB22E680F7C5054441B /* SecurityAndPrivacyScreenViewModelProtocol.swift */; }; 0DC815CA24E1BD7F408F37D3 /* CollapsibleTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */; }; 0E08BB72B2258652CF501A8B /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = 2B9ACE4FCACB5A8812154424 /* Version */; }; 0E3A2787C6AEC761A81A938A /* AuthenticationStartScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8609BE4CA71C30D1FCE3AF9B /* AuthenticationStartScreenModels.swift */; }; @@ -466,6 +467,7 @@ 5FCD8AFA364206EE32B909A3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B050A6B233D95807A09289E7 /* Settings.bundle */; }; 601AB75BD52B0B4276CEB84A /* SessionVerificationScreenStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161CD412E75F4086F422AE39 /* SessionVerificationScreenStateMachine.swift */; }; 60ED66E63A169E47489348A8 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 886A0A498FA01E8EDD451D05 /* Sentry */; }; + 611BEE29B8B622204E1E6B04 /* SecurityAndPrivacyScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97F2F6B6E56055EF173A2DD3 /* SecurityAndPrivacyScreenCoordinator.swift */; }; 6146996D5C4DDD5DA816FC87 /* AuthenticationTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */; }; 617624A97BDBB75ED3DD8156 /* RoomScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */; }; 6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */; }; @@ -525,6 +527,7 @@ 6AEB650311F694A5702255C9 /* UserProfileScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B4932E4EFBC8FAC10972CD /* UserProfileScreenCoordinator.swift */; }; 6B31508C6334C617360C2EAB /* RoomMemberDetailsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */; }; 6B61F5B27412ED4BC2F9769C /* test_audio.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 66B96842BF5F8ACA1AC84C55 /* test_audio.mp3 */; }; + 6B80C24A52411EAF10E06E96 /* SecurityAndPrivacyScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBADF8010C813D905C172CE /* SecurityAndPrivacyScreenModels.swift */; }; 6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */; }; 6C34237AFB808E38FC8776B9 /* RoomStateEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */; }; 6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFE1F410969ECB23FE9BB2 /* TimelineItemMenu.swift */; }; @@ -552,6 +555,7 @@ 71AC1CAAC23403FFE847F2C9 /* ComposerToolbarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */; }; 71B62C48B8079D49F3FBC845 /* ExpiringTaskRunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */; }; 71C1347F23868324A4F43940 /* NavigationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22A05E472533ED3C5A31B3 /* NavigationModule.swift */; }; + 7254FB2EFDD43BC8BB7A1213 /* SecurityAndPrivacyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AE42C19EDE64B7CB7BE4D0 /* SecurityAndPrivacyScreen.swift */; }; 733E2B19AB1FDA3B93293A28 /* AppLockSetupPINScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3F275432954C8C6B1B7D966 /* AppLockSetupPINScreen.swift */; }; 7354D094A4C59B555F407FA1 /* RustTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542D4F49FABA056DEEEB3400 /* RustTracing.swift */; }; 73F33E9776B7A50B65A031D2 /* AppLockSettingsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BA67B3E4EF9D29D14A78CE /* AppLockSettingsScreenViewModelTests.swift */; }; @@ -613,6 +617,7 @@ 7C0E29E0279866C62EC67A28 /* JoinRoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5127D6EA05B2E45D0A7D59 /* JoinRoomScreenViewModelTests.swift */; }; 7C164A642E8932B5F9004550 /* test_voice_message.m4a in Resources */ = {isa = PBXBuildFile; fileRef = DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */; }; 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; + 7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */; }; 7C6376192F578E0BA801BFEC /* AnalyticsSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */; }; 7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */; }; 7D249465ED00988EEEC14E05 /* JoinedRoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */; }; @@ -993,6 +998,7 @@ CB6956565D858C523E3E3B16 /* ComposerDraftServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */; }; CB6BCBF28E4B76EA08C2926D /* StateRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */; }; CB99B0FA38A4AC596F38CC13 /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */; }; + CB9FB2BEF313072C705AC9B5 /* SecurityAndPrivacyScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0315C328FF40F84276364E66 /* SecurityAndPrivacyScreenViewModelTests.swift */; }; CBA9EDF305036039166E76FF /* StartChatScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2AEC1AB349A341FE13DEC1 /* StartChatScreenUITests.swift */; }; CBD2ABE4C1A47ECD99E1488E /* NotificationSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421FA93BCC2840E66E4F306F /* NotificationSettingsScreenViewModelProtocol.swift */; }; CC0D088F505F33A20DC5590F /* RoomStateEventStringBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEAFB646E583655652C3D04 /* RoomStateEventStringBuilderTests.swift */; }; @@ -1322,6 +1328,7 @@ 029D5701F80A9AF7167BB4D0 /* TimelineModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineModels.swift; sourceTree = ""; }; 02D155E09BF961BBA8F85263 /* InviteUsersScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenViewModel.swift; sourceTree = ""; }; 02EE0FABA8ED6D6C1D6CE71D /* ReactionsSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsSummaryView.swift; sourceTree = ""; }; + 0315C328FF40F84276364E66 /* SecurityAndPrivacyScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenViewModelTests.swift; sourceTree = ""; }; 03277E40D0E0DE0712021A71 /* ServerConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenCoordinator.swift; sourceTree = ""; }; 033DB41C51865A2E83174E87 /* target.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = target.yml; sourceTree = ""; }; 035177BCD8E8308B098AC3C2 /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = ""; }; @@ -1884,6 +1891,7 @@ 7B3D16709ADD4F4BCC710B1E /* SecureBackupScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenModels.swift; sourceTree = ""; }; 7B849D2FF2CC12BA411A1651 /* CreateRoomModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomModels.swift; sourceTree = ""; }; 7B9FCA1CFD07B8CF9BD21266 /* FlowCoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCoordinatorProtocol.swift; sourceTree = ""; }; + 7BBADF8010C813D905C172CE /* SecurityAndPrivacyScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenModels.swift; sourceTree = ""; }; 7C1AF829F12FDC99717082D9 /* RoomRolesAndPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenViewModel.swift; sourceTree = ""; }; 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenCoordinator.swift; sourceTree = ""; }; 7C71B9802433F1B4252291BB /* IdentityConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -2014,9 +2022,11 @@ 974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPermissions.swift; sourceTree = ""; }; 976ED77B772F50C4BAD757E7 /* MediaEventsTimelineScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaEventsTimelineScreenViewModel.swift; sourceTree = ""; }; 9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModelProtocol.swift; sourceTree = ""; }; + 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenViewModel.swift; sourceTree = ""; }; 97B2ACA28A854E41AE3AC9AD /* TimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModel.swift; sourceTree = ""; }; 97C8E13A1FBA717B0C277ECC /* ProgressCursorModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressCursorModifier.swift; sourceTree = ""; }; 97CE98208321C4D66E363612 /* ShimmerModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShimmerModifier.swift; sourceTree = ""; }; + 97F2F6B6E56055EF173A2DD3 /* SecurityAndPrivacyScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenCoordinator.swift; sourceTree = ""; }; 981663D961C94270FA035FD0 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenUITests.swift; sourceTree = ""; }; 989D7380D9C86B3A10D30B13 /* AppLockSetupPINScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupPINScreenViewModelTests.swift; sourceTree = ""; }; @@ -2153,6 +2163,7 @@ B43456E73F8A2D52B69B9FB9 /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = ""; }; B4427AF4B7FB7EF3E3D424C7 /* QRCodeLoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeLoginService.swift; sourceTree = ""; }; B48B7AD4908C5C374517B892 /* MapAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MapAssets.xcassets; sourceTree = ""; }; + B4AE42C19EDE64B7CB7BE4D0 /* SecurityAndPrivacyScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreen.swift; sourceTree = ""; }; B4CFE236419E830E8946639C /* Analytics+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Analytics+SwiftUI.swift"; sourceTree = ""; }; B50F03079F6B5EF9CA005F14 /* TimelineProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyProtocol.swift; sourceTree = ""; }; B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = ""; }; @@ -2282,6 +2293,7 @@ CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = ""; }; CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = ""; }; D01FD1171FF40E34D707FD00 /* BigIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigIcon.swift; sourceTree = ""; }; + D046ABB22E680F7C5054441B /* SecurityAndPrivacyScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenViewModelProtocol.swift; sourceTree = ""; }; D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = ""; }; D086854995173E897F993C26 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = ""; }; D09227E671DB30795C43FFFD /* KnockRequestsListScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KnockRequestsListScreenViewModel.swift; sourceTree = ""; }; @@ -3118,6 +3130,14 @@ path = Style; sourceTree = ""; }; + 31602635E5D50101A3A24D51 /* View */ = { + isa = PBXGroup; + children = ( + B4AE42C19EDE64B7CB7BE4D0 /* SecurityAndPrivacyScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 31CE4DA53232AA534057F912 /* Mocks */ = { isa = PBXGroup; children = ( @@ -4147,6 +4167,7 @@ 848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */, C0FF08D0BD7D0B4B6877AB7D /* SecureBackupRecoveryKeyScreenViewModelTests.swift */, 40316EFFEAC7B206EE9A55AE /* SecureBackupScreenViewModelTests.swift */, + 0315C328FF40F84276364E66 /* SecurityAndPrivacyScreenViewModelTests.swift */, 277C20CDD5B64510401B6D0D /* ServerConfigurationScreenViewStateTests.swift */, F08776C48FFB47CACF64ED10 /* ServerConfirmationScreenViewModelTests.swift */, E45EBAFF1A83538D54ABDF92 /* ServerSelectionScreenViewModelTests.swift */, @@ -5256,6 +5277,18 @@ path = RoomDirectorySearchScreen; sourceTree = ""; }; + C59BA103987B953BA374509F /* SecurityAndPrivacyScreen */ = { + isa = PBXGroup; + children = ( + 97F2F6B6E56055EF173A2DD3 /* SecurityAndPrivacyScreenCoordinator.swift */, + 7BBADF8010C813D905C172CE /* SecurityAndPrivacyScreenModels.swift */, + 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */, + D046ABB22E680F7C5054441B /* SecurityAndPrivacyScreenViewModelProtocol.swift */, + 31602635E5D50101A3A24D51 /* View */, + ); + path = SecurityAndPrivacyScreen; + sourceTree = ""; + }; C844840F3DD48A154C65AE0C /* View */ = { isa = PBXGroup; children = ( @@ -5580,6 +5613,7 @@ 679E9837ECA8D6776079D16E /* RoomScreen */, 2E42D43DB6835A58D88B2F91 /* RoomSelectionScreen */, 2565414373E6F68005966B8E /* SecureBackup */, + C59BA103987B953BA374509F /* SecurityAndPrivacyScreen */, 70B74A432C241E56A7ACE610 /* Settings */, EC4545C7E37E8294D3FE6800 /* StartChatScreen */, 15D44FCA9475E660B7F56DB9 /* Timeline */, @@ -6593,6 +6627,7 @@ EB87DF90CF6F8D5D12404C6E /* SecureBackupLogoutConfirmationScreenViewModelTests.swift in Sources */, 06B31F84CE52A7A7C271267C /* SecureBackupRecoveryKeyScreenViewModelTests.swift in Sources */, 1B8E30B35BF8F541C1318F19 /* SecureBackupScreenViewModelTests.swift in Sources */, + CB9FB2BEF313072C705AC9B5 /* SecurityAndPrivacyScreenViewModelTests.swift in Sources */, 53A55748D5F587C9061F98BF /* ServerConfigurationScreenViewStateTests.swift in Sources */, 89658A44C9FC19B58FD1C226 /* ServerConfirmationScreenViewModelTests.swift in Sources */, 67ECD32538F6DAFE38A623F9 /* ServerSelectionScreenViewModelTests.swift in Sources */, @@ -7327,6 +7362,11 @@ DA7E867F5EAFF8E20B2EE3B6 /* SecureBackupScreenModels.swift in Sources */, 7BF368A78E6D9AFD222F25AF /* SecureBackupScreenViewModel.swift in Sources */, AC90434798E7894370E80E66 /* SecureBackupScreenViewModelProtocol.swift in Sources */, + 7254FB2EFDD43BC8BB7A1213 /* SecurityAndPrivacyScreen.swift in Sources */, + 611BEE29B8B622204E1E6B04 /* SecurityAndPrivacyScreenCoordinator.swift in Sources */, + 6B80C24A52411EAF10E06E96 /* SecurityAndPrivacyScreenModels.swift in Sources */, + 7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */, + 0D617A152D099D94271D3BA8 /* SecurityAndPrivacyScreenViewModelProtocol.swift in Sources */, 08547E55DD3686A84550996D /* SeparatorMediaEventsTimelineView.swift in Sources */, 14E99D27628B1A6F0CB46FEA /* SeparatorRoomTimelineItem.swift in Sources */, 5341D48F833E3E30F16FA2A3 /* SeparatorRoomTimelineView.swift in Sources */, diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index 45a40ba3e..d86a412e3 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -405,6 +405,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { return .mediaEventsTimeline(previousState: fromState) case (.mediaEventsTimeline(let previousState), .dismissMediaEventsTimeline): return previousState + + case (.roomDetails, .presentSecurityAndPrivacyScreen): + return .securityAndPrivacy(previousState: fromState) + case (.securityAndPrivacy(let previousState), .dismissSecurityAndPrivacyScreen): + return previousState default: return nil @@ -571,6 +576,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { Task { await self.startMediaEventsTimelineFlow() } case (.mediaEventsTimeline, .dismissMediaEventsTimeline, .roomDetails): break + + case (.roomDetails, .presentSecurityAndPrivacyScreen, .securityAndPrivacy): + presentSecurityAndPrivacyScreen() + case (.securityAndPrivacy, .dismissSecurityAndPrivacyScreen, .roomDetails): + break // Child flow case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild): @@ -849,6 +859,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { stateMachine.tryEvent(.presentKnockRequestsListScreen) case .presentMediaEventsTimeline: stateMachine.tryEvent(.presentMediaEventsTimeline) + case .presentSecurityAndPrivacyScreen: + stateMachine.tryEvent(.presentSecurityAndPrivacyScreen) } } .store(in: &cancellables) @@ -1453,6 +1465,24 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { } } + private func presentSecurityAndPrivacyScreen() { + let coordinator = SecurityAndPrivacyScreenCoordinator(parameters: .init(roomProxy: roomProxy)) + + coordinator.actionsPublisher.sink { [weak self] action in + guard let self else { return } + + switch action { + case .done: + break + } + } + .store(in: &cancellables) + + navigationStackCoordinator.push(coordinator) { [weak self] in + self?.stateMachine.tryEvent(.dismissSecurityAndPrivacyScreen) + } + } + // MARK: - Other flows private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async { @@ -1604,6 +1634,7 @@ private extension RoomFlowCoordinator { case resolveSendFailure case knockRequestsList(previousState: State) case mediaEventsTimeline(previousState: State) + case securityAndPrivacy(previousState: State) /// A child flow is in progress. case presentingChild(childRoomID: String, previousState: State) @@ -1687,6 +1718,9 @@ private extension RoomFlowCoordinator { case presentMediaEventsTimeline case dismissMediaEventsTimeline + + case presentSecurityAndPrivacyScreen + case dismissSecurityAndPrivacyScreen } } diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenCoordinator.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenCoordinator.swift index f758a84fc..012bed15b 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenCoordinator.swift @@ -31,6 +31,7 @@ enum RoomDetailsScreenCoordinatorAction { case presentPinnedEventsTimeline case presentMediaEventsTimeline case presentKnockingRequestsListScreen + case presentSecurityAndPrivacyScreen } final class RoomDetailsScreenCoordinator: CoordinatorProtocol { @@ -85,6 +86,8 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol { actionsSubject.send(.presentMediaEventsTimeline) case .displayKnockingRequests: actionsSubject.send(.presentKnockingRequestsListScreen) + case .displaySecurityAndPrivacy: + actionsSubject.send(.presentSecurityAndPrivacyScreen) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift index a7a74dca2..b133ec7a7 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenModels.swift @@ -24,6 +24,7 @@ enum RoomDetailsScreenViewModelAction { case displayPinnedEventsTimeline case displayMediaEventsTimeline case displayKnockingRequests + case displaySecurityAndPrivacy } // MARK: View @@ -56,6 +57,10 @@ struct RoomDetailsScreenViewState: BindableState { knockingEnabled && dmRecipient == nil && isKnockableRoom && (canInviteUsers || canKickUsers || canBanUsers) } + var canSeeSecurityAndPrivacy: Bool { + knockingEnabled && dmRecipient == nil && canEditRolesOrPermissions + } + var mediaBrowserEnabled = false var canEdit: Bool { @@ -198,6 +203,7 @@ enum RoomDetailsScreenViewAction { case processTapPolls case toggleFavourite(isFavourite: Bool) case processTapRolesAndPermissions + case processTapSecurityAndPrivacy case processTapCall case processTapPinnedEvents case processTapMediaEvents diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift index 75fe6ab78..d1bfc0a7b 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/RoomDetailsScreenViewModel.swift @@ -172,6 +172,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr actionsSubject.send(.displayMediaEventsTimeline) case .processTapRequestsToJoin: actionsSubject.send(.displayKnockingRequests) + case .processTapSecurityAndPrivacy: + actionsSubject.send(.displaySecurityAndPrivacy) } } diff --git a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift index 10d806a9d..6fd104d72 100644 --- a/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsScreen/View/RoomDetailsScreen.swift @@ -207,6 +207,14 @@ struct RoomDetailsScreen: View { .onChange(of: context.isFavourite) { _, newValue in context.send(viewAction: .toggleFavourite(isFavourite: newValue)) } + + if context.viewState.canSeeSecurityAndPrivacy { + ListRow(label: .default(title: L10n.screenRoomDetailsSecurityAndPrivacyTitle, + icon: \.lock), + kind: .navigationLink { + context.send(viewAction: .processTapSecurityAndPrivacy) + }) + } } } diff --git a/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenCoordinator.swift b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenCoordinator.swift new file mode 100644 index 000000000..247414a65 --- /dev/null +++ b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenCoordinator.swift @@ -0,0 +1,54 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import Combine +import SwiftUI + +struct SecurityAndPrivacyScreenCoordinatorParameters { + let roomProxy: JoinedRoomProxyProtocol +} + +enum SecurityAndPrivacyScreenCoordinatorAction { + case done + + // Consider adding CustomStringConvertible conformance if the actions contain PII +} + +final class SecurityAndPrivacyScreenCoordinator: CoordinatorProtocol { + private let parameters: SecurityAndPrivacyScreenCoordinatorParameters + private let viewModel: SecurityAndPrivacyScreenViewModelProtocol + + private var cancellables = Set() + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: SecurityAndPrivacyScreenCoordinatorParameters) { + self.parameters = parameters + + viewModel = SecurityAndPrivacyScreenViewModel(roomProxy: parameters.roomProxy) + } + + func start() { + viewModel.actionsPublisher.sink { [weak self] action in + MXLog.info("Coordinator: received view model action: \(action)") + + guard let self else { return } + switch action { + case .done: + actionsSubject.send(.done) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(SecurityAndPrivacyScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenModels.swift b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenModels.swift new file mode 100644 index 000000000..c01787101 --- /dev/null +++ b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenModels.swift @@ -0,0 +1,54 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import Foundation + +enum SecurityAndPrivacyScreenViewModelAction { + case done +} + +struct SecurityAndPrivacyScreenViewState: BindableState { + var bindings: SecurityAndPrivacyScreenViewStateBindings + + var currentSettings: SecurityAndPrivacySettings + + var hasChanges: Bool { + currentSettings != bindings.desiredSettings + } + + init(accessType: SecurityAndPrivacyRoomAccessType, + isEncryptionEnabled: Bool) { + let settings = SecurityAndPrivacySettings(accessType: accessType, isEncryptionEnabled: isEncryptionEnabled) + currentSettings = settings + bindings = SecurityAndPrivacyScreenViewStateBindings(desiredSettings: settings) + } +} + +struct SecurityAndPrivacyScreenViewStateBindings { + var desiredSettings: SecurityAndPrivacySettings + var alertInfo: AlertInfo? +} + +struct SecurityAndPrivacySettings: Equatable { + var accessType: SecurityAndPrivacyRoomAccessType + var isEncryptionEnabled: Bool +} + +enum SecurityAndPrivacyRoomAccessType { + case inviteOnly + case askToJoin + case anyone +} + +enum SecurityAndPrivacyAlertType { + case enableEncryption +} + +enum SecurityAndPrivacyScreenViewAction { + case save + case tryUpdatingEncryption(Bool) +} diff --git a/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModel.swift b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModel.swift new file mode 100644 index 000000000..4b6f74e96 --- /dev/null +++ b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModel.swift @@ -0,0 +1,61 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import Combine +import SwiftUI + +typealias SecurityAndPrivacyScreenViewModelType = StateStoreViewModel + +class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType, SecurityAndPrivacyScreenViewModelProtocol { + private let roomProxy: JoinedRoomProxyProtocol + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(roomProxy: JoinedRoomProxyProtocol) { + self.roomProxy = roomProxy + super.init(initialViewState: SecurityAndPrivacyScreenViewState(accessType: roomProxy.infoPublisher.value.roomAccessType, + isEncryptionEnabled: roomProxy.isEncrypted)) + } + + // MARK: - Public + + override func process(viewAction: SecurityAndPrivacyScreenViewAction) { + MXLog.info("View model: received view action: \(viewAction)") + + switch viewAction { + case .save: + actionsSubject.send(.done) + case .tryUpdatingEncryption(let updatedValue): + if updatedValue { + state.bindings.alertInfo = .init(id: .enableEncryption, + title: L10n.screenSecurityAndPrivacyEnableEncryptionAlertTitle, + message: L10n.screenSecurityAndPrivacyEnableEncryptionAlertDescription, + primaryButton: .init(title: L10n.screenSecurityAndPrivacyEnableEncryptionAlertConfirmButtonTitle, + action: { [weak self] in self?.state.bindings.desiredSettings.isEncryptionEnabled = true }), + secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil)) + } else { + state.bindings.desiredSettings.isEncryptionEnabled = false + } + } + } +} + +private extension RoomInfoProxy { + var roomAccessType: SecurityAndPrivacyRoomAccessType { + switch joinRule { + case .invite, .restricted: + return .inviteOnly + case .knock, .knockRestricted: + return .askToJoin + default: + return .anyone + } + } +} diff --git a/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModelProtocol.swift b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModelProtocol.swift new file mode 100644 index 000000000..a7e41e348 --- /dev/null +++ b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/SecurityAndPrivacyScreenViewModelProtocol.swift @@ -0,0 +1,14 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import Combine + +@MainActor +protocol SecurityAndPrivacyScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: SecurityAndPrivacyScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/SecurityAndPrivacyScreen/View/SecurityAndPrivacyScreen.swift b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/View/SecurityAndPrivacyScreen.swift new file mode 100644 index 000000000..47379e3c6 --- /dev/null +++ b/ElementX/Sources/Screens/SecurityAndPrivacyScreen/View/SecurityAndPrivacyScreen.swift @@ -0,0 +1,87 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import Compound +import SwiftUI + +struct SecurityAndPrivacyScreen: View { + @ObservedObject var context: SecurityAndPrivacyScreenViewModel.Context + + var body: some View { + Form { + roomAccessSection + encryptionSection + } + .compoundList() + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(L10n.screenSecurityAndPrivacyTitle) + .toolbar { toolbar } + .alert(item: $context.alertInfo) + } + + private var roomAccessSection: some View { + Section { + ListRow(label: .plain(title: L10n.screenSecurityAndPrivacyRoomAccessInviteOnlyOptionTitle, + description: L10n.screenSecurityAndPrivacyRoomAccessInviteOnlyOptionDescription), + kind: .selection(isSelected: context.desiredSettings.accessType == .inviteOnly) { context.desiredSettings.accessType = .inviteOnly }) + ListRow(label: .plain(title: L10n.screenSecurityAndPrivacyAskToJoinOptionTitle, + description: L10n.screenSecurityAndPrivacyAskToJoinOptionDescription), + kind: .selection(isSelected: context.desiredSettings.accessType == .askToJoin) { context.desiredSettings.accessType = .askToJoin }) + ListRow(label: .plain(title: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionTitle, + description: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionDescription), + kind: .selection(isSelected: context.desiredSettings.accessType == .anyone) { context.desiredSettings.accessType = .anyone }) + } header: { + Text(L10n.screenSecurityAndPrivacyRoomAccessSectionTitle) + .compoundListSectionHeader() + } + } + + @ViewBuilder + private var encryptionSection: some View { + let encryptionBinding = Binding(get: { + context.desiredSettings.isEncryptionEnabled + }, set: { newValue in + context.send(viewAction: .tryUpdatingEncryption(newValue)) + }) + + Section { + ListRow(label: .plain(title: L10n.screenSecurityAndPrivacyEncryptionToggleTitle), + kind: .toggle(encryptionBinding)) + // We don't allow editing the encryption state if the current setting on the server is `enabled` + .disabled(context.viewState.currentSettings.isEncryptionEnabled) + } header: { + Text(L10n.screenSecurityAndPrivacyEncryptionSectionTitle) + .compoundListSectionHeader() + } footer: { + Text(L10n.screenSecurityAndPrivacyEncryptionSectionFooter) + .compoundListSectionFooter() + } + } + + @ToolbarContentBuilder + var toolbar: some ToolbarContent { + ToolbarItem(placement: .confirmationAction) { + Button(L10n.actionSave) { + context.send(viewAction: .save) + } + .disabled(!context.viewState.hasChanges) + } + } +} + +// MARK: - Previews + +// TODO: Add back TestablePreview, this is WIP so running preview tests for it is not necessary +struct SecurityAndPrivacyScreen_Previews: PreviewProvider { + static let inviteOnlyViewModel = SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(joinRule: .invite))) + + static var previews: some View { + NavigationStack { + SecurityAndPrivacyScreen(context: inviteOnlyViewModel.context) + } + } +} diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Generic-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Generic-Room.png index cae4a2227..44d9cc85e 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Generic-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Generic-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b85a4d43317a3e429b63ca3b5e8c0302588ec79cd301ccd4dbe006f8fbabbcc -size 168419 +oid sha256:060065ca3bd133753e075be975b29c5147bd5cde2eb3cb61cd1b376986bae37c +size 174821 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Simple-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Simple-Room.png index ee18da242..e179ec66f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Simple-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-en-GB.Simple-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f855bcf215c22c3e8f73adc493092c041bcc532ccc8044632a86e4eebdab45d3 -size 144080 +oid sha256:29136d24366425eaef80bd40fa69a332fcc92378f83b85a376f62ea40e22aa26 +size 144375 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Generic-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Generic-Room.png index f22374e16..0b872f47d 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Generic-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Generic-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b0911b93749fea8d6d0e1e9fce015cd3b7e99c8f2005542f1a0468dc0da48d4 -size 173188 +oid sha256:002d4dc3993adddc0b07aa927be8d15a3cbd028f1dfb7c4176d44a1ba202091f +size 180485 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Simple-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Simple-Room.png index 3ec47b087..50e5b0ede 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Simple-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPad-pseudo.Simple-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1227fb48ff0248992eebb56931e54943bd344308f0f9de4ceb3871c7b72add9e -size 152712 +oid sha256:1d90754cfbb2541edbc1e9d43dcbc7dd7067e440b230b1de0a8812ee091de655 +size 152665 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Generic-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Generic-Room.png index 0bb82fb23..20d1dd2c4 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Generic-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Generic-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1d7d735ffbb1d5ddf39e0a64b6a8520164ec675d605d930f5f4fb9d759962d9 -size 106360 +oid sha256:12c7fd9be85bb2d5a245a4a8e5087068317c37c9116ff44492245dda2272aa2b +size 112422 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Simple-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Simple-Room.png index 3c33f35fb..92d81e70e 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Simple-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-en-GB.Simple-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3c4d1613cd852097d5350acbe7f197b5515f2487b550c4be74a4953fd5fc7494 -size 91217 +oid sha256:9dc76892f1a8ad57ec5b39e477544761cc83abbe7ca2df49d3a5c02c4f784dd3 +size 91560 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Generic-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Generic-Room.png index 58392d831..0944f23bc 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Generic-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Generic-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bdfea363c096f74335c13b9db377acd924e2ac0de3b56dba1c1a8037ab43b16f -size 124309 +oid sha256:8d89c461638b63209b79f5c4161fa87fb2bb95a6f1d340a5157a0fdafa32a28c +size 124126 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Simple-Room.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Simple-Room.png index af8a596f1..ca90715e9 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Simple-Room.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDetailsScreen-iPhone-16-pseudo.Simple-Room.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74848803e9727d3a0f36941aa93a19e681f24c2d3e28c594a9275f38ad8160d8 -size 106302 +oid sha256:f695712aa0f2caf38e73cab6a9b512d8534bc98c77b9c806dc088a8d7f4ae4df +size 112161 diff --git a/UnitTests/Sources/SecurityAndPrivacyScreenViewModelTests.swift b/UnitTests/Sources/SecurityAndPrivacyScreenViewModelTests.swift new file mode 100644 index 000000000..15cf4c3d7 --- /dev/null +++ b/UnitTests/Sources/SecurityAndPrivacyScreenViewModelTests.swift @@ -0,0 +1,19 @@ +// +// Copyright 2022-2024 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only +// Please see LICENSE in the repository root for full details. +// + +import XCTest + +@testable import ElementX + +@MainActor +class SecurityAndPrivacyScreenViewModelTests: XCTestCase { + var viewModel: SecurityAndPrivacyScreenViewModelProtocol! + + var context: SecurityAndPrivacyScreenViewModelType.Context { + viewModel.context + } +}