Add a WebRegistrationScreen (not included in the flow yet). (#3281)

This commit is contained in:
Doug 2024-09-16 11:03:29 +01:00 committed by GitHub
parent 2745eabc0a
commit 6cfe09b96d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 743 additions and 34 deletions

View File

@ -102,7 +102,6 @@
149D1942DC005D0485FB8D93 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DC1943ADE6A62ED5129D7C8 /* LoggingTests.swift */; };
14E99D27628B1A6F0CB46FEA /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A9F49B3EE59147AF2F70BB /* SeparatorRoomTimelineItem.swift */; };
151D2477F75782C8702F2873 /* PollInteractionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */; };
152AE2B8650FB23AFD2E28B9 /* MockAuthenticationServiceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */; };
155063E980E763D4910EA3CF /* Analytics+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CFE236419E830E8946639C /* Analytics+SwiftUI.swift */; };
1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4549FCB53F43DB0B278374BC /* TemplateScreen.swift */; };
1583E2D766E4485FF91662FC /* PermalinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3EB5B1848CF4F64E63C6B7 /* PermalinkTests.swift */; };
@ -223,6 +222,7 @@
3116693C5EB476E028990416 /* XCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74611A4182DCF5F4D42696EC /* XCTestCase.swift */; };
3118D9ABFD4BE5A3492FF88A /* ElementCallConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC437C491EA6996513B1CEAB /* ElementCallConfiguration.swift */; };
32B7891D937377A59606EDFC /* UserFlowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8599815136EFF5B73F38 /* UserFlowTests.swift */; };
32FC143630CE22A9E403370B /* MockAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA38899517F08FE2AF34EB45 /* MockAuthenticationService.swift */; };
339BC18777912E1989F2F17D /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584A61D9C459FAFEF038A7C0 /* Section.swift */; };
33CAC1226DFB8B5D8447D286 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = 1BCD21310B997A6837B854D6 /* GZIP */; };
33F1FB19F222BA9930AB1A00 /* RoomListFiltersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6372DD10DED30E7AD7BCE21 /* RoomListFiltersView.swift */; };
@ -254,6 +254,7 @@
38896D54D6D675534E606195 /* RoomTimelineControllerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FCC416A3BFE73DF7B3E6BF /* RoomTimelineControllerFactory.swift */; };
388D39ED9FE1122EA6D76BF2 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BC84BA0AF11C2128D58ABD /* Common.swift */; };
3895969759E68FAB90C63EF7 /* ElementCallServiceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406C90AF8C3E98DF5D4E5430 /* ElementCallServiceConstants.swift */; };
38CC67C7673FA97C21CCD5B5 /* WebRegistrationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */; };
3982C505960006B341CFD0C6 /* UserDetailsEditScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D0EA07BD545CC9F234DB8D /* UserDetailsEditScreenModels.swift */; };
3982E60F9C126437D5E488A3 /* PillContextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A6314FDC51DA25712D9A81 /* PillContextTests.swift */; };
39A987B3E41B976D1DF944C6 /* CallScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A63A59BFDDC494B1C20119 /* CallScreenViewModel.swift */; };
@ -446,6 +447,7 @@
6586E1F1D5F0651D0638FFAF /* UserSessionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4469F6AE311BDC439B3A5EC /* UserSessionMock.swift */; };
659E5B766F76FDEC1BF393A4 /* RoomDetailsEditScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E413F4CBD7BF0588F394A9DD /* RoomDetailsEditScreenViewModel.swift */; };
661EF50C1F7D4B0BC8A7AAE3 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44ABA63DBE7F76C58260B43B /* EmoteRoomTimelineView.swift */; };
66357ECB73B1290E5490A012 /* WebRegistrationScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */; };
663E198678778F7426A9B27D /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FAFE1C2149E6AC8156ED2B /* Collection.swift */; };
67160204A8D362BB7D4AD259 /* Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693E16574C6F7F9FA1015A8C /* Search.swift */; };
6786C4B0936AC84D993B20BF /* NotificationSettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F06F2F09B2EDD067DC2174 /* NotificationSettingsScreen.swift */; };
@ -713,6 +715,7 @@
9F19096BFA629C0AC282B1E4 /* CreateRoomScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CEB4634C0DD7779C4AB504 /* CreateRoomScreenUITests.swift */; };
9FB41B0E8B2AA9B404E52C8B /* AppLockSetupBiometricsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCC6C31102E1D8B9106DEDE /* AppLockSetupBiometricsScreenViewModelProtocol.swift */; };
9FBE1FB20171012260A32492 /* TimelineSenderAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53FCCE44F96E0BC411A6CF0 /* TimelineSenderAvatarView.swift */; };
9FC820C410ED733CE6FC6616 /* WebRegistrationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */; };
A009BDFB0A6816D4C392ADCB /* SettingsScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF715D4FD4710EBB637D661 /* SettingsScreenViewModelProtocol.swift */; };
A021827B528F1EDC9101CA58 /* AppCoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBC776F301D374A3298C69DA /* AppCoordinatorProtocol.swift */; };
A0601810597769B81C2358AF /* EncryptionResetPasswordScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2B5274C1D3D2999D643786 /* EncryptionResetPasswordScreenViewModelProtocol.swift */; };
@ -723,6 +726,7 @@
A17FAD2EBC53E17B5FD384DB /* InviteUsersScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22730A30C50AC2E3D5BA8642 /* InviteUsersScreenViewModelProtocol.swift */; };
A1BA8D6BABAFA9BAAEAA3FFD /* NotificationSettingsProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FDD775CFD72DD2D3C8A8390 /* NotificationSettingsProxyProtocol.swift */; };
A1DF0E1E526A981ED6D5DF44 /* UserIndicatorControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2429224EB0EEA34D35CE9249 /* UserIndicatorControllerTests.swift */; };
A20364EE08D902E647C11FB3 /* WebRegistrationScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */; };
A216C83ADCF32BA5EF8A6FBC /* InviteUsersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845DDBDE5A0887E73D38B826 /* InviteUsersViewModelTests.swift */; };
A2172B5A26976F9174228B8A /* AppHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E4AB573FAEBB7B853DD04C /* AppHooks.swift */; };
A23B8B27A1436A1049EEF68E /* InfoPlistReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */; };
@ -740,6 +744,7 @@
A4B123C635F70DDD4BC2FAC9 /* BlockedUsersScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E76A706B3EEA32B882DA5E2D /* BlockedUsersScreenViewModelProtocol.swift */; };
A4C29D373986AFE4559696D5 /* SecureBackupKeyBackupScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4525E8C0FBDD27D1ACE90952 /* SecureBackupKeyBackupScreenViewModelProtocol.swift */; };
A4E885358D7DD5A072A06824 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCE5BF78B125320CBF3BB834 /* PostHog */; };
A52090A4FE0DB826578DFC03 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0724EBDFE8BB4C9E5547C57D /* Client.swift */; };
A5B9EF45C7B8ACEB4954AE36 /* LoginScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9780389F8A53E4D26E23DD03 /* LoginScreenViewModelProtocol.swift */; };
A5D551E5691749066E0E0C44 /* RoomDetailsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837B440C4705E4B899BCB899 /* RoomDetailsScreenViewModel.swift */; };
A64B52D9F73F9A6B95AF24FE /* UserDetailsEditScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CD503F5E0938FE53C7C6E7 /* UserDetailsEditScreenCoordinator.swift */; };
@ -1058,6 +1063,7 @@
F07D88421A9BC4D03D4A5055 /* VideoRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F348B5F2C12F9D4F4B4D3884 /* VideoRoomTimelineItem.swift */; };
F08F7BC07CA9AEF5CD157918 /* Snapshotting.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF17EA323AD0205A6AB621AA /* Snapshotting.swift */; };
F0A26CD502C3A5868353B0FA /* ServerConfirmationScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24DEE0682C95F897B6C7CB0D /* ServerConfirmationScreenViewModel.swift */; };
F0C2C49D707839F5273BFC6D /* WebRegistrationScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */; };
F0DACC95F24128A54CD537E4 /* GlobalSearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24B8177BD2AF45A286F5DA31 /* GlobalSearchScreen.swift */; };
F0F82C3C848C865C3098AA52 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 21C83087604B154AA30E9A8F /* SnapshotTesting */; };
F103924DED414ADFE398CE99 /* RoomPollsHistoryScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A130A2251A15A7AACC84FD37 /* RoomPollsHistoryScreenViewModelProtocol.swift */; };
@ -1109,6 +1115,7 @@
FBD402E3170EB1ED0D1AA672 /* EncryptionKeyProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */; };
FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */; };
FC10228E73323BDC09526F97 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = 4278261E147DB2DE5CFB7FC5 /* PostHog */; };
FC8B95EC506E6BB5793D81CE /* ClientProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34685D186453E429ADEE58E /* ClientProtocolTests.swift */; };
FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */; };
FD29471C72872F8B7580E3E1 /* KeychainControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C0D861FC397AC34BCF089E /* KeychainControllerMock.swift */; };
@ -1214,6 +1221,7 @@
06B098A612DCB5A7358EECD5 /* DeveloperOptionsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenModels.swift; sourceTree = "<group>"; };
06F27F588F9059128E17C669 /* WindowManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManagerProtocol.swift; sourceTree = "<group>"; };
06FAE373A7F20780BA84B59C /* MessageForwardingScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenCoordinator.swift; sourceTree = "<group>"; };
0724EBDFE8BB4C9E5547C57D /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
07579F9C29001E40715F3014 /* NotificationSettingsChatType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsChatType.swift; sourceTree = "<group>"; };
077D7C3BE199B6E5DDEC07EC /* AppCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinatorStateMachine.swift; sourceTree = "<group>"; };
07C6B0B087FE6601C3F77816 /* JoinedRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinedRoomProxy.swift; sourceTree = "<group>"; };
@ -1287,6 +1295,7 @@
1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+Untranslated.swift"; sourceTree = "<group>"; };
1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMap.swift; sourceTree = "<group>"; };
1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoURITests.swift; sourceTree = "<group>"; };
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreen.swift; sourceTree = "<group>"; };
1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItem.swift; sourceTree = "<group>"; };
1B53D6C5C0D14B04D3AB3F6E /* PillAttachmentViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillAttachmentViewProvider.swift; sourceTree = "<group>"; };
1B564D748B67A156F413CD97 /* NotificationSettingsEditScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenModels.swift; sourceTree = "<group>"; };
@ -1621,7 +1630,6 @@
653610CB5F9776EAAAB98155 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
6569593FA36B22259E806A67 /* AudioRecorderState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderState.swift; sourceTree = "<group>"; };
65AAD845E53B0C8B5E0812C2 /* UserDiscoveryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoveryService.swift; sourceTree = "<group>"; };
65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationServiceProxy.swift; sourceTree = "<group>"; };
664ABD745A746C45CB842158 /* CallInviteRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallInviteRoomTimelineView.swift; sourceTree = "<group>"; };
6654859746B0BE9611459391 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
6663BFB9FDB8752562CD12CA /* AuthenticationStartScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenCoordinator.swift; sourceTree = "<group>"; };
@ -1655,6 +1663,7 @@
6EA1D2CBAEA5D0BD00B90D1B /* BindableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableState.swift; sourceTree = "<group>"; };
6F1C3CBBC62C566DDF5E84C1 /* TimelineItemMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenuAction.swift; sourceTree = "<group>"; };
6F3DFE5B444F131648066F05 /* StateStoreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateStoreViewModel.swift; sourceTree = "<group>"; };
6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
6F6E6EDC4BBF962B2ED595A4 /* MessageForwardingScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelTests.swift; sourceTree = "<group>"; };
6FA38E813BE14149F173F461 /* PinnedEventsBannerStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsBannerStateTests.swift; sourceTree = "<group>"; };
6FC5015B9634698BDB8701AF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = it; path = it.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@ -1879,6 +1888,7 @@
A4A1003A0F7A1DFB47F4E2D0 /* TimelineItemMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMock.swift; sourceTree = "<group>"; };
A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineFlowCoordinator.swift; sourceTree = "<group>"; };
A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiDetectionTests.swift; sourceTree = "<group>"; };
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModel.swift; sourceTree = "<group>"; };
A69869844D2B6F5BD9AABF85 /* OIDCConfigurationProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCConfigurationProxy.swift; sourceTree = "<group>"; };
A6B19D10B102956066AF117B /* PollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionView.swift; sourceTree = "<group>"; };
A6B891A6DA826E2461DBB40F /* PHGPostHogConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogConfiguration.swift; sourceTree = "<group>"; };
@ -2039,6 +2049,7 @@
C733D11B421CFE3A657EF230 /* test_image.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_image.png; sourceTree = "<group>"; };
C75EF87651B00A176AB08E97 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomList.swift; sourceTree = "<group>"; };
C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenCoordinator.swift; sourceTree = "<group>"; };
C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; };
C833673B334A0651AB46F30B /* StaticLocationScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticLocationScreenViewModelTests.swift; sourceTree = "<group>"; };
C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
@ -2115,6 +2126,7 @@
D95E8C0EFEC0C6F96EDAA71A /* PreviewTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PreviewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DA14564EE143F73F7E4D1F79 /* RoomNotificationSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsScreenModels.swift; sourceTree = "<group>"; };
DA2AEC1AB349A341FE13DEC1 /* StartChatScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenUITests.swift; sourceTree = "<group>"; };
DA38899517F08FE2AF34EB45 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = "<group>"; };
DA3D82522494E78746B2214E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SAS.strings; sourceTree = "<group>"; };
DAB8D7926A5684E18196B538 /* VoiceMessageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageCache.swift; sourceTree = "<group>"; };
DB06F22CFA34885B40976061 /* RoomDetailsEditScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreen.swift; sourceTree = "<group>"; };
@ -2147,6 +2159,7 @@
E2F96CCBEAAA7F2185BFA354 /* ClientProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProxyMock.swift; sourceTree = "<group>"; };
E3059CFA00C67D8787273B20 /* ServerSelectionScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModel.swift; sourceTree = "<group>"; };
E321E840DCC63790049984F4 /* ElementCallServiceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallServiceMock.swift; sourceTree = "<group>"; };
E34685D186453E429ADEE58E /* ClientProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientProtocolTests.swift; sourceTree = "<group>"; };
E36CB905A2B9EC2C92A2DA7C /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
E3B97591B2D3D4D67553506D /* AnalyticsClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsClientProtocol.swift; sourceTree = "<group>"; };
E4103AB4340F2974D690A12A /* CallScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallScreen.swift; sourceTree = "<group>"; };
@ -2242,6 +2255,7 @@
F733F135E6D67BBBEB76CC30 /* AppLockUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockUITests.swift; sourceTree = "<group>"; };
F74532E01B317C56C1BE8FA8 /* RoomTimelineProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderMock.swift; sourceTree = "<group>"; };
F7478623CECC9438014244BA /* ServerConfirmationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConfirmationScreen.swift; sourceTree = "<group>"; };
F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenModels.swift; sourceTree = "<group>"; };
F875D71347DC81EAE7687446 /* NavigationRootCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationRootCoordinatorTests.swift; sourceTree = "<group>"; };
F899D02CF26EA7675EEBE74C /* UserSessionScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionScreenTests.swift; sourceTree = "<group>"; };
F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupBiometricsScreen.swift; sourceTree = "<group>"; };
@ -2699,6 +2713,14 @@
path = Progress;
sourceTree = "<group>";
};
25A88085FB8D8227DCDB0C9C /* View */ = {
isa = PBXGroup;
children = (
1B065EC39C99C1303A101C1C /* WebRegistrationScreen.swift */,
);
path = View;
sourceTree = "<group>";
};
26C16326BCCCED74A85A0F48 /* View */ = {
isa = PBXGroup;
children = (
@ -3742,6 +3764,7 @@
7EECE8B331CD169790EF284F /* BugReportScreenViewModelTests.swift */,
EFFD3200F9960D4996159F10 /* BugReportServiceTests.swift */,
CAD9547E47C58930E2CE8306 /* CallScreenViewModelTests.swift */,
E34685D186453E429ADEE58E /* ClientProtocolTests.swift */,
D5EA0312A6262484AA393AC9 /* CompletionSuggestionServiceTests.swift */,
CA29952595B804DA221A0C1D /* ComposerToolbarViewModelTests.swift */,
69D42EE0102D2857933625DD /* CreateRoomViewModelTests.swift */,
@ -4033,6 +4056,7 @@
8039515BAA53B7C3275AC64A /* Client */ = {
isa = PBXGroup;
children = (
0724EBDFE8BB4C9E5547C57D /* Client.swift */,
D09A267106B9585D3D0CFC0D /* ClientError.swift */,
18F2958E6D247AE2516BEEE8 /* ClientProxy.swift */,
6033779EB37259F27F938937 /* ClientProxyProtocol.swift */,
@ -4596,7 +4620,7 @@
0F569CFB77E0D40BD82203D9 /* AuthenticationClientBuilder.swift */,
F3A1AB5A84D843B6AC8D5F1E /* AuthenticationService.swift */,
5E75948AA1FE1D1A7809931F /* AuthenticationServiceProtocol.swift */,
65C2B80DD0BF6F10BB5FA922 /* MockAuthenticationServiceProxy.swift */,
DA38899517F08FE2AF34EB45 /* MockAuthenticationService.swift */,
A69869844D2B6F5BD9AABF85 /* OIDCConfigurationProxy.swift */,
);
path = Authentication;
@ -5047,6 +5071,18 @@
path = RoomChangeRolesScreen;
sourceTree = "<group>";
};
D847C12EC9B19A5FCDF2C815 /* WebRegistrationScreen */ = {
isa = PBXGroup;
children = (
C7D851A10FDA55579960DC61 /* WebRegistrationScreenCoordinator.swift */,
F7C161B06F417CA5D1F1E088 /* WebRegistrationScreenModels.swift */,
A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */,
6F418426410F3823F3EB0828 /* WebRegistrationScreenViewModelProtocol.swift */,
25A88085FB8D8227DCDB0C9C /* View */,
);
path = WebRegistrationScreen;
sourceTree = "<group>";
};
D977D4E565C06D3F41C8F8FC /* Virtual */ = {
isa = PBXGroup;
children = (
@ -5240,6 +5276,7 @@
BA1938A75D8C780F694CEB62 /* ServerConfirmationScreen */,
2D0D49B0533C4C2EB889BF3A /* ServerSelectionScreen */,
5B2C520AB9863B8CBC8EB3CA /* SoftLogoutScreen */,
D847C12EC9B19A5FCDF2C815 /* WebRegistrationScreen */,
);
path = Authentication;
sourceTree = "<group>";
@ -6007,6 +6044,7 @@
1B2F9F368619FFF8C63C87CC /* BugReportScreenViewModelTests.swift in Sources */,
7F61F9ACD5EC9E845EF3EFBF /* BugReportServiceTests.swift in Sources */,
366D5BFE52CB79E804C7D095 /* CallScreenViewModelTests.swift in Sources */,
FC8B95EC506E6BB5793D81CE /* ClientProtocolTests.swift in Sources */,
B5321A1F5B26A0F3EC54909E /* CollapsibleFlowLayoutTests.swift in Sources */,
3A164187907DA43B7858F9EC /* CompletionSuggestionServiceTests.swift in Sources */,
0C932A5158C1D0604DFC5750 /* ComposerToolbarViewModelTests.swift in Sources */,
@ -6253,6 +6291,7 @@
BB6BF528BC7F5B87E08C4F18 /* CameraPicker.swift in Sources */,
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */,
DF8F1211F2B0B56F0FCCA5C2 /* CertificateValidatorHook.swift in Sources */,
A52090A4FE0DB826578DFC03 /* Client.swift in Sources */,
C80E06ED97CE52704A46C148 /* ClientBuilder.swift in Sources */,
87CEA3E07B602705BC2D2A20 /* ClientBuilderHook.swift in Sources */,
6A0E7551E0D1793245F34CDD /* ClientError.swift in Sources */,
@ -6483,7 +6522,7 @@
F54E2D6CAD96E1AC15BC526F /* MessageForwardingScreenViewModel.swift in Sources */,
C13128AAA787A4C2CBE4EE82 /* MessageForwardingScreenViewModelProtocol.swift in Sources */,
C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */,
152AE2B8650FB23AFD2E28B9 /* MockAuthenticationServiceProxy.swift in Sources */,
32FC143630CE22A9E403370B /* MockAuthenticationService.swift in Sources */,
B659E3A49889E749E3239EA7 /* MockMediaProvider.swift in Sources */,
09C83DDDB07C28364F325209 /* MockRoomTimelineController.swift in Sources */,
B721125D17A0BA86794F29FB /* MockServerSelectionScreenState.swift in Sources */,
@ -6925,6 +6964,11 @@
CA12AE0DCD57D49CD96C699A /* WaveformCursorView.swift in Sources */,
63CDC201A5980F304F6D0A1C /* WaveformInteractionModifier.swift in Sources */,
B773ACD8881DB18E876D950C /* WaveformSource.swift in Sources */,
38CC67C7673FA97C21CCD5B5 /* WebRegistrationScreen.swift in Sources */,
A20364EE08D902E647C11FB3 /* WebRegistrationScreenCoordinator.swift in Sources */,
F0C2C49D707839F5273BFC6D /* WebRegistrationScreenModels.swift in Sources */,
9FC820C410ED733CE6FC6616 /* WebRegistrationScreenViewModel.swift in Sources */,
66357ECB73B1290E5490A012 /* WebRegistrationScreenViewModelProtocol.swift in Sources */,
08CB4BD12CEEDE6AAE4A18DD /* WindowManager.swift in Sources */,
AE5AAD9E32511544FDFA5560 /* WindowManagerProtocol.swift in Sources */,
);
@ -7691,7 +7735,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 1.0.48;
version = 1.0.49;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {

View File

@ -149,8 +149,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "08f243c64b2b5104e431cf0d485c0c5a455073c6",
"version" : "1.0.48"
"revision" : "7e9a927b6ae4b0380fb403f54a55e52990af54b3",
"version" : "1.0.49"
}
},
{

View File

@ -341,6 +341,81 @@ open class ClientSDKMock: MatrixRustSDK.Client {
}
}
//MARK: - awaitRoomRemoteEcho
open var awaitRoomRemoteEchoRoomIdThrowableError: Error?
var awaitRoomRemoteEchoRoomIdUnderlyingCallsCount = 0
open var awaitRoomRemoteEchoRoomIdCallsCount: Int {
get {
if Thread.isMainThread {
return awaitRoomRemoteEchoRoomIdUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = awaitRoomRemoteEchoRoomIdUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
awaitRoomRemoteEchoRoomIdUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
awaitRoomRemoteEchoRoomIdUnderlyingCallsCount = newValue
}
}
}
}
open var awaitRoomRemoteEchoRoomIdCalled: Bool {
return awaitRoomRemoteEchoRoomIdCallsCount > 0
}
open var awaitRoomRemoteEchoRoomIdReceivedRoomId: String?
open var awaitRoomRemoteEchoRoomIdReceivedInvocations: [String] = []
var awaitRoomRemoteEchoRoomIdUnderlyingReturnValue: Room!
open var awaitRoomRemoteEchoRoomIdReturnValue: Room! {
get {
if Thread.isMainThread {
return awaitRoomRemoteEchoRoomIdUnderlyingReturnValue
} else {
var returnValue: Room? = nil
DispatchQueue.main.sync {
returnValue = awaitRoomRemoteEchoRoomIdUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
awaitRoomRemoteEchoRoomIdUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
awaitRoomRemoteEchoRoomIdUnderlyingReturnValue = newValue
}
}
}
}
open var awaitRoomRemoteEchoRoomIdClosure: ((String) async throws -> Room)?
open override func awaitRoomRemoteEcho(roomId: String) async throws -> Room {
if let error = awaitRoomRemoteEchoRoomIdThrowableError {
throw error
}
awaitRoomRemoteEchoRoomIdCallsCount += 1
awaitRoomRemoteEchoRoomIdReceivedRoomId = roomId
DispatchQueue.main.async {
self.awaitRoomRemoteEchoRoomIdReceivedInvocations.append(roomId)
}
if let awaitRoomRemoteEchoRoomIdClosure = awaitRoomRemoteEchoRoomIdClosure {
return try await awaitRoomRemoteEchoRoomIdClosure(roomId)
} else {
return awaitRoomRemoteEchoRoomIdReturnValue
}
}
//MARK: - cachedAvatarUrl
open var cachedAvatarUrlThrowableError: Error?
@ -2662,6 +2737,71 @@ open class ClientSDKMock: MatrixRustSDK.Client {
}
}
//MARK: - server
var serverUnderlyingCallsCount = 0
open var serverCallsCount: Int {
get {
if Thread.isMainThread {
return serverUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = serverUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
serverUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
serverUnderlyingCallsCount = newValue
}
}
}
}
open var serverCalled: Bool {
return serverCallsCount > 0
}
var serverUnderlyingReturnValue: String?
open var serverReturnValue: String? {
get {
if Thread.isMainThread {
return serverUnderlyingReturnValue
} else {
var returnValue: String?? = nil
DispatchQueue.main.sync {
returnValue = serverUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
serverUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
serverUnderlyingReturnValue = newValue
}
}
}
}
open var serverClosure: (() -> String?)?
open override func server() -> String? {
serverCallsCount += 1
if let serverClosure = serverClosure {
return serverClosure()
} else {
return serverReturnValue
}
}
//MARK: - session
open var sessionThrowableError: Error?
@ -9974,6 +10114,82 @@ open class NotificationSettingsSDKMock: MatrixRustSDK.NotificationSettings {
try await unmuteRoomRoomIdIsEncryptedIsOneToOneClosure?(roomId, isEncrypted, isOneToOne)
}
}
open class OidcAuthorizationDataSDKMock: MatrixRustSDK.OidcAuthorizationData {
init() {
super.init(noPointer: .init())
}
public required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
fatalError("init(unsafeFromRawPointer:) has not been implemented")
}
fileprivate var pointer: UnsafeMutableRawPointer!
//MARK: - loginUrl
var loginUrlUnderlyingCallsCount = 0
open var loginUrlCallsCount: Int {
get {
if Thread.isMainThread {
return loginUrlUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingCallsCount = newValue
}
}
}
}
open var loginUrlCalled: Bool {
return loginUrlCallsCount > 0
}
var loginUrlUnderlyingReturnValue: String!
open var loginUrlReturnValue: String! {
get {
if Thread.isMainThread {
return loginUrlUnderlyingReturnValue
} else {
var returnValue: String? = nil
DispatchQueue.main.sync {
returnValue = loginUrlUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
loginUrlUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
loginUrlUnderlyingReturnValue = newValue
}
}
}
}
open var loginUrlClosure: (() -> String)?
open override func loginUrl() -> String {
loginUrlCallsCount += 1
if let loginUrlClosure = loginUrlClosure {
return loginUrlClosure()
} else {
return loginUrlReturnValue
}
}
}
open class QrCodeDataSDKMock: MatrixRustSDK.QrCodeData {
init() {
super.init(noPointer: .init())

View File

@ -13,6 +13,8 @@ struct LoginHomeserver: Equatable {
let address: String
/// The types login supported by the homeserver.
var loginMode: LoginMode
/// A temporary helper URL that can be used for registration.
var registrationHelperURL: URL?
/// Creates a new homeserver value.
init(address: String, loginMode: LoginMode) {

View File

@ -23,6 +23,7 @@ enum LoginScreenCoordinatorAction {
case signedIn(UserSessionProtocol)
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class LoginScreenCoordinator: CoordinatorProtocol {
private let parameters: LoginScreenCoordinatorParameters
private var viewModel: LoginScreenViewModelProtocol

View File

@ -66,9 +66,9 @@ struct ServerConfirmationScreen: View {
// MARK: - Previews
struct ServerConfirmationScreen_Previews: PreviewProvider, TestablePreview {
static let loginViewModel = ServerConfirmationScreenViewModel(authenticationService: MockAuthenticationServiceProxy(),
static let loginViewModel = ServerConfirmationScreenViewModel(authenticationService: MockAuthenticationService(),
authenticationFlow: .login)
static let registerViewModel = ServerConfirmationScreenViewModel(authenticationService: MockAuthenticationServiceProxy(),
static let registerViewModel = ServerConfirmationScreenViewModel(authenticationService: MockAuthenticationService(),
authenticationFlow: .register)
static var previews: some View {

View File

@ -21,6 +21,7 @@ enum ServerSelectionScreenCoordinatorAction {
case dismiss
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class ServerSelectionScreenCoordinator: CoordinatorProtocol {
private let parameters: ServerSelectionScreenCoordinatorParameters
private let userIndicatorController: UserIndicatorControllerProtocol

View File

@ -32,6 +32,7 @@ enum SoftLogoutScreenCoordinatorResult: CustomStringConvertible {
}
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
private let parameters: SoftLogoutScreenCoordinatorParameters
private var viewModel: SoftLogoutScreenViewModelProtocol

View File

@ -0,0 +1,139 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Compound
import SwiftUI
import WebKit
struct WebRegistrationScreen: View {
@ObservedObject var context: WebRegistrationScreenViewModel.Context
var body: some View {
NavigationStack {
WebRegistrationWebView(url: context.viewState.url, viewModelContext: context)
.navigationTitle(L10n.screenCreateAccountTitle)
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.actionCancel) {
context.send(viewAction: .cancel)
}
}
}
}
}
}
struct WebRegistrationWebView: UIViewRepresentable {
let url: URL
let viewModelContext: WebRegistrationScreenViewModel.Context
func makeUIView(context: Context) -> WKWebView {
context.coordinator.webView
}
func updateUIView(_ webView: WKWebView, context: Context) { }
func makeCoordinator() -> Coordinator {
Coordinator(url: url, viewModelContext: viewModelContext)
}
class Coordinator: NSObject, WKUIDelegate {
private let url: URL
private let viewModelContext: WebRegistrationScreenViewModel.Context
private(set) var webView: WKWebView!
init(url: URL, viewModelContext: WebRegistrationScreenViewModel.Context) {
self.url = url
self.viewModelContext = viewModelContext
super.init()
let eventHandlerName = "elementx"
let userContentController = WKUserContentController()
userContentController.add(WKScriptMessageHandlerWrapper(self), name: eventHandlerName)
let eventHandlerScript = """
window.addEventListener(
"mobileregistrationresponse",
(event) => {
window.webkit.messageHandlers.\(eventHandlerName).postMessage(JSON.stringify(event.detail));
},
false,
);
"""
let userScript = WKUserScript(source: eventHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webView = WKWebView(frame: .zero, configuration: configuration)
webView.uiDelegate = self
webView.load(URLRequest(url: url))
}
nonisolated func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let jsonString = message.body as? String, let jsonData = jsonString.data(using: .utf8) else {
MXLog.error("Unexpected response.")
return
}
guard let credentials = try? JSONDecoder().decode(WebRegistrationCredentials.self, from: jsonData) else {
MXLog.error("Invalid response.")
return
}
MXLog.info("Received login credentials.")
Task { await viewModelContext.send(viewAction: .signedIn(credentials)) }
}
// MARK: WKUIDelegate
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures) -> WKWebView? {
if let url = navigationAction.request.url, UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
return nil
}
}
/// Avoids retain loops between the configuration and webView coordinator
private class WKScriptMessageHandlerWrapper: NSObject, WKScriptMessageHandler {
private weak var coordinator: Coordinator?
init(_ coordinator: Coordinator) {
self.coordinator = coordinator
}
// MARK: WKScriptMessageHandler
nonisolated func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
coordinator?.userContentController(userContentController, didReceive: message)
}
}
}
// MARK: - Previews
struct WebRegistrationScreen_Previews: PreviewProvider {
static let viewModel = WebRegistrationScreenViewModel(registrationHelperURL: "https://develop.element.io/#/mobile_register")
static var previews: some View {
NavigationStack {
WebRegistrationScreen(context: viewModel.context)
}
}
}

View File

@ -0,0 +1,83 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Combine
import MatrixRustSDK
import SwiftUI
struct WebRegistrationScreenCoordinatorParameters {
/// The service used to authenticate the user.
let authenticationService: AuthenticationServiceProtocol
let userIndicatorController: UserIndicatorControllerProtocol
}
enum WebRegistrationScreenCoordinatorAction: CustomStringConvertible {
case cancel
case signedIn(UserSessionProtocol)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
// Note: This code was based on the LoginScreen, we should move the authentication service logic into the view model.
final class WebRegistrationScreenCoordinator: CoordinatorProtocol {
private let parameters: WebRegistrationScreenCoordinatorParameters
private let viewModel: WebRegistrationScreenViewModelProtocol
private var cancellables = Set<AnyCancellable>()
private let actionsSubject: PassthroughSubject<WebRegistrationScreenCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(parameters: WebRegistrationScreenCoordinatorParameters) {
self.parameters = parameters
guard let registrationHelperURL = parameters.authenticationService.homeserver.value.registrationHelperURL else {
MXLog.error("Attempted registration without a helper URL.")
fatalError("A helper URL is required.")
}
viewModel = WebRegistrationScreenViewModel(registrationHelperURL: registrationHelperURL)
}
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 .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
Task { await self.completeRegistration(using: credentials) }
}
}
.store(in: &cancellables)
}
func toPresentable() -> AnyView {
AnyView(WebRegistrationScreen(context: viewModel.context))
}
// MARK: - Private
private func completeRegistration(using credentials: WebRegistrationCredentials) async {
switch await parameters.authenticationService.completeWebRegistration(using: credentials) {
case .success(let userSession):
actionsSubject.send(.signedIn(userSession))
case .failure(let error):
MXLog.error("Failed registration: \(error)")
parameters.userIndicatorController.alertInfo = .init(id: UUID(), title: L10n.errorUnknown, message: String(describing: error))
}
}
}

View File

@ -0,0 +1,51 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Foundation
enum WebRegistrationScreenViewModelAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationScreenViewState: BindableState {
var url: URL
var bindings = WebRegistrationScreenViewStateBindings()
}
struct WebRegistrationScreenViewStateBindings { }
enum WebRegistrationScreenViewAction: CustomStringConvertible {
case cancel
case signedIn(WebRegistrationCredentials)
var description: String {
switch self {
case .cancel: "cancel"
case .signedIn: "signedIn"
}
}
}
struct WebRegistrationCredentials: Decodable {
let userID: String
let accessToken: String
let deviceID: String
enum CodingKeys: String, CodingKey {
case userID = "user_id"
case accessToken = "access_token"
case deviceID = "device_id"
}
}

View File

@ -0,0 +1,34 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Combine
import MatrixRustSDK
import SwiftUI
typealias WebRegistrationScreenViewModelType = StateStoreViewModel<WebRegistrationScreenViewState, WebRegistrationScreenViewAction>
class WebRegistrationScreenViewModel: WebRegistrationScreenViewModelType, WebRegistrationScreenViewModelProtocol {
private let actionsSubject: PassthroughSubject<WebRegistrationScreenViewModelAction, Never> = .init()
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(registrationHelperURL: URL) {
super.init(initialViewState: WebRegistrationScreenViewState(url: registrationHelperURL))
}
override func process(viewAction: WebRegistrationScreenViewAction) {
MXLog.info("View model: received view action: \(viewAction)")
switch viewAction {
case .cancel:
actionsSubject.send(.cancel)
case .signedIn(let credentials):
actionsSubject.send(.signedIn(credentials))
}
}
}

View File

@ -0,0 +1,14 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Combine
@MainActor
protocol WebRegistrationScreenViewModelProtocol {
var actionsPublisher: AnyPublisher<WebRegistrationScreenViewModelAction, Never> { get }
var context: WebRegistrationScreenViewModelType.Context { get }
}

View File

@ -40,15 +40,21 @@ class AuthenticationService: AuthenticationServiceProtocol {
let client = try await makeClientBuilder().build(homeserverAddress: homeserverAddress)
let loginDetails = await client.homeserverLoginDetails()
let elementWellKnown = await client.getElementWellKnown()
MXLog.info("Sliding sync: \(client.slidingSyncVersion())")
if loginDetails.supportsOidcLogin() {
homeserver.loginMode = .oidc
homeserver.loginMode = if loginDetails.supportsOidcLogin() {
.oidc
} else if loginDetails.supportsPasswordLogin() {
homeserver.loginMode = .password
.password
} else {
homeserver.loginMode = .unsupported
.unsupported
}
homeserver.registrationHelperURL = switch elementWellKnown {
case .success(let wellKnown): wellKnown.registrationHelperUrl.flatMap(URL.init)
case .failure: nil
}
self.client = client
@ -125,6 +131,25 @@ class AuthenticationService: AuthenticationServiceProtocol {
}
}
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<any UserSessionProtocol, AuthenticationServiceError> {
guard let client else { return .failure(.failedLoggingIn) }
let session = Session(accessToken: credentials.accessToken,
refreshToken: nil,
userId: credentials.userID,
deviceId: credentials.deviceID,
homeserverUrl: client.homeserver(),
oidcData: nil,
slidingSyncVersion: client.slidingSyncVersion())
do {
try await client.restoreSession(session: session)
return await userSession(for: client)
} catch {
MXLog.error("Failed restoring the client using the provided credentials.")
return .failure(.failedUsingWebCredentials)
}
}
// MARK: - Private
private func makeClientBuilder() -> AuthenticationClientBuilder {

View File

@ -27,6 +27,7 @@ enum AuthenticationServiceError: Error {
case accountDeactivated
case failedLoggingIn
case sessionTokenRefreshNotSupported
case failedUsingWebCredentials
}
protocol AuthenticationServiceProtocol {
@ -43,6 +44,8 @@ protocol AuthenticationServiceProtocol {
func loginWithOIDCCallback(_ callbackURL: URL, data: OIDCAuthorizationDataProxy) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Performs a password login using the current homeserver.
func login(username: String, password: String, initialDeviceName: String?, deviceID: String?) async -> Result<UserSessionProtocol, AuthenticationServiceError>
/// Completes registration using the credentials obtained via the helper URL.
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<UserSessionProtocol, AuthenticationServiceError>
}
// MARK: - OIDC

View File

@ -9,7 +9,7 @@ import Combine
import Foundation
import MatrixRustSDK
class MockAuthenticationServiceProxy: AuthenticationServiceProtocol {
class MockAuthenticationService: AuthenticationServiceProtocol {
let validCredentials = (username: "alice", password: "12345678")
private let homeserverSubject: CurrentValueSubject<LoginHomeserver, Never>
@ -58,4 +58,8 @@ class MockAuthenticationServiceProxy: AuthenticationServiceProtocol {
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: username))))
return .success(userSession)
}
func completeWebRegistration(using credentials: WebRegistrationCredentials) async -> Result<any UserSessionProtocol, AuthenticationServiceError> {
.failure(.failedLoggingIn)
}
}

View File

@ -0,0 +1,32 @@
//
// Copyright 2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Foundation
import MatrixRustSDK
extension ClientProtocol {
func getElementWellKnown() async -> Result<MatrixRustSDK.ElementWellKnown, ClientProxyError> {
do {
let serverName = if let userIDServerName = try? userIdServerName() {
"https://\(userIDServerName)"
} else {
server()
}
guard let serverName,
let url = URL(string: serverName)?.appending(path: "/.well-known/element/element.json") else {
return .failure(.invalidServerName)
}
let response = try await getUrl(url: url.absoluteString)
let wellKnown = try makeElementWellKnown(string: response)
return .success(wellKnown)
} catch {
return .failure(.sdkError(error))
}
}
}

View File

@ -594,20 +594,7 @@ class ClientProxy: ClientProxyProtocol {
}
func getElementWellKnown() async -> Result<ElementWellKnown?, ClientProxyError> {
guard let userIDServerName,
var url = URL(string: "https://\(userIDServerName)") else {
return .failure(.invalidUserIDServerName)
}
url.append(path: "/.well-known/element/element.json")
do {
let response = try await client.getUrl(url: url.absoluteString)
let sdkWellKnown = try makeElementWellKnown(string: response)
return .success(ElementWellKnown(sdkWellKnown))
} catch {
return .failure(.sdkError(error))
}
await client.getElementWellKnown().map(ElementWellKnown.init)
}
// MARK: Ignored users

View File

@ -32,7 +32,7 @@ enum ClientProxyError: Error {
case sdkError(Error)
case invalidMedia
case invalidUserIDServerName
case invalidServerName
case failedUploadingMedia(Error, MatrixErrorCode)
case roomPreviewIsPrivate
}

View File

@ -19,8 +19,10 @@ struct ElementWellKnown {
}
let call: Call?
let registrationHelperURL: URL?
init?(_ wellKnown: MatrixRustSDK.ElementWellKnown) {
call = Call(wellKnown.call)
call = wellKnown.call.flatMap(Call.init)
registrationHelperURL = wellKnown.registrationHelperUrl.flatMap(URL.init)
}
}

View File

@ -111,20 +111,20 @@ class MockScreen: Identifiable {
switch id {
case .login:
let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = LoginScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
let coordinator = LoginScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationService(),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController))
navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator
case .serverSelection:
let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = ServerSelectionScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
let coordinator = ServerSelectionScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationService(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
isModallyPresented: true))
navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator
case .authenticationFlow:
let flowCoordinator = AuthenticationFlowCoordinator(authenticationService: MockAuthenticationServiceProxy(),
let flowCoordinator = AuthenticationFlowCoordinator(authenticationService: MockAuthenticationService(),
qrCodeLoginService: QRCodeLoginServiceMock(),
bugReportService: BugReportServiceMock(),
navigationRootCoordinator: navigationRootCoordinator,

View File

@ -0,0 +1,70 @@
//
// Copyright 2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import XCTest
@testable import ElementX
@testable import MatrixRustSDK
class ClientProtocolTests: XCTestCase {
let server = "https://matrix.org"
let userIDServerName = "matrix.org"
let wellKnownURL = "https://matrix.org/.well-known/element/element.json"
var client: ClientProtocol!
func testWellKnownLoggedOut() async {
// Given a client that is logged out but has discovered a server.
let client = ClientSDKMock()
client.userIdServerNameThrowableError = MockError.notAvailable
client.serverReturnValue = server
// When discovering a server that contains the registration helper URL.
client.getUrlUrlClosure = { [wellKnownURL] url in
guard url == wellKnownURL else {
XCTFail("An unexpected URL was used.")
throw MockError.notAvailable
}
return "{\"registration_helper_url\":\"https://develop.element.io/#/mobile_register\"}"
}
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
XCTFail("The request should succeed.")
return
}
// Then the well-known should include that URL.
XCTAssertEqual(wellKnown, .init(call: nil, registrationHelperUrl: "https://develop.element.io/#/mobile_register"))
}
func testWellKnownLoggedIn() async {
// Given a client that is logged in.
let client = ClientSDKMock()
client.userIdServerNameReturnValue = userIDServerName
// When discovering a server that contains a custom call widget URL.
client.getUrlUrlClosure = { [wellKnownURL] url in
guard url == wellKnownURL else {
XCTFail("An unexpected URL was used.")
throw MockError.notAvailable
}
return "{\"call\":{\"widget_url\":\"https://call.element.dev\"}}"
}
guard case let .success(wellKnown) = await client.getElementWellKnown() else {
XCTFail("The request should succeed.")
return
}
// Then the well-known should include that URL.
XCTAssertEqual(wellKnown, .init(call: .init(widgetUrl: "https://call.element.dev"), registrationHelperUrl: nil))
}
enum MockError: Error {
case notAvailable
}
}

View File

@ -60,7 +60,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 1.0.48
exactVersion: 1.0.49
# path: ../matrix-rust-sdk
Compound:
url: https://github.com/element-hq/compound-ios