diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 05fd36819a..555bb361b3 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ /* Begin PBXBuildFile section */ 0033481EE363E4914295F188 /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C070FD43DC6BF4E50217965A /* LocalizationTests.swift */; }; + 01681E8B20AD6F0D237F2DC1 /* IdentityConfirmedScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6624240FFD32B7F0834229 /* IdentityConfirmedScreenViewModel.swift */; }; 0180C44B997EDA8D21F883AC /* RoomNotificationSettingsCustomSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B746EFA112532A7B701FB914 /* RoomNotificationSettingsCustomSectionView.swift */; }; 01B63F1A04A276B39AC17014 /* CallInviteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9A3D3CFA199FA7897364547 /* CallInviteRoomTimelineItem.swift */; }; 020C530986D7B97631877FEF /* TimelineItemMacContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4AD793D50748F8997E5B15 /* TimelineItemMacContextMenu.swift */; }; @@ -36,6 +37,7 @@ 04A16B45228F7678A027C079 /* RoomHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 422724361B6555364C43281E /* RoomHeaderView.swift */; }; 04F17DE71A50206336749BAC /* UserPreferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA241DEEF7C8A7181C0AEDC9 /* UserPreferenceTests.swift */; }; 059173B3C77056C406906B6D /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = D4DA544B2520BFA65D6DB4BB /* target.yml */; }; + 05BAB510CBC2ED35C154ADD0 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */; }; 05EC896A4B9AF4A56670C0BB /* SessionVerificationUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4777F0142E330A75C46FE4 /* SessionVerificationUITests.swift */; }; 066A1E9B94723EE9F3038044 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EBB5D698CE9A25BB553A2D /* Strings.swift */; }; 06AA515C7053FD7E17A5CF81 /* RoomNotificationSettingsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66901977F6469D03C333DF32 /* RoomNotificationSettingsScreenUITests.swift */; }; @@ -56,13 +58,13 @@ 09C83DDDB07C28364F325209 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D7074991B3267B26D89B22 /* MockRoomTimelineController.swift */; }; 09EF4222EEBBA1A7B8F4071E /* VoiceMessageRecordingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E61DDB42C0DE429C0955D8 /* VoiceMessageRecordingButton.swift */; }; 0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; }; - 0AA0477E063E72B786A983CF /* AnalyticsPromptScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E1FF2DA52B1DE7CAEC5422 /* AnalyticsPromptScreenViewModel.swift */; }; 0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; }; 0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */; }; 0B57C2399B9E1CE5CE0D8005 /* ComposerToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D121B4FCFC38DBCC17BCC6D6 /* ComposerToolbar.swift */; }; 0BDA19079FD6E17C5AC62E22 /* RoomDetailsEditScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06F22CFA34885B40976061 /* RoomDetailsEditScreen.swift */; }; 0BE4D5CBF86956410F071F91 /* CreateRoomViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15A657D96779D1DEB8EF1327 /* CreateRoomViewModel.swift */; }; 0BFA67AFD757EE2BA569836A /* ScrollViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53482ECA4B6633961EC224F5 /* ScrollViewAdapter.swift */; }; + 0C346A4AD174F441EDB1414E /* IdentityConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */; }; 0C47AE2CA7929CB3B0E2D793 /* ServerSelectionScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0685156EB62D7E243F097CFC /* ServerSelectionScreenViewModelProtocol.swift */; }; 0C58A846F61949B1D545D661 /* NoticeRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421E716C521F96D24ECE69B3 /* NoticeRoomTimelineItem.swift */; }; 0C797CD650DFD2876BEC5173 /* CollapsibleReactionLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7C6DDBB5D12F6EF6A3D6E1 /* CollapsibleReactionLayout.swift */; }; @@ -82,6 +84,7 @@ 0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */; }; 1146E9EDCF8344F7D6E0D553 /* MockCoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0376C429FAB1687C3D905F3E /* MockCoder.swift */; }; 119AE9A3FC6E0606C1146528 /* NotificationSettingsEditScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97F8963B14EB0AF3940DDBF /* NotificationSettingsEditScreenRoomCell.swift */; }; + 11A6B8E3CBDBF0A4107FF4CE /* OnboardingFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3285BD95B564CA2A948E511 /* OnboardingFlowCoordinator.swift */; }; 126EE01D8BEAEF26105D83C5 /* RoomDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A5FEF17ED7E6176D922D4F /* RoomDetailsScreen.swift */; }; 12C867E85E6D12EEDFD0B127 /* CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C4762F8D6112E43117DB2F /* CustomStringConvertible.swift */; }; 12CCA59536EDD99A3272CF77 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC3F82523D6F48B926D6AF68 /* AppSettings.swift */; }; @@ -149,6 +152,7 @@ 241CDEFE23819867D9B39066 /* RoomChangePermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */; }; 244407B18B2F2D6466BA5961 /* RoomChangeRolesScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DFA1B7B088D033E0794B82 /* RoomChangeRolesScreenCoordinator.swift */; }; 245F7FE5961BD10C145A26E0 /* UITimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA689E792E679F5E3956F21 /* UITimelineView.swift */; }; + 24A1BBADAC43DC3F3A7347DA /* AnalyticsPromptScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */; }; 24A75F72EEB7561B82D726FD /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2141693488CE5446BB391964 /* Date.swift */; }; 24B7CD41342C143117ADA768 /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2B1CC9AA154F4D5435BF60A /* Comparable.swift */; }; 24BDDD09A90B8BFE3793F3AA /* ClientProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */; }; @@ -182,6 +186,7 @@ 2BA59D0AEFB4B82A2EC2A326 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 50009897F60FAE7D63EF5E5B /* Kingfisher */; }; 2BAA5B222856068158D0B3C6 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = B1E8B697DF78FE7F61FC6CA4 /* MatrixRustSDK */; }; 2BBA132149DEBED6624084A8 /* MessageForwardingScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FAE373A7F20780BA84B59C /* MessageForwardingScreenCoordinator.swift */; }; + 2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00AFC5F08734C2EA4EE79C59 /* IdentityConfirmationScreen.swift */; }; 2C4C750D0039AFABDF24236C /* TemplateScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */; }; 2C5E832434EE94E21AB3B238 /* EmojiPickerScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3EAE3E9D5EF4A6D5D9C6CFD /* EmojiPickerScreenViewModel.swift */; }; 2CA6ABBC9A88EB89EA52FCCB /* ConfettiScene.scn in Resources */ = {isa = PBXBuildFile; fileRef = B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */; }; @@ -250,6 +255,7 @@ 3DA57CA0D609A6B37CA1DC2F /* BugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DC38E64A5ED3FDB201029A /* BugReportService.swift */; }; 3DAD62988F072607441CB7A5 /* PollFormScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */; }; 3DAF325D8AE461F7CDB282BD /* StartChatScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6861FE915C7B5466E6962BBA /* StartChatScreen.swift */; }; + 3E7B65C2C97748D5D65AAA8B /* NotificationPermissionsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB2FC2AA9A07EE792DF65CF /* NotificationPermissionsScreenModels.swift */; }; 3EC5A41F9FB7DD63A4DC6144 /* RoomChangeRolesScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14B1DE3E2D5D26732C49036 /* RoomChangeRolesScreenViewModel.swift */; }; 3EC698F80DDEEFA273857841 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893777A4997BBDB68079D4F5 /* ArrayTests.swift */; }; 3ED2725734568F6B8CC87544 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */; }; @@ -278,6 +284,7 @@ 44BDD670FF9095ACE240A3A2 /* VoiceMessageMediaManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC4F10BDD56FA77FEC742333 /* VoiceMessageMediaManagerTests.swift */; }; 44DA28B1E1F9C97C5795F7B3 /* AppLockSetupUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A1BBEF7318CA6B6ACCF4AE /* AppLockSetupUITests.swift */; }; 44F0E1B576C7599DF8022071 /* SwiftOGG in Frameworks */ = {isa = PBXBuildFile; productRef = 391D11F92DFC91666AA1503F /* SwiftOGG */; }; + 454311EAC17D778E19F46592 /* NotificationPermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91868EB98818044E6FEBE532 /* NotificationPermissionsScreenCoordinator.swift */; }; 454F8DDC4442C0DE54094902 /* LABiometryType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3F219838588C62198E726E3 /* LABiometryType.swift */; }; 4557192F5B15A8D9BB920232 /* AdvancedSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E492690C8B27A892C194CC4 /* AdvancedSettingsScreenCoordinator.swift */; }; 46562110EE202E580A5FFD9C /* RoomScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93CF7B19FFCF8EFBE0A8696A /* RoomScreenViewModelTests.swift */; }; @@ -292,13 +299,14 @@ 47FF70C051A991FB65CDBCF3 /* RoomScreenInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0135A608FFAD86E6674EE730 /* RoomScreenInteractionHandler.swift */; }; 4807E8F51DB54F56B25E1C7E /* AppLockSetupSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8C38663020DF2EB2D13F5E /* AppLockSetupSettingsScreenViewModel.swift */; }; 484202C5D50983442D24D061 /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; }; + 489BB6A733D3DA0FE7062650 /* IdentityConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C71B9802433F1B4252291BB /* IdentityConfirmationScreenViewModelProtocol.swift */; }; 491D62ACD19E6F134B1766AF /* RoomNotificationSettingsUserDefinedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3203C6566DC17B7AECC1B7FD /* RoomNotificationSettingsUserDefinedScreen.swift */; }; 492274DA6691EE985C2FCCAA /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 67E7A6F388D3BF85767609D9 /* Sentry */; }; 4940B439681767BE9D78CFDB /* AppLockSetupBiometricsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F5EE5DE3B55D59299DB5BC /* AppLockSetupBiometricsScreenViewModelTests.swift */; }; - 496CC9D59ACFAB84FD9B3B5F /* AnalyticsPromptScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840E86A67DB2C92C09771EAD /* AnalyticsPromptScreenModels.swift */; }; 49814A48470F347426513B07 /* TimelineReadReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1877038D1AD3D5A029F8AE2C /* TimelineReadReceiptsView.swift */; }; 49F2E7DD8CAACE09CEECE3E6 /* SeparatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */; }; 4A618590DEB72C4F186BFED4 /* UserSessionFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C99FDEEB71173C4C6FA2734C /* UserSessionFlowCoordinator.swift */; }; + 4A8287E5281B44A8754BE509 /* SessionVerificationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */; }; 4A85928E27D4C1A548A06EE9 /* StartChatScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052B2F924572AFD70B5F500E /* StartChatScreenViewModel.swift */; }; 4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24EC819497BB5F8C4998D760 /* RoomListFilterView.swift */; }; 4AAA8606FBA290E23D15422E /* AvatarHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */; }; @@ -326,6 +334,7 @@ 50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; }; 50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542D4F49FABA056DEEEB3400 /* RustTracing.swift */; }; 5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; }; + 5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */; }; 518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; }; 51B3B19FA5F91B455C807BA7 /* RoomPollsHistoryScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E964AF2DFEB31E2B799999F /* RoomPollsHistoryScreenModels.swift */; }; 520EEDAFBC778AB0B41F2F53 /* ClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */; }; @@ -349,9 +358,8 @@ 565868808A1DA565707394ED /* CurrentValuePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */; }; 56BAB81A0D03C2EF09B86294 /* ComposerToolbarModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA188BB0A216D763E46E3279 /* ComposerToolbarModels.swift */; }; 56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */; }; - 5770C4906668C6D3008A2AC9 /* SessionVerificationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */; }; + 5710AAB27D5D866292C1FE06 /* SessionVerificationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF848B41DAF1066F3054D4A1 /* SessionVerificationScreenModels.swift */; }; 5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E521D6C2BF8DF0DFB35146 /* DeveloperOptionsScreen.swift */; }; - 584590D0EA548152A393E72C /* HomeScreenSessionVerificationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */; }; 588411C8FD72B2A2DFE5F7DE /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E992D7B8BE54B2AB454613AF /* XCUIElement.swift */; }; 5894C2514400A4FBC9327632 /* ServerConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03277E40D0E0DE0712021A71 /* ServerConfirmationScreenCoordinator.swift */; }; 5897A59DDBD3592282092223 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49B9785E3AD7D1C15A29F2F /* MediaSourceProxy.swift */; }; @@ -375,8 +383,8 @@ 5E0F2E612718BB4397A6D40A /* TextRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */; }; 5EE1D4E316D66943E97FDCF2 /* BloomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BEB970F500BFB248443FA1 /* BloomView.swift */; }; 5F06AD3C66884CE793AE6119 /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */; }; - 5F28C9146694B381BB82E18C /* AnalyticsPromptScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B65A314DF40B6BBF775C2BC /* AnalyticsPromptScreenCoordinator.swift */; }; 5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7109E709A7738E6BCC4553E6 /* Localizable.strings */; }; + 601AB75BD52B0B4276CEB84A /* SessionVerificationScreenStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161CD412E75F4086F422AE39 /* SessionVerificationScreenStateMachine.swift */; }; 60ED66E63A169E47489348A8 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 886A0A498FA01E8EDD451D05 /* Sentry */; }; 6146996D5C4DDD5DA816FC87 /* AuthenticationTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */; }; 617624A97BDBB75ED3DD8156 /* RoomScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */; }; @@ -435,6 +443,7 @@ 6CD61FAF03E8986523C2ABB8 /* StartChatScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */; }; 6D046D653DA28ADF1E6E59A4 /* BackgroundTaskServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE73D571D4F9C36DD45255A /* BackgroundTaskServiceProtocol.swift */; }; 6D6E651ACACE27E9C5690818 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE47A97726F0675DEE387BF9 /* TypingIndicatorView.swift */; }; + 6DC8E43BA04AC2AC4EB2EB97 /* AnalyticsPromptScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18486B87745B1811E7FBD3D2 /* AnalyticsPromptScreenModels.swift */; }; 6E47D126DD7585E8F8237CE7 /* LoadableAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */; }; 6E4E401BE97AC241DA7C7716 /* AppLockSetupSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502F986D57158674172C58E3 /* AppLockSetupSettingsScreenModels.swift */; }; 6E63704717F17593A475D152 /* RoomNotificationSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA14564EE143F73F7E4D1F79 /* RoomNotificationSettingsScreenModels.swift */; }; @@ -449,6 +458,7 @@ 70558528EF68CAAEF09972D5 /* RoomTimelineItemFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96ED747FF90332EA1333C22 /* RoomTimelineItemFixtures.swift */; }; 706289B086B0A6B0C211763F /* UITestsSignalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F0192CE2F891141A25B49F /* UITestsSignalling.swift */; }; 706F79A39BDB32F592B8C2C7 /* UIKitBackgroundTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92FCD9116ADDE820E4E30F92 /* UIKitBackgroundTask.swift */; }; + 707E49BE07E8EB8A13C0EB1E /* SessionVerificationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FACD034DB52525A3CEF2BDF /* SessionVerificationScreen.swift */; }; 70B83D44043293B4B77440B9 /* PollFormScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB63761D9F9CE8B23CBD6179 /* PollFormScreenModels.swift */; }; 719E7AAD1F8E68F68F30FECD /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = A40C19719687984FD9478FBE /* Task.swift */; }; 71B62C48B8079D49F3FBC845 /* ExpiringTaskRunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */; }; @@ -466,6 +476,7 @@ 755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */; }; 755727E0B756430DFFEC4732 /* SessionVerificationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */; }; 762DAF94846C7AC8550F1CC1 /* MediaPlayerProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E23D8EE6CBACF32F1EC874 /* MediaPlayerProviderProtocol.swift */; }; + 762DB0973865293F0C3D3D7B /* SessionVerificationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */; }; 763D69741D58D2B650BC1FC9 /* CallScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37FA1A5D55633E1942B153B /* CallScreenCoordinator.swift */; }; 7640A4B412CACF15D143CCD4 /* Strings+SAS.swift in Sources */ = {isa = PBXBuildFile; fileRef = B172057567E049007A5C4D92 /* Strings+SAS.swift */; }; 764AFCC225B044CF5F9B41E5 /* PaginationIndicatorRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42EEA67A6796BDC2761619C5 /* PaginationIndicatorRoomTimelineView.swift */; }; @@ -474,6 +485,7 @@ 76BA28216FBAF83B2D86A027 /* InvitesScreenCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2A71915C1F075E403F559C /* InvitesScreenCell.swift */; }; 7708976CEE6AFB5CFAEFBA68 /* PillTextAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CF1EE0AA78470C674554262 /* PillTextAttachment.swift */; }; 7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6FEA87EA3752203065ECE27 /* BugReportUITests.swift */; }; + 77574A519A4E484880053EAD /* IdentityConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FDF541AE914059942B575B4 /* IdentityConfirmationScreenModels.swift */; }; 77693820498ABF3508814D49 /* AppLockServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97F9661ABF08CE002054A2 /* AppLockServiceTests.swift */; }; 77920AFA8091AC6B9F190C90 /* Signposter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */; }; 77BB228AEA861E50FFD6A228 /* HomeScreenEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FEA560929DD73FFEF8C3DF /* HomeScreenEmptyStateView.swift */; }; @@ -485,7 +497,6 @@ 795A854F63301DC6B46217B9 /* AccessibilityIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */; }; 79741C1953269FF1A211D246 /* RoomPollsHistoryScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E14FF533D25A0692F7CEB0 /* RoomPollsHistoryScreenViewModel.swift */; }; 7A02EB29F3B993AB20E0A198 /* RoomPollsHistoryScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C8C368A611B9CB79C7F5FA /* RoomPollsHistoryScreen.swift */; }; - 7A0A0929556792FB19B812C5 /* SessionVerificationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84816E0D2F34E368BF64FA60 /* SessionVerificationScreen.swift */; }; 7A170A5A4A352954BB2A1B96 /* AuthenticationStartScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E8C8817F59BEC7E358EB78 /* AuthenticationStartScreen.swift */; }; 7A642EE5F1ADC5D520F21924 /* MediaProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85EB16E7FE59A947CA441531 /* MediaProviderProtocol.swift */; }; 7A71AEF419904209BB8C2833 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; }; @@ -598,6 +609,7 @@ 934051B17A884AB0635DF81B /* BlockedUsersScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A010B8EAD1A9F6B4686DF2F4 /* BlockedUsersScreenViewModel.swift */; }; 93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; }; 93A549135E6C027A0D823BFE /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 593FBBF394712F2963E98A0B /* DTCoreText */; }; + 93AC1E8418D8C827671FB3A9 /* IdentityConfirmedScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 595EC503DA5517BBE6D39406 /* IdentityConfirmedScreenCoordinator.swift */; }; 93BA4A81B6D893271101F9F0 /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = A7CA6F33C553805035C3B114 /* DeviceKit */; }; 93BAF04D9CCBC0A8841414D0 /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D67E616BCA82D8A1258D488 /* NetworkMonitor.swift */; }; 9408CE8B8865C0C8DD4C9869 /* NoticeRoomTimelineItemContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD51B4D5173F7FC886F5360 /* NoticeRoomTimelineItemContent.swift */; }; @@ -619,7 +631,6 @@ 988BA75A182738150894A23F /* UserIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8AE4B3273BA189FDCD4055C /* UserIndicator.swift */; }; 9912F9EB2D6589141A2957B4 /* AppLockScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C44BBC892499BE45B074F89 /* AppLockScreenCoordinator.swift */; }; 992F5E750F5030C4BA2D0D03 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01C4C7DB37597D7D8379511A /* Assets.xcassets */; }; - 9965CB800CE6BC74ACA969FC /* EncryptedHistoryRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */; }; 99ED42B8F8D6BFB1DBCF4C45 /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = D661CAB418C075A94306A792 /* AnalyticsEvents */; }; 9A3B0CDF097E3838FB1B9595 /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; }; 9A4E3D5AA44B041DAC3A0D81 /* OIDCAuthenticationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */; }; @@ -632,6 +643,7 @@ 9BB91CABB10D8FE90C491BCD /* StaticLocationScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */; }; 9BD3A773186291560DF92B62 /* RoomTimelineProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66F2402D738694F98729A441 /* RoomTimelineProvider.swift */; }; 9BEA56957B3AF954E7321658 /* ComposerToolbarViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44928D844E16EE48A311FCA /* ComposerToolbarViewModelProtocol.swift */; }; + 9C4EC28A921486B1775D7F8C /* IdentityConfirmedScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */; }; 9C55746D8F6A3E35CFCF4A7A /* AuthenticationStartLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 598F01EBD0C4CC550C644418 /* AuthenticationStartLogo.swift */; }; 9C5A07E7C33F3F40287D7861 /* SettingsScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EC57A32ABC80D774CC663DB /* SettingsScreenUITests.swift */; }; 9D2E03DB175A6AB14589076D /* AnalyticsEvents in Frameworks */ = {isa = PBXBuildFile; productRef = 2A3F7BCCB18C15B30CCA39A9 /* AnalyticsEvents */; }; @@ -641,7 +653,6 @@ 9DD5AA10E85137140FEA86A3 /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F17EFA1D3D09FC2F9C5E1CB2 /* MediaProvider.swift */; }; 9DD84E014ADFB2DD813022D5 /* RoomDetailsEditScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E5B2CBEF8F96424F095508 /* RoomDetailsEditScreenViewModelTests.swift */; }; 9DE801D278AC34737467F937 /* VoiceMessageMediaManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 889DEDD63C68ABDA8AD29812 /* VoiceMessageMediaManagerProtocol.swift */; }; - 9DF3F6318A4402305F5EB869 /* AnalyticsPromptScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8002D0392A476D2758B291 /* AnalyticsPromptScreen.swift */; }; 9E838A62918E47BC72D6640D /* UserIndicatorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AB54B4F94686CCF0289B72F /* UserIndicatorPresenter.swift */; }; 9EBDC79CAC9B63A0D626E333 /* LegalInformationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB2CAA266B921D128C35710 /* LegalInformationScreenCoordinator.swift */; }; 9F11E743EA01482E78A438B0 /* GlobalSearchScreenCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DB19219E6CC4D002E15D48 /* GlobalSearchScreenCell.swift */; }; @@ -704,6 +715,7 @@ AA050DF4AEE54A641BA7CA22 /* RoomSummaryProviderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10CC626F97AD70FF0420C115 /* RoomSummaryProviderProtocol.swift */; }; AA5924D3B67F7ACD98BBEFDC /* OrientationManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4756240773D26AB74C22668 /* OrientationManagerProtocol.swift */; }; AA93B3F9B5DD097DEF79F981 /* NotificationSettingsEditScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB0328F2887BF0A65BC5D49 /* NotificationSettingsEditScreen.swift */; }; + AADE7C2497A7B55D8BED7BD6 /* IdentityConfirmedScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8319173DD66C07F45DC48848 /* IdentityConfirmedScreenViewModelProtocol.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 */; }; @@ -722,7 +734,6 @@ AFA1F2543DFF7B45DF68ACD6 /* CompletionSuggestionModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170BF6F7923A5C3792442F27 /* CompletionSuggestionModels.swift */; }; B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */; }; B064D42BA087649ACAE462E8 /* SoftLogoutUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55F30E764BED111C81739844 /* SoftLogoutUITests.swift */; }; - B09DC6E3D0EE87C4D4ABFAB3 /* EncryptedHistoryRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */; }; B0CB16349B96262AA65A04AF /* Version in Frameworks */ = {isa = PBXBuildFile; productRef = A05AF81DDD14AD58CB0E1B9B /* Version */; }; B1069F361E604D5436AE9FFD /* StaticLocationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B06663F7858E45882E63471 /* StaticLocationScreen.swift */; }; B13774779EA19FDD7A35A4A8 /* RoomRolesAndPermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C28B70BEFD3676F11D5D51F /* RoomRolesAndPermissionsScreenCoordinator.swift */; }; @@ -731,7 +742,6 @@ B188D0907A4D38AAAF6FEFA8 /* AppLockSetupFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DBB08A95EFA668F2CF27211 /* AppLockSetupFlowCoordinator.swift */; }; B22D857D1E8FCA6DD74A58E3 /* UserSessionScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F899D02CF26EA7675EEBE74C /* UserSessionScreenTests.swift */; }; B245583C63F8F90357B87FAE /* KZFileWatchers in Frameworks */ = {isa = PBXBuildFile; productRef = A2AE110B053B55E38F8D10C7 /* KZFileWatchers */; }; - B27D3190784F85916DA1C394 /* SessionVerificationScreenStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B1EE0908B2BF9212436AD3E /* SessionVerificationScreenStateMachine.swift */; }; B2F8E01ABA1BA30265B4ECBE /* RoundedCornerShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */; }; B3D652AA1654270742072FB3 /* DeveloperOptionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86A6F283BC574FDB96ABBB07 /* DeveloperOptionsScreenViewModel.swift */; }; B3EDDEC1839BB5A3747624BB /* FormButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A1CCDEE545CB6453B084BF /* FormButtonStyles.swift */; }; @@ -779,6 +789,7 @@ BB9B800C6094E34860E89DC5 /* AppLockSetupBiometricsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */; }; BCC864190651B3A3CF51E4DF /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; }; BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */; }; + BD11E639CF566A9DA8FCA717 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7C80EF77AD102053D3646E /* RoundedLabelItem.swift */; }; BD203FC6A7AE7637EA003643 /* RoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ABDE6F66532CBEB0E016F94 /* RoomProxyMock.swift */; }; BD6685592716CA957D7BAAC4 /* RoomChangeRolesScreenSelectedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */; }; BD6D98676111DA8FC2BE4908 /* InvitesScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */; }; @@ -804,6 +815,7 @@ C32765D740C81AD4C42E8F50 /* CreateRoomFlowParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935C2FB18EFB8EEE96B26330 /* CreateRoomFlowParameters.swift */; }; C3317EF833AB4060988DF098 /* SAS.strings in Resources */ = {isa = PBXBuildFile; fileRef = 135FC689EA39AE1D34153B58 /* SAS.strings */; }; C3522917C0C367C403429EEC /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */; }; + C3BB6887CF13B19182E81F87 /* IdentityConfirmationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A03E073077D92AA19C43DCF /* IdentityConfirmationScreenCoordinator.swift */; }; C4078364FD9FA00EA9D00A15 /* RoomMembersListScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CDF9A107BFE6C79B58D6B5 /* RoomMembersListScreenViewModelProtocol.swift */; }; C413D36D44F89DE63D3ADFA4 /* ReportContentScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A433BE28B40D418237BE37B5 /* ReportContentScreen.swift */; }; C4180F418235DAD9DD173951 /* TemplateScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9873076F224E4CE09D8BD47D /* TemplateScreenUITests.swift */; }; @@ -823,6 +835,7 @@ C7ABEBECDC513F7887DACF66 /* ProgressMaskModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68010886142843705E342645 /* ProgressMaskModifier.swift */; }; C7CFDB4929DDD9A3B5BA085D /* BugReportViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */; }; C85C7A201E4CFDA477ACEBEB /* AppLockSetupSettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8610C1D21565C950BCA6A454 /* AppLockSetupSettingsScreenViewModelProtocol.swift */; }; + C8A9C595038AFA2D707AC8C1 /* NotificationPermissionsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20E69F67D2A70ABD08CA6D54 /* NotificationPermissionsScreenViewModelProtocol.swift */; }; C8BD80891BAD688EF2C15CDB /* MediaUploadPreviewScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74DD0855F2F76D47E5555082 /* MediaUploadPreviewScreenCoordinator.swift */; }; C8E0FA0FF2CD6613264FA6B9 /* MessageForwardingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFEA446F8618DBA79A9239CC /* MessageForwardingScreen.swift */; }; C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E0B4A34E69BD2132BEC521 /* MessageText.swift */; }; @@ -855,6 +868,7 @@ CF4044A8EED5C41BC0ED6ABE /* SoftLogoutScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D316BB02636AF2174F2580E6 /* SoftLogoutScreenViewModelProtocol.swift */; }; CFEC53440C572CEEABC4A6A0 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; D02AA6208C7ACB9BE6332394 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; }; + D02DEB36D32A72A1B365E452 /* SessionVerificationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */; }; D050D7756E92CA061ED0ABF0 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */; }; D0550B8E0AE2C0CDBE52C88F /* MediaPlayerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE87C931165F5E201CACBB87 /* MediaPlayerProtocol.swift */; }; D0A965852D6C04138FA55181 /* SecureBackupLogoutConfirmationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */; }; @@ -865,6 +879,7 @@ D1E29F345F1220E1AF1BE9DF /* ReadReceiptsSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0A77874B29D79DDFC051AC /* ReadReceiptsSummaryView.swift */; }; D1EEF0CB0F5D9C15E224E670 /* landscape_test_video.mov in Resources */ = {isa = PBXBuildFile; fileRef = 9A2AC7BE17C05CF7D2A22338 /* landscape_test_video.mov */; }; D2048FD56760BDABA3DB5FC2 /* AppLockServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */; }; + D22345698F6548C1EE960940 /* IdentityConfirmedScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBE70FFB7936F35811772C1 /* IdentityConfirmedScreenModels.swift */; }; D2825E013A8ECFB66D9A1DE6 /* RoomChangeRolesScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F841F219ACDFC1D3F42FEFB /* RoomChangeRolesScreenViewModelTests.swift */; }; D29E046C1E3045E0346C479D /* RoomRolesAndPermissionsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45571C2EBD98ED7E0CEA7AF7 /* RoomRolesAndPermissionsUITests.swift */; }; D2D70B5DB1A5E4AF0CD88330 /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 033DB41C51865A2E83174E87 /* target.yml */; }; @@ -874,8 +889,8 @@ D415764645491F10344FC6AC /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60F18AECC9D38C2B6D85F99C /* Publisher.swift */; }; D43F0503EF2CBC55272538FE /* SDKGeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F079B5DBD0D85FEA687AAE /* SDKGeneratedMocks.swift */; }; D46C33F8B61B55F0C8C2D15F /* LocationRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */; }; - D4ACF3276F5D0DA28D4028C9 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8196D64EB9CF2AF1F43E4ED1 /* AnalyticsPromptScreenViewModelProtocol.swift */; }; D4D5595C4A2A702CFF4E94FF /* HeroImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EC2F1622C5BBABED6012E12 /* HeroImage.swift */; }; + D4D7CCECC6C0AAFC42E165BB /* NotificationPermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */; }; D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */; }; D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */; }; D5681C80D8281560AACE0035 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = 045253F9967A535EE5B16691 /* Label.swift */; }; @@ -887,17 +902,18 @@ D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */; }; D7CDBAE82782BD0529DECB5F /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; }; D8359F67AF3A83516E9083C1 /* MockUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */; }; - D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */; }; D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; }; D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */; }; D98B5EE8C4F5A2CE84687AE8 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; }; D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352359663A0E52BA20761EE /* LoadableImage.swift */; }; DA7E867F5EAFF8E20B2EE3B6 /* SecureBackupScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3D16709ADD4F4BCC710B1E /* SecureBackupScreenModels.swift */; }; DB079D1929B5A5F52D207C83 /* RoomDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */; }; + DB65401349C143DFF883E2B0 /* AnalyticsPromptScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C8EC6EA7EDFCE46710DA306 /* AnalyticsPromptScreenViewModel.swift */; }; DBC8D1DBFE9F9CA7662BC8AA /* RoomPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 974AEAF3FE0C577A6C04AD6E /* RoomPermissions.swift */; }; DC08ADC41E792086A340A8B3 /* AccessibilityIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */; }; DC68E866D6E664B0D2B06E74 /* MockImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC1DA29A5A041CC0BACA7CB0 /* MockImageCache.swift */; }; DC77E9DB2CFBE84A2BDF20C5 /* RoomRolesAndPermissionsFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0833F51229E166BCA141D004 /* RoomRolesAndPermissionsFlowCoordinator.swift */; }; + DCFE7CB3B9A104330BBB96AD /* AnalyticsPromptScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B67DF223EEB8DCAF178A1D4 /* AnalyticsPromptScreenCoordinator.swift */; }; DDB47D29C6865669288BF87C /* UIFont+AttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = E8CA187FE656EE5A3F6C7DE5 /* UIFont+AttributedStringBuilder.m */; }; DDFBDEE1DC32BDD5488F898C /* ClientProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2F96CCBEAAA7F2185BFA354 /* ClientProxyMock.swift */; }; DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D6764D6976D235926FE5FC /* HomeScreenViewModel.swift */; }; @@ -932,7 +948,6 @@ E4B07FF075C99D04D9AF792D /* AppLockSetupPINScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B410B32B72C90BF94E481F33 /* AppLockSetupPINScreenModels.swift */; }; E4BAEED438A843D7B01D8069 /* CompletionSuggestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F421E51DF00377DE1A01354 /* CompletionSuggestionView.swift */; }; E4F924DECC66389C1C810550 /* AuthenticationStartScreenBackgroundImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D685B4DB38BB5BD87C956A /* AuthenticationStartScreenBackgroundImage.swift */; }; - E570117376826665640F0CFD /* SessionVerificationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16CAF20C9AC874A210E2DCF /* SessionVerificationScreenViewModelProtocol.swift */; }; E58F1F3276E98A93F7D39219 /* RoomPollsHistoryScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D8479BB704B7EF696F8ABE /* RoomPollsHistoryScreenCoordinator.swift */; }; E5F4C992845388B50BABACAA /* ServerSelectionScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */; }; E62EC30B39354A391E32A126 /* AudioRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC2D505742FDA21FCDC4C18A /* AudioRoomTimelineView.swift */; }; @@ -950,7 +965,6 @@ E9347F56CF0683208F4D9249 /* RoomNotificationSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A9B5225D0881CEFA2CF7C9 /* RoomNotificationSettingsScreenViewModel.swift */; }; E9560744F7B0292E20ECE5F2 /* RoomDetailsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E8A1E8EE094F570573B6E8 /* RoomDetailsScreenViewModelProtocol.swift */; }; E96005321849DBD7C72A28F2 /* UITestsAppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */; }; - E9F148072F9513EC2272AA21 /* SessionVerificationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A96A67AD0E32C48941EFBB3 /* SessionVerificationScreenCoordinator.swift */; }; EA01A06EEDFEF4AE7652E5F3 /* NSRegularExpresion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */; }; EA6613B29BA671F39CE1B1D2 /* ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = B383DCD3DCB19E00FD478A5F /* ConfirmationDialog.swift */; }; EA78A7512AFB1E5451744EB1 /* AppRouteURLParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E461B3C8BBBFCA400B268D14 /* AppRouteURLParserTests.swift */; }; @@ -997,7 +1011,6 @@ F3F38062C6CA21CF403C5C90 /* AudioConverterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2757B1BE23DF8AA239937243 /* AudioConverterProtocol.swift */; }; F40B097470D3110DFDB1FAAA /* LegalInformationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47873756E45B46683D97DC32 /* LegalInformationScreenModels.swift */; }; F421FD5979EF53C8204BDC77 /* SecureBackupLogoutConfirmationScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC09F30B0E1010951952BDC /* SecureBackupLogoutConfirmationScreenUITests.swift */; }; - F4433EF57B4BB3C077F8B00E /* SessionVerificationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */; }; F4971845B5C4F270F6BC5745 /* ScaledFrameModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D82F234B3576BD6268C7950 /* ScaledFrameModifier.swift */; }; F4996C82A4B3A5FF0C8EDD03 /* RoomListFilterModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E06AAD6D9D3F5833E7A5A2F9 /* RoomListFilterModels.swift */; }; F508683B76EF7B23BB2CBD6D /* TimelineItemPlainStylerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BCC8A9C73C1F838122C645 /* TimelineItemPlainStylerView.swift */; }; @@ -1104,6 +1117,7 @@ /* Begin PBXFileReference section */ 00245D40CD90FD71D6A05239 /* EmojiPickerScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreen.swift; sourceTree = ""; }; + 00AFC5F08734C2EA4EE79C59 /* IdentityConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreen.swift; sourceTree = ""; }; 00E5B2CBEF8F96424F095508 /* RoomDetailsEditScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelTests.swift; sourceTree = ""; }; 0135A608FFAD86E6674EE730 /* RoomScreenInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenInteractionHandler.swift; sourceTree = ""; }; 01B795AAAB7B8747FE2FF311 /* LogViewerScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenModels.swift; sourceTree = ""; }; @@ -1193,10 +1207,12 @@ 15A657D96779D1DEB8EF1327 /* CreateRoomViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModel.swift; sourceTree = ""; }; 15F30E7AE8A303E8FEC2499E /* ReadReceiptCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceiptCell.swift; sourceTree = ""; }; 16037EE9E9A52AF37B7818E3 /* AnalyticsSettingsScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenUITests.swift; sourceTree = ""; }; + 161CD412E75F4086F422AE39 /* SessionVerificationScreenStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenStateMachine.swift; sourceTree = ""; }; 16D09C79746BDCD9173EB3A7 /* RoomDetailsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenModels.swift; sourceTree = ""; }; 170BF6F7923A5C3792442F27 /* CompletionSuggestionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionModels.swift; sourceTree = ""; }; 1715E3D7F53C0748AA50C91C /* PostHogAnalyticsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHogAnalyticsClient.swift; sourceTree = ""; }; 1734A445A58ED855B977A0A8 /* TracingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationTests.swift; sourceTree = ""; }; + 18486B87745B1811E7FBD3D2 /* AnalyticsPromptScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenModels.swift; sourceTree = ""; }; 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecorationTimelineItemProtocol.swift; sourceTree = ""; }; 1877038D1AD3D5A029F8AE2C /* TimelineReadReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineReadReceiptsView.swift; sourceTree = ""; }; 18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxy.swift; sourceTree = ""; }; @@ -1210,7 +1226,6 @@ 1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoURITests.swift; sourceTree = ""; }; 1AB58EF0176D4CFB1040DA22 /* WaitlistScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenViewModel.swift; sourceTree = ""; }; 1ABDE6F66532CBEB0E016F94 /* RoomProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyMock.swift; sourceTree = ""; }; - 1B1EE0908B2BF9212436AD3E /* SessionVerificationScreenStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenStateMachine.swift; sourceTree = ""; }; 1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = ""; }; 1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillAttachmentViewProvider.swift; sourceTree = ""; }; 1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = ""; }; @@ -1227,6 +1242,7 @@ 1D67E616BCA82D8A1258D488 /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = ""; }; 1D8866FE1CCCF10305FCACBC /* CallScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreenUITests.swift; sourceTree = ""; }; 1D8C38663020DF2EB2D13F5E /* AppLockSetupSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenViewModel.swift; sourceTree = ""; }; + 1DB2FC2AA9A07EE792DF65CF /* NotificationPermissionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenModels.swift; sourceTree = ""; }; 1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenUITests.swift; sourceTree = ""; }; 1DE7969EBCAF078813E18EA1 /* RoomRolesAndPermissionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomRolesAndPermissionsScreenModels.swift; sourceTree = ""; }; 1DF8F7A3AD83D04C08D75E01 /* RoomDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -1238,6 +1254,7 @@ 1FD51B4D5173F7FC886F5360 /* NoticeRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItemContent.swift; sourceTree = ""; }; 201305507D7DFD16E544563A /* EmojiLoaderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiLoaderProtocol.swift; sourceTree = ""; }; 20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMapProtocol.swift; sourceTree = ""; }; + 20E69F67D2A70ABD08CA6D54 /* NotificationPermissionsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenViewModelProtocol.swift; sourceTree = ""; }; 2141693488CE5446BB391964 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRoomTimelineItemContent.swift; sourceTree = ""; }; 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBasedTimelineItemProtocol.swift; sourceTree = ""; }; @@ -1282,7 +1299,6 @@ 28C19F54A0C4FC9AB7ABD583 /* TextRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItemContent.swift; sourceTree = ""; }; 295E28C3B9EAADF519BF2F44 /* AuthenticationFlowCoordinatorUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationFlowCoordinatorUITests.swift; sourceTree = ""; }; 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = ""; }; - 2A96A67AD0E32C48941EFBB3 /* SessionVerificationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenCoordinator.swift; sourceTree = ""; }; 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = ""; }; 2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenViewModelProtocol.swift; sourceTree = ""; }; 2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutScreenModels.swift; sourceTree = ""; }; @@ -1301,6 +1317,7 @@ 2F36C5D9B37E50915ECBD3EE /* RoomMemberProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxy.swift; sourceTree = ""; }; 2FD0E68C42CA7DDCD4CAD68D /* MentionSuggestionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSuggestionItemView.swift; sourceTree = ""; }; 303FCADE77DF1F3670C086ED /* BugReportScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModel.swift; sourceTree = ""; }; + 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreen.swift; sourceTree = ""; }; 309AD8BAE6437C31BA7157BF /* ElementCallWidgetDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriver.swift; sourceTree = ""; }; 30ED584467DB380E3CEFB1DB /* NotificationManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManagerTests.swift; sourceTree = ""; }; 314F1C79850BE46E8ABEAFCB /* ReadReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceipt.swift; sourceTree = ""; }; @@ -1352,6 +1369,7 @@ 3D65BCC659FD9087E49B3C25 /* AppAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAppearance.swift; sourceTree = ""; }; 3D9B45D584D232CB9E5C7734 /* RoomChangeRolesScreenSelectedItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenSelectedItem.swift; sourceTree = ""; }; 3D9FCE4D1E3A81AC1CC5CB91 /* AppLockSetupSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupSettingsScreenCoordinator.swift; sourceTree = ""; }; + 3DBE70FFB7936F35811772C1 /* IdentityConfirmedScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenModels.swift; sourceTree = ""; }; 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = ""; }; 3DF1FFC3336EB23374BBBFCC /* UIKitBackgroundTaskService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitBackgroundTaskService.swift; sourceTree = ""; }; 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageRoomTimelineItem.swift; sourceTree = ""; }; @@ -1388,6 +1406,7 @@ 45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterProtocol.swift; sourceTree = ""; }; 466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = ""; }; 46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = ""; }; + 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreen.swift; sourceTree = ""; }; 46D560DDA3B20C82766ACFAD /* NotificationSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenViewModel.swift; sourceTree = ""; }; 46F52419AEEDA2C006CB7181 /* NotificationSettingsEditScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenUITests.swift; sourceTree = ""; }; 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyProtocol.swift; sourceTree = ""; }; @@ -1412,7 +1431,6 @@ 4AB7D7DAAAF662DED9D02379 /* MockMediaLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaLoader.swift; sourceTree = ""; }; 4B2D4EEBE8C098BBADD10939 /* SecureBackupKeyBackupScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenCoordinator.swift; sourceTree = ""; }; 4B41FABA2B0AEF4389986495 /* LoginMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginMode.swift; sourceTree = ""; }; - 4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenModels.swift; sourceTree = ""; }; 4BD371B60E07A5324B9507EF /* AnalyticsSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenCoordinator.swift; sourceTree = ""; }; 4CD6AC7546E8D7E5C73CEA48 /* ElementX.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = ElementX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4CDDDDD9FE1A699D23A5E096 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreen.swift; sourceTree = ""; }; @@ -1462,6 +1480,7 @@ 58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModelTests.swift; sourceTree = ""; }; 58DCB219D7B7B0299358FF81 /* SecureBackupKeyBackupScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenUITests.swift; sourceTree = ""; }; 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreStaticMapView.swift; sourceTree = ""; }; + 595EC503DA5517BBE6D39406 /* IdentityConfirmedScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenCoordinator.swift; sourceTree = ""; }; 596AA8843AC1A234F3387767 /* SecureBackupRecoveryKeyScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreenCoordinator.swift; sourceTree = ""; }; 59846FA04E1DBBFDD8829C2A /* MessageForwardingScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenUITests.swift; sourceTree = ""; }; 598F01EBD0C4CC550C644418 /* AuthenticationStartLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartLogo.swift; sourceTree = ""; }; @@ -1479,7 +1498,7 @@ 5EB2CAA266B921D128C35710 /* LegalInformationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalInformationScreenCoordinator.swift; sourceTree = ""; }; 5F12E996BFBEB43815189ABF /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = ""; }; 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionProtocol.swift; sourceTree = ""; }; - 5F8002D0392A476D2758B291 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = ""; }; + 5FACD034DB52525A3CEF2BDF /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = ""; }; 6033779EB37259F27F938937 /* ClientProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyProtocol.swift; sourceTree = ""; }; 60F18AECC9D38C2B6D85F99C /* Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = ""; }; 612EF972F2A1800682D32C5E /* StickerRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerRoomTimelineView.swift; sourceTree = ""; }; @@ -1491,7 +1510,6 @@ 62B07B296D7A9D2F09120853 /* OrderedSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderedSet.swift; sourceTree = ""; }; 638A81B97D51591D0FCFA598 /* InteractiveQuickLook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveQuickLook.swift; sourceTree = ""; }; 6390A6DC140CA3D6865A66FF /* SeparatorRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineView.swift; sourceTree = ""; }; - 63E1FF2DA52B1DE7CAEC5422 /* AnalyticsPromptScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModel.swift; sourceTree = ""; }; 63E8A1E8EE094F570573B6E8 /* RoomDetailsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenViewModelProtocol.swift; sourceTree = ""; }; 645E027C112740573D27765C /* SecureBackupRecoveryKeyScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupRecoveryKeyScreenModels.swift; sourceTree = ""; }; 648DD1C10E4957CB791FE0B8 /* OverridableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverridableAvatarImage.swift; sourceTree = ""; }; @@ -1522,6 +1540,7 @@ 6B2A421198FD20AAAED20004 /* RoomChangeRolesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreen.swift; sourceTree = ""; }; 6B5E29E9A22F45534FBD5B58 /* EmojiPickerScreenHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenHeaderView.swift; sourceTree = ""; }; 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiProvider.swift; sourceTree = ""; }; + 6C8EC6EA7EDFCE46710DA306 /* AnalyticsPromptScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModel.swift; sourceTree = ""; }; 6CEBE5EA91E8691EDF364EC2 /* UITestsScreenIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsScreenIdentifier.swift; sourceTree = ""; }; 6D0A27607AB09784C8501B5C /* DeveloperOptionsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenViewModelTests.swift; sourceTree = ""; }; 6D4777F0142E330A75C46FE4 /* SessionVerificationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationUITests.swift; sourceTree = ""; }; @@ -1550,7 +1569,6 @@ 7310D8DFE01AF45F0689C3AA /* Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = ""; }; 7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportFlowCoordinator.swift; sourceTree = ""; }; 7447C0AD7EF302CD027D6230 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SAS.strings; sourceTree = ""; }; - 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedLabelItem.swift; sourceTree = ""; }; 74611A4182DCF5F4D42696EC /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = ""; }; 7463464054DDF194C54F0B04 /* LogViewerScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenViewModelProtocol.swift; sourceTree = ""; }; 74653BE903970C0E36867D46 /* GlobalSearchScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchScreenCoordinator.swift; sourceTree = ""; }; @@ -1561,7 +1579,6 @@ 74E08B8A66948E9690F38B94 /* SecureBackupLogoutConfirmationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelProtocol.swift; sourceTree = ""; }; 7509AB72755DCC4B4E721B36 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/SAS.strings; sourceTree = ""; }; 752A0EB49BF5BCEA37EDF7A3 /* Signposter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signposter.swift; sourceTree = ""; }; - 75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineView.swift; sourceTree = ""; }; 76310030C831D4610A705603 /* URLComponentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLComponentsTests.swift; sourceTree = ""; }; 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = ""; }; 7773CBFDBD458E0B7E270507 /* PillView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillView.swift; sourceTree = ""; }; @@ -1569,11 +1586,14 @@ 78910787F967CBC6042A101E /* StartChatScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenViewModelProtocol.swift; sourceTree = ""; }; 78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSplitCoordinatorTests.swift; sourceTree = ""; }; 7893780A1FD6E3F38B3E9049 /* UserIndicatorControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIndicatorControllerMock.swift; sourceTree = ""; }; + 796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenCoordinator.swift; sourceTree = ""; }; + 7A03E073077D92AA19C43DCF /* IdentityConfirmationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenCoordinator.swift; sourceTree = ""; }; 7A5D2323D7B6BF4913EB7EED /* landscape_test_image.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = landscape_test_image.jpg; sourceTree = ""; }; 7AAD8C633AA57948B34EDCF7 /* RoomChangeRolesScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenViewModelProtocol.swift; sourceTree = ""; }; 7AB7ED3A898B07976F3AA90F /* BugReportViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportViewModelTests.swift; sourceTree = ""; }; 7AE094FCB6387D268C436161 /* SecureBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenViewModel.swift; sourceTree = ""; }; 7AE75941583A033A9EDC9FE0 /* RoomChangePermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangePermissionsScreenViewModel.swift; sourceTree = ""; }; + 7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModelProtocol.swift; sourceTree = ""; }; 7B04BD3874D736127A8156B8 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 7B19B2BCC779ED934E0BBC2A /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; 7B25F959A434BB9923A3223F /* ExpiringTaskRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpiringTaskRunner.swift; sourceTree = ""; }; @@ -1582,6 +1602,7 @@ 7B9FCA1CFD07B8CF9BD21266 /* FlowCoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCoordinatorProtocol.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 = ""; }; 7CA3F8E905DF50BF22ECC18F /* ThreadDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadDecorator.swift; sourceTree = ""; }; 7D0CBC76C80E04345E11F2DB /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactoryProtocol.swift; sourceTree = ""; }; @@ -1593,22 +1614,21 @@ 7EC2F1622C5BBABED6012E12 /* HeroImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeroImage.swift; sourceTree = ""; }; 7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoveryServiceProtocol.swift; sourceTree = ""; }; 7FB2253D36E81E045E1CB432 /* Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Duration.swift; sourceTree = ""; }; + 7FDF541AE914059942B575B4 /* IdentityConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenModels.swift; sourceTree = ""; }; 80C4927D09099497233E9980 /* WaitlistScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreen.swift; sourceTree = ""; }; 80E815FF3CC5E5A355E3A25E /* RoomMessageEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageEventStringBuilder.swift; sourceTree = ""; }; 818695BED971753243FEF897 /* StickerRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerRoomTimelineItem.swift; sourceTree = ""; }; - 8196D64EB9CF2AF1F43E4ED1 /* AnalyticsPromptScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenViewModelProtocol.swift; sourceTree = ""; }; 81A9B5225D0881CEFA2CF7C9 /* RoomNotificationSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenViewModel.swift; sourceTree = ""; }; 81B17B1F29448D1B9049B11C /* ReportContentScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentScreenViewModel.swift; sourceTree = ""; }; 81B17DB1BC3B0C62AF84D230 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8296D6FB451E25CEC0767BBA /* RoomNotificationSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenCoordinator.swift; sourceTree = ""; }; 82B612853BFB68373249777B /* SecureBackupKeyBackupScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupKeyBackupScreenViewModel.swift; sourceTree = ""; }; 82DFA1B7B088D033E0794B82 /* RoomChangeRolesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenCoordinator.swift; sourceTree = ""; }; + 8319173DD66C07F45DC48848 /* IdentityConfirmedScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenViewModelProtocol.swift; sourceTree = ""; }; 837B440C4705E4B899BCB899 /* RoomDetailsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenViewModel.swift; sourceTree = ""; }; 839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedCornerShape.swift; sourceTree = ""; }; - 840E86A67DB2C92C09771EAD /* AnalyticsPromptScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenModels.swift; sourceTree = ""; }; 84311D707B09854D67F78BBF /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersViewModelTests.swift; sourceTree = ""; }; - 84816E0D2F34E368BF64FA60 /* SessionVerificationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreen.swift; sourceTree = ""; }; 848F69921527D31CAACB93AF /* SecureBackupLogoutConfirmationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenViewModelTests.swift; sourceTree = ""; }; 84A00BB9CD12CF6AC98D5485 /* SecureBackupScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreen.swift; sourceTree = ""; }; 84A87D0471D438A233C2CF4A /* RoomMemberDetailsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenViewModel.swift; sourceTree = ""; }; @@ -1661,6 +1681,7 @@ 90F2F8998E5632668B0AD848 /* RoomTimelineItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemView.swift; sourceTree = ""; }; 913C8E13B8B602C7B6C0C4AE /* PillTextAttachmentData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillTextAttachmentData.swift; sourceTree = ""; }; 91831D7042EADD0CC2B5EC36 /* SecureBackupScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupScreenUITests.swift; sourceTree = ""; }; + 91868EB98818044E6FEBE532 /* NotificationPermissionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenCoordinator.swift; sourceTree = ""; }; 91CF6F7D08228D16BA69B63B /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.strings"; sourceTree = ""; }; 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCAuthenticationPresenter.swift; sourceTree = ""; }; 92FCD9116ADDE820E4E30F92 /* UIKitBackgroundTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitBackgroundTask.swift; sourceTree = ""; }; @@ -1691,12 +1712,13 @@ 9A2AC7BE17C05CF7D2A22338 /* landscape_test_video.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = landscape_test_video.mov; sourceTree = ""; }; 9A68BCE6438873D2661D93D0 /* BugReportServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportServiceProtocol.swift; sourceTree = ""; }; 9B06663F7858E45882E63471 /* StaticLocationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreen.swift; sourceTree = ""; }; - 9B65A314DF40B6BBF775C2BC /* AnalyticsPromptScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenCoordinator.swift; sourceTree = ""; }; 9B663BE498BB39EADC24025D /* SettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenModels.swift; sourceTree = ""; }; + 9B67DF223EEB8DCAF178A1D4 /* AnalyticsPromptScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreenCoordinator.swift; sourceTree = ""; }; 9B7D8D3638864B7482E148CC /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; 9C3ACC093F88FD9888518561 /* AuthenticationStartScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModel.swift; sourceTree = ""; }; 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestMeasurementParser.swift; sourceTree = ""; }; 9C5E81214D27A6B898FC397D /* ElementX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = ""; }; + 9C6624240FFD32B7F0834229 /* IdentityConfirmedScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmedScreenViewModel.swift; sourceTree = ""; }; 9C698E30698EC59302A8EEBD /* NavigationStackCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationStackCoordinatorTests.swift; sourceTree = ""; }; 9C7F7DE62D33C6A26CBFCD72 /* IntegrationTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenViewModel.swift; sourceTree = ""; }; @@ -1733,6 +1755,7 @@ A6C11AD9813045E44F950410 /* ElementCallWidgetDriverProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallWidgetDriverProtocol.swift; sourceTree = ""; }; A73A07BAEDD74C48795A996A /* AsyncSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncSequence.swift; sourceTree = ""; }; A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = ""; }; + A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = ""; }; A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = ""; }; A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = ""; }; A8903A9F615BBD0E6D7CD133 /* ApplicationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationProtocol.swift; sourceTree = ""; }; @@ -1763,7 +1786,6 @@ AD9CB3B9DFA353AB2B7CD9F8 /* NotificationSettingsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenCoordinator.swift; sourceTree = ""; }; ADB35E2DB4EFE8E6F3959629 /* InviteUsersScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenUITests.swift; sourceTree = ""; }; ADCB8A232D3A8FB3E16A7303 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; - ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = ""; }; ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientMock.swift; sourceTree = ""; }; AE203026B9AD3DB412439866 /* MediaUploadingPreprocessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadingPreprocessorTests.swift; sourceTree = ""; }; AE40D4A5DD857AC16EED945A /* URLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSession.swift; sourceTree = ""; }; @@ -1773,12 +1795,12 @@ AF042B0FB2EE88977C91E330 /* portrait_test_image.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = portrait_test_image.jpg; sourceTree = ""; }; AF11DD57D9FACF2A757AB024 /* AnalyticsPromptUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptUITests.swift; sourceTree = ""; }; AF25E364AE85090A70AE4644 /* AttributedStringBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilderTests.swift; sourceTree = ""; }; + AF848B41DAF1066F3054D4A1 /* SessionVerificationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenModels.swift; sourceTree = ""; }; AFEF489B8E2450E2BA1A314E /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/SAS.strings; sourceTree = ""; }; B0A307A44F952CD73E63AE31 /* RoomEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomEventStringBuilder.swift; sourceTree = ""; }; B0BA67B3E4EF9D29D14A78CE /* AppLockSettingsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSettingsScreenViewModelTests.swift; sourceTree = ""; }; B14B1DE3E2D5D26732C49036 /* RoomChangeRolesScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomChangeRolesScreenViewModel.swift; sourceTree = ""; }; B16048D30F0438731C41F775 /* StateRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineItem.swift; sourceTree = ""; }; - B16CAF20C9AC874A210E2DCF /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = ""; }; B172057567E049007A5C4D92 /* Strings+SAS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+SAS.swift"; sourceTree = ""; }; B1E227F34BE43B08E098796E /* TestablePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestablePreview.swift; sourceTree = ""; }; B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; @@ -1833,6 +1855,7 @@ BCF54536699ACEE3DB6BA3CB /* CompletionSuggestionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionSuggestionService.swift; sourceTree = ""; }; BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNNotificationContent.swift; sourceTree = ""; }; BE89A8BD65CCE3FCC925CA14 /* TimelineItemReplyDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemReplyDetails.swift; sourceTree = ""; }; + BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreenViewModel.swift; sourceTree = ""; }; BEA38B9851CFCC4D67F5587D /* EmojiPickerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerScreenCoordinator.swift; sourceTree = ""; }; BEBA759D1347CFFB3D84ED1F /* UserSessionStoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStoreProtocol.swift; sourceTree = ""; }; BF34A2FD6797535C95AC918D /* PlaceholderScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderScreenCoordinator.swift; sourceTree = ""; }; @@ -1855,6 +1878,7 @@ C2886615BEBAE33A0AA4D5F8 /* RoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenModels.swift; sourceTree = ""; }; C2E9B841EE4878283ECDB554 /* InviteUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreen.swift; sourceTree = ""; }; C2F079B5DBD0D85FEA687AAE /* SDKGeneratedMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKGeneratedMocks.swift; sourceTree = ""; }; + C3285BD95B564CA2A948E511 /* OnboardingFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFlowCoordinator.swift; sourceTree = ""; }; C352359663A0E52BA20761EE /* LoadableImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableImage.swift; sourceTree = ""; }; C4756240773D26AB74C22668 /* OrientationManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManagerProtocol.swift; sourceTree = ""; }; C4C89820BB2B88D4EA28131C /* BugReportScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -1911,7 +1935,6 @@ 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 = ""; }; CF48AF076424DBC1615C74AD /* AuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProxy.swift; sourceTree = ""; }; - D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedHistoryRoomTimelineItem.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 = ""; }; D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = ""; }; @@ -1964,6 +1987,7 @@ DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = ""; }; DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = ""; }; DD97F9661ABF08CE002054A2 /* AppLockServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceTests.swift; sourceTree = ""; }; + DE7C80EF77AD102053D3646E /* RoundedLabelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedLabelItem.swift; sourceTree = ""; }; DE846DDA83BFD7EC5C03760B /* ServerConfirmationScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreenUITests.swift; sourceTree = ""; }; DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaFileHandleProxy.swift; sourceTree = ""; }; DF05DA24F71B455E8EFEBC3B /* SessionVerificationViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationViewModelTests.swift; sourceTree = ""; }; @@ -1992,6 +2016,7 @@ E461B3C8BBBFCA400B268D14 /* AppRouteURLParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteURLParserTests.swift; sourceTree = ""; }; E51E3D86A84341C3A0CB8A40 /* FileRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRoomTimelineView.swift; sourceTree = ""; }; E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; + E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = ""; }; E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = ""; }; E5E94DCFEE803E5ABAE8ACCE /* KeychainControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerProtocol.swift; sourceTree = ""; }; E5F2B6443D1ED8602F328539 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -2000,7 +2025,6 @@ E6E6BDF9D26DB05C88901416 /* RedactedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedactedRoomTimelineItem.swift; sourceTree = ""; }; E6F5D66F158A6662F953733E /* NotificationSettingsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsProxy.swift; sourceTree = ""; }; E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineControllerFactory.swift; sourceTree = ""; }; - E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSessionVerificationBanner.swift; sourceTree = ""; }; E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreenViewModelProtocol.swift; sourceTree = ""; }; E78FC546F28E045A560F2963 /* EncryptionKeyProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyProviderProtocol.swift; sourceTree = ""; }; E8294DB9E95C0C0630418466 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; @@ -2017,6 +2041,7 @@ EA880E78AF4BD24E45A7808C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = ""; }; EB3B237387B8288A5A938F1B /* UserAgentBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilderTests.swift; sourceTree = ""; }; EB63761D9F9CE8B23CBD6179 /* PollFormScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenModels.swift; sourceTree = ""; }; + EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityConfirmationScreenViewModel.swift; sourceTree = ""; }; EBEB8D9F4940E161B18FE4BC /* UITestsNotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsNotificationCenter.swift; sourceTree = ""; }; EC589E641AE46EFB2962534D /* RoomMemberDetailsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsViewModelTests.swift; sourceTree = ""; }; ECB08484CD5D77C9BF97AA78 /* WaitlistScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenUITests.swift; sourceTree = ""; }; @@ -2025,6 +2050,7 @@ ED003DF1B7CF40E7073A2280 /* TracingConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfiguration.swift; sourceTree = ""; }; ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomCell.swift; sourceTree = ""; }; ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProtocol.swift; sourceTree = ""; }; + ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModel.swift; sourceTree = ""; }; ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; path = message.caf; sourceTree = ""; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = ""; }; ED983D4DCA5AFA6E1ED96099 /* StateRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRoomTimelineView.swift; sourceTree = ""; }; @@ -2255,15 +2281,6 @@ path = Logging; sourceTree = ""; }; - 076087FC60064C702EF94796 /* View */ = { - isa = PBXGroup; - children = ( - 5F8002D0392A476D2758B291 /* AnalyticsPromptScreen.swift */, - 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */, - ); - path = View; - sourceTree = ""; - }; 0787F81684E503024BD0C051 /* Services */ = { isa = PBXGroup; children = ( @@ -2621,19 +2638,6 @@ path = View; sourceTree = ""; }; - 3153FCA3F4B0E88B16D99D12 /* SessionVerificationScreen */ = { - isa = PBXGroup; - children = ( - 2A96A67AD0E32C48941EFBB3 /* SessionVerificationScreenCoordinator.swift */, - 4B5046BB295AEAFA6FB81655 /* SessionVerificationScreenModels.swift */, - 1B1EE0908B2BF9212436AD3E /* SessionVerificationScreenStateMachine.swift */, - ADD9E0FFA29EAACFF3AB9732 /* SessionVerificationScreenViewModel.swift */, - B16CAF20C9AC874A210E2DCF /* SessionVerificationScreenViewModelProtocol.swift */, - 914D71CD209A34A8C142CB93 /* View */, - ); - path = SessionVerificationScreen; - sourceTree = ""; - }; 31CE4DA53232AA534057F912 /* Mocks */ = { isa = PBXGroup; children = ( @@ -2679,6 +2683,7 @@ 648DD1C10E4957CB791FE0B8 /* OverridableAvatarImage.swift */, C705E605EF57C19DBE86FFA1 /* PlaceholderAvatarImage.swift */, 839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */, + DE7C80EF77AD102053D3646E /* RoundedLabelItem.swift */, E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */, ); path = Views; @@ -2704,6 +2709,18 @@ path = View; sourceTree = ""; }; + 336A13CA8A1DD526D9C41DD4 /* IdentityConfirmationScreen */ = { + isa = PBXGroup; + children = ( + 7A03E073077D92AA19C43DCF /* IdentityConfirmationScreenCoordinator.swift */, + 7FDF541AE914059942B575B4 /* IdentityConfirmationScreenModels.swift */, + EB76A9AFC6CCAD4998D9B045 /* IdentityConfirmationScreenViewModel.swift */, + 7C71B9802433F1B4252291BB /* IdentityConfirmationScreenViewModelProtocol.swift */, + DDC32FD8B94AA19C4FC062AD /* View */, + ); + path = IdentityConfirmationScreen; + sourceTree = ""; + }; 337015ADFBA3AB96660DB3A6 /* Generated */ = { isa = PBXGroup; children = ( @@ -2862,6 +2879,14 @@ path = SupportingFiles; sourceTree = ""; }; + 4044C040B64B9F077298C947 /* View */ = { + isa = PBXGroup; + children = ( + E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 405B00F139AEE3994601B36A = { isa = PBXGroup; children = ( @@ -3092,7 +3117,6 @@ 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */, ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */, C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */, - E71C28CF29CD05B6D6AE8580 /* HomeScreenSessionVerificationBanner.swift */, 037A5661B26EC6BE068188D7 /* Filters */, ); path = View; @@ -3166,6 +3190,7 @@ 0DBB08A95EFA668F2CF27211 /* AppLockSetupFlowCoordinator.swift */, A9B069D7772DDF6513E0F1B8 /* AuthenticationFlowCoordinator.swift */, 7367B3B9A8CAF902220F31D1 /* BugReportFlowCoordinator.swift */, + C3285BD95B564CA2A948E511 /* OnboardingFlowCoordinator.swift */, 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */, 0833F51229E166BCA141D004 /* RoomRolesAndPermissionsFlowCoordinator.swift */, D28F7A6CEEA4A2815B0F0F55 /* SettingsFlowCoordinator.swift */, @@ -3263,18 +3288,6 @@ path = SecureBackupLogoutConfirmationScreen; sourceTree = ""; }; - 669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */ = { - isa = PBXGroup; - children = ( - 9B65A314DF40B6BBF775C2BC /* AnalyticsPromptScreenCoordinator.swift */, - 840E86A67DB2C92C09771EAD /* AnalyticsPromptScreenModels.swift */, - 63E1FF2DA52B1DE7CAEC5422 /* AnalyticsPromptScreenViewModel.swift */, - 8196D64EB9CF2AF1F43E4ED1 /* AnalyticsPromptScreenViewModelProtocol.swift */, - 076087FC60064C702EF94796 /* View */, - ); - path = AnalyticsPromptScreen; - sourceTree = ""; - }; 6709362D60732DED2069AE0F /* MediaPlayer */ = { isa = PBXGroup; children = ( @@ -3333,6 +3346,14 @@ path = TimelineItemContent; sourceTree = ""; }; + 6D7503E64A458DD09E65A3F7 /* View */ = { + isa = PBXGroup; + children = ( + 307702DD66E7DDCDD9214784 /* IdentityConfirmedScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 6DE13A7AE6587B079F4049D7 /* Notification */ = { isa = PBXGroup; children = ( @@ -3701,6 +3722,11 @@ 7DA2A18CFD03E0BACE6B5C4B /* AnalyticsPromptScreen */ = { isa = PBXGroup; children = ( + 9B67DF223EEB8DCAF178A1D4 /* AnalyticsPromptScreenCoordinator.swift */, + 18486B87745B1811E7FBD3D2 /* AnalyticsPromptScreenModels.swift */, + 6C8EC6EA7EDFCE46710DA306 /* AnalyticsPromptScreenViewModel.swift */, + 7AFD012C3A9F5EF276DDD4AA /* AnalyticsPromptScreenViewModelProtocol.swift */, + 4044C040B64B9F077298C947 /* View */, ); path = AnalyticsPromptScreen; sourceTree = ""; @@ -3866,6 +3892,10 @@ isa = PBXGroup; children = ( 7DA2A18CFD03E0BACE6B5C4B /* AnalyticsPromptScreen */, + 336A13CA8A1DD526D9C41DD4 /* IdentityConfirmationScreen */, + F6D661C666128C74BF0A7482 /* IdentityConfirmedScreen */, + F526F4FE387B32380592BA53 /* NotificationPermissionsScreen */, + C1CD278862878F9545608040 /* SessionVerificationScreen */, ); path = Onboarding; sourceTree = ""; @@ -3909,14 +3939,6 @@ path = LoginScreen; sourceTree = ""; }; - 914D71CD209A34A8C142CB93 /* View */ = { - isa = PBXGroup; - children = ( - 84816E0D2F34E368BF64FA60 /* SessionVerificationScreen.swift */, - ); - path = View; - sourceTree = ""; - }; 92E99C57D7F92ED16F73282C /* ElementCall */ = { isa = PBXGroup; children = ( @@ -4054,6 +4076,14 @@ path = Templates; sourceTree = ""; }; + 9C0C1CB9E16302C00AB4956D /* View */ = { + isa = PBXGroup; + children = ( + 46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */, + ); + path = View; + sourceTree = ""; + }; 9C4193C4524B35FD6B94B5A9 /* Pills */ = { isa = PBXGroup; children = ( @@ -4195,6 +4225,14 @@ path = LayoutTests; sourceTree = ""; }; + A722D372674EE5687E1A67E4 /* View */ = { + isa = PBXGroup; + children = ( + 5FACD034DB52525A3CEF2BDF /* SessionVerificationScreen.swift */, + ); + path = View; + sourceTree = ""; + }; A78C2592419CA4C76FBA8FD2 /* Application */ = { isa = PBXGroup; children = ( @@ -4360,7 +4398,6 @@ CA8F098AE48D958B4257EB24 /* CallInviteRoomTimelineView.swift */, 6E2656184491C505700D2405 /* CollapsibleRoomTimelineView.swift */, 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */, - 75697AB5E64A12F1F069F511 /* EncryptedHistoryRoomTimelineView.swift */, 56C1BCB9E83B09A45387FCA2 /* EncryptedRoomTimelineView.swift */, E51E3D86A84341C3A0CB8A40 /* FileRoomTimelineView.swift */, F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */, @@ -4515,6 +4552,19 @@ path = CreateRoom; sourceTree = ""; }; + C1CD278862878F9545608040 /* SessionVerificationScreen */ = { + isa = PBXGroup; + children = ( + 796CBD0C56FA0D3AEDAB255B /* SessionVerificationScreenCoordinator.swift */, + AF848B41DAF1066F3054D4A1 /* SessionVerificationScreenModels.swift */, + 161CD412E75F4086F422AE39 /* SessionVerificationScreenStateMachine.swift */, + ED33988DA4FD4FC666800106 /* SessionVerificationScreenViewModel.swift */, + A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */, + A722D372674EE5687E1A67E4 /* View */, + ); + path = SessionVerificationScreen; + sourceTree = ""; + }; CA15BB3F6C62B35AE2C281A9 /* Provider */ = { isa = PBXGroup; children = ( @@ -4634,7 +4684,6 @@ D977D4E565C06D3F41C8F8FC /* Virtual */ = { isa = PBXGroup; children = ( - D0140615D2232612C813FD6C /* EncryptedHistoryRoomTimelineItem.swift */, 0B987FC3FDBAA0E1C5AA235C /* PaginationIndicatorRoomTimelineItem.swift */, DF3D25B3EDB283B5807EADCF /* ReadMarkerRoomTimelineItem.swift */, C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */, @@ -4663,6 +4712,14 @@ path = View; sourceTree = ""; }; + DDC32FD8B94AA19C4FC062AD /* View */ = { + isa = PBXGroup; + children = ( + 00AFC5F08734C2EA4EE79C59 /* IdentityConfirmationScreen.swift */, + ); + path = View; + sourceTree = ""; + }; DDF77194AB6E167891D0A8F3 /* View */ = { isa = PBXGroup; children = ( @@ -4716,7 +4773,6 @@ E59565F441830B19DBAE567C /* Screens */ = { isa = PBXGroup; children = ( - 669239C03835CD8B51E0FFDB /* AnalyticsPromptScreen */, 13263FFEA7749D822B51AA90 /* AppLock */, E74CD7681375AD2EAA34D66B /* Authentication */, 295BCC81AB45927F5F2033B1 /* AuthenticationStartScreen */, @@ -4751,7 +4807,6 @@ 7B890CCD20B037760BFDF957 /* RoomRolesAndPermissionsScreen */, 679E9837ECA8D6776079D16E /* RoomScreen */, 2565414373E6F68005966B8E /* SecureBackup */, - 3153FCA3F4B0E88B16D99D12 /* SessionVerificationScreen */, 70B74A432C241E56A7ACE610 /* Settings */, EC4545C7E37E8294D3FE6800 /* StartChatScreen */, ); @@ -4912,6 +4967,18 @@ path = View; sourceTree = ""; }; + F526F4FE387B32380592BA53 /* NotificationPermissionsScreen */ = { + isa = PBXGroup; + children = ( + 91868EB98818044E6FEBE532 /* NotificationPermissionsScreenCoordinator.swift */, + 1DB2FC2AA9A07EE792DF65CF /* NotificationPermissionsScreenModels.swift */, + BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */, + 20E69F67D2A70ABD08CA6D54 /* NotificationPermissionsScreenViewModelProtocol.swift */, + 9C0C1CB9E16302C00AB4956D /* View */, + ); + path = NotificationPermissionsScreen; + sourceTree = ""; + }; F5A65D1D3B83593598DC278D /* EmojiPickerScreen */ = { isa = PBXGroup; children = ( @@ -4924,6 +4991,18 @@ path = EmojiPickerScreen; sourceTree = ""; }; + F6D661C666128C74BF0A7482 /* IdentityConfirmedScreen */ = { + isa = PBXGroup; + children = ( + 595EC503DA5517BBE6D39406 /* IdentityConfirmedScreenCoordinator.swift */, + 3DBE70FFB7936F35811772C1 /* IdentityConfirmedScreenModels.swift */, + 9C6624240FFD32B7F0834229 /* IdentityConfirmedScreenViewModel.swift */, + 8319173DD66C07F45DC48848 /* IdentityConfirmedScreenViewModelProtocol.swift */, + 6D7503E64A458DD09E65A3F7 /* View */, + ); + path = IdentityConfirmedScreen; + sourceTree = ""; + }; F84100ED0C09031BAB7BB77E /* View */ = { isa = PBXGroup; children = ( @@ -5638,11 +5717,11 @@ F7567DD6635434E8C563BF85 /* AnalyticsClientProtocol.swift in Sources */, 54C774874BED4A8FAD1F22FE /* AnalyticsConfiguration.swift in Sources */, 8DDC6F28C797D8685F2F8E32 /* AnalyticsConsentState.swift in Sources */, - 9DF3F6318A4402305F5EB869 /* AnalyticsPromptScreen.swift in Sources */, - 5F28C9146694B381BB82E18C /* AnalyticsPromptScreenCoordinator.swift in Sources */, - 496CC9D59ACFAB84FD9B3B5F /* AnalyticsPromptScreenModels.swift in Sources */, - 0AA0477E063E72B786A983CF /* AnalyticsPromptScreenViewModel.swift in Sources */, - D4ACF3276F5D0DA28D4028C9 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */, + 24A1BBADAC43DC3F3A7347DA /* AnalyticsPromptScreen.swift in Sources */, + DCFE7CB3B9A104330BBB96AD /* AnalyticsPromptScreenCoordinator.swift in Sources */, + 6DC8E43BA04AC2AC4EB2EB97 /* AnalyticsPromptScreenModels.swift in Sources */, + DB65401349C143DFF883E2B0 /* AnalyticsPromptScreenViewModel.swift in Sources */, + 05BAB510CBC2ED35C154ADD0 /* AnalyticsPromptScreenViewModelProtocol.swift in Sources */, 3C73442084BF8A6939F0F80B /* AnalyticsService.swift in Sources */, 020F7E70167FB2833266F2F0 /* AnalyticsSettingsScreen.swift in Sources */, 95690DDD9D547D3D842ACBE3 /* AnalyticsSettingsScreenCoordinator.swift in Sources */, @@ -5812,8 +5891,6 @@ 8B41D0357B91CD3B6F6A3BCA /* EmoteRoomTimelineItemContent.swift in Sources */, 68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */, 8B1D5CE017EEC734CF5FE130 /* Encodable.swift in Sources */, - B09DC6E3D0EE87C4D4ABFAB3 /* EncryptedHistoryRoomTimelineItem.swift in Sources */, - 9965CB800CE6BC74ACA969FC /* EncryptedHistoryRoomTimelineView.swift in Sources */, 4C5A638DAA8AF64565BA4866 /* EncryptedRoomTimelineItem.swift in Sources */, B5903E48CF43259836BF2DBF /* EncryptedRoomTimelineView.swift in Sources */, FBD402E3170EB1ED0D1AA672 /* EncryptionKeyProvider.swift in Sources */, @@ -5850,9 +5927,18 @@ B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */, 0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */, A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */, - 584590D0EA548152A393E72C /* HomeScreenSessionVerificationBanner.swift in Sources */, DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */, 56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */, + 2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */, + C3BB6887CF13B19182E81F87 /* IdentityConfirmationScreenCoordinator.swift in Sources */, + 77574A519A4E484880053EAD /* IdentityConfirmationScreenModels.swift in Sources */, + 0C346A4AD174F441EDB1414E /* IdentityConfirmationScreenViewModel.swift in Sources */, + 489BB6A733D3DA0FE7062650 /* IdentityConfirmationScreenViewModelProtocol.swift in Sources */, + 9C4EC28A921486B1775D7F8C /* IdentityConfirmedScreen.swift in Sources */, + 93AC1E8418D8C827671FB3A9 /* IdentityConfirmedScreenCoordinator.swift in Sources */, + D22345698F6548C1EE960940 /* IdentityConfirmedScreenModels.swift in Sources */, + 01681E8B20AD6F0D237F2DC1 /* IdentityConfirmedScreenViewModel.swift in Sources */, + AADE7C2497A7B55D8BED7BD6 /* IdentityConfirmedScreenViewModelProtocol.swift in Sources */, BA31448FBD9697F8CB9A83CD /* ImageCache.swift in Sources */, 85813D87DDD7F67A46BD9AF7 /* ImageProviderProtocol.swift in Sources */, 7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */, @@ -5970,6 +6056,11 @@ 652ACCF104A8CEF30788963C /* NotificationManager.swift in Sources */, 06D3942496E9E0E655F14D21 /* NotificationManagerProtocol.swift in Sources */, C4C84901ABAC9B17564AB7EB /* NotificationName.swift in Sources */, + 5139F4BD5A5DF6F8D11A9BDE /* NotificationPermissionsScreen.swift in Sources */, + 454311EAC17D778E19F46592 /* NotificationPermissionsScreenCoordinator.swift in Sources */, + 3E7B65C2C97748D5D65AAA8B /* NotificationPermissionsScreenModels.swift in Sources */, + D4D7CCECC6C0AAFC42E165BB /* NotificationPermissionsScreenViewModel.swift in Sources */, + C8A9C595038AFA2D707AC8C1 /* NotificationPermissionsScreenViewModelProtocol.swift in Sources */, C0090506A52A1991BAF4BA68 /* NotificationSettingsChatType.swift in Sources */, AA93B3F9B5DD097DEF79F981 /* NotificationSettingsEditScreen.swift in Sources */, 53A59720F4729D9BBFFB7CAB /* NotificationSettingsEditScreenCoordinator.swift in Sources */, @@ -5987,6 +6078,7 @@ CBD2ABE4C1A47ECD99E1488E /* NotificationSettingsScreenViewModelProtocol.swift in Sources */, 523C6800ED85D5810CF18C19 /* OIDCAccountSettingsPresenter.swift in Sources */, 9A4E3D5AA44B041DAC3A0D81 /* OIDCAuthenticationPresenter.swift in Sources */, + 11A6B8E3CBDBF0A4107FF4CE /* OnboardingFlowCoordinator.swift in Sources */, 3CE4C5071B6D2576E2473989 /* OrderedSet.swift in Sources */, AA5924D3B67F7ACD98BBEFDC /* OrientationManagerProtocol.swift in Sources */, 804C15D8ADE0EA7A5268F58A /* OverridableAvatarImage.swift in Sources */, @@ -6139,7 +6231,7 @@ 9BD3A773186291560DF92B62 /* RoomTimelineProvider.swift in Sources */, 77D7DAA41AAB36800C1F2E2D /* RoomTimelineProviderProtocol.swift in Sources */, B2F8E01ABA1BA30265B4ECBE /* RoundedCornerShape.swift in Sources */, - D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */, + BD11E639CF566A9DA8FCA717 /* RoundedLabelItem.swift in Sources */, 50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */, D43F0503EF2CBC55272538FE /* SDKGeneratedMocks.swift in Sources */, F4971845B5C4F270F6BC5745 /* ScaledFrameModifier.swift in Sources */, @@ -6187,12 +6279,12 @@ 237FC70AA257B935F53316BA /* SessionVerificationControllerProxy.swift in Sources */, AE1A73B24D63DA3D63DC4EE3 /* SessionVerificationControllerProxyMock.swift in Sources */, 94A65DD8A353DF112EBEF67A /* SessionVerificationControllerProxyProtocol.swift in Sources */, - 7A0A0929556792FB19B812C5 /* SessionVerificationScreen.swift in Sources */, - E9F148072F9513EC2272AA21 /* SessionVerificationScreenCoordinator.swift in Sources */, - 5770C4906668C6D3008A2AC9 /* SessionVerificationScreenModels.swift in Sources */, - B27D3190784F85916DA1C394 /* SessionVerificationScreenStateMachine.swift in Sources */, - F4433EF57B4BB3C077F8B00E /* SessionVerificationScreenViewModel.swift in Sources */, - E570117376826665640F0CFD /* SessionVerificationScreenViewModelProtocol.swift in Sources */, + 707E49BE07E8EB8A13C0EB1E /* SessionVerificationScreen.swift in Sources */, + D02DEB36D32A72A1B365E452 /* SessionVerificationScreenCoordinator.swift in Sources */, + 5710AAB27D5D866292C1FE06 /* SessionVerificationScreenModels.swift in Sources */, + 601AB75BD52B0B4276CEB84A /* SessionVerificationScreenStateMachine.swift in Sources */, + 4A8287E5281B44A8754BE509 /* SessionVerificationScreenViewModel.swift in Sources */, + 762DB0973865293F0C3D3D7B /* SessionVerificationScreenViewModelProtocol.swift in Sources */, 755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */, 34F1261CEF6D6A00D559B520 /* SettingsScreen.swift in Sources */, AF8BFA37791E1756EE243E08 /* SettingsScreenCoordinator.swift in Sources */, @@ -6737,7 +6829,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.5.13; + MARKETING_VERSION = 1.6.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6813,7 +6905,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.4; KEYCHAIN_ACCESS_GROUP_IDENTIFIER = "$(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)"; MACOSX_DEPLOYMENT_TARGET = 13.3; - MARKETING_VERSION = 1.5.13; + MARKETING_VERSION = 1.6.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; diff --git a/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/Contents.json b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/Contents.json new file mode 100644 index 0000000000..3ca614ee7e --- /dev/null +++ b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "background-bottom-light.png", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "background-bottom-dark.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-dark.png b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-dark.png new file mode 100644 index 0000000000..075078e12d Binary files /dev/null and b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-dark.png differ diff --git a/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-light.png b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-light.png new file mode 100644 index 0000000000..0de5a0ff64 Binary files /dev/null and b/ElementX/Resources/Assets.xcassets/images/background-bottom.imageset/background-bottom-light.png differ diff --git a/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Alerts.svg b/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Alerts.svg new file mode 100644 index 0000000000..98673b3f44 --- /dev/null +++ b/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Alerts.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Contents.json b/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Contents.json new file mode 100644 index 0000000000..643d2effbe --- /dev/null +++ b/ElementX/Resources/Assets.xcassets/images/notifications-prompt-graphic.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Alerts.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 55794b14fe..b19aa1c283 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -398,6 +398,10 @@ "screen_edit_profile_error_title" = "Unable to update profile"; "screen_edit_profile_title" = "Edit profile"; "screen_edit_profile_updating_details" = "Updating profile…"; +"screen_identity_confirmation_subtitle" = "Verify this device to set up secure messaging."; +"screen_identity_confirmation_title" = "Confirm that it's you"; +"screen_identity_confirmed_subtitle" = "Now you can read or send messages securely, and anyone you chat with can also trust this device."; +"screen_identity_confirmed_title" = "Device verified"; "screen_invites_decline_chat_message" = "Are you sure you want to decline the invitation to join %1$@?"; "screen_invites_decline_chat_title" = "Decline invite"; "screen_invites_decline_direct_chat_message" = "Are you sure you want to decline this private chat with %1$@?"; diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 0eec504617..095a5802d5 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -83,7 +83,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg MXLog.info("\(appName) \(appVersion) (\(appBuild))") if ProcessInfo.processInfo.environment["RESET_APP_SETTINGS"].map(Bool.init) == true { - AppSettings.reset() + AppSettings.resetAllSettings() } self.appDelegate = appDelegate @@ -154,11 +154,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg return } - if appSettings.appLockIsMandatory, !appLockFlowCoordinator.appLockService.isEnabled { - stateMachine.processEvent(.startWithAppLockSetup) - } else { - stateMachine.processEvent(.startWithExistingSession) - } + stateMachine.processEvent(.startWithExistingSession) } func stop() { @@ -319,13 +315,21 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg appSettings.migratedAccounts[userID] = true } } + + if oldVersion < Version(1, 6, 0) { + MXLog.info("Migrating to v1.6.0, marking identity confirmation onboarding as ran.") + if !userSessionStore.userIDs.isEmpty { + appSettings.hasRunIdentityConfirmationOnboarding = true + appSettings.hasRunNotificationPermissionsOnboarding = true + } + } } /// Clears the keychain, app support directory etc ready for a fresh use. /// - Parameter includingSettings: Whether to additionally wipe the user's app settings too. private func wipeUserData(includingSettings: Bool = false) { if includingSettings { - AppSettings.reset() + AppSettings.resetAllSettings() appLockFlowCoordinator.appLockService.disable() } userSessionStore.reset() @@ -339,20 +343,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg case (.initial, .startWithAuthentication, .signedOut): startAuthentication() case (.signedOut, .createdUserSession, .signedIn): - setupUserSession() + setupUserSession(isNewLogin: true) case (.initial, .startWithExistingSession, .restoringSession): restoreUserSession() case (.restoringSession, .failedRestoringSession, .signedOut): showLoginErrorToast() presentSplashScreen() case (.restoringSession, .createdUserSession, .signedIn): - setupUserSession() - - case (.initial, .startWithAppLockSetup, .mandatoryAppLockSetup): - startMandatoryAppLockSetup() - case (.mandatoryAppLockSetup, .appLockSetupComplete, .restoringSession): - restoreUserSession() - + setupUserSession(isNewLogin: false) + case (.signingOut, .signOut, .signingOut): // We can ignore signOut when already in the process of signing out, // such as the SDK sending an authError due to token invalidation. @@ -397,7 +396,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg encryptionKeyProvider: EncryptionKeyProvider(), appSettings: appSettings) authenticationFlowCoordinator = AuthenticationFlowCoordinator(authenticationService: authenticationService, - appLockService: appLockFlowCoordinator.appLockService, bugReportService: ServiceLocator.shared.bugReportService, navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings, @@ -450,7 +448,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } } - private func setupUserSession() { + private func setupUserSession(isNewLogin: Bool) { guard let userSession else { fatalError("User session not setup") } @@ -462,9 +460,11 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg bugReportService: ServiceLocator.shared.bugReportService, roomTimelineControllerFactory: RoomTimelineControllerFactory(), appSettings: appSettings, - analytics: ServiceLocator.shared.analytics) + analytics: ServiceLocator.shared.analytics, + notificationManager: notificationManager, + isNewLogin: isNewLogin) - userSessionFlowCoordinator.actions + userSessionFlowCoordinator.actionsPublisher .sink { [weak self] action in guard let self else { return } @@ -487,32 +487,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg userSessionFlowCoordinator.handleAppRoute(storedAppRoute, animated: false) } } - - /// Used to add a PIN code to an existing session that somehow missed out mandatory PIN setup. - private func startMandatoryAppLockSetup() { - MXLog.info("Mandatory App Lock enabled but no PIN is set. Showing the setup flow.") - let navigationCoordinator = NavigationStackCoordinator() - let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .onboarding, - appLockService: appLockFlowCoordinator.appLockService, - navigationStackCoordinator: navigationCoordinator) - coordinator.actions.sink { [weak self] action in - guard let self else { return } - switch action { - case .complete: - stateMachine.processEvent(.appLockSetupComplete) - appLockSetupFlowCoordinator = nil - case .forceLogout: - fatalError("Creating a PIN shouldn't be able to fail in this way") - } - } - .store(in: &cancellables) - - appLockSetupFlowCoordinator = coordinator - navigationRootCoordinator.setRootCoordinator(navigationCoordinator) - coordinator.start() - } - private func logout(isSoft: Bool) { guard let userSession else { fatalError("User session not setup") @@ -544,6 +519,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg userSessionStore.logout(userSession: userSession) tearDownUserSession() + AppSettings.resetSessionSpecificSettings() + // Reset analytics ServiceLocator.shared.analytics.optOut() ServiceLocator.shared.analytics.resetConsentState() @@ -591,7 +568,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private func configureNotificationManager() { notificationManager.setUserSession(userSession) - notificationManager.requestAuthorization() appDelegateObserver = appDelegate.callbacks .receive(on: DispatchQueue.main) @@ -689,7 +665,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg // MARK: Toasts and loading indicators - private static let loadingIndicatorIdentifier = "AppCoordinatorLoading" + private static let loadingIndicatorIdentifier = "\(AppCoordinator.self)-Loading" private func showLoadingIndicator() { ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Application/AppCoordinatorStateMachine.swift b/ElementX/Sources/Application/AppCoordinatorStateMachine.swift index 9de14967ce..f4806073da 100644 --- a/ElementX/Sources/Application/AppCoordinatorStateMachine.swift +++ b/ElementX/Sources/Application/AppCoordinatorStateMachine.swift @@ -28,12 +28,7 @@ class AppCoordinatorStateMachine { case softLogout /// Opening an existing session. case restoringSession - - /// Showing the mandatory app lock setup flow before restoring the session. - /// This state should only be allowed before restoring an existing session. For - /// new users the setup is inserted in the middle of the authentication flow. - case mandatoryAppLockSetup - + /// User session started case signedIn @@ -48,21 +43,13 @@ class AppCoordinatorStateMachine { /// Start the `AppCoordinator` by restoring an existing account. case startWithExistingSession - - /// Start the `AppCoordinator` by showing the mandatory PIN creation flow. - /// This event should only be sent if an account exists and a mandatory PIN is - /// missing. Normally it will be handled as part of the authentication flow. - case startWithAppLockSetup /// Restoring session failed. case failedRestoringSession /// A session has been created. case createdUserSession - - /// The app lock setup has been completed. - case appLockSetupComplete - + /// Request sign out. case signOut(isSoft: Bool, disableAppLock: Bool) /// Request the soft logout screen. @@ -92,10 +79,7 @@ class AppCoordinatorStateMachine { stateMachine.addRoutes(event: .startWithExistingSession, transitions: [.initial => .restoringSession]) stateMachine.addRoutes(event: .createdUserSession, transitions: [.restoringSession => .signedIn]) stateMachine.addRoutes(event: .failedRestoringSession, transitions: [.restoringSession => .signedOut]) - - stateMachine.addRoutes(event: .startWithAppLockSetup, transitions: [.initial => .mandatoryAppLockSetup]) - stateMachine.addRoutes(event: .appLockSetupComplete, transitions: [.mandatoryAppLockSetup => .restoringSession]) - + stateMachine.addRoutes(event: .completedSigningOut, transitions: [.signingOut(isSoft: false, disableAppLock: false) => .signedOut, .signingOut(isSoft: false, disableAppLock: true) => .signedOut]) stateMachine.addRoutes(event: .showSoftLogout, transitions: [.signingOut(isSoft: true, disableAppLock: false) => .softLogout]) diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 6b51150976..cb63f2fba6 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -24,10 +24,13 @@ final class AppSettings { case seenInvites case appLockNumberOfPINAttempts case appLockNumberOfBiometricAttempts - case lastLoginDate case migratedAccounts case timelineStyle + case analyticsConsentState + case hasRunNotificationPermissionsOnboarding + case hasRunIdentityConfirmationOnboarding + case enableNotifications case enableInAppNotifications case pusherProfileTag @@ -59,11 +62,16 @@ final class AppSettings { #if IS_MAIN_APP - static func reset() { + static func resetAllSettings() { MXLog.warning("Resetting the AppSettings.") store.removePersistentDomain(forName: suiteName) } + static func resetSessionSpecificSettings() { + MXLog.warning("Resetting the user session specific AppSettings.") + store.removeObject(forKey: UserDefaultsKeys.hasRunIdentityConfirmationOnboarding.rawValue) + } + static func configureWithSuiteName(_ name: String) { suiteName = name @@ -120,7 +128,9 @@ final class AppSettings { let privacyURL: URL = "https://element.io/privacy" /// An email address that should be used for support requests. let supportEmailAddress = "support@element.io" - // A URL where users can go read more about the chat backup. + /// A URL where users can go read more about encryption in general. + let encryptionURL: URL = "https://element.io/help#encryption" + /// A URL where users can go read more about the chat backup. let chatBackupDetailsURL: URL = "https://element.io/help#encryption5" @UserPreference(key: UserDefaultsKeys.appAppearance, defaultValue: .system, storageType: .userDefaults(store)) @@ -153,13 +163,6 @@ final class AppSettings { return url }() - - /// The date that the call to `/login` completed successfully. This is used to put - /// a hard wall on the history of encrypted messages until we have key backup. - /// - /// Not a multi-account aware setting as key backup will come before multi-account. - @UserPreference(key: UserDefaultsKeys.lastLoginDate, defaultValue: nil, storageType: .userDefaults(store)) - var lastLoginDate: Date? /// A dictionary of accounts that have performed an initial sync through their proxy. /// @@ -211,6 +214,12 @@ final class AppSettings { @UserPreference(key: UserDefaultsKeys.analyticsConsentState, defaultValue: AnalyticsConsentState.unknown, storageType: .userDefaults(store)) var analyticsConsentState + @UserPreference(key: UserDefaultsKeys.hasRunNotificationPermissionsOnboarding, defaultValue: false, storageType: .userDefaults(store)) + var hasRunNotificationPermissionsOnboarding + + @UserPreference(key: UserDefaultsKeys.hasRunIdentityConfirmationOnboarding, defaultValue: false, storageType: .userDefaults(store)) + var hasRunIdentityConfirmationOnboarding + // MARK: - Home Screen @UserPreference(key: UserDefaultsKeys.hideUnreadMessagesBadge, defaultValue: false, storageType: .userDefaults(store)) diff --git a/ElementX/Sources/FlowCoordinators/AuthenticationFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/AuthenticationFlowCoordinator.swift index 2d051e547f..dd38ba5b72 100644 --- a/ElementX/Sources/FlowCoordinators/AuthenticationFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/AuthenticationFlowCoordinator.swift @@ -24,7 +24,6 @@ protocol AuthenticationFlowCoordinatorDelegate: AnyObject { class AuthenticationFlowCoordinator: FlowCoordinatorProtocol { private let authenticationService: AuthenticationServiceProxyProtocol - private let appLockService: AppLockServiceProtocol private let bugReportService: BugReportServiceProtocol private let navigationRootCoordinator: NavigationRootCoordinator private let navigationStackCoordinator: NavigationStackCoordinator @@ -36,23 +35,18 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol { private var oidcPresenter: OIDCAuthenticationPresenter? - // periphery: ignore - used to store the coordinator to avoid deallocation - private var appLockFlowCoordinator: AppLockSetupFlowCoordinator? - // periphery:ignore - retaining purpose private var bugReportFlowCoordinator: BugReportFlowCoordinator? weak var delegate: AuthenticationFlowCoordinatorDelegate? init(authenticationService: AuthenticationServiceProxyProtocol, - appLockService: AppLockServiceProtocol, bugReportService: BugReportServiceProtocol, navigationRootCoordinator: NavigationRootCoordinator, appSettings: AppSettings, analytics: AnalyticsService, userIndicatorController: UserIndicatorControllerProtocol) { self.authenticationService = authenticationService - self.appLockService = appLockService self.bugReportService = bugReportService self.navigationRootCoordinator = navigationRootCoordinator self.appSettings = appSettings @@ -108,7 +102,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol { private func showReportProblemScreen() { bugReportFlowCoordinator = BugReportFlowCoordinator(parameters: .init(presentationMode: .sheet(navigationStackCoordinator), - userIndicatorController: ServiceLocator.shared.userIndicatorController, + userIndicatorController: userIndicatorController, bugReportService: bugReportService, userID: nil, deviceID: nil)) @@ -265,58 +259,10 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol { } private func userHasSignedIn(userSession: UserSessionProtocol) { - appSettings.lastLoginDate = .now - - if appSettings.appLockIsMandatory, !appLockService.isEnabled { - showAppLockSetupFlow(userSession: userSession) - } else if analytics.shouldShowAnalyticsPrompt { - showAnalyticsPrompt(userSession: userSession) - } else { - delegate?.authenticationFlowCoordinator(didLoginWithSession: userSession) - } - } - - private func showAppLockSetupFlow(userSession: UserSessionProtocol) { - let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .onboarding, - appLockService: appLockService, - navigationStackCoordinator: navigationStackCoordinator) - coordinator.actions.sink { [weak self] action in - guard let self else { return } - switch action { - case .complete: - appLockFlowCoordinator = nil - if analytics.shouldShowAnalyticsPrompt { - showAnalyticsPrompt(userSession: userSession) - } else { - delegate?.authenticationFlowCoordinator(didLoginWithSession: userSession) - } - case .forceLogout: - fatalError("The PIN creation flow should not fail.") - } - } - .store(in: &cancellables) - - appLockFlowCoordinator = coordinator - coordinator.start() - } - - private func showAnalyticsPrompt(userSession: UserSessionProtocol) { - let coordinator = AnalyticsPromptScreenCoordinator(analytics: analytics, termsURL: appSettings.analyticsConfiguration.termsURL) - - coordinator.actions - .sink { [weak self] action in - guard let self else { return } - switch action { - case .done: - delegate?.authenticationFlowCoordinator(didLoginWithSession: userSession) - } - } - .store(in: &cancellables) - - navigationStackCoordinator.push(coordinator) + delegate?.authenticationFlowCoordinator(didLoginWithSession: userSession) } - private static let loadingIndicatorIdentifier = "authenticationFlowCoordinatorLoading" + private static let loadingIndicatorIdentifier = "\(AuthenticationFlowCoordinator.self)-Loading" private func startLoading() { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift new file mode 100644 index 0000000000..51b38350b6 --- /dev/null +++ b/ElementX/Sources/FlowCoordinators/OnboardingFlowCoordinator.swift @@ -0,0 +1,343 @@ +// +// Copyright 2024 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 Foundation +import SwiftState + +class OnboardingFlowCoordinator: FlowCoordinatorProtocol { + private let userSession: UserSessionProtocol + private let appLockService: AppLockServiceProtocol + private let analyticsService: AnalyticsService + private let appSettings: AppSettings + private let notificationManager: NotificationManagerProtocol + private let rootNavigationStackCoordinator: NavigationStackCoordinator + private let userIndicatorController: UserIndicatorControllerProtocol + private let isNewLogin: Bool + + private var navigationStackCoordinator: NavigationStackCoordinator! + + enum State: StateType { + case initial + case identityConfirmation + case identityConfirmed + case appLockSetup + case analyticsPrompt + case notificationPermissions + case finished + } + + enum Event: EventType { + case next + } + + private let stateMachine: StateMachine + private var cancellables = Set() + + // periphery: ignore - used to store the coordinator to avoid deallocation + private var appLockFlowCoordinator: AppLockSetupFlowCoordinator? + + init(userSession: UserSessionProtocol, + appLockService: AppLockServiceProtocol, + analyticsService: AnalyticsService, + appSettings: AppSettings, + notificationManager: NotificationManagerProtocol, + navigationStackCoordinator: NavigationStackCoordinator, + userIndicatorController: UserIndicatorControllerProtocol, + isNewLogin: Bool) { + self.userSession = userSession + self.appLockService = appLockService + self.analyticsService = analyticsService + self.appSettings = appSettings + self.notificationManager = notificationManager + self.userIndicatorController = userIndicatorController + self.isNewLogin = isNewLogin + + rootNavigationStackCoordinator = navigationStackCoordinator + self.navigationStackCoordinator = NavigationStackCoordinator() + + stateMachine = .init(state: .initial) + } + + var shouldStart: Bool { + guard stateMachine.state == .initial, !ProcessInfo.isRunningIntegrationTests else { + return false + } + + return isNewLogin || requiresVerification || requiresAppLockSetup || requiresAnalyticsSetup || requiresNotificationsSetup + } + + func start() { + guard shouldStart else { + fatalError("This flow coordinator shouldn't have been started") + } + + configureStateMachine() + + stateMachine.tryEvent(.next) + + rootNavigationStackCoordinator.setFullScreenCoverCoordinator(navigationStackCoordinator, animated: !isNewLogin) + } + + func handleAppRoute(_ appRoute: AppRoute, animated: Bool) { + fatalError() + } + + func clearRoute(animated: Bool) { + fatalError() + } + + // MARK: - Private + + private var requiresVerification: Bool { + // We want to make sure onboarding finishes but also every time the user becomes unverified (e.g. account reset) + !appSettings.hasRunIdentityConfirmationOnboarding || userSession.sessionSecurityStatePublisher.value.verificationState == .unverified + } + + private var requiresAppLockSetup: Bool { + appSettings.appLockIsMandatory && !appLockService.isEnabled + } + + private var requiresAnalyticsSetup: Bool { + analyticsService.shouldShowAnalyticsPrompt + } + + private var requiresNotificationsSetup: Bool { + !appSettings.hasRunNotificationPermissionsOnboarding + } + + private func configureStateMachine() { + stateMachine.addRouteMapping { [weak self] _, fromState, _ in + guard let self else { + return nil + } + + switch (fromState, requiresVerification, requiresAppLockSetup, requiresAnalyticsSetup, requiresNotificationsSetup) { + case (.initial, true, _, _, _): + return .identityConfirmation + case (.initial, false, true, _, _): + return .appLockSetup + case (.initial, false, false, true, _): + return .analyticsPrompt + case (.initial, false, false, false, true): + return .notificationPermissions + + case (.identityConfirmation, _, _, _, _): + return .identityConfirmed + + case (.identityConfirmed, _, true, _, _): + return .appLockSetup + case (.identityConfirmed, _, false, true, _): + return .analyticsPrompt + case (.identityConfirmed, _, false, false, true): + return .notificationPermissions + case (.identityConfirmed, _, false, false, false): + return .finished + + case (.appLockSetup, _, _, true, _): + return .analyticsPrompt + case (.appLockSetup, _, _, false, true): + return .notificationPermissions + case (.appLockSetup, _, _, false, false): + return .finished + + case (.analyticsPrompt, _, _, _, true): + return .notificationPermissions + case (.analyticsPrompt, _, _, _, false): + return .finished + + case (.notificationPermissions, _, _, _, _): + return .finished + + default: + return nil + } + } + + stateMachine.addAnyHandler(.any => .any) { [weak self] context in + guard let self else { return } + + switch (context.fromState, context.event, context.toState) { + case (_, _, .identityConfirmation): + presentIdentityConfirmationScreen() + case (_, _, .identityConfirmed): + presentIdentityConfirmedScreen() + case (_, _, .appLockSetup): + presentAppLockSetupFlow() + case (_, _, .analyticsPrompt): + presentAnalyticsPromptScreen() + case (_, _, .notificationPermissions): + presentNotificationPermissionsScreen() + case (_, _, .finished): + rootNavigationStackCoordinator.setFullScreenCoverCoordinator(nil) + default: + fatalError("Unknown transition: \(context)") + } + } + + stateMachine.addErrorHandler { context in + fatalError("Unexpected transition: \(context)") + } + } + + private func presentIdentityConfirmationScreen() { + let parameters = IdentityConfirmationScreenCoordinatorParameters(userSession: userSession, + appSettings: appSettings, + userIndicatorController: userIndicatorController) + + let coordinator = IdentityConfirmationScreenCoordinator(parameters: parameters) + coordinator.actionsPublisher.sink { [weak self] action in + guard let self else { return } + + switch action { + case .otherDevice: + Task { + await self.presentSessionVerificationScreen() + } + case .recoveryKey: + presentRecoveryKeyScreen() + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentSessionVerificationScreen() async { + guard case let .success(sessionVerificationController) = await userSession.clientProxy.sessionVerificationControllerProxy() else { + fatalError("The sessionVerificationController should aways be valid at this point") + } + + let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController) + + let coordinator = SessionVerificationScreenCoordinator(parameters: parameters) + + coordinator.actions + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .done: + appSettings.hasRunIdentityConfirmationOnboarding = true + stateMachine.tryEvent(.next) + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentRecoveryKeyScreen() { + let parameters = SecureBackupRecoveryKeyScreenCoordinatorParameters(secureBackupController: userSession.clientProxy.secureBackupController, + userIndicatorController: ServiceLocator.shared.userIndicatorController, + isModallyPresented: false) + + let coordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: parameters) + + coordinator.actions + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .recoveryFixed: + appSettings.hasRunIdentityConfirmationOnboarding = true + stateMachine.tryEvent(.next) + default: + fatalError("Other flows shouldn't be possible") + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentIdentityConfirmedScreen() { + let coordinator = IdentityConfirmedScreenCoordinator(parameters: .init()) + coordinator.actionsPublisher + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .done: + stateMachine.tryEvent(.next) + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentAppLockSetupFlow() { + let coordinator = AppLockSetupFlowCoordinator(presentingFlow: .onboarding, + appLockService: appLockService, + navigationStackCoordinator: navigationStackCoordinator) + coordinator.actions.sink { [weak self] action in + guard let self else { return } + switch action { + case .complete: + appLockFlowCoordinator = nil + stateMachine.tryEvent(.next) + case .forceLogout: + fatalError("The PIN creation flow should not fail.") + } + } + .store(in: &cancellables) + + appLockFlowCoordinator = coordinator + coordinator.start() + } + + private func presentAnalyticsPromptScreen() { + let coordinator = AnalyticsPromptScreenCoordinator(analytics: analyticsService, termsURL: appSettings.analyticsConfiguration.termsURL) + + coordinator.actions + .sink { [weak self] action in + guard let self else { return } + switch action { + case .done: + stateMachine.tryEvent(.next) + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentNotificationPermissionsScreen() { + let coordinator = NotificationPermissionsScreenCoordinator(parameters: .init(notificationManager: notificationManager)) + + coordinator.actions + .sink { [weak self] action in + guard let self else { return } + switch action { + case .done: + appSettings.hasRunNotificationPermissionsOnboarding = true + stateMachine.tryEvent(.next) + } + } + .store(in: &cancellables) + + presentCoordinator(coordinator) + } + + private func presentCoordinator(_ coordinator: CoordinatorProtocol) { + if navigationStackCoordinator.rootCoordinator == nil { + navigationStackCoordinator.setRootCoordinator(coordinator) + } else { + navigationStackCoordinator.push(coordinator) + } + } +} diff --git a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift index f0eeb8ce9b..4e84847e7d 100644 --- a/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift @@ -434,8 +434,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)) let timelineController = roomTimelineControllerFactory.buildRoomTimelineController(roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - secureBackupController: userSession.clientProxy.secureBackupController) + timelineItemFactory: timelineItemFactory) self.timelineController = timelineController analytics.trackViewRoom(isDM: roomProxy.isDirect, isSpace: roomProxy.isSpace) @@ -918,8 +917,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol { stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)) let roomTimelineController = roomTimelineControllerFactory.buildRoomTimelineController(roomProxy: roomProxy, - timelineItemFactory: timelineItemFactory, - secureBackupController: userSession.clientProxy.secureBackupController) + timelineItemFactory: timelineItemFactory) let parameters = RoomPollsHistoryScreenCoordinatorParameters(roomProxy: roomProxy, pollInteractionHandler: PollInteractionHandler(analyticsService: analytics, roomProxy: roomProxy), diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index 1ea9db5057..c6e97f42f6 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -130,10 +130,6 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { presentLegalInformationScreen() case .blockedUsers: presentBlockedUsersScreen() - case .sessionVerification: - Task { - await self.presentSessionVerificationScreen() - } case .accountSessions: presentAccountSessionsListURL() case .notifications: @@ -212,35 +208,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { userIndicatorController: parameters.userIndicatorController)) navigationStackCoordinator.push(coordinator) } - - private func presentSessionVerificationScreen() async { - guard case let .success(sessionVerificationController) = await parameters.userSession.clientProxy.sessionVerificationControllerProxy() else { - fatalError("The sessionVerificationController should aways be valid at this point") - } - - let verificationParameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController, - recoveryState: parameters.userSession.sessionSecurityStatePublisher.value.recoveryState) - let coordinator = SessionVerificationScreenCoordinator(parameters: verificationParameters) - coordinator.actions - .sink { [weak self] action in - guard let self else { return } - - switch action { - case .recoveryKey: - navigationStackCoordinator.setSheetCoordinator(nil) - handleAppRoute(.chatBackupSettings, animated: true) - case .done: - navigationStackCoordinator.setSheetCoordinator(nil) - } - } - .store(in: &cancellables) - - navigationStackCoordinator.setSheetCoordinator(coordinator) { [weak self] in - self?.navigationStackCoordinator.setSheetCoordinator(nil) - } - } - private func presentNotificationSettings() { let notificationParameters = NotificationSettingsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator, userSession: parameters.userSession, diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index a13c99c9f7..f121e97967 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -31,7 +31,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { private let windowManager: WindowManagerProtocol private let bugReportService: BugReportServiceProtocol private let appSettings: AppSettings - private let actionsSubject: PassthroughSubject = .init() private let stateMachine: UserSessionFlowCoordinatorStateMachine @@ -39,6 +38,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { private let settingsFlowCoordinator: SettingsFlowCoordinator + private let onboardingFlowCoordinator: OnboardingFlowCoordinator + // periphery:ignore - retaining purpose private var bugReportFlowCoordinator: BugReportFlowCoordinator? @@ -52,7 +53,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { private let selectedRoomSubject = CurrentValueSubject(nil) - var actions: AnyPublisher { + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { actionsSubject.eraseToAnyPublisher() } @@ -63,7 +65,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { bugReportService: BugReportServiceProtocol, roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol, appSettings: AppSettings, - analytics: AnalyticsService) { + analytics: AnalyticsService, + notificationManager: NotificationManagerProtocol, + isNewLogin: Bool) { stateMachine = UserSessionFlowCoordinatorStateMachine() self.userSession = userSession self.navigationRootCoordinator = navigationRootCoordinator @@ -98,8 +102,29 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { navigationSplitCoordinator: navigationSplitCoordinator, userIndicatorController: ServiceLocator.shared.userIndicatorController)) + onboardingFlowCoordinator = OnboardingFlowCoordinator(userSession: userSession, + appLockService: appLockService, + analyticsService: analytics, + appSettings: appSettings, + notificationManager: notificationManager, + navigationStackCoordinator: detailNavigationStackCoordinator, + userIndicatorController: ServiceLocator.shared.userIndicatorController, + isNewLogin: isNewLogin) + setupStateMachine() + userSession.sessionSecurityStatePublisher + .map(\.verificationState) + .filter { $0 != .unknown } + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self else { return } + + attemptStartingOnboarding() + } + .store(in: &cancellables) + roomFlowCoordinator.actions.sink { [weak self] action in guard let self else { return } @@ -208,11 +233,18 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } func clearRoute(animated: Bool) { - fatalError("not necessary as of right now") + roomFlowCoordinator.clearRoute(animated: animated) } // MARK: - Private + func attemptStartingOnboarding() { + if onboardingFlowCoordinator.shouldStart { + clearRoute(animated: false) + onboardingFlowCoordinator.start() + } + } + private func clearPresentedSheets(animated: Bool, completion: @escaping () -> Void) { if navigationSplitCoordinator.sheetCoordinator == nil { completion() @@ -234,6 +266,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { switch (context.fromState, context.event, context.toState) { case (.initial, .start, .roomList): presentHomeScreen() + attemptStartingOnboarding() case(.roomList, .selectRoom, .roomList): break @@ -244,13 +277,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { break case (.invitesScreen, .deselectRoom, .invitesScreen): break - - case (.roomList, .showSessionVerificationScreen, .sessionVerificationScreen): - Task { - await self.presentSessionVerification(animated: animated) - } - case (.sessionVerificationScreen, .dismissedSessionVerificationScreen, .roomList): - break case (.roomList, .showSettingsScreen, .settingsScreen): break @@ -334,8 +360,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { settingsFlowCoordinator.handleAppRoute(.settings, animated: true) case .presentFeedbackScreen: stateMachine.processEvent(.feedbackScreen) - case .presentSessionVerificationScreen: - stateMachine.processEvent(.showSessionVerificationScreen) case .presentSecureBackupSettings: settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true) case .presentStartChatScreen: @@ -400,36 +424,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { presentSecureBackupLogoutConfirmationScreen() } - // MARK: Session verification - - private func presentSessionVerification(animated: Bool) async { - guard case let .success(sessionVerificationController) = await userSession.clientProxy.sessionVerificationControllerProxy() else { - fatalError("The sessionVerificationController should aways be valid at this point") - } - - let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController, - recoveryState: userSession.sessionSecurityStatePublisher.value.recoveryState) - - let coordinator = SessionVerificationScreenCoordinator(parameters: parameters) - - coordinator.actions - .sink { [weak self] action in - guard let self else { return } - - switch action { - case .recoveryKey: - settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true) - case .done: - navigationSplitCoordinator.setSheetCoordinator(nil) - } - } - .store(in: &cancellables) - - navigationSplitCoordinator.setSheetCoordinator(coordinator, animated: animated) { [weak self] in - self?.stateMachine.processEvent(.dismissedSessionVerificationScreen) - } - } - // MARK: Start Chat private func presentStartChat(animated: Bool) { diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift index 16727ac8c1..e0154cbedc 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift @@ -26,9 +26,6 @@ class UserSessionFlowCoordinatorStateMachine { /// Showing the home screen. The `selectedRoomID` represents the timeline shown on the detail panel (if any) case roomList(selectedRoomID: String?) - /// Showing the session verification flows - case sessionVerificationScreen(selectedRoomID: String?) - /// Showing the session verification flows case feedbackScreen(selectedRoomID: String?) @@ -70,11 +67,6 @@ class UserSessionFlowCoordinatorStateMachine { /// The feedback screen has been dismissed case dismissedFeedbackScreen - /// Request the start of the session verification flow - case showSessionVerificationScreen - /// Session verification has finished - case dismissedSessionVerificationScreen - /// Request the start of the start chat flow case showStartChatScreen /// Start chat has been dismissed @@ -126,11 +118,6 @@ class UserSessionFlowCoordinatorStateMachine { case (.feedbackScreen(let selectedRoomID), .dismissedFeedbackScreen): return .roomList(selectedRoomID: selectedRoomID) - case (.roomList(let selectedRoomID), .showSessionVerificationScreen): - return .sessionVerificationScreen(selectedRoomID: selectedRoomID) - case (.sessionVerificationScreen(let selectedRoomID), .dismissedSessionVerificationScreen): - return .roomList(selectedRoomID: selectedRoomID) - case (.roomList(let selectedRoomID), .showStartChatScreen): return .startChatScreen(selectedRoomID: selectedRoomID) case (.startChatScreen(let selectedRoomID), .dismissedStartChatScreen): diff --git a/ElementX/Sources/Generated/Assets.swift b/ElementX/Sources/Generated/Assets.swift index aebca381e7..0d3120d350 100644 --- a/ElementX/Sources/Generated/Assets.swift +++ b/ElementX/Sources/Generated/Assets.swift @@ -33,6 +33,7 @@ internal enum Asset { internal enum Images { internal static let appLogo = ImageAsset(name: "images/app-logo") internal static let serverSelectionIcon = ImageAsset(name: "images/server-selection-icon") + internal static let backgroundBottom = ImageAsset(name: "images/background-bottom") internal static let closeRte = ImageAsset(name: "images/close-rte") internal static let composerAttachment = ImageAsset(name: "images/composer-attachment") internal static let stopRecording = ImageAsset(name: "images/stop-recording") @@ -41,6 +42,7 @@ internal enum Asset { internal static let locationMarkerShape = ImageAsset(name: "images/location-marker-shape") internal static let mediaPause = ImageAsset(name: "images/media-pause") internal static let mediaPlay = ImageAsset(name: "images/media-play") + internal static let notificationsPromptGraphic = ImageAsset(name: "images/notifications-prompt-graphic") internal static let waitingGradient = ImageAsset(name: "images/waiting-gradient") } } diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index c84393abd9..0ba214ac1a 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -991,6 +991,14 @@ internal enum L10n { internal static var screenEditProfileTitle: String { return L10n.tr("Localizable", "screen_edit_profile_title") } /// Updating profile… internal static var screenEditProfileUpdatingDetails: String { return L10n.tr("Localizable", "screen_edit_profile_updating_details") } + /// Verify this device to set up secure messaging. + internal static var screenIdentityConfirmationSubtitle: String { return L10n.tr("Localizable", "screen_identity_confirmation_subtitle") } + /// Confirm that it's you + internal static var screenIdentityConfirmationTitle: String { return L10n.tr("Localizable", "screen_identity_confirmation_title") } + /// Now you can read or send messages securely, and anyone you chat with can also trust this device. + internal static var screenIdentityConfirmedSubtitle: String { return L10n.tr("Localizable", "screen_identity_confirmed_subtitle") } + /// Device verified + internal static var screenIdentityConfirmedTitle: String { return L10n.tr("Localizable", "screen_identity_confirmed_title") } /// Are you sure you want to decline the invitation to join %1$@? internal static func screenInvitesDeclineChatMessage(_ p1: Any) -> String { return L10n.tr("Localizable", "screen_invites_decline_chat_message", String(describing: p1)) diff --git a/ElementX/Sources/Other/ProcessInfo.swift b/ElementX/Sources/Other/ProcessInfo.swift index 11fa261ac0..d41b811443 100644 --- a/ElementX/Sources/Other/ProcessInfo.swift +++ b/ElementX/Sources/Other/ProcessInfo.swift @@ -34,10 +34,18 @@ extension ProcessInfo { false #endif } + + static var isRunningIntegrationTests: Bool { + #if DEBUG + processInfo.environment["IS_RUNNING_INTEGRATION_TESTS"] == "1" + #else + false + #endif + } /// Flag indicating whether the app is running the UI tests or unit tests. static var isRunningTests: Bool { - isRunningUITests || isRunningUnitTests + isRunningUITests || isRunningUnitTests || isRunningIntegrationTests } /// The identifier of the screen to be loaded when running UI tests. diff --git a/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift b/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift index 86edb78ff3..08804e9bd3 100644 --- a/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift +++ b/ElementX/Sources/Other/SwiftUI/Layout/FullscreenDialog.swift @@ -33,6 +33,8 @@ struct FullscreenDialog: View { /// The spacing between the content and the buttons. var spacing: CGFloat = 16 + var showBackgroundGradient = false + /// The main content shown at the top of the layout. @ViewBuilder var content: () -> Content /// The content shown at the bottom of the layout. @@ -62,23 +64,32 @@ struct FullscreenDialog: View { } .scrollBounceBehavior(.basedOnSize) .safeAreaInset(edge: .bottom) { - VStack(spacing: 0) { - bottomContent() - .readableFrame() - .padding(.horizontal, horizontalPadding) - .padding(.top, spacing) - .padding(.bottom, UIConstants.actionButtonBottomPadding) - - Spacer() - .frame(height: UIConstants.spacerHeight(in: geometry)) + if showBackgroundGradient { + adjustedBottomContent(geometry: geometry) + .background(Asset.Images.backgroundBottom.swiftUIImage.resizable().ignoresSafeArea()) + } else { + adjustedBottomContent(geometry: geometry) + .background() } - .background() } } } + private func adjustedBottomContent(geometry: GeometryProxy) -> some View { + VStack(spacing: 0) { + bottomContent() + .readableFrame() + .padding(.horizontal, horizontalPadding) + .padding(.top, spacing) + .padding(.bottom, UIConstants.actionButtonBottomPadding) + + Spacer() + .frame(height: UIConstants.spacerHeight(in: geometry)) + } + } + /// A continuously scrolling layout used for accessibility font sizes. - var accessibilityLayout: some View { + private var accessibilityLayout: some View { GeometryReader { geometry in ScrollView { VStack(spacing: 0) { diff --git a/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift b/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift index 54154e453b..b9ca45e04a 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/HeroImage.swift @@ -21,35 +21,61 @@ import SwiftUI /// takes a compound icon. If you would like to apply it to an SFSymbol, you can call /// the `heroImage()` modifier directly on the Image. struct HeroImage: View { + enum Style { + case normal + case positive + + var foregroundColor: Color { + switch self { + case .normal: + return .compound.iconPrimary + case .positive: + return .compound.iconSuccessPrimary + } + } + + var backgroundFillColor: Color { + switch self { + case .normal: + return .compound.bgSubtleSecondary + case .positive: + return .compound.bgSuccessSubtle + } + } + } + /// The icon that is shown. let icon: KeyPath + var style: Style = .normal var body: some View { CompoundIcon(icon, size: .custom(42), relativeTo: .title) - .modifier(HeroImageModifier()) + .modifier(HeroImageModifier(style: style)) } } extension Image { /// Styles the image for use as the main/top/hero screen icon. You should prefer /// the HeroImage component when possible, by using an icon from Compound. - func heroImage(insets: CGFloat = 16) -> some View { + func heroImage(insets: CGFloat = 16, style: HeroImage.Style = .normal) -> some View { resizable() .renderingMode(.template) .aspectRatio(contentMode: .fit) .scaledPadding(insets, relativeTo: .title) - .modifier(HeroImageModifier()) + .modifier(HeroImageModifier(style: style)) } } private struct HeroImageModifier: ViewModifier { + let style: HeroImage.Style + func body(content: Content) -> some View { content - .foregroundColor(.compound.iconPrimary) .scaledFrame(size: 70, relativeTo: .title) + .foregroundColor(style.foregroundColor) .background { RoundedRectangle(cornerRadius: 14) - .fill(Color.compound.bgSubtleSecondary) + .fill(style.backgroundFillColor) } .accessibilityHidden(true) } diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/View/RoundedLabelItem.swift b/ElementX/Sources/Other/SwiftUI/Views/RoundedLabelItem.swift similarity index 100% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/View/RoundedLabelItem.swift rename to ElementX/Sources/Other/SwiftUI/Views/RoundedLabelItem.swift diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginScreenCoordinator.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginScreenCoordinator.swift index 2001538e54..44640cf054 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginScreenCoordinator.swift @@ -85,7 +85,7 @@ final class LoginScreenCoordinator: CoordinatorProtocol { // MARK: - Private - private static let loadingIndicatorIdentifier = "LoginCoordinatorLoading" + private static let loadingIndicatorIdentifier = "\(LoginScreenCoordinatorAction.self)-Loading" private func startLoading(isInteractionBlocking: Bool) { if isInteractionBlocking { diff --git a/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/SoftLogoutScreenCoordinator.swift b/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/SoftLogoutScreenCoordinator.swift index 844df8816d..722966791f 100644 --- a/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/SoftLogoutScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/SoftLogoutScreenCoordinator.swift @@ -104,7 +104,7 @@ final class SoftLogoutScreenCoordinator: CoordinatorProtocol { // MARK: - Private - private static let loadingIndicatorIdentifier = "SoftLogoutLoading" + private static let loadingIndicatorIdentifier = "\(SoftLogoutScreenCoordinator.self)-Loading" /// Show an activity indicator whilst loading. @MainActor private func startLoading() { diff --git a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift index 53fd790949..ae6e256744 100644 --- a/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift +++ b/ElementX/Sources/Screens/BlockedUsersScreen/BlockedUsersScreenViewModel.swift @@ -82,7 +82,7 @@ class BlockedUsersScreenViewModel: BlockedUsersScreenViewModelType, BlockedUsers // MARK: Loading indicator - private static let loadingIndicatorIdentifier = "BlockedUsersLoading" + private static let loadingIndicatorIdentifier = "\(BlockedUsersScreenViewModel.self)-Loading" private func showLoadingIndicator() { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift index 0ed65537e7..3c89c82c6b 100644 --- a/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift +++ b/ElementX/Sources/Screens/BugReportScreen/BugReportScreenCoordinator.swift @@ -90,7 +90,7 @@ final class BugReportScreenCoordinator: CoordinatorProtocol { // MARK: - Private - private static let loadingIndicatorIdentifier = "BugReportLoading" + private static let loadingIndicatorIdentifier = "\(BugReportScreenCoordinator.self)-Loading" private func startLoading(label: String = L10n.commonLoading, progressPublisher: CurrentValuePublisher) { parameters.userIndicatorController?.submitIndicator( diff --git a/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift b/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift index 1b20d96aa0..358d9a4a3b 100644 --- a/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift +++ b/ElementX/Sources/Screens/CreateRoom/CreateRoomViewModel.swift @@ -171,7 +171,7 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol // MARK: Loading indicator - private static let loadingIndicatorIdentifier = "CreateRoomLoading" + private static let loadingIndicatorIdentifier = "\(CreateRoomViewModel.self)-Loading" private func showLoadingIndicator() { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift index 1d4d510c29..f5bbb46724 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift @@ -31,7 +31,6 @@ enum HomeScreenCoordinatorAction { case roomLeft(roomIdentifier: String) case presentSettingsScreen case presentFeedbackScreen - case presentSessionVerificationScreen case presentSecureBackupSettings case presentStartChatScreen case presentInvitesScreen @@ -74,8 +73,6 @@ final class HomeScreenCoordinator: CoordinatorProtocol { actionsSubject.send(.presentFeedbackScreen) case .presentSettingsScreen: actionsSubject.send(.presentSettingsScreen) - case .presentSessionVerificationScreen: - actionsSubject.send(.presentSessionVerificationScreen) case .presentSecureBackupSettings: actionsSubject.send(.presentSecureBackupSettings) case .logout: diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index 99aacd8952..4ec962c03f 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -22,7 +22,6 @@ enum HomeScreenViewModelAction { case presentRoom(roomIdentifier: String) case presentRoomDetails(roomIdentifier: String) case roomLeft(roomIdentifier: String) - case presentSessionVerificationScreen case presentSecureBackupSettings case presentSettingsScreen case presentFeedbackScreen @@ -39,9 +38,7 @@ enum HomeScreenViewAction { case confirmLeaveRoom(roomIdentifier: String) case showSettings case startChat - case verifySession case confirmRecoveryKey - case skipSessionVerification case skipRecoveryKeyConfirmation case updateVisibleItemRange(range: Range, isScrolling: Bool) case selectInvites @@ -74,7 +71,6 @@ enum HomeScreenRoomListMode: CustomStringConvertible { enum SecurityBannerMode { case none case dismissed - case sessionVerification case recoveryKeyConfirmation } diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 72c959d7d8..198cd2d466 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -70,11 +70,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol guard let self else { return } switch (securityState.verificationState, securityState.recoveryState) { - case (.unverified, _): - state.requiresExtraAccountSetup = true - if state.securityBannerMode != .dismissed { - state.securityBannerMode = .sessionVerification - } case (.verified, .disabled): state.requiresExtraAccountSetup = true state.securityBannerMode = .none @@ -134,12 +129,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol leaveRoom(roomId: roomIdentifier) case .showSettings: actionsSubject.send(.presentSettingsScreen) - case .verifySession: - actionsSubject.send(.presentSessionVerificationScreen) case .confirmRecoveryKey: actionsSubject.send(.presentSecureBackupSettings) - case .skipSessionVerification: - state.securityBannerMode = .dismissed case .skipRecoveryKeyConfirmation: state.securityBannerMode = .dismissed case .updateVisibleItemRange(let range, let isScrolling): diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenContent.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenContent.swift index 95ea9fcc13..203c9f17b1 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenContent.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenContent.swift @@ -106,7 +106,6 @@ struct HomeScreenContent: View { } @ViewBuilder - /// The session verification banner and invites button if either are needed. private var topSection: some View { VStack(spacing: 0) { if !context.isSearchFieldFocused { @@ -114,9 +113,7 @@ struct HomeScreenContent: View { .frame(alignment: .top) } - if context.viewState.securityBannerMode == .sessionVerification { - HomeScreenSessionVerificationBanner(context: context) - } else if context.viewState.securityBannerMode == .recoveryKeyConfirmation { + if context.viewState.securityBannerMode == .recoveryKeyConfirmation { HomeScreenRecoveryKeyConfirmationBanner(context: context) } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenSessionVerificationBanner.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenSessionVerificationBanner.swift deleted file mode 100644 index 681cade607..0000000000 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenSessionVerificationBanner.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright 2023 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Combine -import SwiftUI - -struct HomeScreenSessionVerificationBanner: View { - @ObservedObject var context: HomeScreenViewModel.Context - - var body: some View { - VStack(alignment: .leading, spacing: 16) { - VStack(alignment: .leading, spacing: 4) { - HStack(spacing: 16) { - Text(L10n.sessionVerificationBannerTitle) - .font(.compound.bodyLGSemibold) - .foregroundColor(.compound.textPrimary) - - Spacer() - - Button { - context.send(viewAction: .skipSessionVerification) - } label: { - Image(systemName: "xmark") - .foregroundColor(.compound.iconSecondary) - .frame(width: 12, height: 12) - } - } - Text(L10n.sessionVerificationBannerMessage) - .font(.compound.bodyMD) - .foregroundColor(.compound.textSecondary) - } - - Button(L10n.actionContinue) { - context.send(viewAction: .verifySession) - } - .frame(maxWidth: .infinity) - .buttonStyle(.compound(.primary, size: .medium)) - .accessibilityIdentifier(A11yIdentifiers.homeScreen.verificationBannerContinue) - } - .padding(16) - .background(Color.compound.bgSubtleSecondary) - .cornerRadius(14) - .padding(.horizontal, 16) - } -} - -struct HomeScreenSessionVerificationBanner_Previews: PreviewProvider, TestablePreview { - static let viewModel = buildViewModel() - - static var previews: some View { - HomeScreenSessionVerificationBanner(context: viewModel.context) - } - - static func buildViewModel() -> HomeScreenViewModel { - let clientProxy = ClientProxyMock(.init(userID: "@alice:example.com", - roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loading)))) - - let userSession = MockUserSession(clientProxy: clientProxy, - mediaProvider: MockMediaProvider(), - voiceMessageMediaManager: VoiceMessageMediaManagerMock()) - - return HomeScreenViewModel(userSession: userSession, - analyticsService: ServiceLocator.shared.analytics, - appSettings: ServiceLocator.shared.settings, - selectedRoomPublisher: CurrentValueSubject(nil).asCurrentValuePublisher(), - userIndicatorController: ServiceLocator.shared.userIndicatorController) - } -} diff --git a/ElementX/Sources/Screens/MediaPickerScreen/CameraPicker.swift b/ElementX/Sources/Screens/MediaPickerScreen/CameraPicker.swift index cb1146c244..e7d2546437 100644 --- a/ElementX/Sources/Screens/MediaPickerScreen/CameraPicker.swift +++ b/ElementX/Sources/Screens/MediaPickerScreen/CameraPicker.swift @@ -63,7 +63,7 @@ struct CameraPicker: UIViewControllerRepresentable { self.cameraPicker = cameraPicker } - private static let loadingIndicatorIdentifier = "CameraPickerLoadingIndicator" + private static let loadingIndicatorIdentifier = "\(CameraPicker.self)-Loading" func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { picker.delegate = nil diff --git a/ElementX/Sources/Screens/MediaPickerScreen/DocumentPicker.swift b/ElementX/Sources/Screens/MediaPickerScreen/DocumentPicker.swift index a8f717a337..62e5969bd6 100644 --- a/ElementX/Sources/Screens/MediaPickerScreen/DocumentPicker.swift +++ b/ElementX/Sources/Screens/MediaPickerScreen/DocumentPicker.swift @@ -62,7 +62,7 @@ struct DocumentPicker: UIViewControllerRepresentable { documentPicker.callback(.cancel) } - private static let loadingIndicatorIdentifier = "DocumentPickerLoadingIndicator" + private static let loadingIndicatorIdentifier = "\(DocumentPicker.self)-Loading" func documentPicker(_ picker: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let url = urls.first else { diff --git a/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift b/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift index 9c8c3b0c0b..33b2165a31 100644 --- a/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift +++ b/ElementX/Sources/Screens/MediaPickerScreen/PhotoLibraryPicker.swift @@ -62,7 +62,7 @@ struct PhotoLibraryPicker: UIViewControllerRepresentable { // MARK: PHPickerViewControllerDelegate - private static let loadingIndicatorIdentifier = "PhotoLibraryPickerLoadingIndicator" + private static let loadingIndicatorIdentifier = "\(PhotoLibraryPicker.self)-Loading" func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { guard let provider = results.first?.itemProvider, diff --git a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift index 6b184fcecf..a97369676c 100644 --- a/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift +++ b/ElementX/Sources/Screens/MediaUploadPreviewScreen/MediaUploadPreviewScreenViewModel.swift @@ -102,7 +102,7 @@ class MediaUploadPreviewScreenViewModel: MediaUploadPreviewScreenViewModelType, } } - private static let loadingIndicatorIdentifier = "MediaUploadPreviewLoading" + private static let loadingIndicatorIdentifier = "\(MediaUploadPreviewScreenViewModel.self)-Loading" private func startLoading(progressPublisher: CurrentValuePublisher) { userIndicatorController.submitIndicator( diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenCoordinator.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenCoordinator.swift similarity index 100% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenCoordinator.swift rename to ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenCoordinator.swift diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift similarity index 100% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift rename to ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenModels.swift diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenViewModel.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenViewModel.swift similarity index 100% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenViewModel.swift rename to ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenViewModel.swift diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenViewModelProtocol.swift similarity index 100% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/AnalyticsPromptScreenViewModelProtocol.swift rename to ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/AnalyticsPromptScreenViewModelProtocol.swift diff --git a/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift similarity index 92% rename from ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift rename to ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift index 785a97e6ec..ade52f248a 100644 --- a/ElementX/Sources/Screens/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift +++ b/ElementX/Sources/Screens/Onboarding/AnalyticsPromptScreen/View/AnalyticsPromptScreen.swift @@ -21,7 +21,7 @@ struct AnalyticsPromptScreen: View { @ObservedObject var context: AnalyticsPromptScreenViewModel.Context var body: some View { - FullscreenDialog(topPadding: UIConstants.startScreenBreakerScreenTopPadding) { + FullscreenDialog(topPadding: UIConstants.startScreenBreakerScreenTopPadding, showBackgroundGradient: true) { mainContent } bottomContent: { buttons @@ -30,6 +30,7 @@ struct AnalyticsPromptScreen: View { .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) .navigationBarHidden(true) .navigationBarBackButtonHidden(true) + .interactiveDismissDisabled() } /// The main content of the screen that is shown inside the scroll view. @@ -88,12 +89,9 @@ struct AnalyticsPromptScreen: View { /// The stack of enable/disable buttons. private var buttons: some View { VStack(spacing: 16) { - Button { context.send(viewAction: .enable) } label: { - Text(L10n.actionOk) - .font(.compound.bodyLGSemibold) - } - .buttonStyle(.compound(.primary)) - .accessibilityIdentifier(A11yIdentifiers.analyticsPromptScreen.enable) + Button(L10n.actionOk) { context.send(viewAction: .enable) } + .buttonStyle(.compound(.primary)) + .accessibilityIdentifier(A11yIdentifiers.analyticsPromptScreen.enable) Button { context.send(viewAction: .disable) } label: { Text(L10n.actionNotNow) diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenCoordinator.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenCoordinator.swift new file mode 100644 index 0000000000..3e953e9a3b --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenCoordinator.swift @@ -0,0 +1,70 @@ +// +// 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. +// + +// periphery:ignore:all - this is just a identityConfirmation remove this comment once generating the final file + +import Combine +import SwiftUI + +struct IdentityConfirmationScreenCoordinatorParameters { + let userSession: UserSessionProtocol + let appSettings: AppSettings + let userIndicatorController: UserIndicatorControllerProtocol +} + +enum IdentityConfirmationScreenCoordinatorAction { + case otherDevice + case recoveryKey +} + +final class IdentityConfirmationScreenCoordinator: CoordinatorProtocol { + private let parameters: IdentityConfirmationScreenCoordinatorParameters + private let viewModel: IdentityConfirmationScreenViewModelProtocol + + private var cancellables = Set() + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: IdentityConfirmationScreenCoordinatorParameters) { + self.parameters = parameters + + viewModel = IdentityConfirmationScreenViewModel(userSession: parameters.userSession, + appSettings: parameters.appSettings, + userIndicatorController: parameters.userIndicatorController) + } + + func start() { + viewModel.actionsPublisher.sink { [weak self] action in + guard let self else { return } + + MXLog.info("Coordinator: received view model action: \(action)") + switch action { + case .otherDevice: + actionsSubject.send(.otherDevice) + case .recoveryKey: + actionsSubject.send(.recoveryKey) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(IdentityConfirmationScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenModels.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenModels.swift new file mode 100644 index 0000000000..e358b78c1f --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenModels.swift @@ -0,0 +1,37 @@ +// +// 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 IdentityConfirmationScreenViewModelAction { + case otherDevice + case recoveryKey +} + +struct IdentityConfirmationScreenViewState: BindableState { + enum Mode { + case recoveryOnly + case recoveryAndVerification + } + + var mode = Mode.recoveryOnly + let learnMoreURL: URL +} + +enum IdentityConfirmationScreenViewAction { + case otherDevice + case recoveryKey +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModel.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModel.swift new file mode 100644 index 0000000000..0cdf8f7996 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModel.swift @@ -0,0 +1,95 @@ +// +// 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 IdentityConfirmationScreenViewModelType = StateStoreViewModel + +class IdentityConfirmationScreenViewModel: IdentityConfirmationScreenViewModelType, IdentityConfirmationScreenViewModelProtocol { + private let userSession: UserSessionProtocol + private let userIndicatorController: UserIndicatorControllerProtocol + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(userSession: UserSessionProtocol, appSettings: AppSettings, userIndicatorController: UserIndicatorControllerProtocol) { + self.userSession = userSession + self.userIndicatorController = userIndicatorController + + super.init(initialViewState: IdentityConfirmationScreenViewState(learnMoreURL: appSettings.encryptionURL)) + + userSession.sessionSecurityStatePublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] state in + Task { + await self?.updateWithSessionSecurityState(state) + } + } + .store(in: &cancellables) + + Task { + await updateWithSessionSecurityState(userSession.sessionSecurityStatePublisher.value) + } + } + + // MARK: - Public + + override func process(viewAction: IdentityConfirmationScreenViewAction) { + MXLog.info("View model: received view action: \(viewAction)") + switch viewAction { + case .otherDevice: + actionsSubject.send(.otherDevice) + case .recoveryKey: + actionsSubject.send(.recoveryKey) + } + } + + // MARK: - Private + + private func updateWithSessionSecurityState(_ sessionSecurityState: SessionSecurityState) async { + if sessionSecurityState.verificationState == .unknown { + showLoadingIndicator() + } else { + hideLoadingIndicator() + } + + guard sessionSecurityState.verificationState == .unverified else { + return + } + + guard case let .success(isOnlyDeviceLeft) = await userSession.clientProxy.isOnlyDeviceLeft() else { + return + } + + state.mode = isOnlyDeviceLeft ? .recoveryOnly : .recoveryAndVerification + } + + private static let loadingIndicatorIdentifier = "\(IdentityConfirmationScreenViewModel.self)-Loading" + + private func showLoadingIndicator() { + userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: L10n.commonLoading, + persistent: true)) + } + + private func hideLoadingIndicator() { + userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModelProtocol.swift new file mode 100644 index 0000000000..fff1cb67ed --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/IdentityConfirmationScreenViewModelProtocol.swift @@ -0,0 +1,23 @@ +// +// 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 IdentityConfirmationScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: IdentityConfirmationScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift new file mode 100644 index 0000000000..d4dc6a0cb8 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmationScreen/View/IdentityConfirmationScreen.swift @@ -0,0 +1,107 @@ +// +// 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 Compound +import SwiftUI + +struct IdentityConfirmationScreen: View { + @ObservedObject var context: IdentityConfirmationScreenViewModel.Context + + var body: some View { + FullscreenDialog(topPadding: UIConstants.startScreenBreakerScreenTopPadding) { + screenHeader + } bottomContent: { + actionButtons + } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .navigationBarHidden(true) + .navigationBarBackButtonHidden(true) + .interactiveDismissDisabled() + } + + // MARK: - Private + + @ViewBuilder + private var screenHeader: some View { + VStack(spacing: 0) { + HeroImage(icon: \.lockSolid) + .padding(.bottom, 16) + + Text(L10n.screenIdentityConfirmationTitle) + .font(.compound.headingMDBold) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textPrimary) + .padding(.bottom, 8) + + Text(L10n.screenIdentityConfirmationSubtitle) + .font(.compound.bodyMD) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textSecondary) + + Button(L10n.actionLearnMore) { + UIApplication.shared.open(context.viewState.learnMoreURL) + } + .buttonStyle(.compound(.plain)) + .padding(.top, 16) + } + } + + @ViewBuilder + private var actionButtons: some View { + VStack(spacing: 32) { + switch context.viewState.mode { + case .recoveryOnly: + Button(L10n.screenSessionVerificationEnterRecoveryKey) { + context.send(viewAction: .recoveryKey) + } + .buttonStyle(.compound(.primary)) + + case .recoveryAndVerification: + Button(L10n.actionStartVerification) { + context.send(viewAction: .otherDevice) + } + .buttonStyle(.compound(.primary)) + + Button(L10n.screenSessionVerificationEnterRecoveryKey) { + context.send(viewAction: .recoveryKey) + } + .buttonStyle(.compound(.plain)) + } + } + } +} + +// MARK: - Previews + +struct IdentityConfirmationScreen_Previews: PreviewProvider, TestablePreview { + static var previews: some View { + NavigationStack { + IdentityConfirmationScreen(context: viewModel.context) + } + } + + private static var viewModel: IdentityConfirmationScreenViewModel { + let userSession = MockUserSession(clientProxy: ClientProxyMock(.init(userID: "@user:example.com", + roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded([]))))), + mediaProvider: MockMediaProvider(), + voiceMessageMediaManager: VoiceMessageMediaManagerMock()) + + return IdentityConfirmationScreenViewModel(userSession: userSession, + appSettings: ServiceLocator.shared.settings, + userIndicatorController: ServiceLocator.shared.userIndicatorController) + } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenCoordinator.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenCoordinator.swift new file mode 100644 index 0000000000..4d33fcc77f --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenCoordinator.swift @@ -0,0 +1,61 @@ +// +// 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. +// + +// periphery:ignore:all - this is just a identityConfirmed remove this comment once generating the final file + +import Combine +import SwiftUI + +struct IdentityConfirmedScreenCoordinatorParameters { } + +enum IdentityConfirmedScreenCoordinatorAction { + case done +} + +final class IdentityConfirmedScreenCoordinator: CoordinatorProtocol { + private let parameters: IdentityConfirmedScreenCoordinatorParameters + private let viewModel: IdentityConfirmedScreenViewModelProtocol + + private var cancellables = Set() + + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: IdentityConfirmedScreenCoordinatorParameters) { + self.parameters = parameters + + viewModel = IdentityConfirmedScreenViewModel() + } + + 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: + self.actionsSubject.send(.done) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(IdentityConfirmedScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/EncryptedHistoryRoomTimelineItem.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenModels.swift similarity index 73% rename from ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/EncryptedHistoryRoomTimelineItem.swift rename to ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenModels.swift index 13d2935385..2861edbdc1 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Virtual/EncryptedHistoryRoomTimelineItem.swift +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenModels.swift @@ -1,5 +1,5 @@ // -// Copyright 2023 New Vector Ltd +// 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. @@ -16,7 +16,12 @@ import Foundation -struct EncryptedHistoryRoomTimelineItem: DecorationTimelineItemProtocol, Equatable { - let id: TimelineItemIdentifier - let isSessionVerified: Bool +enum IdentityConfirmedScreenViewModelAction { + case done +} + +struct IdentityConfirmedScreenViewState: BindableState { } + +enum IdentityConfirmedScreenViewAction { + case done } diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModel.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModel.swift new file mode 100644 index 0000000000..4def13f96d --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModel.swift @@ -0,0 +1,42 @@ +// +// 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 IdentityConfirmedScreenViewModelType = StateStoreViewModel + +class IdentityConfirmedScreenViewModel: IdentityConfirmedScreenViewModelType, IdentityConfirmedScreenViewModelProtocol { + private let actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init() { + super.init(initialViewState: .init()) + } + + // MARK: - Public + + override func process(viewAction: IdentityConfirmedScreenViewAction) { + MXLog.info("View model: received view action: \(viewAction)") + + switch viewAction { + case .done: + actionsSubject.send(.done) + } + } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModelProtocol.swift new file mode 100644 index 0000000000..6bb2969eac --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/IdentityConfirmedScreenViewModelProtocol.swift @@ -0,0 +1,23 @@ +// +// 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 IdentityConfirmedScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: IdentityConfirmedScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/View/IdentityConfirmedScreen.swift b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/View/IdentityConfirmedScreen.swift new file mode 100644 index 0000000000..e5f0924c54 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/IdentityConfirmedScreen/View/IdentityConfirmedScreen.swift @@ -0,0 +1,75 @@ +// +// 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 Compound +import SwiftUI + +struct IdentityConfirmedScreen: View { + @ObservedObject var context: IdentityConfirmedScreenViewModel.Context + + var body: some View { + FullscreenDialog(topPadding: UIConstants.startScreenBreakerScreenTopPadding) { + screenHeader + } bottomContent: { + actionButtons + } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .navigationBarHidden(true) + .navigationBarBackButtonHidden(true) + .interactiveDismissDisabled() + } + + // MARK: - Private + + @ViewBuilder + private var screenHeader: some View { + VStack(spacing: 0) { + HeroImage(icon: \.checkCircle, style: .positive) + .padding(.bottom, 16) + + Text(L10n.screenIdentityConfirmedTitle) + .font(.compound.headingMDBold) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textPrimary) + .padding(.bottom, 8) + + Text(L10n.screenIdentityConfirmedSubtitle) + .font(.compound.bodyMD) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textSecondary) + } + } + + @ViewBuilder + private var actionButtons: some View { + Button(L10n.actionContinue) { + context.send(viewAction: .done) + } + .buttonStyle(.compound(.primary)) + } +} + +// MARK: - Previews + +struct IdentityConfirmedScreen_Previews: PreviewProvider, TestablePreview { + static let viewModel = IdentityConfirmedScreenViewModel() + static var previews: some View { + NavigationStack { + IdentityConfirmedScreen(context: viewModel.context) + } + } +} diff --git a/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenCoordinator.swift b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenCoordinator.swift new file mode 100644 index 0000000000..07e958986b --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenCoordinator.swift @@ -0,0 +1,59 @@ +// +// Copyright 2021 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 NotificationPermissionsScreenCoordinatorParameters { + let notificationManager: NotificationManagerProtocol +} + +enum NotificationPermissionsScreenCoordinatorAction { + case done +} + +final class NotificationPermissionsScreenCoordinator: CoordinatorProtocol { + private var viewModel: NotificationPermissionsScreenViewModelProtocol + private let actionsSubject: PassthroughSubject = .init() + private var cancellables = Set() + + var actions: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(parameters: NotificationPermissionsScreenCoordinatorParameters) { + viewModel = NotificationPermissionsScreenViewModel(notificationManager: parameters.notificationManager) + } + + // MARK: - Public + + func start() { + viewModel.actionsPublisher + .sink { [weak self] action in + guard let self else { return } + + switch action { + case .done: + actionsSubject.send(.done) + } + } + .store(in: &cancellables) + } + + func toPresentable() -> AnyView { + AnyView(NotificationPermissionsScreen(context: viewModel.context)) + } +} diff --git a/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenModels.swift b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenModels.swift new file mode 100644 index 0000000000..d841d9f1dd --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenModels.swift @@ -0,0 +1,28 @@ +// +// Copyright 2021 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 NotificationPermissionsScreenViewAction { + case enable + case notNow +} + +enum NotificationPermissionsScreenViewModelAction { + case done +} + +struct NotificationPermissionsScreenViewState: BindableState { } diff --git a/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModel.swift b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModel.swift new file mode 100644 index 0000000000..b2f957a072 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModel.swift @@ -0,0 +1,48 @@ +// +// Copyright 2021 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 NotificationPermissionsScreenViewModelType = StateStoreViewModel + +class NotificationPermissionsScreenViewModel: NotificationPermissionsScreenViewModelType, NotificationPermissionsScreenViewModelProtocol { + private let notificationManager: NotificationManagerProtocol + + private var actionsSubject: PassthroughSubject = .init() + var actionsPublisher: AnyPublisher { + actionsSubject.eraseToAnyPublisher() + } + + init(notificationManager: NotificationManagerProtocol) { + self.notificationManager = notificationManager + + super.init(initialViewState: .init()) + } + + // MARK: - Public + + override func process(viewAction: NotificationPermissionsScreenViewAction) { + switch viewAction { + case .enable: + notificationManager.requestAuthorization() + + actionsSubject.send(.done) + case .notNow: + actionsSubject.send(.done) + } + } +} diff --git a/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModelProtocol.swift new file mode 100644 index 0000000000..016d539683 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/NotificationPermissionsScreenViewModelProtocol.swift @@ -0,0 +1,23 @@ +// +// Copyright 2021 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 NotificationPermissionsScreenViewModelProtocol { + var actionsPublisher: AnyPublisher { get } + var context: NotificationPermissionsScreenViewModelType.Context { get } +} diff --git a/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/View/NotificationPermissionsScreen.swift b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/View/NotificationPermissionsScreen.swift new file mode 100644 index 0000000000..7e5cafc911 --- /dev/null +++ b/ElementX/Sources/Screens/Onboarding/NotificationPermissionsScreen/View/NotificationPermissionsScreen.swift @@ -0,0 +1,77 @@ +// +// Copyright 2021 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 + +/// A prompt that asks the user whether they would like to enable Analytics or not. +struct NotificationPermissionsScreen: View { + @ObservedObject var context: NotificationPermissionsScreenViewModel.Context + + var body: some View { + FullscreenDialog(topPadding: UIConstants.startScreenBreakerScreenTopPadding, showBackgroundGradient: true) { + mainContent + } bottomContent: { + buttons + } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .navigationBarHidden(true) + .navigationBarBackButtonHidden(true) + .interactiveDismissDisabled() + } + + /// The main content of the screen that is shown inside the scroll view. + private var mainContent: some View { + VStack(spacing: 8) { + HeroImage(icon: \.notificationsSolid) + .padding(.bottom, 8) + + Text(L10n.screenNotificationOptinTitle) + .font(.compound.headingMDBold) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textPrimary) + + Text(L10n.screenNotificationOptinSubtitle) + .font(.compound.bodyMD) + .multilineTextAlignment(.center) + .foregroundColor(.compound.textSecondary) + + Asset.Images.notificationsPromptGraphic.swiftUIImage.resizable().aspectRatio(contentMode: .fit) + } + } + + private var buttons: some View { + VStack(spacing: 16) { + Button(L10n.actionOk) { context.send(viewAction: .enable) } + .buttonStyle(.compound(.primary)) + + Button { context.send(viewAction: .notNow) } label: { + Text(L10n.actionNotNow) + .font(.compound.bodyLGSemibold) + .padding(14) + } + } + } +} + +// MARK: - Previews + +struct NotificationPermissionsScreen_Previews: PreviewProvider, TestablePreview { + static let viewModel = NotificationPermissionsScreenViewModel(notificationManager: NotificationManagerMock()) + static var previews: some View { + NotificationPermissionsScreen(context: viewModel.context) + } +} diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift similarity index 88% rename from ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift index 4e664470f4..bd9465508b 100644 --- a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenCoordinator.swift @@ -18,13 +18,11 @@ import Combine import SwiftUI enum SessionVerificationScreenCoordinatorAction { - case recoveryKey case done } struct SessionVerificationScreenCoordinatorParameters { let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol - let recoveryState: SecureBackupRecoveryState } final class SessionVerificationScreenCoordinator: CoordinatorProtocol { @@ -38,8 +36,7 @@ final class SessionVerificationScreenCoordinator: CoordinatorProtocol { } init(parameters: SessionVerificationScreenCoordinatorParameters) { - viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: parameters.sessionVerificationControllerProxy, - recoveryState: parameters.recoveryState) + viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: parameters.sessionVerificationControllerProxy) } // MARK: - Public @@ -50,8 +47,6 @@ final class SessionVerificationScreenCoordinator: CoordinatorProtocol { guard let self else { return } switch action { - case .recoveryKey: - actionsSubject.send(.recoveryKey) case .finished: actionsSubject.send(.done) } @@ -59,6 +54,10 @@ final class SessionVerificationScreenCoordinator: CoordinatorProtocol { .store(in: &cancellables) } + func stop() { + viewModel.stop() + } + func toPresentable() -> AnyView { AnyView(SessionVerificationScreen(context: viewModel.context)) } diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenModels.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenModels.swift similarity index 97% rename from ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenModels.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenModels.swift index b2c5c9da73..dd0a865fb7 100644 --- a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenModels.swift +++ b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenModels.swift @@ -17,13 +17,10 @@ import Foundation enum SessionVerificationScreenViewModelAction { - case recoveryKey case finished } struct SessionVerificationScreenViewState: BindableState { - let showRecoveryOption: Bool - var verificationState: SessionVerificationScreenStateMachine.State = .initial var title: String? { @@ -86,11 +83,9 @@ struct SessionVerificationScreenViewState: BindableState { } enum SessionVerificationScreenViewAction { - case recoveryKey case requestVerification case startSasVerification case restart case accept case decline - case close } diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenStateMachine.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenStateMachine.swift similarity index 100% rename from ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenStateMachine.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenStateMachine.swift diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModel.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModel.swift similarity index 88% rename from ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModel.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModel.swift index 47d8b2f181..c2f9c615b6 100644 --- a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModel.swift +++ b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModel.swift @@ -31,13 +31,12 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess } init(sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol, - recoveryState: SecureBackupRecoveryState, verificationState: SessionVerificationScreenStateMachine.State = .initial) { self.sessionVerificationControllerProxy = sessionVerificationControllerProxy stateMachine = SessionVerificationScreenStateMachine() - super.init(initialViewState: .init(showRecoveryOption: recoveryState == .incomplete, verificationState: verificationState)) + super.init(initialViewState: .init(verificationState: verificationState)) setupStateMachine() @@ -71,23 +70,12 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess override func process(viewAction: SessionVerificationScreenViewAction) { switch viewAction { - case .recoveryKey: - actionsSubject.send(.recoveryKey) case .requestVerification: stateMachine.processEvent(.requestVerification) case .startSasVerification: stateMachine.processEvent(.startSasVerification) case .restart: stateMachine.processEvent(.restart) - case .close: - guard stateMachine.state == .initial || - stateMachine.state == .verified || - stateMachine.state == .cancelled else { - stateMachine.processEvent(.cancel) - return - } - - actionsSubject.send(.finished) case .accept: stateMachine.processEvent(.acceptChallenge) case .decline: @@ -95,6 +83,14 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess } } + func stop() { + let uncancellableStates: [SessionVerificationScreenStateMachine.State] = [.initial, .verified, .cancelled] + + if !uncancellableStates.contains(stateMachine.state) { + stateMachine.processEvent(.cancel) + } + } + // MARK: - Private private func setupStateMachine() { @@ -115,11 +111,7 @@ class SessionVerificationScreenViewModel: SessionVerificationViewModelType, Sess case (_, .cancel, .cancelling): cancelVerification() case (_, _, .verified): - // Dismiss the success screen automatically. - Task { - try? await Task.sleep(for: .seconds(2)) - self.actionsSubject.send(.finished) - } + actionsSubject.send(.finished) default: break } diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift similarity index 97% rename from ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift index c145f0a7db..e94a5738a8 100644 --- a/ElementX/Sources/Screens/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift +++ b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/SessionVerificationScreenViewModelProtocol.swift @@ -20,4 +20,6 @@ import Combine protocol SessionVerificationScreenViewModelProtocol { var actions: AnyPublisher { get } var context: SessionVerificationViewModelType.Context { get } + + func stop() } diff --git a/ElementX/Sources/Screens/SessionVerificationScreen/View/SessionVerificationScreen.swift b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/View/SessionVerificationScreen.swift similarity index 78% rename from ElementX/Sources/Screens/SessionVerificationScreen/View/SessionVerificationScreen.swift rename to ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/View/SessionVerificationScreen.swift index cbb1af994c..f1aefbc077 100644 --- a/ElementX/Sources/Screens/SessionVerificationScreen/View/SessionVerificationScreen.swift +++ b/ElementX/Sources/Screens/Onboarding/SessionVerificationScreen/View/SessionVerificationScreen.swift @@ -20,23 +20,18 @@ struct SessionVerificationScreen: View { @ObservedObject var context: SessionVerificationScreenViewModel.Context var body: some View { - NavigationStack { - ScrollView { - VStack(spacing: 32) { - screenHeader - Spacer() - mainContent - } - .padding(.horizontal, 16) - .padding(.top, 24) - .frame(maxWidth: .infinity) - .navigationBarTitleDisplayMode(.inline) - .toolbar { toolbarContent } + FullscreenDialog { + VStack(spacing: 32) { + screenHeader + Spacer() + mainContent } - .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) - .safeAreaInset(edge: .bottom) { actionButtons.padding() } + } bottomContent: { + actionButtons } - .interactiveDismissDisabled() // Make sure dismissal goes through the state machine(s). + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .interactiveDismissDisabled() } // MARK: - Private @@ -44,7 +39,7 @@ struct SessionVerificationScreen: View { private var headerImageName: String { switch context.viewState.verificationState { case .initial: - return "macbook.and.iphone" + return "lock" case .cancelled: return "exclamationmark.shield" case .requestingVerification: @@ -71,19 +66,24 @@ struct SessionVerificationScreen: View { @ViewBuilder private var screenHeader: some View { VStack(spacing: 0) { - Image(systemName: headerImageName) - .heroImage() - .padding(.bottom, 16) + if context.viewState.verificationState == .initial { + HeroImage(icon: \.lockSolid) + .padding(.bottom, 16) + } else { + Image(systemName: headerImageName) + .heroImage() + .padding(.bottom, 16) + } Text(context.viewState.title ?? "") - .font(.title2.bold()) + .font(.compound.headingMDBold) .multilineTextAlignment(.center) .foregroundColor(.compound.textPrimary) .padding(.bottom, 8) .accessibilityIdentifier(context.viewState.titleAccessibilityIdentifier) Text(context.viewState.message) - .font(.subheadline) + .font(.compound.bodyMD) .multilineTextAlignment(.center) .foregroundColor(.compound.textSecondary) } @@ -134,14 +134,6 @@ struct SessionVerificationScreen: View { } .buttonStyle(.compound(.primary)) .accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.requestVerification) - - if context.viewState.showRecoveryOption { - Button(L10n.screenSessionVerificationEnterRecoveryKey) { - context.send(viewAction: .recoveryKey) - } - .buttonStyle(.compound(.plain)) - .accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.enterRecoveryKey) - } } case .cancelled: Button(L10n.actionRetry) { @@ -157,9 +149,9 @@ struct SessionVerificationScreen: View { .accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.startSasVerification) case .showingChallenge: - VStack(spacing: 30) { - Button { context.send(viewAction: .accept) } label: { - Label(L10n.screenSessionVerificationTheyMatch, systemImage: "checkmark") + VStack(spacing: 32) { + Button(L10n.screenSessionVerificationTheyMatch) { + context.send(viewAction: .accept) } .buttonStyle(.compound(.primary)) .accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.acceptChallenge) @@ -172,12 +164,12 @@ struct SessionVerificationScreen: View { } case .acceptingChallenge: - VStack(spacing: 30) { + VStack(spacing: 32) { Button { context.send(viewAction: .accept) } label: { HStack(spacing: 16) { ProgressView() .tint(.compound.textOnSolidPrimary) - Label(L10n.screenSessionVerificationTheyMatch, systemImage: "checkmark") + Text(L10n.screenSessionVerificationTheyMatch) } } .buttonStyle(.compound(.primary)) @@ -197,16 +189,6 @@ struct SessionVerificationScreen: View { } } - @ToolbarContentBuilder - private var toolbarContent: some ToolbarContent { - ToolbarItem(placement: .cancellationAction) { - Button(L10n.actionCancel) { - context.send(viewAction: .close) - } - .accessibilityIdentifier(A11yIdentifiers.sessionVerificationScreen.close) - } - } - struct EmojiView: View { let emoji: SessionVerificationEmoji @@ -244,7 +226,6 @@ struct SessionVerification_Previews: PreviewProvider, TestablePreview { static func sessionVerificationScreen(state: SessionVerificationScreenStateMachine.State) -> some View { let viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: SessionVerificationControllerProxyMock.configureMock(), - recoveryState: .incomplete, verificationState: state) return SessionVerificationScreen(context: viewModel.context) diff --git a/ElementX/Sources/Screens/ReportContentScreen/ReportContentScreenCoordinator.swift b/ElementX/Sources/Screens/ReportContentScreen/ReportContentScreenCoordinator.swift index 1edc27a072..f55d79fba3 100644 --- a/ElementX/Sources/Screens/ReportContentScreen/ReportContentScreenCoordinator.swift +++ b/ElementX/Sources/Screens/ReportContentScreen/ReportContentScreenCoordinator.swift @@ -82,7 +82,7 @@ final class ReportContentScreenCoordinator: CoordinatorProtocol { // MARK: - Private - private static let loadingIndicatorIdentifier = "ReportContentLoading" + private static let loadingIndicatorIdentifier = "\(ReportContentScreenCoordinator.self)-Loading" private func startLoading() { parameters.userIndicatorController.submitIndicator( diff --git a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift index 1c2ffbc6fa..7e5c305a80 100644 --- a/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomMemberDetailsScreen/RoomMemberDetailsScreenViewModel.swift @@ -171,7 +171,7 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro // MARK: Loading indicator - private static let loadingIndicatorIdentifier = "RoomMemberLoading" + private static let loadingIndicatorIdentifier = "\(RoomMemberDetailsScreenViewModel.self)-Loading" private func showMemberLoadingIndicator() { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemPlainStylerView.swift b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemPlainStylerView.swift index ef557e25b6..b37f8bcafc 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemPlainStylerView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemPlainStylerView.swift @@ -97,9 +97,8 @@ struct TimelineItemPlainStylerView: View { HStack(spacing: 8) { TimelineSenderAvatarView(timelineItem: timelineItem) Text(timelineItem.sender.displayName ?? timelineItem.sender.id) - .font(.subheadline) + .font(.compound.bodyMDSemibold) .foregroundColor(.compound.decorativeColor(for: timelineItem.sender.id).text) - .fontWeight(.semibold) .lineLimit(1) } .onTapGesture { diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/EncryptedHistoryRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/EncryptedHistoryRoomTimelineView.swift deleted file mode 100644 index 85633e5e17..0000000000 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/EncryptedHistoryRoomTimelineView.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2023 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Compound -import SwiftUI - -/// The item shown when all previous items are un-decryptable due to -/// key backup not yet being supported in the app. -struct EncryptedHistoryRoomTimelineView: View { - let timelineItem: EncryptedHistoryRoomTimelineItem - - var body: some View { - Label { - Text(title) - .font(.compound.bodyMDSemibold) - .foregroundColor(.compound.textInfoPrimary) - } icon: { - CompoundIcon(\.infoSolid, size: .small, relativeTo: .compound.bodyMDSemibold) - .foregroundColor(.compound.iconInfoPrimary) - } - .labelStyle(EncryptedHistoryLabelStyle()) - .padding(16) - .background { - RoundedRectangle(cornerRadius: 8) - .fill(Color.compound.bgInfoSubtle) - RoundedRectangle(cornerRadius: 8) - .stroke(Color.compound.borderInfoSubtle) - } - .frame(maxWidth: .infinity) - .padding(.horizontal, 8) - .padding(.vertical, 16) - } - - private var title: String { - timelineItem.isSessionVerified ? L10n.screenRoomEncryptedHistoryBanner : L10n.screenRoomEncryptedHistoryBannerUnverified - } -} - -private struct EncryptedHistoryLabelStyle: LabelStyle { - func makeBody(configuration: Configuration) -> some View { - HStack(alignment: .top, spacing: 16) { - configuration.icon - configuration.title - } - } -} - -struct EncryptedHistoryRoomTimelineView_Previews: PreviewProvider, TestablePreview { - static var previews: some View { - VStack(spacing: 8) { - EncryptedHistoryRoomTimelineView(timelineItem: .init(id: .random, isSessionVerified: true)) - EncryptedHistoryRoomTimelineView(timelineItem: .init(id: .random, isSessionVerified: false)) - } - } -} diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/SecureBackupKeyBackupScreenViewModel.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/SecureBackupKeyBackupScreenViewModel.swift index 6572c7a58c..0f12612ba7 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/SecureBackupKeyBackupScreenViewModel.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/SecureBackupKeyBackupScreenViewModel.swift @@ -86,7 +86,7 @@ class SecureBackupKeyBackupScreenViewModel: SecureBackupKeyBackupScreenViewModel } } - private static let loadingIndicatorIdentifier = "SecureBackupKeyBackupScreenLoading" + private static let loadingIndicatorIdentifier = "\(SecureBackupKeyBackupScreenViewModel.self)-Loading" private func showLoadingIndicator() { userIndicatorController?.submitIndicator(.init(id: Self.loadingIndicatorIdentifier, type: .modal, title: L10n.commonLoading, persistent: true)) diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/View/SecureBackupKeyBackupScreen.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/View/SecureBackupKeyBackupScreen.swift index a27e3d6327..10e5d8652a 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/View/SecureBackupKeyBackupScreen.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupKeyBackupScreen/View/SecureBackupKeyBackupScreen.swift @@ -22,12 +22,21 @@ struct SecureBackupKeyBackupScreen: View { @ObservedObject var context: SecureBackupKeyBackupScreenViewModel.Context var body: some View { - mainContent - .padding() - .interactiveDismissDisabled() - .toolbar { toolbar } - .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) - .alert(item: $context.alertInfo) + FullscreenDialog { + mainContent + } bottomContent: { + Button(role: .destructive) { + context.send(viewAction: .toggleBackup) + } label: { + Text(L10n.screenChatBackupKeyBackupActionDisable) + } + .buttonStyle(.compound(.primary)) + } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .interactiveDismissDisabled() + .toolbar { toolbar } + .alert(item: $context.alertInfo) } @ViewBuilder @@ -71,15 +80,6 @@ struct SecureBackupKeyBackupScreen: View { .foregroundColor(.compound.iconCriticalPrimary) } } - - Spacer() - - Button(role: .destructive) { - context.send(viewAction: .toggleBackup) - } label: { - Text(L10n.screenChatBackupKeyBackupActionDisable) - } - .buttonStyle(.compound(.primary)) } } diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupLogoutConfirmationScreen/View/SecureBackupLogoutConfirmationScreen.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupLogoutConfirmationScreen/View/SecureBackupLogoutConfirmationScreen.swift index 1e29b4e638..817f5eeff3 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupLogoutConfirmationScreen/View/SecureBackupLogoutConfirmationScreen.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupLogoutConfirmationScreen/View/SecureBackupLogoutConfirmationScreen.swift @@ -22,26 +22,21 @@ struct SecureBackupLogoutConfirmationScreen: View { @ObservedObject var context: SecureBackupLogoutConfirmationScreenViewModel.Context var body: some View { - NavigationStack { - ScrollView { - VStack(spacing: 16) { - header - content - } - .padding() + FullscreenDialog { + VStack(spacing: 16) { + HeroImage(icon: \.keyOffSolid) + content } - .toolbar { toolbar } - .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) - .safeAreaInset(edge: .bottom) { footer.padding() } - .alert(item: $context.alertInfo) + .padding() + } bottomContent: { + footer.padding() } + .toolbar { toolbar } + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .alert(item: $context.alertInfo) } - - @ViewBuilder - private var header: some View { - HeroImage(icon: \.keyOffSolid) - } - + @ViewBuilder private var content: some View { Text(title) @@ -62,21 +57,23 @@ struct SecureBackupLogoutConfirmationScreen: View { @ViewBuilder private var footer: some View { - if context.viewState.mode == .saveRecoveryKey { - Button { - context.send(viewAction: .settings) + VStack(spacing: 16.0) { + if context.viewState.mode == .saveRecoveryKey { + Button { + context.send(viewAction: .settings) + } label: { + Text(L10n.commonSettings) + } + .buttonStyle(.compound(.primary)) + } + + Button(role: .destructive) { + context.send(viewAction: .logout) } label: { - Text(L10n.commonSettings) + Text(L10n.actionSignout) } .buttonStyle(.compound(.primary)) } - - Button(role: .destructive) { - context.send(viewAction: .logout) - } label: { - Text(L10n.actionSignout) - } - .buttonStyle(.compound(.primary)) } @ToolbarContentBuilder @@ -88,7 +85,7 @@ struct SecureBackupLogoutConfirmationScreen: View { } } - var title: String { + private var title: String { switch context.viewState.mode { case .saveRecoveryKey: return L10n.screenSignoutSaveRecoveryKeyTitle @@ -99,7 +96,7 @@ struct SecureBackupLogoutConfirmationScreen: View { } } - var subtitle: String { + private var subtitle: String { switch context.viewState.mode { case .saveRecoveryKey: return L10n.screenSignoutSaveRecoveryKeySubtitle diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift index 543767f65c..28dbf0f380 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenCoordinator.swift @@ -20,6 +20,7 @@ import SwiftUI struct SecureBackupRecoveryKeyScreenCoordinatorParameters { let secureBackupController: SecureBackupControllerProtocol let userIndicatorController: UserIndicatorControllerProtocol + let isModallyPresented: Bool } enum SecureBackupRecoveryKeyScreenCoordinatorAction { @@ -40,7 +41,8 @@ final class SecureBackupRecoveryKeyScreenCoordinator: CoordinatorProtocol { init(parameters: SecureBackupRecoveryKeyScreenCoordinatorParameters) { viewModel = SecureBackupRecoveryKeyScreenViewModel(secureBackupController: parameters.secureBackupController, - userIndicatorController: parameters.userIndicatorController) + userIndicatorController: parameters.userIndicatorController, + isModallyPresented: parameters.isModallyPresented) } func start() { diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift index 44f60f78fd..b5d9e92732 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenModels.swift @@ -28,6 +28,9 @@ enum SecureBackupRecoveryKeyScreenViewMode { } struct SecureBackupRecoveryKeyScreenViewState: BindableState { + /// Whether the screen is presented modally or within a navigation stack. + var isModallyPresented: Bool + let mode: SecureBackupRecoveryKeyScreenViewMode var recoveryKey: String? diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift index 53175d65e1..08a19cb43a 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/SecureBackupRecoveryKeyScreenViewModel.swift @@ -28,11 +28,15 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM actionsSubject.eraseToAnyPublisher() } - init(secureBackupController: SecureBackupControllerProtocol, userIndicatorController: UserIndicatorControllerProtocol) { + init(secureBackupController: SecureBackupControllerProtocol, + userIndicatorController: UserIndicatorControllerProtocol, + isModallyPresented: Bool) { self.secureBackupController = secureBackupController self.userIndicatorController = userIndicatorController - super.init(initialViewState: .init(mode: secureBackupController.recoveryState.value.viewMode, bindings: .init())) + super.init(initialViewState: .init(isModallyPresented: isModallyPresented, + mode: secureBackupController.recoveryState.value.viewMode, + bindings: .init())) secureBackupController.recoveryState .receive(on: DispatchQueue.main) diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift index 666e190319..a7cae0abdd 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupRecoveryKeyScreen/View/SecureBackupRecoveryKeyScreen.swift @@ -24,7 +24,7 @@ struct SecureBackupRecoveryKeyScreen: View { private let textFieldIdentifier = "textFieldIdentifier" var body: some View { - ScrollView { + FullscreenDialog { ScrollViewReader { reader in mainContent .padding(16) @@ -33,17 +33,14 @@ struct SecureBackupRecoveryKeyScreen: View { reader.scrollTo(textFieldIdentifier) } } - } - .safeAreaInset(edge: .bottom) { + } bottomContent: { footer - .padding([.horizontal, .bottom], 16) - .padding(.top, 8) - .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) } - .interactiveDismissDisabled() .toolbar { toolbar } .toolbar(.visible, for: .navigationBar) - .background(Color.compound.bgCanvasDefault.ignoresSafeArea()) + .background() + .environment(\.backgroundStyle, AnyShapeStyle(Color.compound.bgCanvasDefault)) + .interactiveDismissDisabled() .alert(item: $context.alertInfo) } @@ -101,7 +98,7 @@ struct SecureBackupRecoveryKeyScreen: View { @ToolbarContentBuilder private var toolbar: some ToolbarContent { - if context.viewState.recoveryKey == nil { + if context.viewState.isModallyPresented == true, context.viewState.recoveryKey == nil { ToolbarItem(placement: .cancellationAction) { Button(L10n.actionCancel) { context.send(viewAction: .cancel) @@ -235,6 +232,8 @@ struct SecureBackupRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview let backupController = SecureBackupControllerMock() backupController.underlyingRecoveryState = CurrentValueSubject(recoveryState).asCurrentValuePublisher() - return SecureBackupRecoveryKeyScreenViewModel(secureBackupController: backupController, userIndicatorController: UserIndicatorControllerMock()) + return SecureBackupRecoveryKeyScreenViewModel(secureBackupController: backupController, + userIndicatorController: UserIndicatorControllerMock(), + isModallyPresented: true) } } diff --git a/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift b/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift index 693d972e9c..2bfe65c095 100644 --- a/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift +++ b/ElementX/Sources/Screens/SecureBackup/SecureBackupScreen/SecureBackupScreenCoordinator.swift @@ -46,7 +46,8 @@ final class SecureBackupScreenCoordinator: CoordinatorProtocol { let navigationStackCoordinator = NavigationStackCoordinator() let recoveryKeyCoordinator = SecureBackupRecoveryKeyScreenCoordinator(parameters: .init(secureBackupController: parameters.secureBackupController, - userIndicatorController: parameters.userIndicatorController)) + userIndicatorController: parameters.userIndicatorController, + isModallyPresented: true)) recoveryKeyCoordinator.actions.sink { [weak self] action in guard let self else { return } diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift index cc3d8afd5c..5a74d2fbdb 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenCoordinator.swift @@ -33,7 +33,6 @@ enum SettingsScreenCoordinatorAction { case bugReport case about case blockedUsers - case sessionVerification case accountSessions case notifications case advancedSettings @@ -77,8 +76,6 @@ final class SettingsScreenCoordinator: CoordinatorProtocol { actionsSubject.send(.about) case .blockedUsers: actionsSubject.send(.blockedUsers) - case .sessionVerification: - actionsSubject.send(.sessionVerification) case .secureBackup: actionsSubject.send(.secureBackup) case .accountSessionsList: diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift index 65535cb461..1d0d51e4e6 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenModels.swift @@ -26,7 +26,6 @@ enum SettingsScreenViewModelAction { case reportBug case about case blockedUsers - case sessionVerification case secureBackup case accountSessionsList case notifications @@ -37,7 +36,6 @@ enum SettingsScreenViewModelAction { enum SettingsScreenSecuritySectionMode { case none - case sessionVerification case secureBackup } @@ -65,7 +63,6 @@ enum SettingsScreenViewAction { case reportBug case about case blockedUsers - case sessionVerification case secureBackup case accountSessionsList case notifications diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift index 8ea8d04aa6..ebf0ffded4 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/SettingsScreenViewModel.swift @@ -50,9 +50,6 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo guard let self else { return } switch (securityState.verificationState, securityState.recoveryState) { - case (.unverified, _): - state.showSecuritySectionBadge = true - state.securitySectionMode = .sessionVerification case (.verified, .disabled): state.showSecuritySectionBadge = true state.securitySectionMode = .secureBackup @@ -107,8 +104,6 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo actionsSubject.send(.blockedUsers) case .logout: actionsSubject.send(.logout) - case .sessionVerification: - actionsSubject.send(.sessionVerification) case .secureBackup: actionsSubject.send(.secureBackup) case .notifications: diff --git a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift index 487083dce6..6fa81c9aa2 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreen/View/SettingsScreen.swift @@ -81,11 +81,6 @@ struct SettingsScreen: View { private var accountSecuritySection: some View { Section { switch context.viewState.securitySectionMode { - case .sessionVerification: - ListRow(label: .default(title: L10n.actionCompleteVerification, - icon: \.checkCircle), - details: context.viewState.showSecuritySectionBadge ? .icon(securitySectionBadge) : nil, - kind: .button { context.send(viewAction: .sessionVerification) }) case .secureBackup: ListRow(label: .default(title: L10n.commonChatBackup, icon: \.key), diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift index 785a52e46d..8ebfbb9e7d 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift @@ -190,7 +190,7 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { // MARK: Loading indicator - private static let loadingIndicatorIdentifier = "StartChatCoordinatorLoading" + private static let loadingIndicatorIdentifier = "\(StartChatScreenCoordinator.self)-Loading" private func showLoadingIndicator() { parameters.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index 7cc95ca425..ead0e1163a 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -145,7 +145,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie // MARK: Loading indicator - private static let loadingIndicatorIdentifier = "StartChatLoading" + private static let loadingIndicatorIdentifier = "\(StartChatScreenViewModel.self)-Loading" private func showLoadingIndicator() { userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, diff --git a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift index d277c70636..fa7a7a5edc 100644 --- a/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift +++ b/ElementX/Sources/Services/Notification/Manager/NotificationManager.swift @@ -64,15 +64,8 @@ final class NotificationManager: NSObject, NotificationManagerProtocol { self?.enableNotifications(newValue) } .store(in: &cancellables) - - // Request authorization uppon UIApplication.didBecomeActiveNotification notification - NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification) - .sink { [weak self] _ in - self?.requestAuthorization() - } - .store(in: &cancellables) } - + func requestAuthorization() { guard appSettings.enableNotifications, !userSession.isNil else { return } Task { diff --git a/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift b/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift index fdbb4b01f6..7701c3d706 100644 --- a/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift +++ b/ElementX/Sources/Services/Notification/Manager/NotificationManagerProtocol.swift @@ -38,5 +38,6 @@ protocol NotificationManagerProtocol: AnyObject { func registrationFailed(with error: Error) func showLocalNotification(with title: String, subtitle: String?) async func setUserSession(_ userSession: UserSessionProtocol?) + func requestAuthorization() } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineControllerFactory.swift b/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineControllerFactory.swift index 6b05cbfee1..b95c0f0871 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineControllerFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/MockRoomTimelineControllerFactory.swift @@ -18,8 +18,7 @@ import Foundation struct MockRoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol { func buildRoomTimelineController(roomProxy: RoomProxyProtocol, - timelineItemFactory: RoomTimelineItemFactoryProtocol, - secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol { + timelineItemFactory: RoomTimelineItemFactoryProtocol) -> RoomTimelineControllerProtocol { let timelineController = MockRoomTimelineController() timelineController.timelineItems = RoomTimelineItemFixtures.largeChunk return timelineController diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index d45576b462..e8ff0c6124 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -24,7 +24,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol { private let timelineProvider: RoomTimelineProviderProtocol private let timelineItemFactory: RoomTimelineItemFactoryProtocol private let appSettings: AppSettings - private let secureBackupController: SecureBackupControllerProtocol private let serialDispatchQueue: DispatchQueue private var cancellables = Set() @@ -39,13 +38,11 @@ class RoomTimelineController: RoomTimelineControllerProtocol { init(roomProxy: RoomProxyProtocol, timelineItemFactory: RoomTimelineItemFactoryProtocol, - appSettings: AppSettings, - secureBackupController: SecureBackupControllerProtocol) { + appSettings: AppSettings) { self.roomProxy = roomProxy timelineProvider = roomProxy.timeline.timelineProvider self.timelineItemFactory = timelineItemFactory self.appSettings = appSettings - self.secureBackupController = secureBackupController serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider", qos: .utility) timelineProvider @@ -253,7 +250,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol { var newTimelineItems = [RoomTimelineItemProtocol]() var canBackPaginate = !roomProxy.timeline.timelineStartReached var isBackPaginating = false - var lastEncryptedHistoryItemIndex: Int? let collapsibleChunks = timelineProvider.itemProxies.groupBy { isItemCollapsible($0) } @@ -264,10 +260,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol { let timelineItem = buildTimelineItem(for: itemProxy) - if timelineItem is EncryptedHistoryRoomTimelineItem { - canBackPaginate = false - } - return timelineItem } @@ -282,35 +274,25 @@ class RoomTimelineController: RoomTimelineControllerProtocol { continue } - if timelineItem is EncryptedHistoryRoomTimelineItem { - lastEncryptedHistoryItemIndex = newTimelineItems.endIndex - } - newTimelineItems.append(timelineItem) } else { newTimelineItems.append(CollapsibleTimelineItem(items: items)) } } - if let lastEncryptedHistoryItemIndex { - // Remove everything up to the last encrypted history item. - // It only contains encrypted messages, state changes and date separators. - newTimelineItems.removeFirst(lastEncryptedHistoryItemIndex) - } else { - // Otherwise check if we need to add anything to the top of the timeline. - switch timelineProvider.backPaginationState { - case .timelineStartReached: - if !roomProxy.isEncryptedOneToOneRoom { - let timelineStart = TimelineStartRoomTimelineItem(name: roomProxy.name) - newTimelineItems.insert(timelineStart, at: 0) - } - canBackPaginate = false - case .paginating: - newTimelineItems.insert(PaginationIndicatorRoomTimelineItem(), at: 0) - isBackPaginating = true - case .idle: - break + // Check if we need to add anything to the top of the timeline. + switch timelineProvider.backPaginationState { + case .timelineStartReached: + if !roomProxy.isEncryptedOneToOneRoom { + let timelineStart = TimelineStartRoomTimelineItem(name: roomProxy.name) + newTimelineItems.insert(timelineStart, at: 0) } + canBackPaginate = false + case .paginating: + newTimelineItems.insert(PaginationIndicatorRoomTimelineItem(), at: 0) + isBackPaginating = true + case .idle: + break } DispatchQueue.main.sync { @@ -326,17 +308,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { switch itemProxy { case .event(let eventTimelineItem): let timelineItem = timelineItemFactory.buildTimelineItem(for: eventTimelineItem, isDM: roomProxy.isEncryptedOneToOneRoom) - - // When backup is enabled just show the timeline items, they will most likely - // resolve eventually. If we don't know the backup state then we assume the session is not verified yet, - // otherwise we just treat it as fully disabled. - if secureBackupController.keyBackupState.value != .enabled { - if timelineItem is EncryptedRoomTimelineItem, isItemInEncryptionHistory(eventTimelineItem) { - return EncryptedHistoryRoomTimelineItem(id: eventTimelineItem.id, - isSessionVerified: secureBackupController.keyBackupState.value != .unknown) - } - } - + if let messageTimelineItem = timelineItem as? EventBasedMessageTimelineItemProtocol { // Avoid fetching this over and over again as it changes states if it keeps failing to load // Errors will be handled again on appearance @@ -358,14 +330,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { return nil } } - - /// Whether or not a specific item is part of the room's history that can't be decrypted due - /// to the lack of key-backup. This is handled differently so we only show a single item. - private func isItemInEncryptionHistory(_ itemProxy: EventTimelineItemProxy) -> Bool { - guard roomProxy.isEncrypted, let lastLoginDate = appSettings.lastLoginDate else { return false } - return itemProxy.timestamp < lastLoginDate - } - + private func isItemCollapsible(_ item: TimelineItemProxy) -> Bool { if !appSettings.shouldCollapseRoomStateEvents { return false diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactory.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactory.swift index 87aa4e848a..199eeaaa7b 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactory.swift @@ -18,11 +18,9 @@ import Foundation struct RoomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol { func buildRoomTimelineController(roomProxy: RoomProxyProtocol, - timelineItemFactory: RoomTimelineItemFactoryProtocol, - secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol { + timelineItemFactory: RoomTimelineItemFactoryProtocol) -> RoomTimelineControllerProtocol { RoomTimelineController(roomProxy: roomProxy, timelineItemFactory: timelineItemFactory, - appSettings: ServiceLocator.shared.settings, - secureBackupController: secureBackupController) + appSettings: ServiceLocator.shared.settings) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactoryProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactoryProtocol.swift index 60fe5be1c6..7e8db09c1d 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactoryProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerFactoryProtocol.swift @@ -19,6 +19,5 @@ import Foundation @MainActor protocol RoomTimelineControllerFactoryProtocol { func buildRoomTimelineController(roomProxy: RoomProxyProtocol, - timelineItemFactory: RoomTimelineItemFactoryProtocol, - secureBackupController: SecureBackupControllerProtocol) -> RoomTimelineControllerProtocol + timelineItemFactory: RoomTimelineItemFactoryProtocol) -> RoomTimelineControllerProtocol } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemView.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemView.swift index 0d999ca3ae..98b0391da7 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemView.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemView.swift @@ -64,8 +64,6 @@ struct RoomTimelineItemView: View { UnsupportedRoomTimelineView(timelineItem: item) case .timelineStart(let item): TimelineStartRoomTimelineView(timelineItem: item) - case .encryptedHistory(let item): - EncryptedHistoryRoomTimelineView(timelineItem: item) case .state(let item): StateRoomTimelineView(timelineItem: item) case .group(let item): diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift index c9a5643278..e013043b6a 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemViewState.swift @@ -60,7 +60,6 @@ enum RoomTimelineItemType: Equatable { case sticker(StickerRoomTimelineItem) case unsupported(UnsupportedRoomTimelineItem) case timelineStart(TimelineStartRoomTimelineItem) - case encryptedHistory(EncryptedHistoryRoomTimelineItem) case state(StateRoomTimelineItem) case group(CollapsibleTimelineItem) case location(LocationRoomTimelineItem) @@ -100,8 +99,6 @@ enum RoomTimelineItemType: Equatable { self = .unsupported(item) case let item as TimelineStartRoomTimelineItem: self = .timelineStart(item) - case let item as EncryptedHistoryRoomTimelineItem: - self = .encryptedHistory(item) case let item as StateRoomTimelineItem: self = .state(item) case let item as CollapsibleTimelineItem: @@ -136,7 +133,6 @@ enum RoomTimelineItemType: Equatable { .sticker(let item as RoomTimelineItemProtocol), .unsupported(let item as RoomTimelineItemProtocol), .timelineStart(let item as RoomTimelineItemProtocol), - .encryptedHistory(let item as RoomTimelineItemProtocol), .state(let item as RoomTimelineItemProtocol), .group(let item as RoomTimelineItemProtocol), .location(let item as RoomTimelineItemProtocol), diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index a20632214f..2aa3afcbdc 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -42,7 +42,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate { ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) AppSettings.configureWithSuiteName("io.element.elementx.uitests") - AppSettings.reset() + AppSettings.resetAllSettings() ServiceLocator.shared.register(appSettings: AppSettings()) ServiceLocator.shared.register(bugReportService: BugReportServiceMock()) ServiceLocator.shared.register(analytics: AnalyticsService(client: AnalyticsClientMock(), @@ -149,7 +149,6 @@ class MockScreen: Identifiable { return navigationStackCoordinator case .authenticationFlow: let flowCoordinator = AuthenticationFlowCoordinator(authenticationService: MockAuthenticationServiceProxy(), - appLockService: AppLockServiceMock(), bugReportService: BugReportServiceMock(), navigationRootCoordinator: navigationRootCoordinator, appSettings: ServiceLocator.shared.settings, @@ -567,8 +566,7 @@ class MockScreen: Identifiable { return navigationStackCoordinator case .sessionVerification: var sessionVerificationControllerProxy = SessionVerificationControllerProxyMock.configureMock(requestDelay: .seconds(5)) - let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy, - recoveryState: .unknown) + let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy) return SessionVerificationScreenCoordinator(parameters: parameters) case .userSessionScreen, .userSessionScreenReply, .userSessionScreenRTE: let appSettings: AppSettings = ServiceLocator.shared.settings @@ -586,7 +584,9 @@ class MockScreen: Identifiable { bugReportService: BugReportServiceMock(), roomTimelineControllerFactory: MockRoomTimelineControllerFactory(), appSettings: appSettings, - analytics: ServiceLocator.shared.analytics) + analytics: ServiceLocator.shared.analytics, + notificationManager: NotificationManagerMock(), + isNewLogin: false) flowCoordinator.start() diff --git a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift index 66df820829..d8ee1972ad 100644 --- a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift +++ b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift @@ -24,7 +24,7 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol { ServiceLocator.shared.register(userIndicatorController: UserIndicatorControllerMock.default) AppSettings.configureWithSuiteName("io.element.elementx.unittests") - AppSettings.reset() + AppSettings.resetAllSettings() ServiceLocator.shared.register(appSettings: AppSettings()) ServiceLocator.shared.register(bugReportService: BugReportServiceMock()) ServiceLocator.shared.register(analytics: AnalyticsService(client: AnalyticsClientMock(), diff --git a/IntegrationTests/Sources/Application.swift b/IntegrationTests/Sources/Application.swift index e006bbc8e1..05a8aa9a5f 100644 --- a/IntegrationTests/Sources/Application.swift +++ b/IntegrationTests/Sources/Application.swift @@ -19,7 +19,14 @@ import XCTest enum Application { @discardableResult static func launch() -> XCUIApplication { let app = XCUIApplication() + + var launchEnvironment = [ + "IS_RUNNING_INTEGRATION_TESTS": "1" + ] + + app.launchEnvironment = launchEnvironment app.launch() + return app } } diff --git a/IntegrationTests/Sources/Common.swift b/IntegrationTests/Sources/Common.swift index d0a02000e3..34ec6c6a0f 100644 --- a/IntegrationTests/Sources/Common.swift +++ b/IntegrationTests/Sources/Common.swift @@ -65,33 +65,13 @@ extension XCUIApplication { // Wait for login to finish currentTestCase.expectation(for: doesNotExistPredicate, evaluatedWith: usernameTextField) currentTestCase.waitForExpectations(timeout: 300.0) - - // Handle analytics prompt screen - if staticTexts[A11yIdentifiers.analyticsPromptScreen.title].waitForExistence(timeout: 10.0) { - // Wait for login and then handle save password sheet - let savePasswordButton = buttons["Save Password"] - if savePasswordButton.waitForExistence(timeout: 10.0) { - savePasswordButton.tap() - } - - let enableButton = buttons[A11yIdentifiers.analyticsPromptScreen.enable] - XCTAssertTrue(enableButton.waitForExistence(timeout: 10.0)) - enableButton.tap() - } - + // This might come in a different order, wait for both. let savePasswordButton = buttons["Save Password"] if savePasswordButton.waitForExistence(timeout: 10.0) { savePasswordButton.tap() } - // Handle the notifications permission alert https://stackoverflow.com/a/58171074/730924 - let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") - let notificationAlertDeclineButton = springboard.buttons.element(boundBy: 0) - if notificationAlertDeclineButton.waitForExistence(timeout: 10.0) { - notificationAlertDeclineButton.tap() - } - // Migration screen may be shown as an overlay. // if that pops up soon enough, we just let that happen and wait let message = staticTexts[A11yIdentifiers.migrationScreen.message] diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-en-GB.1.png index 0069e930e7..2c2fac715c 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70fcd44d149c0c7633fe2bee0ba85f3ae81d1fedd801a66239f0d1307909a430 -size 173623 +oid sha256:0a46cd7cf5e0e13a6d7c60300a9fcb6311c20bb2bae22778a2783a2f0afc7c0e +size 415851 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-pseudo.1.png index 5dcf51263a..6db3ba7e13 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5eb23616fd2661ac5a2990e0dfef92c504da2726db2138222b88fba79fcd7500 -size 267411 +oid sha256:f83e16e68a399d2e9db7c69e3fd6fe83a42ebe497b23cb4dde5b6d230d373c4c +size 508866 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-en-GB.1.png index 2bfbab7558..e6f23b9629 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9be44c03d825f3650984e0cfd0540915913f896951acd0d39991f9843371c111 -size 122394 +oid sha256:7815860f7b70f4aca237db12ec782a0b39276e5b3e5144cb1535254992a25c57 +size 248416 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-pseudo.1.png index ec952675ef..f58a7ef256 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_analyticsPromptScreen-iPhone-15-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28cffcec20c859af14d5e018c63da99c3014375d56ffd30751c15846f823f031 -size 200260 +oid sha256:ef5bc386c26e9f4777531b8e439de9cad04a98d02e25d4f7298192589720b0b9 +size 325644 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-en-GB.1.png deleted file mode 100644 index ab2e817ac8..0000000000 --- a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-en-GB.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5832efbb9c9ee554cbcb18a9d36931e0d255385791994ec328fb489ab571c731 -size 118356 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-pseudo.1.png deleted file mode 100644 index 59c93729fe..0000000000 --- a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPad-pseudo.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dfe734442f32895cf014454a9819b0c9dffcb47866876294156cb209b3695278 -size 163863 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-en-GB.1.png deleted file mode 100644 index e3f1c4fe44..0000000000 --- a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-en-GB.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:47d083e6284305c4c8c182415a15b28ed58c0e4435420557c5628bb51fb79e2c -size 70572 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-pseudo.1.png deleted file mode 100644 index 4d5c9be6ff..0000000000 --- a/PreviewTests/__Snapshots__/PreviewTests/test_homeScreenSessionVerificationBanner-iPhone-15-pseudo.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f87532f0e14e153708a24b12d5c1f232eb537fa9317d0906562c03e3e7ad8617 -size 105302 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-en-GB.1.png new file mode 100644 index 0000000000..76e8ab4640 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47d502c8c6fbec6e38497bf9aabe3803f9006145d5c7e9c0997f892405826bc1 +size 119605 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-pseudo.1.png new file mode 100644 index 0000000000..9e713c4aa5 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86e9a45f6ab26a072edfba0258e275d2f234765ecf0a69f1301aba6108090d07 +size 153905 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-en-GB.1.png new file mode 100644 index 0000000000..752e6039cd --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15e443ca166ca691ac1f7ba73732e564c5ea3e18297f290337d94fc55da1a821 +size 71486 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-pseudo.1.png new file mode 100644 index 0000000000..934c7ff3eb --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmationScreen-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f44459b131c9d4a9c88547b9b58c23814919fe2311ffac7694cf19e5f584e817 +size 106764 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-en-GB.1.png new file mode 100644 index 0000000000..897fed7e7e --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8dfc9897f5cef15fa16a1e51ec869b6dfd3c05a1376300ffed7440ff4b490d0c +size 120872 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-pseudo.1.png new file mode 100644 index 0000000000..34d63ed504 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0dd9ce4a46cff45390876e7dfdbaeecce78c69a40a403f8563544e05e3efc379 +size 162211 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-en-GB.1.png new file mode 100644 index 0000000000..8bb83fea55 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a9cd6d7a9970fa0a77aff7201990172dfdfb9c25c48b4197ab5c229f01bffce +size 73653 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-pseudo.1.png new file mode 100644 index 0000000000..09ff97a039 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_identityConfirmedScreen-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be25dc7183d5821ffab59e57d022f69bc014aa7b51111ca57cba636f52934d18 +size 114490 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-en-GB.1.png new file mode 100644 index 0000000000..b0121994ba --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab736cdeff320ccf70d67b34009536b723ce9abe7348d8f885caf74a17967229 +size 389835 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-pseudo.1.png new file mode 100644 index 0000000000..43f8bc4399 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b591ed050b9a913a500c0ef0bb935bd7940dfe631a3486810ab18b5ebbe947c +size 441047 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-en-GB.1.png new file mode 100644 index 0000000000..9a1fc77715 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10a1bb28971bb64a6679b6a4cfd08c060f5305e40032768db88ffd24a97dab8c +size 214792 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-pseudo.1.png new file mode 100644 index 0000000000..d3bd39e0a8 --- /dev/null +++ b/PreviewTests/__Snapshots__/PreviewTests/test_notificationPermissionsScreen-iPhone-15-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95219b6d0cff9700acf62799558ad527ed405cafb4565fbe8c48e8b3210d7b4c +size 254130 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-en-GB.Set-up.png index 4f0918d3da..97d2d52233 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a961330081c52fb6d358ee458351c5a9e9b482e2dc129fc30bd4365877ff6bd5 -size 188454 +oid sha256:3d8c27b325869c82555047403415f58e28872e76e5f045cd064b2ab3ba243fc1 +size 196801 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-pseudo.Set-up.png index 10d69526f5..cb3039bf92 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPad-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d7f02dcad9dd8ded74b8d3ae51b010085ea800143426d32eaa41084ba142e7f -size 287728 +oid sha256:dc127a68581e3163e6f2349bd7e2ffc201ce2fa8fd066187b483ddb33fd67fa0 +size 304422 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-en-GB.Set-up.png index 800ebb2850..9fc6e37168 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92e84ea5a58fb3b0337e5221c91aae1c640c1d79ac3f5d1002fddb301cfe35e0 -size 146863 +oid sha256:b8363d9bb0f0497005e0d88487aea70523c08fe88d7ac97185dfcfd5e71784d4 +size 147319 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-pseudo.Set-up.png index ee6bfd7dce..ad10f0d711 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupKeyBackupScreen-iPhone-15-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb6d2272487d56ad6c91d206ebcae25734d1b2ddf41106cbe29ceb9a8c92c2e4 -size 228920 +oid sha256:49ca04fc3f8ac3eb8bd54b360004f8fecce4aeb012436b090403328b69d23a99 +size 228907 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-en-GB.1.png index 649037ec2a..4788ffbbb7 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0e94ed0775d91f4b05caebdac22c73f120a6861b621269108a35c30a8f478a5 -size 143570 +oid sha256:f6d0962c09da93a8abcc499017c24c28555622e3e02d978043b3c7f3874729f2 +size 156994 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-pseudo.1.png index 2cefcd6c02..4214cdadfc 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5805c22d5fd0e778eee4ab6f6e2065c4500abe121edb94c2a4a2e4d0f9eab4f8 -size 202973 +oid sha256:df6d9523e1659465f080f56e76db707fbe027803be5f83e0e9b8dc064d1251a8 +size 217178 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-en-GB.1.png index 61533439eb..cd32906050 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3b7ea1241f90e40c8677c0ee085b6c9a4e4df35b6492e61b7aaa7f20fa673a2 -size 94098 +oid sha256:16a97c200a8e66deb943df7cb8bde5a1f84776f680fd1a89cbc80d474b87eba7 +size 101247 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-pseudo.1.png index 0deac24878..479041026c 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupLogoutConfirmationScreen-iPhone-15-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1979f42f8b6e8c3a40d24af8731d5d843bab9452c007ea477dee7a299ee28273 -size 146888 +oid sha256:76f33c85188d8c10bc304dd4bd5d7d92652b184204a1720650189a4d6da8663b +size 159534 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png index 44fc2709ed..2ac0f706a9 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30240be156fa9702ab5a06af238f883c3729c4d67787c512c3afd8e4c5380201 -size 137295 +oid sha256:baf9353b8c7a809f2156328608d6a104f1e0ca70132ab635932ad840344c55f4 +size 137132 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png index d932844a13..f332c94424 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ceb94c28825aee0aba729eb8c236488a5b8aa44fdb8f7721df6f4a4682e89e6 -size 172886 +oid sha256:e7c5c210baa3a397ea02c6a1af578b71d74a9ec0b16f0fb3bdfba95d5ff07232 +size 179233 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png index 7f6d022aa9..60bb1ea1af 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72e2785a7cbd3449ad18851156c5ad20c4cf39f23e88f6cc2fd9f3664f52da5f -size 171608 +oid sha256:28e9bbf6e09a25bb02a9a9f678520d64b75544923628ee730c3565402daa5ee5 +size 182095 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png index 1dacba460d..cccb8beff3 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1b51a5fab01b184ade32cbc30e7dcd0cc7b9c41d8d9de97ae010890f0735adb -size 182447 +oid sha256:4bdfa8f2fdb918150acf2b4d923ed3a2037e1b4cbbf7cb42f46353f4dadcd9f8 +size 195582 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png index e5a57a4d1f..f01b769330 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac04fbf081d504bbc9f048bdf69bfa1aaa274182a1398dbc4f4453cf69d37ab5 -size 259583 +oid sha256:7aa089fb7520df5dcdb62e350db2342b0510f6ef62a31864f376b17cfe3c295b +size 278457 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png index e9d8e956f1..575e3c37b7 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPad-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:074bf361c6a7d4df4768ccdeb12bf2a13608fd307b6b2ce2539d9e69d3ab6cda -size 251075 +oid sha256:3adfc60a26f525cecdd61437ddc2bddac5b21cbe265bd0ce1ecfd406c2750bed +size 267003 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png index 11096840b4..7bfa7f5417 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac47db578faa7c4744ad058955324090b20ce8e531c4f5d0bcdd4533f6830483 -size 89728 +oid sha256:b22c4508725a4db10d1fff18cffca76d4690dfe84e48237a8f83936b54718576 +size 90849 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png index 1d10f35de9..d7084d53c2 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fea447cd269455d6324e27ee2c24e702fa6f7d55929ab0d4367b31c18d9fa8e -size 124048 +oid sha256:c2a76ee26b4f5d690f67aabd7f86494621823eacab9e5400c203ef5b85abab11 +size 129082 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png index 1318c28adf..c0e6eaf50e 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-en-GB.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3515b93222d228e5e2dcaec8e1de42cace4a520354423418d3c5b1bb1f212efe -size 126061 +oid sha256:94f45a1eef76250e677b87a35231bfe17b2ee3e27495c907b8e3b0ebe876898c +size 129889 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png index 77c35dcb50..a28e57d959 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Incomplete.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7a93826727cdd4f3cbfb2b04079b23f07efe2d43bf30eaaebd9124a6d14df2f -size 131666 +oid sha256:b21f513f45a15eef2b500c534ec7c60daf6b658cef2fef44b73b58cca8575c66 +size 138362 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png index cef354b327..6dc9435a7c 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Not-set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af863478b0d63e57d2c8e876ed7911bf98c65830748cea0fb582c3d29e285a8f -size 212546 +oid sha256:201ba4003d78745c4b6387726d640604d80e9f05cf9e9f44e4e26c0583d18394 +size 224523 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png index 1a27c71fd9..93b8d21943 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_secureBackupRecoveryKeyScreen-iPhone-15-pseudo.Set-up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8dba9aac09c608abf637c9527d2ab6f026f4443fe4671de7376582b089493a78 -size 202804 +oid sha256:1d12dc8245858d615eb22ddb811d9663a3845c0943c6da1a024cd6b7afe3b351 +size 218259 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Cancelled.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Cancelled.png index 258635e05d..abc8d7bfa7 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Cancelled.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Cancelled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f11bc47b5fa10be69909319681ead2fd1f749c7eff763a788ec38d2cfe15b163 -size 122535 +oid sha256:7d5c3d555619bdd748dd000259f2164e288d8f7e0a751088d754435ed7fb4029 +size 124629 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial.png index c812d23eec..728d0eb791 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Initial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8aa5677fe309a3ef02fbf62821c559d5529d0ba85faf492e041198f18c74d3a -size 131005 +oid sha256:c2d80c9a388f9ad1d6bbaa2ed83f2f02dc81b8fbf01d8ff96f7bd673500c094d +size 122493 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Request-Accepted.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Request-Accepted.png index e36bbab72a..0c41faca46 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Request-Accepted.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Request-Accepted.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fad40f3a6a65e5fb257d42c0977c51834e52f7d9db00a0cf76ee73a0a5fc2db9 -size 118552 +oid sha256:9da8908c5b57fb81d15e7460853e89ae37910020f33b4641a0b237feaaf1cf24 +size 112890 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Requesting-Verification.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Requesting-Verification.png index be600fdcea..6826d520fc 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Requesting-Verification.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Requesting-Verification.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf6062e17075c673bc7e4ac0f71261f0dfb6f5a3fab7909dd8c56b0e347ba60b -size 119456 +oid sha256:955beb56556aa67500cc77c8b9da243da18729663e1d033323962e3e7e6b1ca5 +size 124265 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Showing-Challenge.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Showing-Challenge.png index a851fbbd5d..8035b4cdc1 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Showing-Challenge.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Showing-Challenge.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ece83e5ae298e2ef469632bdde8a165993568ddd629249b9d37d6fa46d21f166 -size 203235 +oid sha256:08a81a2769a8e8f697525080a845e283a71edaeaa7d3462b4a865f8ce3ecd443 +size 202818 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Verified.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Verified.png index 2c4c8c88ad..ae4792d605 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Verified.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-en-GB.Verified.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7578c0de358bac94f3bcb8be0d1a1d17205a193be3abfde52bcb8fc1985c76d -size 122484 +oid sha256:13a68b96593f09de7300f9031f17dd0c35684531cb318c734e94db959748f94d +size 125490 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Cancelled.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Cancelled.png index 6d37377a48..e7f007d082 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Cancelled.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Cancelled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eecc61d3446466cc3f3da6f4a23f7892762ec1dafab5f14246609a1af8a78195 -size 164759 +oid sha256:af5e0d91c5a10ce75e42dba7ffc73c91979c3bbfcb35efe12e0931fb6e30b459 +size 167169 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial.png index a85cb636c4..3ace83cbc2 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Initial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4698453b82745f07f1b83eea133d3d540c1fc9891ddd5bcf301f34bb9e13efd5 -size 181226 +oid sha256:db4372d64cc643e0e07226bd794a478f4fd3329ff2c0e1beb59d9762e5ed7094 +size 162017 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Request-Accepted.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Request-Accepted.png index ccc8760a80..c749f9b81b 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Request-Accepted.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Request-Accepted.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd0d3d827c5c8771341cd71f05a62af980113d60e7e069731b2c813971a6576e -size 148465 +oid sha256:326d124d879ddd3460209f4b104bc4c6ea6d5a739029086bcd4d218bcd29a548 +size 151351 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Requesting-Verification.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Requesting-Verification.png index 33742e0c93..ed0c6caeec 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Requesting-Verification.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Requesting-Verification.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:858f8dd1d64c4e3ab9696d111c786dbc8ebd292a66c0a34b9d7d1762d9e0c3ad -size 161853 +oid sha256:42587aaca36304daf16e419bbcf3ae3b02db96638262f38d49dbe40b2f2a70ee +size 165908 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Showing-Challenge.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Showing-Challenge.png index 3ecfb51943..4685a17904 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Showing-Challenge.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Showing-Challenge.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb6ae2fd7378b5858fd6907cecc46b6136416ca6c979a61e13b7b2720712060a -size 254477 +oid sha256:108f111d9c80da099d29eb9693f15b3ce5fc9c8f81365ce02c36ed5dbf8d24e8 +size 256712 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Verified.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Verified.png index 443304b94c..e82200e7c4 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Verified.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPad-pseudo.Verified.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c13077c41cb571d2d55fe3b8c47e3dcef99611d1d5d2154a37e96b96a13f4d90 -size 171286 +oid sha256:8872853b5b71cca86d37fd800391631464f791cc6095d3a0a50839b5fffbf351 +size 173239 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Cancelled.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Cancelled.png index 7089704174..56aef81bbf 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Cancelled.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Cancelled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2a96129826e8f24e5b4fa417cdc104909fb88be4fdb3d740761e50c0e31df7b -size 78576 +oid sha256:296d8b28d222c3ef9f6cf7725456221b36822e4eb8c117aa52981cda89e6a101 +size 75022 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Initial.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Initial.png index 3811f028f5..1a8e3a1db4 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Initial.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Initial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56b0318d28b8cedff62792e6be7e65871dd130e1f2a2b46efa11b8d643a4388c -size 86673 +oid sha256:48d31bd2915e6b7f34ca93855279c76d100b5ff30f8f37097262c3776058bf87 +size 73446 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Request-Accepted.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Request-Accepted.png index 12d6ef3ec0..2a45dceca6 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Request-Accepted.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Request-Accepted.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df6adb6614f1f916c223574798fe4e0599af323236f04e27a91303d64707087a -size 72320 +oid sha256:a3265aa36d9f0d2cc6751fc6d034c3ffbdd1ac79626e99da19c196fd18f43583 +size 68232 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Requesting-Verification.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Requesting-Verification.png index 31778d6716..45e6895fb9 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Requesting-Verification.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Requesting-Verification.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f53b5a56e45c00c47e6ec825e2c9261e6edfe1c7d87f5f55da669d388028a3f8 -size 78458 +oid sha256:b5581a2a8067d8e9e1583f550428cd41b7e3dfedfd43cab603b1f02c2b3994a3 +size 74678 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Showing-Challenge.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Showing-Challenge.png index a66c8cba6d..e7b51c4744 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Showing-Challenge.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Showing-Challenge.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:071580d15a2f417df09ad9913a336d3a9719feb65c724708458942ac7ce41b4a -size 149999 +oid sha256:4a1fc2cd381c49b911e4cb4f133fc09f601668f58fd095cdbc964cafcb010114 +size 145509 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Verified.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Verified.png index 3b8d6d041d..ae6f946314 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Verified.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-en-GB.Verified.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a98db6b8dc611df5dd12a19b9eafe1268eea72701d8e3c1c6b08c8602d806897 -size 77593 +oid sha256:60a25f5124021ee967d989b115f37bb56b800908d8ab0e603f982c4214d18ba0 +size 73933 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Cancelled.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Cancelled.png index fed715c635..6e010b192c 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Cancelled.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Cancelled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62b7fe25164a6d84df7aab70c63cb907ea7f12e3d9f4befc68820ab7f815ddad -size 115441 +oid sha256:86df5d48b1af9d36e0aa210e4d569d10d24bb170c678e65b1cc6e84f5811f28c +size 108486 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Initial.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Initial.png index 72b3c38efa..8f3416993e 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Initial.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Initial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fddf070b4223906a9af6c30ab4f72a0fccf999eeb97e3828b4b1343afc376653 -size 133556 +oid sha256:c5d923e3408694e036bc9cf0884d8d992be57077c1989042beac3b39b13516dd +size 111808 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Request-Accepted.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Request-Accepted.png index 2c9ff02a73..073dd20863 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Request-Accepted.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Request-Accepted.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd2d09544c3f2aed9f5a931d0e4553247259f07ded32b8f67d6f93063d771cc6 -size 107939 +oid sha256:acde40c352609c2d3603041c1bbfb230781262d7c62e882492ca823b5dcbc5dd +size 100388 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Requesting-Verification.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Requesting-Verification.png index 8373064ae7..f392944f36 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Requesting-Verification.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Requesting-Verification.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c0e3bff463860a99a7d8b5d55705fe67ccf8fe2383107e6dad3100309d98e44 -size 118912 +oid sha256:d83f9afa2c3a44d26d3ed077e932f28282b9c1e009e3430d422ee0f3af06aba8 +size 110056 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Showing-Challenge.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Showing-Challenge.png index 162c6daa84..e26fc379be 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Showing-Challenge.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Showing-Challenge.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9371f5c4c9648736c08507b2eaec2486a88372ecbd067e2242eff58e7047104c -size 201928 +oid sha256:cafcb832b6ecc7bfc15fb5c4ed1f802a68231360e38fae6a56cfff1013a75a19 +size 195326 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Verified.png b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Verified.png index d538609d88..0e80b4fb0f 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Verified.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_sessionVerification-iPhone-15-pseudo.Verified.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9baade6f1527a66442c8947b901d2e4a5c0946e132310fd02c9fd8b1cedd36bb -size 124007 +oid sha256:791fbd6b6784eb0fedbbcf3bff1b3c9a77e6d86ffb58939192a5e4d910505477 +size 116469 diff --git a/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift b/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift index 283f4deac9..bb2fa19f66 100644 --- a/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift +++ b/UnitTests/Sources/AnalyticsSettingsScreenViewModelTests.swift @@ -25,11 +25,11 @@ class AnalyticsSettingsScreenViewModelTests: XCTestCase { private var context: AnalyticsSettingsScreenViewModelType.Context! override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } @MainActor override func setUpWithError() throws { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() let analyticsClient = AnalyticsClientMock() analyticsClient.isRunning = false diff --git a/UnitTests/Sources/AnalyticsTests.swift b/UnitTests/Sources/AnalyticsTests.swift index 525808560c..9653c9752b 100644 --- a/UnitTests/Sources/AnalyticsTests.swift +++ b/UnitTests/Sources/AnalyticsTests.swift @@ -24,7 +24,7 @@ class AnalyticsTests: XCTestCase { private var bugReportService: BugReportServiceMock! override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() bugReportService = BugReportServiceMock() @@ -38,7 +38,7 @@ class AnalyticsTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testAnalyticsPromptNewUser() { diff --git a/UnitTests/Sources/AppLock/AppLockScreenViewModelTests.swift b/UnitTests/Sources/AppLock/AppLockScreenViewModelTests.swift index 207655ff83..d36cc0fb77 100644 --- a/UnitTests/Sources/AppLock/AppLockScreenViewModelTests.swift +++ b/UnitTests/Sources/AppLock/AppLockScreenViewModelTests.swift @@ -28,7 +28,7 @@ class AppLockScreenViewModelTests: XCTestCase { var context: AppLockScreenViewModelType.Context { viewModel.context } override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() keychainController = KeychainControllerMock() appLockService = AppLockService(keychainController: keychainController, appSettings: appSettings) @@ -36,7 +36,7 @@ class AppLockScreenViewModelTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testUnlock() async throws { diff --git a/UnitTests/Sources/AppLock/AppLockServiceTests.swift b/UnitTests/Sources/AppLock/AppLockServiceTests.swift index bfc953ed42..7048bdcac6 100644 --- a/UnitTests/Sources/AppLock/AppLockServiceTests.swift +++ b/UnitTests/Sources/AppLock/AppLockServiceTests.swift @@ -25,7 +25,7 @@ class AppLockServiceTests: XCTestCase { var service: AppLockService! override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() keychainController = KeychainController(service: .tests, accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier) @@ -36,7 +36,7 @@ class AppLockServiceTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } // MARK: - PIN Code diff --git a/UnitTests/Sources/AppLock/AppLockSetupBiometricsScreenViewModelTests.swift b/UnitTests/Sources/AppLock/AppLockSetupBiometricsScreenViewModelTests.swift index 41bb246235..07fdc17d67 100644 --- a/UnitTests/Sources/AppLock/AppLockSetupBiometricsScreenViewModelTests.swift +++ b/UnitTests/Sources/AppLock/AppLockSetupBiometricsScreenViewModelTests.swift @@ -26,7 +26,7 @@ class AppLockSetupBiometricsScreenViewModelTests: XCTestCase { var context: AppLockSetupBiometricsScreenViewModelType.Context { viewModel.context } override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appLockService = AppLockServiceMock() appLockService.underlyingIsEnabled = true @@ -36,7 +36,7 @@ class AppLockSetupBiometricsScreenViewModelTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testAllow() async throws { diff --git a/UnitTests/Sources/AppLock/AppLockSetupPINScreenViewModelTests.swift b/UnitTests/Sources/AppLock/AppLockSetupPINScreenViewModelTests.swift index c0c7b2f04b..1cc4043e8d 100644 --- a/UnitTests/Sources/AppLock/AppLockSetupPINScreenViewModelTests.swift +++ b/UnitTests/Sources/AppLock/AppLockSetupPINScreenViewModelTests.swift @@ -27,13 +27,13 @@ class AppLockSetupPINScreenViewModelTests: XCTestCase { var context: AppLockSetupPINScreenViewModelType.Context { viewModel.context } override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() keychainController = KeychainControllerMock() appLockService = AppLockService(keychainController: keychainController, appSettings: AppSettings()) } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testCreatePIN() async throws { diff --git a/UnitTests/Sources/AppRouteURLParserTests.swift b/UnitTests/Sources/AppRouteURLParserTests.swift index 44319eeb50..a7a29412ec 100644 --- a/UnitTests/Sources/AppRouteURLParserTests.swift +++ b/UnitTests/Sources/AppRouteURLParserTests.swift @@ -23,7 +23,7 @@ class AppRouteURLParserTests: XCTestCase { var appRouteURLParser: AppRouteURLParser! override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() appRouteURLParser = AppRouteURLParser(appSettings: appSettings) } diff --git a/UnitTests/Sources/ComposerToolbarViewModelTests.swift b/UnitTests/Sources/ComposerToolbarViewModelTests.swift index 6bc2b1938d..ccdf536aff 100644 --- a/UnitTests/Sources/ComposerToolbarViewModelTests.swift +++ b/UnitTests/Sources/ComposerToolbarViewModelTests.swift @@ -28,7 +28,7 @@ class ComposerToolbarViewModelTests: XCTestCase { private var completionSuggestionServiceMock: CompletionSuggestionServiceMock! override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() appSettings.richTextEditorEnabled = true ServiceLocator.shared.register(appSettings: appSettings) @@ -42,7 +42,7 @@ class ComposerToolbarViewModelTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testComposerFocus() { diff --git a/UnitTests/Sources/HomeScreenViewModelTests.swift b/UnitTests/Sources/HomeScreenViewModelTests.swift index b1737f6648..46dbcc598e 100644 --- a/UnitTests/Sources/HomeScreenViewModelTests.swift +++ b/UnitTests/Sources/HomeScreenViewModelTests.swift @@ -41,7 +41,7 @@ class HomeScreenViewModelTests: XCTestCase { } override func tearDown() { - AppSettings.reset() + AppSettings.resetAllSettings() } func testSelectRoom() async throws { diff --git a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift index 424feb8818..701614ac77 100644 --- a/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift +++ b/UnitTests/Sources/NotificationManager/NotificationManagerTests.swift @@ -37,7 +37,7 @@ final class NotificationManagerTests: XCTestCase { private var appSettings: AppSettings { ServiceLocator.shared.settings } override func setUp() { - AppSettings.reset() + AppSettings.resetAllSettings() notificationCenter = UserNotificationCenterMock() notificationCenter.requestAuthorizationOptionsReturnValue = true diff --git a/UnitTests/Sources/NotificationSettingsScreenViewModelTests.swift b/UnitTests/Sources/NotificationSettingsScreenViewModelTests.swift index 9000eb5be5..bc3eeb7089 100644 --- a/UnitTests/Sources/NotificationSettingsScreenViewModelTests.swift +++ b/UnitTests/Sources/NotificationSettingsScreenViewModelTests.swift @@ -28,7 +28,7 @@ class NotificationSettingsScreenViewModelTests: XCTestCase { private var notificationSettingsProxy: NotificationSettingsProxyMock! @MainActor override func setUpWithError() throws { - AppSettings.reset() + AppSettings.resetAllSettings() userNotificationCenter = UserNotificationCenterMock() userNotificationCenter.authorizationStatusReturnValue = .authorized diff --git a/UnitTests/Sources/PermalinkBuilderTests.swift b/UnitTests/Sources/PermalinkBuilderTests.swift index 5e0264eaf1..053334ba02 100644 --- a/UnitTests/Sources/PermalinkBuilderTests.swift +++ b/UnitTests/Sources/PermalinkBuilderTests.swift @@ -22,7 +22,7 @@ class PermalinkBuilderTests: XCTestCase { override func setUp() { AppSettings.configureWithSuiteName("io.element.elementx.unitests") - AppSettings.reset() + AppSettings.resetAllSettings() appSettings = AppSettings() } diff --git a/UnitTests/Sources/RoomDetailsViewModelTests.swift b/UnitTests/Sources/RoomDetailsViewModelTests.swift index 0b21fdac89..a7abfbbcc5 100644 --- a/UnitTests/Sources/RoomDetailsViewModelTests.swift +++ b/UnitTests/Sources/RoomDetailsViewModelTests.swift @@ -43,7 +43,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase { mentionBuilder: MentionBuilder()), appSettings: ServiceLocator.shared.settings) - AppSettings.reset() + AppSettings.resetAllSettings() } func testLeaveRoomTappedWhenPublic() async throws { diff --git a/UnitTests/Sources/RoomScreenViewModelTests.swift b/UnitTests/Sources/RoomScreenViewModelTests.swift index f95103d3ad..c3dbaeecbb 100644 --- a/UnitTests/Sources/RoomScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomScreenViewModelTests.swift @@ -25,7 +25,7 @@ class RoomScreenViewModelTests: XCTestCase { var cancellables = Set() override func setUp() async throws { - AppSettings.reset() + AppSettings.resetAllSettings() cancellables.removeAll() userIndicatorControllerMock = UserIndicatorControllerMock.default } diff --git a/UnitTests/Sources/SessionVerificationViewModelTests.swift b/UnitTests/Sources/SessionVerificationViewModelTests.swift index c17e27b427..5ec7c4b213 100644 --- a/UnitTests/Sources/SessionVerificationViewModelTests.swift +++ b/UnitTests/Sources/SessionVerificationViewModelTests.swift @@ -27,8 +27,7 @@ class SessionVerificationViewModelTests: XCTestCase { override func setUpWithError() throws { sessionVerificationController = SessionVerificationControllerProxyMock.configureMock() - viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: sessionVerificationController, - recoveryState: .incomplete) + viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: sessionVerificationController) context = viewModel.context } @@ -47,7 +46,7 @@ class SessionVerificationViewModelTests: XCTestCase { context.send(viewAction: .requestVerification) - context.send(viewAction: .close) + viewModel.stop() XCTAssertEqual(context.viewState.verificationState, .cancelling) diff --git a/changelog.d/2592.change b/changelog.d/2592.change new file mode 100644 index 0000000000..51f4075043 --- /dev/null +++ b/changelog.d/2592.change @@ -0,0 +1 @@ +Move session verification to the onboarding flows, make it mandatory \ No newline at end of file diff --git a/changelog.d/2593.feature b/changelog.d/2593.feature new file mode 100644 index 0000000000..029fe0a66e --- /dev/null +++ b/changelog.d/2593.feature @@ -0,0 +1 @@ +Introduce a new notification permissions screen as part of the onboarding flows \ No newline at end of file diff --git a/changelog.d/2594.change b/changelog.d/2594.change new file mode 100644 index 0000000000..0e594823be --- /dev/null +++ b/changelog.d/2594.change @@ -0,0 +1 @@ +Remove the outdated welcome screen \ No newline at end of file diff --git a/changelog.d/2595.change b/changelog.d/2595.change new file mode 100644 index 0000000000..4968492cec --- /dev/null +++ b/changelog.d/2595.change @@ -0,0 +1 @@ +Update onboarding flows to consolidate identity confirmation, analytics consent and notification permissions \ No newline at end of file diff --git a/project.yml b/project.yml index 66dcde14ae..743cd8a972 100644 --- a/project.yml +++ b/project.yml @@ -29,7 +29,7 @@ settings: APP_NAME: ElementX APP_DISPLAY_NAME: Element X KEYCHAIN_ACCESS_GROUP_IDENTIFIER: $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER) - MARKETING_VERSION: 1.5.13 + MARKETING_VERSION: 1.6.0 CURRENT_PROJECT_VERSION: 1 DEVELOPMENT_TEAM: 7J4U792NQT SUPPORTS_MACCATALYST: NO