From 009f918b324cdb30f53bf643324ea5433de8114d Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 26 Feb 2025 18:49:31 +0100 Subject: [PATCH 01/10] Implemented join room by address --- ElementX.xcodeproj/project.pbxproj | 44 ++++----- .../AuthenticationTextFieldStyle.swift | 91 ++++++++++++++----- .../View/ServerSelectionScreen.swift | 2 +- .../StartChatScreenModels.swift | 12 +++ .../StartChatScreenViewModel.swift | 59 ++++++++++++ .../View/JoinRoomByAddressView.swift | 88 ++++++++++++++++++ .../View/StartChatScreen.swift | 16 ++++ .../Sources/GeneratedPreviewTests.swift | 6 ++ 8 files changed, 270 insertions(+), 48 deletions(-) create mode 100644 ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 6f9c06ee46..33d4d826f8 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 56; objects = { /* Begin PBXAggregateTarget section */ @@ -859,6 +859,7 @@ A722F426FD81FC67706BB1E0 /* CustomLayoutLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42236480CF0431535EBE8387 /* CustomLayoutLabelStyle.swift */; }; A74438ED16F8683A4B793E6A /* AnalyticsSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCE3FAF40932AC7C7639AC4 /* AnalyticsSettingsScreenViewModel.swift */; }; A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */; }; + A7F55DC52D6F5CEC00CE60E9 /* JoinRoomByAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F55DC42D6F5CCF00CE60E9 /* JoinRoomByAddressView.swift */; }; A808DC3F72D15C6C5A52317E /* TimelineItemDebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDA016D05107DED3B9495CB /* TimelineItemDebugView.swift */; }; A816F7087C495D85048AC50E /* RoomMemberDetailsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */; }; A851635B3255C6DC07034A12 /* RoomScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8108C8F0ACF6A7EB72D0117 /* RoomScreenCoordinator.swift */; }; @@ -1364,7 +1365,7 @@ 044E501B8331B339874D1B96 /* CompoundIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompoundIcon.swift; sourceTree = ""; }; 045253F9967A535EE5B16691 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; }; 046C0D3F53B0B5EF0A1F5BEA /* RoomSummaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryTests.swift; sourceTree = ""; }; - 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 048A21188AB19349D026BECD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 04BB8DDE245ED86C489BA983 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = ""; }; 04DF593C3F7AF4B2FBAEB05D /* FileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; 0516C69708D5CBDE1A8E77EC /* RoomDirectorySearchProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchProxyProtocol.swift; sourceTree = ""; }; @@ -1436,7 +1437,7 @@ 128501375217576AF0FE3E92 /* RoomAttachmentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomAttachmentPicker.swift; sourceTree = ""; }; 12B09A94C519227264A41208 /* RoomMembershipDetailsProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembershipDetailsProxy.swift; sourceTree = ""; }; 12FD5280AF55AB7F50F8E47D /* preview_avatar_room.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_avatar_room.jpg; sourceTree = ""; }; - 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; path = IntegrationTests.xctestplan; sourceTree = ""; }; + 1304D9191300873EADA52D6E /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = IntegrationTests.xctestplan; sourceTree = ""; }; 130ED565A078F7E0B59D9D25 /* UNTextInputNotificationResponse+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNTextInputNotificationResponse+Creator.swift"; sourceTree = ""; }; 136F80A613B55BDD071DCEA5 /* JoinRoomScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomScreenModels.swift; sourceTree = ""; }; 13802897C7AFA360EA74C0B0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -1537,7 +1538,7 @@ 25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = ""; }; 25F8664F1FB95AF3C4202478 /* PollFormScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenCoordinator.swift; sourceTree = ""; }; 260004737C573A56FA01E86E /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = ""; }; - 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; path = PreviewTests.xctestplan; sourceTree = ""; }; + 267BB1D5B08A9511F894CB57 /* PreviewTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = PreviewTests.xctestplan; sourceTree = ""; }; 26B0A96B8FE4849227945067 /* VoiceMessageRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecorder.swift; sourceTree = ""; }; 26EAAB54C6CE91D64B69A9F8 /* AppLockServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockServiceProtocol.swift; sourceTree = ""; }; 2711E5996016ABD6EAAEB58A /* LogLevel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogLevel.swift; sourceTree = ""; }; @@ -1611,7 +1612,7 @@ 3558A15CFB934F9229301527 /* RestorationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestorationToken.swift; sourceTree = ""; }; 35AFCF4C05DEED04E3DB1A16 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 35FA991289149D31F4286747 /* UserPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreference.swift; sourceTree = ""; }; - 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 36DA824791172B9821EACBED /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 36FD673E24FBFCFDF398716A /* RoomMemberProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberProxyMock.swift; sourceTree = ""; }; 371B248460BD1A3F20318137 /* TimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProvider.swift; sourceTree = ""; }; 376D941BF8BB294389C0DE24 /* MapTilerURLBuildersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerURLBuildersTests.swift; sourceTree = ""; }; @@ -2016,7 +2017,7 @@ 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomStateEventStringBuilder.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitorMock.swift; sourceTree = ""; }; - 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = ""; }; + 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = ""; }; 8E1584F8BCF407BB94F48F04 /* EncryptionResetPasswordScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetPasswordScreen.swift; sourceTree = ""; }; 8EAF4A49F3ACD8BB8B0D2371 /* ClientSDKMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSDKMock.swift; sourceTree = ""; }; 8F062DD2CCD95DC33528A16F /* KnockRequestProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KnockRequestProxy.swift; sourceTree = ""; }; @@ -2134,6 +2135,7 @@ A7C4EA55DA62F9D0F984A2AE /* CollapsibleTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTimelineItem.swift; sourceTree = ""; }; A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = ""; }; A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = ""; }; + A7F55DC42D6F5CCF00CE60E9 /* JoinRoomByAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomByAddressView.swift; sourceTree = ""; }; A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = ""; }; A8558D41DD4B553A752C868A /* StackedAvatarsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackedAvatarsView.swift; sourceTree = ""; }; A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = ""; }; @@ -2210,7 +2212,7 @@ B50F03079F6B5EF9CA005F14 /* TimelineProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProxyProtocol.swift; sourceTree = ""; }; B53AC78E49A297AC1D72A7CF /* AppMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMediator.swift; sourceTree = ""; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = ""; }; - B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = ""; }; + B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = ConfettiScene.scn; sourceTree = ""; }; B63B69F9A2BC74DD40DC75C8 /* AdvancedSettingsScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModel.swift; sourceTree = ""; }; B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = ""; }; B655A536341D2695158C6664 /* AuthenticationClientBuilderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationClientBuilderFactory.swift; sourceTree = ""; }; @@ -2237,7 +2239,7 @@ BA40B98B098B6F0371B750B3 /* TemplateScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenModels.swift; sourceTree = ""; }; BA919F521E9F0EE3638AFC85 /* BugReportScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreen.swift; sourceTree = ""; }; BB284643AF7AB131E307DCE0 /* AudioSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioSessionProtocol.swift; sourceTree = ""; }; - BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; path = test_apple_image.heic; sourceTree = ""; }; + BB576F4118C35E6B5124FA22 /* test_apple_image.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_apple_image.heic; sourceTree = ""; }; BB5B00A014307CE37B2812CD /* TimelineViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewModelProtocol.swift; sourceTree = ""; }; BB8BC4C791D0E88CFCF4E5DF /* ServerSelectionScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenCoordinator.swift; sourceTree = ""; }; BBEC57C204D77908E355EF42 /* AudioRecorderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecorderProtocol.swift; sourceTree = ""; }; @@ -2337,7 +2339,7 @@ CDB3227C7A74B734924942E9 /* RoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSummaryProvider.swift; sourceTree = ""; }; CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; 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 = ""; }; + CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = ""; }; D01FD1171FF40E34D707FD00 /* BigIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigIcon.swift; sourceTree = ""; }; D046ABB22E680F7C5054441B /* SecurityAndPrivacyScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityAndPrivacyScreenViewModelProtocol.swift; sourceTree = ""; }; D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = ""; }; @@ -2394,7 +2396,7 @@ DC0AEA686E425F86F6BA0404 /* UNNotification+Creator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotification+Creator.swift"; sourceTree = ""; }; DC10CCC8D68B863E20660DBC /* MessageForwardingScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageForwardingScreenViewModelProtocol.swift; sourceTree = ""; }; DC528B3764E3CF7FCFEF40E7 /* PollInteractionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollInteractionHandler.swift; sourceTree = ""; }; - DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; path = test_voice_message.m4a; sourceTree = ""; }; + DCA2D836BD10303F37FAAEED /* test_voice_message.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_voice_message.m4a; sourceTree = ""; }; DCAC01A97A43BE07B9E94E43 /* ShareExtensionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionModels.swift; sourceTree = ""; }; DCF239C619971FDE48132550 /* SecureBackupLogoutConfirmationScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBackupLogoutConfirmationScreenModels.swift; sourceTree = ""; }; DD8C9BBB729C941BEE0E2A63 /* TimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineProviderProtocol.swift; sourceTree = ""; }; @@ -2435,7 +2437,7 @@ 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 = ""; }; - E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; path = portrait_test_video.mp4; sourceTree = ""; }; + E5E7D4EE7CA295E5039FDA21 /* portrait_test_video.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = portrait_test_video.mp4; 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 = ""; }; E5FDFAA04174CC99FB66391C /* EditRoomAddressScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditRoomAddressScreenViewModel.swift; sourceTree = ""; }; @@ -2477,7 +2479,7 @@ ED0CBEAB5F796BEFBAF7BB6A /* VideoRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRoomTimelineView.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 = ""; }; + ED482057AE39D5C6D9C5F3D8 /* message.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = message.caf; sourceTree = ""; }; ED49073BB1C1FC649DAC2CCD /* LocationRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineView.swift; sourceTree = ""; }; ED60E4D2CD678E1EBF16F77A /* BlockedUsersScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockedUsersScreen.swift; sourceTree = ""; }; EE378083653EF0C9B5E9D580 /* EmoteRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItemContent.swift; sourceTree = ""; }; @@ -5063,6 +5065,7 @@ A7F3784CAF9F4CF654BC52CD /* View */ = { isa = PBXGroup; children = ( + A7F55DC42D6F5CCF00CE60E9 /* JoinRoomByAddressView.swift */, F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */, 6861FE915C7B5466E6962BBA /* StartChatScreen.swift */, ); @@ -7515,6 +7518,7 @@ 5710AAB27D5D866292C1FE06 /* SessionVerificationScreenModels.swift in Sources */, 601AB75BD52B0B4276CEB84A /* SessionVerificationScreenStateMachine.swift in Sources */, 4A8287E5281B44A8754BE509 /* SessionVerificationScreenViewModel.swift in Sources */, + A7F55DC52D6F5CEC00CE60E9 /* JoinRoomByAddressView.swift in Sources */, 762DB0973865293F0C3D3D7B /* SessionVerificationScreenViewModelProtocol.swift in Sources */, 755395927DDD6EBDDA5E217A /* SettingsFlowCoordinator.swift in Sources */, 34F1261CEF6D6A00D559B520 /* SettingsScreen.swift in Sources */, @@ -7956,9 +7960,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; @@ -8007,9 +8009,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -8035,9 +8035,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_MAIN_APP", - ); + OTHER_SWIFT_FLAGS = "-DIS_MAIN_APP"; PILLS_UT_TYPE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).pills"; PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER)"; PRODUCT_NAME = "$(APP_NAME)"; @@ -8301,9 +8299,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = "$(MARKETING_VERSION)"; - OTHER_SWIFT_FLAGS = ( - "-DIS_NSE", - ); + OTHER_SWIFT_FLAGS = "-DIS_NSE"; PRODUCT_BUNDLE_IDENTIFIER = "${BASE_BUNDLE_IDENTIFIER}.nse"; PRODUCT_DISPLAY_NAME = "$(APP_DISPLAY_NAME)"; PRODUCT_NAME = NSE; diff --git a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift b/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift index 59db271042..d42c8b5cd5 100644 --- a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift +++ b/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift @@ -9,38 +9,48 @@ import Compound import SwiftUI import SwiftUIIntrospect -public extension TextFieldStyle where Self == AuthenticationTextFieldStyle { +extension TextFieldStyle where Self == AuthenticationTextFieldStyle { static func authentication(labelText: String? = nil, footerText: String? = nil, - isError: Bool = false, + state: AuthenticationTextFieldStyle.State = .default, accessibilityIdentifier: String? = nil) -> AuthenticationTextFieldStyle { AuthenticationTextFieldStyle(labelText: labelText.map(Text.init), footerText: footerText.map(Text.init), - isError: isError, + state: state, accessibilityIdentifier: accessibilityIdentifier) } @_disfavoredOverload static func authentication(labelText: Text? = nil, footerText: Text? = nil, - isError: Bool = false, + state: AuthenticationTextFieldStyle.State = .default, accessibilityIdentifier: String? = nil) -> AuthenticationTextFieldStyle { AuthenticationTextFieldStyle(labelText: labelText, footerText: footerText, - isError: isError, + state: state, accessibilityIdentifier: accessibilityIdentifier) } } /// The text field style used in authentication screens. -public struct AuthenticationTextFieldStyle: TextFieldStyle { +struct AuthenticationTextFieldStyle: TextFieldStyle { + enum State { + case success + case error + case `default` + } + @Environment(\.isEnabled) private var isEnabled @FocusState private var isFocused: Bool - public let labelText: Text? - public let footerText: Text? - public let isError: Bool - public let accessibilityIdentifier: String? + let labelText: Text? + let footerText: Text? + let state: State + let accessibilityIdentifier: String? + + private var isError: Bool { + state == .error + } /// The color of the text field's border. private var borderColor: Color { @@ -63,7 +73,8 @@ public struct AuthenticationTextFieldStyle: TextFieldStyle { /// The color of the text field's background. private var backgroundColor: Color { - .compound.bgSubtleSecondary.opacity(isEnabled ? 1 : 0.5) + isError ? .compound.bgCriticalSubtleHovered : + .compound.bgSubtleSecondary.opacity(isEnabled ? 1 : 0.5) } /// The color of the placeholder text inside the text field. @@ -77,8 +88,27 @@ public struct AuthenticationTextFieldStyle: TextFieldStyle { } /// The color of the footer label below the text field. - private var footerColor: Color { - isError ? .compound.textCriticalPrimary : .compound.textSecondary + private var footerTextColor: Color { + switch state { + case .default: + .compound.textSecondary + case .error: + .compound.textCriticalPrimary + case .success: + .compound.textSuccessPrimary + } + } + + private var footerIconColor: Color { + switch state { + // Doesn't matter we don't render it + case .default: + .clear + case .error: + .compound.iconCriticalPrimary + case .success: + .compound.iconSuccessPrimary + } } /// Creates the text field style configured as required. @@ -86,20 +116,20 @@ public struct AuthenticationTextFieldStyle: TextFieldStyle { /// - labelText: The text shown in the label above the field. /// - footerText: The text shown in the footer label below the field. /// - isError: Whether or not the text field is currently in the error state. - public init(labelText: Text? = nil, footerText: Text? = nil, isError: Bool = false, accessibilityIdentifier: String? = nil) { + init(labelText: Text? = nil, footerText: Text? = nil, state: State = .default, accessibilityIdentifier: String? = nil) { self.labelText = labelText self.footerText = footerText - self.isError = isError + self.state = state self.accessibilityIdentifier = accessibilityIdentifier } @MainActor - public func _body(configuration: TextField<_Label>) -> some View { + func _body(configuration: TextField<_Label>) -> some View { let rectangle = RoundedRectangle(cornerRadius: 14.0) return VStack(alignment: .leading, spacing: 8) { labelText - .font(.compound.bodySM) + .font(.compound.bodySMSemibold) .foregroundColor(labelColor) .padding(.horizontal, 16) @@ -126,11 +156,26 @@ public struct AuthenticationTextFieldStyle: TextFieldStyle { textField.accessibilityIdentifier = accessibilityIdentifier } - footerText - .tint(.compound.textLinkExternal) - .font(.compound.bodyXS) - .foregroundColor(footerColor) + if let footerText { + HStack(spacing: 4) { + switch state { + case .success: + CompoundIcon(\.checkCircleSolid, size: .xSmall, relativeTo: .compound.bodySM) + .foregroundStyle(.compound.iconSuccessPrimary) + case .error: + CompoundIcon(\.errorSolid, size: .xSmall, relativeTo: .compound.bodySM) + .foregroundStyle(.compound.iconCriticalPrimary) + case .default: + EmptyView() + } + + footerText + .tint(.compound.textLinkExternal) + .font(.compound.bodySM) + .foregroundColor(footerTextColor) + } .padding(.horizontal, 16) + } } } } @@ -148,7 +193,7 @@ struct ElementTextFieldStyle_Previews: PreviewProvider { .textFieldStyle(.authentication()) .disabled(true) TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication(isError: true)) + .textFieldStyle(.authentication(state: .error)) // Text field with labels TextField("Placeholder", text: .constant("")) @@ -156,7 +201,7 @@ struct ElementTextFieldStyle_Previews: PreviewProvider { TextField("Placeholder", text: .constant("Input text")) .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) TextField("Placeholder", text: .constant("Bad text")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", isError: true)) + .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .error)) TextField("Placeholder", text: .constant("")) .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) .disabled(true) diff --git a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift index 62673c6da4..cc377936f3 100644 --- a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift +++ b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift @@ -54,7 +54,7 @@ struct ServerSelectionScreen: View { TextField(L10n.commonServerUrl, text: $context.homeserverAddress) .textFieldStyle(.authentication(labelText: Text(L10n.screenChangeServerFormHeader), footerText: Text(context.viewState.footerMessage), - isError: context.viewState.isShowingFooterError, + state: context.viewState.isShowingFooterError ? .error : .default, accessibilityIdentifier: A11yIdentifiers.changeServerScreen.server)) .keyboardType(.URL) .autocapitalization(.none) diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift index 8beb78ad0b..e97eb41a07 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift @@ -30,15 +30,19 @@ struct StartChatScreenViewState: BindableState { var hasEmptySearchResults: Bool { isSearching && usersSection.type == .searchResult && usersSection.users.isEmpty } + + var joinByAddressState: JoinByAddressState = .example } struct StartChatScreenViewStateBindings { var searchQuery = "" + var roomAddress = "" /// Information describing the currently displayed alert. var alertInfo: AlertInfo? var selectedUserToInvite: UserProfileProxy? + var isJoinRoomByAddressSheetPresented = false } enum StartChatScreenViewAction { @@ -46,4 +50,12 @@ enum StartChatScreenViewAction { case createRoom case createDM(user: UserProfileProxy) case selectUser(UserProfileProxy) + case joinRoomByAddress +} + +enum JoinByAddressState { + case example + case invalidAddress + case addressNotFound + case addressFound(address: String, roomID: String) } diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index 17c23b1e26..b36171a004 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -6,6 +6,7 @@ // import Combine +import MatrixRustSDK import SwiftUI typealias StartChatScreenViewModelType = StateStoreViewModel @@ -71,11 +72,17 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie } case .createDM(let user): Task { await createDirectRoom(user: user) } + case .joinRoomByAddress: + joinRoomByAddress() } } // MARK: - Private + // periphery:ignore - auto cancels when reassigned + @CancellableTask private var resolveAliasTask: Task? + private var internalRoomAddressState: JoinByAddressState = .example + private func setupBindings() { context.$viewState .map(\.bindings.searchQuery) @@ -84,6 +91,41 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie self?.fetchUsers() } .store(in: &cancellables) + + context.$viewState + .map(\.bindings.roomAddress) + .debounceTextQueriesAndRemoveDuplicates() + .sink { [weak self] roomAddress in + guard let self else { + return + } + + state.joinByAddressState = .example + internalRoomAddressState = .example + + guard !roomAddress.isEmpty, + isRoomAliasFormatValid(alias: roomAddress) else { + internalRoomAddressState = .invalidAddress + return + } + + resolveAliasTask = Task { [weak self] in + guard let self else { + return + } + defer { resolveAliasTask = nil } + + guard case let .success(resolved) = await userSession.clientProxy.resolveRoomAlias(roomAddress) else { + internalRoomAddressState = .addressNotFound + return + } + + let result = JoinByAddressState.addressFound(address: roomAddress, roomID: resolved.roomId) + internalRoomAddressState = result + state.joinByAddressState = result + } + } + .store(in: &cancellables) } // periphery:ignore - auto cancels when reassigned @@ -129,6 +171,23 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie title: L10n.commonError, message: L10n.screenStartChatErrorStartingChat) } + + private func joinRoomByAddress() { + if case let .addressFound(lastTestedAddress, roomID) = internalRoomAddressState, + lastTestedAddress == state.bindings.roomAddress { + actionsSubject.send(.openRoom(withIdentifier: roomID)) + } else if let resolveAliasTask { + // If the task is still running we wait for it to complete and we check the state again + showLoadingIndicator(delay: .milliseconds(250)) + Task { + await resolveAliasTask.value + hideLoadingIndicator() + joinRoomByAddress() + } + } else { + state.joinByAddressState = internalRoomAddressState + } + } // MARK: Loading indicator diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift new file mode 100644 index 0000000000..6c5e9c3194 --- /dev/null +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -0,0 +1,88 @@ +// +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. +// + +import Compound +import SwiftUI + +struct JoinRoomByAddressView: View { + @ObservedObject var context: StartChatScreenViewModel.Context + + @Environment(\.dismiss) private var dismiss + + @State private var sheetHeight: CGFloat = .zero + @FocusState private var textFieldFocus + private let topPadding: CGFloat = 22 + + private var footerText: String { + switch context.viewState.joinByAddressState { + case .example: + L10n.screenStartChatJoinRoomByAddressSupportingText + case .addressNotFound: + L10n.screenStartChatJoinRoomByAddressRoomNotFound + case .addressFound: + L10n.screenStartChatJoinRoomByAddressRoomNotFound + case .invalidAddress: + L10n.screenStartChatJoinRoomByAddressInvalidAddress + } + } + + private var textFieldState: AuthenticationTextFieldStyle.State { + switch context.viewState.joinByAddressState { + case .addressFound: + .success + case .example: + .default + case .addressNotFound, .invalidAddress: + .error + } + } + + var body: some View { + ScrollView { + VStack(spacing: 24) { + TextField(L10n.screenStartChatJoinRoomByAddressPlaceholder, + text: $context.roomAddress) + .textFieldStyle(.authentication(labelText: L10n.screenStartChatJoinRoomByAddressAction, + footerText: footerText, + state: textFieldState)) + .focused($textFieldFocus) + + Button(L10n.actionContinue) { + context.send(viewAction: .joinRoomByAddress) + } + .buttonStyle(.compound(.primary)) + } + .padding(.horizontal, 16) + .readHeight($sheetHeight) + } + .scrollBounceBehavior(.basedOnSize) + .padding(.top, topPadding) // For the drag indicator + .presentationDetents([.height(sheetHeight + topPadding)]) + .presentationDragIndicator(.visible) + .presentationBackground(.compound.bgCanvasDefault) + .onAppear { + textFieldFocus = true + } + } +} + +struct JoinRoomByAddressView_Previews: PreviewProvider, TestablePreview { + static let viewModel = { + let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com")))) + let userDiscoveryService = UserDiscoveryServiceMock() + userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice]) + let viewModel = StartChatScreenViewModel(userSession: userSession, + analytics: ServiceLocator.shared.analytics, + userIndicatorController: UserIndicatorControllerMock(), + userDiscoveryService: userDiscoveryService) + return viewModel + }() + + static var previews: some View { + JoinRoomByAddressView(context: viewModel.context) + } +} diff --git a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift index a3ce20b9d9..86fc62f4b9 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift @@ -36,6 +36,11 @@ struct StartChatScreen: View { context.send(viewAction: .createDM(user: user)) } } + .sheet(isPresented: $context.isJoinRoomByAddressSheetPresented) { + context.roomAddress = "" + } content: { + JoinRoomByAddressView(context: context) + } } // MARK: - Private @@ -45,9 +50,20 @@ struct StartChatScreen: View { private var mainContent: some View { createRoomSection inviteFriendsSection + joinRoomByAddressSection usersSection } + private var joinRoomByAddressSection: some View { + Section { + ListRow(label: .default(title: L10n.screenStartChatJoinRoomByAddressAction, + icon: \.room), + kind: .navigationLink { + context.isJoinRoomByAddressSheetPresented = true + }) + } + } + /// The content shown in the form when a search query has been entered. @ViewBuilder private var searchContent: some View { diff --git a/PreviewTests/Sources/GeneratedPreviewTests.swift b/PreviewTests/Sources/GeneratedPreviewTests.swift index 32e3624d0a..9713e5de83 100644 --- a/PreviewTests/Sources/GeneratedPreviewTests.swift +++ b/PreviewTests/Sources/GeneratedPreviewTests.swift @@ -317,6 +317,12 @@ extension PreviewTests { } } + func test_joinRoomByAddressView() async throws { + for preview in JoinRoomByAddressView_Previews._allPreviews { + try await assertSnapshots(matching: preview) + } + } + func test_joinRoomScreen() async throws { for preview in JoinRoomScreen_Previews._allPreviews { try await assertSnapshots(matching: preview) From 5513764536f5cb01e8e015a51381bb17785565c7 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 26 Feb 2025 19:11:58 +0100 Subject: [PATCH 02/10] improved the text field typing --- .../Screens/StartChatScreen/View/JoinRoomByAddressView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index 6c5e9c3194..d93072dd64 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -49,6 +49,8 @@ struct JoinRoomByAddressView: View { .textFieldStyle(.authentication(labelText: L10n.screenStartChatJoinRoomByAddressAction, footerText: footerText, state: textFieldState)) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() .focused($textFieldFocus) Button(L10n.actionContinue) { From 58c49ba3fe200c4a69e3c8aface613e61bc976e7 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 26 Feb 2025 19:24:01 +0100 Subject: [PATCH 03/10] some improvements to how the text is edited --- .../Screens/StartChatScreen/View/JoinRoomByAddressView.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index d93072dd64..a03efccfd8 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -51,7 +51,11 @@ struct JoinRoomByAddressView: View { state: textFieldState)) .textInputAutocapitalization(.never) .autocorrectionDisabled() + .textContentType(.URL) .focused($textFieldFocus) + .onChange(of: context.roomAddress) { _, newValue in + context.roomAddress = newValue.trimmingCharacters(in: .whitespacesAndNewlines) + } Button(L10n.actionContinue) { context.send(viewAction: .joinRoomByAddress) From 335b9f7c3daff681098c6ca2b1f58983c29c68fd Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 26 Feb 2025 20:37:56 +0100 Subject: [PATCH 04/10] remove navigation link --- .../Sources/Screens/StartChatScreen/View/StartChatScreen.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift index 86fc62f4b9..35d755fef4 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift @@ -58,7 +58,7 @@ struct StartChatScreen: View { Section { ListRow(label: .default(title: L10n.screenStartChatJoinRoomByAddressAction, icon: \.room), - kind: .navigationLink { + kind: .button { context.isJoinRoomByAddressSheetPresented = true }) } From 037464c3027286ff90e05e44b4cec7c3d406cab8 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 27 Feb 2025 14:12:24 +0100 Subject: [PATCH 05/10] moved room directory search to the start chat flow --- ElementX.xcodeproj/project.pbxproj | 4 --- .../UserSessionFlowCoordinator.swift | 11 ++++---- .../HomeScreen/HomeScreenCoordinator.swift | 3 -- .../Screens/HomeScreen/HomeScreenModels.swift | 6 +--- .../HomeScreen/HomeScreenViewModel.swift | 6 ---- .../HomeScreen/View/HomeScreenRoomList.swift | 4 --- .../View/RoomDirectorySearchView.swift | 28 ------------------- .../StartChatScreenCoordinator.swift | 6 +++- .../StartChatScreenModels.swift | 3 ++ .../StartChatScreenViewModel.swift | 11 +++++++- .../View/JoinRoomByAddressView.swift | 3 +- .../View/StartChatScreen.swift | 18 +++++++++++- .../Sources/GeneratedPreviewTests.swift | 6 ---- .../Sources/StartChatViewModelTests.swift | 3 +- 14 files changed, 46 insertions(+), 66 deletions(-) delete mode 100644 ElementX/Sources/Screens/HomeScreen/View/RoomDirectorySearchView.swift diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 33d4d826f8..ef2d616b11 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -209,7 +209,6 @@ 2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; }; 27F015B0D5436633B5B3C8C3 /* SecureBackupRecoveryKeyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7061BE2C0BF427C38AEDEF5E /* SecureBackupRecoveryKeyScreenViewModel.swift */; }; 27FEF0F40750465195C9D6D6 /* RoomSelectionScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B9D191A81FFB0C72CE73E77 /* RoomSelectionScreenModels.swift */; }; - 2814E7075BF3A5C0CCBC9F90 /* RoomDirectorySearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */; }; 281BED345D59A9A6A99E9D98 /* UNNotificationContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE148A4FFEE853C5A281500C /* UNNotificationContent.swift */; }; 2835FD52F3F618D07F799B3D /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; }; 290FDB0FFDC2F1DDF660343E /* TestMeasurementParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */; }; @@ -1968,7 +1967,6 @@ 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 = ""; }; - 84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchView.swift; sourceTree = ""; }; 84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpiringTaskRunnerTests.swift; sourceTree = ""; }; 8512B82404B1751D0BCC82D2 /* MediaEventsTimelineScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaEventsTimelineScreenCoordinator.swift; sourceTree = ""; }; 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsEditScreenViewModelProtocol.swift; sourceTree = ""; }; @@ -3778,7 +3776,6 @@ 05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */, ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */, C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */, - 84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */, 037A5661B26EC6BE068188D7 /* Filters */, ); path = View; @@ -7376,7 +7373,6 @@ 49500BBA1CD65A5AE252D970 /* RoomDirectorySearchScreenModels.swift in Sources */, 91C6AC0E9D2B9C0C76CC6AD4 /* RoomDirectorySearchScreenScreenModelProtocol.swift in Sources */, 1DC227816777A2F3A19657E5 /* RoomDirectorySearchScreenViewModel.swift in Sources */, - 2814E7075BF3A5C0CCBC9F90 /* RoomDirectorySearchView.swift in Sources */, 42F1C8731166633E35A6D7E6 /* RoomEventStringBuilder.swift in Sources */, D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */, 9C63171267E22FEB288EC860 /* RoomHeaderView.swift in Sources */, diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index c2a93707b2..7a95b577ea 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -509,8 +509,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { stateMachine.processEvent(.showStartChatScreen) case .presentGlobalSearch: presentGlobalSearch() - case .presentRoomDirectorySearch: - stateMachine.processEvent(.showRoomDirectorySearchScreen) case .logoutWithoutConfirmation: self.actionsSubject.send(.logout) case .logout: @@ -654,10 +652,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { guard let self else { return } switch action { case .close: - self.navigationSplitCoordinator.setSheetCoordinator(nil) + navigationSplitCoordinator.setSheetCoordinator(nil) case .openRoom(let roomID): - self.navigationSplitCoordinator.setSheetCoordinator(nil) - self.stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .room)) + navigationSplitCoordinator.setSheetCoordinator(nil) + stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .room)) + case .openRoomDirectorySearch: + navigationSplitCoordinator.setSheetCoordinator(nil) + stateMachine.processEvent(.showRoomDirectorySearchScreen) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift index e46458fff9..a64bd7298e 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenCoordinator.swift @@ -25,7 +25,6 @@ enum HomeScreenCoordinatorAction { case presentEncryptionResetScreen case presentStartChatScreen case presentGlobalSearch - case presentRoomDirectorySearch case logoutWithoutConfirmation case logout } @@ -75,8 +74,6 @@ final class HomeScreenCoordinator: CoordinatorProtocol { actionsSubject.send(.presentStartChatScreen) case .presentGlobalSearch: actionsSubject.send(.presentGlobalSearch) - case .presentRoomDirectorySearch: - actionsSubject.send(.presentRoomDirectorySearch) case .logoutWithoutConfirmation: actionsSubject.send(.logoutWithoutConfirmation) case .logout: diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index 575f820751..501beedf05 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -20,7 +20,6 @@ enum HomeScreenViewModelAction: Equatable { case presentFeedbackScreen case presentStartChatScreen case presentGlobalSearch - case presentRoomDirectorySearch case logoutWithoutConfirmation case logout } @@ -41,7 +40,6 @@ enum HomeScreenViewAction { case markRoomAsUnread(roomIdentifier: String) case markRoomAsRead(roomIdentifier: String) case markRoomAsFavourite(roomIdentifier: String, isFavourite: Bool) - case selectRoomDirectorySearch case acceptInvite(roomIdentifier: String) case declineInvite(roomIdentifier: String) @@ -97,9 +95,7 @@ struct HomeScreenViewState: BindableState { var roomListMode: HomeScreenRoomListMode = .skeletons var hasPendingInvitations = false - - var isRoomDirectorySearchEnabled = false - + var selectedRoomID: String? var visibleRooms: [HomeScreenRoom] { diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 6229524e17..c036f15368 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -94,10 +94,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol .sink { [weak self] _ in self?.updateRooms() } .store(in: &cancellables) - appSettings.$publicSearchEnabled - .weakAssign(to: \.state.isRoomDirectorySearchEnabled, on: self) - .store(in: &cancellables) - appSettings.$seenInvites .removeDuplicates() .sink { [weak self] _ in @@ -194,8 +190,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol Task { await markRoomAsFavourite(roomIdentifier, isFavourite: isFavourite) } - case .selectRoomDirectorySearch: - actionsSubject.send(.presentRoomDirectorySearch) case .acceptInvite(let roomIdentifier): Task { await acceptInvite(roomID: roomIdentifier) diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift index 70edb0979b..233c522493 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomList.swift @@ -16,10 +16,6 @@ struct HomeScreenRoomList: View { // avoids glitches when focusing the search bar if !context.viewState.shouldHideRoomList { content - } else if context.viewState.isRoomDirectorySearchEnabled { - RoomDirectorySearchView { - context.send(viewAction: .selectRoomDirectorySearch) - } } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/RoomDirectorySearchView.swift b/ElementX/Sources/Screens/HomeScreen/View/RoomDirectorySearchView.swift deleted file mode 100644 index f882dfa3af..0000000000 --- a/ElementX/Sources/Screens/HomeScreen/View/RoomDirectorySearchView.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright 2024 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import Compound -import SwiftUI - -struct RoomDirectorySearchView: View { - let onTap: () -> Void - - var body: some View { - Button(action: onTap) { - Label(L10n.screenRoomlistRoomDirectoryButtonTitle, icon: \.listBulleted) - } - .buttonStyle(.compound(.super)) - .padding(.horizontal, 16) - .padding(.vertical, 8) - } -} - -struct RoomDirectorySearchView_Previews: PreviewProvider, TestablePreview { - static var previews: some View { - RoomDirectorySearchView { } - } -} diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift index 69b7364810..eb7497a970 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift @@ -20,6 +20,7 @@ struct StartChatScreenCoordinatorParameters { enum StartChatScreenCoordinatorAction { case close case openRoom(withIdentifier: String) + case openRoomDirectorySearch } final class StartChatScreenCoordinator: CoordinatorProtocol { @@ -48,7 +49,8 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { viewModel = StartChatScreenViewModel(userSession: parameters.userSession, analytics: ServiceLocator.shared.analytics, userIndicatorController: parameters.userIndicatorController, - userDiscoveryService: parameters.userDiscoveryService) + userDiscoveryService: parameters.userDiscoveryService, + appSettings: ServiceLocator.shared.settings) } func start() { @@ -62,6 +64,8 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { presentInviteUsersScreen() case .openRoom(let identifier): actionsSubject.send(.openRoom(withIdentifier: identifier)) + case .openRoomDirectorySearch: + actionsSubject.send(.openRoomDirectorySearch) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift index e97eb41a07..9a9dea6516 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift @@ -16,12 +16,14 @@ enum StartChatScreenViewModelAction { case close case createRoom case openRoom(withIdentifier: String) + case openRoomDirectorySearch } struct StartChatScreenViewState: BindableState { let userID: String var bindings = StartChatScreenViewStateBindings() var usersSection: UserDiscoverySection = .init(type: .suggestions, users: []) + var isRoomDirectoryEnabled = false var isSearching: Bool { !bindings.searchQuery.isEmpty @@ -51,6 +53,7 @@ enum StartChatScreenViewAction { case createDM(user: UserProfileProxy) case selectUser(UserProfileProxy) case joinRoomByAddress + case openRoomDirectorySearch } enum JoinByAddressState { diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index b36171a004..cadf68db96 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -16,6 +16,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie private let analytics: AnalyticsService private let userIndicatorController: UserIndicatorControllerProtocol private let userDiscoveryService: UserDiscoveryServiceProtocol + private let appSettings: AppSettings private var suggestedUsers = [UserProfileProxy]() @@ -27,11 +28,13 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie init(userSession: UserSessionProtocol, analytics: AnalyticsService, userIndicatorController: UserIndicatorControllerProtocol, - userDiscoveryService: UserDiscoveryServiceProtocol) { + userDiscoveryService: UserDiscoveryServiceProtocol, + appSettings: AppSettings) { self.userSession = userSession self.analytics = analytics self.userIndicatorController = userIndicatorController self.userDiscoveryService = userDiscoveryService + self.appSettings = appSettings super.init(initialViewState: StartChatScreenViewState(userID: userSession.clientProxy.userID), mediaProvider: userSession.mediaProvider) @@ -74,6 +77,8 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie Task { await createDirectRoom(user: user) } case .joinRoomByAddress: joinRoomByAddress() + case .openRoomDirectorySearch: + actionsSubject.send(.openRoomDirectorySearch) } } @@ -84,6 +89,10 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie private var internalRoomAddressState: JoinByAddressState = .example private func setupBindings() { + appSettings.$publicSearchEnabled + .weakAssign(to: \.state.isRoomDirectoryEnabled, on: self) + .store(in: &cancellables) + context.$viewState .map(\.bindings.searchQuery) .debounceTextQueriesAndRemoveDuplicates() diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index a03efccfd8..dfecb5627e 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -84,7 +84,8 @@ struct JoinRoomByAddressView_Previews: PreviewProvider, TestablePreview { let viewModel = StartChatScreenViewModel(userSession: userSession, analytics: ServiceLocator.shared.analytics, userIndicatorController: UserIndicatorControllerMock(), - userDiscoveryService: userDiscoveryService) + userDiscoveryService: userDiscoveryService, + appSettings: ServiceLocator.shared.settings) return viewModel }() diff --git a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift index 35d755fef4..8c15e3de30 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/StartChatScreen.swift @@ -49,6 +49,9 @@ struct StartChatScreen: View { @ViewBuilder private var mainContent: some View { createRoomSection + if context.viewState.isRoomDirectoryEnabled { + roomDirectorySearch + } inviteFriendsSection joinRoomByAddressSection usersSection @@ -64,6 +67,16 @@ struct StartChatScreen: View { } } + private var roomDirectorySearch: some View { + Section { + ListRow(label: .default(title: L10n.screenRoomDirectorySearchTitle, + icon: \.listBulleted), + kind: .navigationLink { + context.send(viewAction: .openRoomDirectorySearch) + }) + } + } + /// The content shown in the form when a search query has been entered. @ViewBuilder private var searchContent: some View { @@ -141,13 +154,16 @@ struct StartChatScreen: View { struct StartChatScreen_Previews: PreviewProvider, TestablePreview { static let viewModel = { + let appSettings = AppSettings() + appSettings.publicSearchEnabled = true let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "@userid:example.com")))) let userDiscoveryService = UserDiscoveryServiceMock() userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice]) let viewModel = StartChatScreenViewModel(userSession: userSession, analytics: ServiceLocator.shared.analytics, userIndicatorController: UserIndicatorControllerMock(), - userDiscoveryService: userDiscoveryService) + userDiscoveryService: userDiscoveryService, + appSettings: appSettings) return viewModel }() diff --git a/PreviewTests/Sources/GeneratedPreviewTests.swift b/PreviewTests/Sources/GeneratedPreviewTests.swift index 9713e5de83..0c1871b652 100644 --- a/PreviewTests/Sources/GeneratedPreviewTests.swift +++ b/PreviewTests/Sources/GeneratedPreviewTests.swift @@ -653,12 +653,6 @@ extension PreviewTests { } } - func test_roomDirectorySearchView() async throws { - for preview in RoomDirectorySearchView_Previews._allPreviews { - try await assertSnapshots(matching: preview) - } - } - func test_roomHeaderView() async throws { for preview in RoomHeaderView_Previews._allPreviews { try await assertSnapshots(matching: preview) diff --git a/UnitTests/Sources/StartChatViewModelTests.swift b/UnitTests/Sources/StartChatViewModelTests.swift index 177ca7c800..b88821e499 100644 --- a/UnitTests/Sources/StartChatViewModelTests.swift +++ b/UnitTests/Sources/StartChatViewModelTests.swift @@ -27,7 +27,8 @@ class StartChatScreenViewModelTests: XCTestCase { viewModel = StartChatScreenViewModel(userSession: userSession, analytics: ServiceLocator.shared.analytics, userIndicatorController: UserIndicatorControllerMock(), - userDiscoveryService: userDiscoveryService) + userDiscoveryService: userDiscoveryService, + appSettings: ServiceLocator.shared.settings) } func testQueryShowingNoResults() async throws { From 36be1c5e3cd16a1c17b2decd1b21b1cd8722f413 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 27 Feb 2025 15:41:51 +0100 Subject: [PATCH 06/10] updated preview tests --- .../UserSessionFlowCoordinator.swift | 4 +- .../AuthenticationTextFieldStyle.swift | 53 ++++++++++--------- .../Sources/GeneratedPreviewTests.swift | 6 +++ ...est_elementTextFieldStyle-iPad-en-GB.1.png | 3 ++ ...st_elementTextFieldStyle-iPad-pseudo.1.png | 3 ++ ...lementTextFieldStyle-iPhone-16-en-GB.1.png | 3 ++ ...ementTextFieldStyle-iPhone-16-pseudo.1.png | 3 ++ ...est_joinRoomByAddressView-iPad-en-GB.1.png | 3 ++ ...st_joinRoomByAddressView-iPad-pseudo.1.png | 3 ++ ...oinRoomByAddressView-iPhone-16-en-GB.1.png | 3 ++ ...inRoomByAddressView-iPhone-16-pseudo.1.png | 3 ++ ...t_roomDirectorySearchView-iPad-en-GB.1.png | 3 -- ..._roomDirectorySearchView-iPad-pseudo.1.png | 3 -- ...mDirectorySearchView-iPhone-16-en-GB.1.png | 3 -- ...DirectorySearchView-iPhone-16-pseudo.1.png | 3 -- .../test_serverSelection-iPad-en-GB.1.png | 4 +- .../test_serverSelection-iPad-en-GB.2.png | 4 +- .../test_serverSelection-iPad-en-GB.3.png | 4 +- .../test_serverSelection-iPad-en-GB.4.png | 3 -- .../test_serverSelection-iPad-pseudo.1.png | 4 +- .../test_serverSelection-iPad-pseudo.2.png | 4 +- .../test_serverSelection-iPad-pseudo.3.png | 4 +- .../test_serverSelection-iPad-pseudo.4.png | 3 -- ...test_serverSelection-iPhone-16-en-GB.1.png | 4 +- ...test_serverSelection-iPhone-16-en-GB.2.png | 4 +- ...test_serverSelection-iPhone-16-en-GB.3.png | 4 +- ...test_serverSelection-iPhone-16-en-GB.4.png | 3 -- ...est_serverSelection-iPhone-16-pseudo.1.png | 4 +- ...est_serverSelection-iPhone-16-pseudo.2.png | 4 +- ...est_serverSelection-iPhone-16-pseudo.3.png | 4 +- ...est_serverSelection-iPhone-16-pseudo.4.png | 3 -- .../test_startChatScreen-iPad-en-GB.1.png | 4 +- .../test_startChatScreen-iPad-pseudo.1.png | 4 +- ...test_startChatScreen-iPhone-16-en-GB.1.png | 4 +- ...est_startChatScreen-iPhone-16-pseudo.1.png | 4 +- 35 files changed, 90 insertions(+), 85 deletions(-) create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-en-GB.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-pseudo.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-en-GB.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-pseudo.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-en-GB.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-pseudo.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-en-GB.1.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-pseudo.1.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-en-GB.1.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-pseudo.1.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-en-GB.1.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-pseudo.1.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.4.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.4.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.4.png delete mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.4.png diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 7a95b577ea..43bee11372 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -669,9 +669,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { self?.stateMachine.processEvent(.dismissedStartChatScreen) } } - - // MARK: Session Verification - + // MARK: Calls private func presentCallScreen(genericCallLink url: URL) { diff --git a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift b/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift index d42c8b5cd5..2487bc841f 100644 --- a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift +++ b/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift @@ -180,33 +180,34 @@ struct AuthenticationTextFieldStyle: TextFieldStyle { } } -struct ElementTextFieldStyle_Previews: PreviewProvider { +struct ElementTextFieldStyle_Previews: PreviewProvider, TestablePreview { static var previews: some View { - ScrollView { - VStack(spacing: 20) { - // Plain text field. - TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication()) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication()) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication()) - .disabled(true) - TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication(state: .error)) - - // Text field with labels - TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication(labelText: "Label", footerText: "Footer")) - TextField("Placeholder", text: .constant("Input text")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) - TextField("Placeholder", text: .constant("Bad text")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .error)) - TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) - .disabled(true) - } - .padding() + VStack(spacing: 20) { + // Plain text field. + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.authentication()) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.authentication()) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.authentication()) + .disabled(true) + TextField("Placeholder", text: .constant("Web")) + .textFieldStyle(.authentication(state: .error)) + + // Text field with labels + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.authentication(labelText: "Label", footerText: "Footer")) + TextField("Placeholder", text: .constant("Input text")) + .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) + TextField("Placeholder", text: .constant("Bad text")) + .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .error)) + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) + .disabled(true) + TextField("Placeholder", text: .constant("")) + .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .success)) } + .previewLayout(.sizeThatFits) + .padding() } } diff --git a/PreviewTests/Sources/GeneratedPreviewTests.swift b/PreviewTests/Sources/GeneratedPreviewTests.swift index 0c1871b652..32422d69b6 100644 --- a/PreviewTests/Sources/GeneratedPreviewTests.swift +++ b/PreviewTests/Sources/GeneratedPreviewTests.swift @@ -149,6 +149,12 @@ extension PreviewTests { } } + func test_elementTextFieldStyle() async throws { + for preview in ElementTextFieldStyle_Previews._allPreviews { + try await assertSnapshots(matching: preview) + } + } + func test_emojiPickerScreenHeaderView() async throws { for preview in EmojiPickerScreenHeaderView_Previews._allPreviews { try await assertSnapshots(matching: preview) diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-en-GB.1.png new file mode 100644 index 0000000000..d5265b92c2 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d70b6990d2e5b30be2fb6b2d77e99c36ea991988413cb9eea85df21c8cc1e87f +size 130748 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-pseudo.1.png new file mode 100644 index 0000000000..453391764d --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfbb5285937c97a49e6a1fb294af3812dd24b24b2468d9f23e4f738da30bb01a +size 134239 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-en-GB.1.png new file mode 100644 index 0000000000..b50389b156 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:11435b5e7c43b3f82305949a50612b47956a966b38483156deacdf1d0fce0a96 +size 80327 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-pseudo.1.png new file mode 100644 index 0000000000..71fde0291f --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_elementTextFieldStyle-iPhone-16-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f682f709d87e02acb31f79961c25a54c103ee196ba737e49dbf59b62ed80d56d +size 83639 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-en-GB.1.png new file mode 100644 index 0000000000..249ad4f628 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ed827a1241328c2590775aff6c4590f6c138a52a59720c26a12b36f038d0d8e +size 85554 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-pseudo.1.png new file mode 100644 index 0000000000..7e8748c0ef --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPad-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b5eaff68a99823f23694cf25956308da24a7e9389719b8ac2bd8ef7fbe56c32 +size 91105 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-en-GB.1.png new file mode 100644 index 0000000000..84cc4334c7 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-en-GB.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19b17304e85bc9d90b8e8cbfec9563a13199674abbbe114fa5e5211afc881292 +size 42071 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-pseudo.1.png new file mode 100644 index 0000000000..a86ff1cb52 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_joinRoomByAddressView-iPhone-16-pseudo.1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f3804bf6226d2bf0b7c378dd1a2974fb5612ad8b75d957072e11447e6e1cbf6 +size 48049 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-en-GB.1.png deleted file mode 100644 index 2f742761eb..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-en-GB.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b27b1d0c202e4e68b33e968c6d0e1323d38e06b831c1e7b4c54483af3c265ad7 -size 94410 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-pseudo.1.png deleted file mode 100644 index abf23e6f3b..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPad-pseudo.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:70dae5ed165df76d10601222a281b154dbc9524f46dfba27e60425ecd33b39c1 -size 96554 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-en-GB.1.png deleted file mode 100644 index 5710819189..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-en-GB.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cdd1ad6f323ae9458d88e4e88fd7802171348477114e71a9301dbc6046e8671a -size 43627 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-pseudo.1.png deleted file mode 100644 index 5eacb23859..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomDirectorySearchView-iPhone-16-pseudo.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d9b252d8d0be84d5cb25c507f46a15e6001600c52c3bee0edce5ac76e4fc629 -size 48201 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.1.png index 90ba98db03..77d01d8ff3 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8b491ed0dec54d7a2f3a584b077b8ad7cf2754a1bf2d330056740b3a49bca12 -size 119704 +oid sha256:e99c82a32fe8ca56727259eeec932e5fc732c2315f62c9698fa165e8d0ead64d +size 120770 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.2.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.2.png index 06455e220e..0568987012 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.2.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1568aeab5ed2fa5b9b7cfb2c7831ab5fb8e60347993bdfff5ac88ddd77a994ea -size 116774 +oid sha256:fd1e150ca89274c128c1415f6c7469042b2b6b711628c795d652158b337573a7 +size 117593 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png index 87c5f78675..c6e979c227 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19589d86321fa6347cce9a2dd229915e3c154d0544b6755bb4616ed11aec11d5 -size 120953 +oid sha256:f172de4c7661d7aa39ad580585e82f771be569b6351567b84b5fd2628f67922d +size 124754 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.4.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.4.png deleted file mode 100644 index bd451c4715..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5ded2fed9334df463a22744183966ac301d7a313f79f4778aa0da4608a75246 -size 116706 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.1.png index 0ee4bea59f..11ef442cb7 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24347f1d5e2940457895544373800ecb5fa90adf742c007cd3ec949b8b5481e6 -size 140253 +oid sha256:e021af7a5e5de6cf6405d673db82335edca645d71f37817409bea68ba53f078a +size 141761 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.2.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.2.png index ac9e66d4e7..a7e24b7364 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.2.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42369c71ada7f05b6c14ea1c479b2417647d9e4a86f0601b04f74e6153ce2922 -size 138013 +oid sha256:6872f520a4f6c79cdeb55d20991d7bf61280a587fe80250df8b10204d05498d5 +size 139516 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png index 6abe1c16ec..6bdcea382f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b59507030a14739ae053cabff10de7ecc336c9e68815a9a2889f881f4535415 -size 145823 +oid sha256:b078e48fa9aa152fa489dceda0a1647c97092139938aeab8f327bde3244dab7f +size 153056 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.4.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.4.png deleted file mode 100644 index a2161add39..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0584b2d8cbec2a452768cabaeeae605e2d88b4139d3f1bb3236aaf4cd90d6d89 -size 136993 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.1.png index 810cf610d6..a1472c4d87 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba29b8a0d4484e5863850bbb8c5b00a4248f98bc6c5e74f09e71635e0e90ca48 -size 71280 +oid sha256:0a812bea493335fedd3e61b13e983e677bd5b6b774d5a6348cfa64737ab971a8 +size 74403 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.2.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.2.png index 950a803833..bd4f61be9f 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.2.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5e5fc7b4b029fe17b64bd71b9e8a0ff4c707c1217748f837603d9d4d5ae66af -size 69040 +oid sha256:4e7b4889100a17b7de624facebb50b75baf42a91d3d2109f95610ed03c5a5911 +size 72168 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png index 78ca3fc5c7..9c09aaff9e 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7337fba28d597a810e92e6d593d635dee1ed4eb8c0bc5eb3e6fd9dc30d30626 -size 75140 +oid sha256:1891577eccb937d0cafaadcce9c5139a89f7df7c5c79fae5e26615bc49204d21 +size 78057 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.4.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.4.png deleted file mode 100644 index e671ffc30a..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6e085e029fba474fb1517601820eae64ac1f249265270cea7d610f1857c42631 -size 67841 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.1.png index b8aaa041ff..633f7cf8cb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c49d85e92d835667b8ec14ca33a48327af2d7523c1c5f234dda40fb3db43e1f0 -size 95613 +oid sha256:062ec9c67e3326551bd45bb0396f25922b688ee6ad754be3216e64d7ba4fa434 +size 100639 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.2.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.2.png index d6cb2f27f9..bbdb195ff2 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.2.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:612ed87898b58482546cb55f36694849daf6edf69c94f28adee957f5af56d3c8 -size 93536 +oid sha256:9200e97526e1162831625c07251ec37073093be66b958f13b6bfa3eb0f41e80d +size 98530 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png index 088f7036b0..50c9504259 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01b30b881e41dc1646a8c2870898bcf4dc54ed61afd7b6a5b06315562c9b7bca -size 103292 +oid sha256:a027ac57a10e25574278f4377bf140fbbd6eb5dcc134fac78e070dc793e2b828 +size 110877 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.4.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.4.png deleted file mode 100644 index b2e75c5a10..0000000000 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:35cbe71d813db5883aece477676ed1fd4038b67bd5deacfa2957568510e41789 -size 92671 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-en-GB.1.png index 6c58fdcb2d..a5c69df28c 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-en-GB.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64090eca5f21a657af2f6f51b64e036a6a404a1db8577c39628c1275b5f7c98f -size 98588 +oid sha256:4b196b0c7ef95387b7e2643e421a7acebec2bd26a4320c470d604f9710f3a1b4 +size 114304 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-pseudo.1.png index 6d0ba01c0b..352539460c 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-pseudo.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:856c98734ddb0d538b17f3a0e4a9abfb4f141703850704ff83abd36332c214c0 -size 104603 +oid sha256:2f296669d40a83c27c5ca06428a7e0e42606a39ea0c9b8ff622b62fba78adc25 +size 121582 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-en-GB.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-en-GB.1.png index da668e56e0..f0f14cd608 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-en-GB.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5bf28ddbc247642cc1b233ceaa0a57023684cf1d97284f4c2ed47c1dfce2af19 -size 51119 +oid sha256:5d6baf08670cc76a5522c8b99a9c83aa25e78c4ed7ecb168b63618830e1a0669 +size 63935 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-pseudo.1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-pseudo.1.png index dd734b3400..7d98d7b4eb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-pseudo.1.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_startChatScreen-iPhone-16-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39a516943fec545ff1bc26f34fb31567c4205c5060395260e30fb07d540ae42e -size 58735 +oid sha256:07e29fb97f007495dec1a3635dfd8185d6a38240dc32079cdeba13d25905c93b +size 79420 From 7ab474f5a3ceaee85c1f7a631f8739e5a7f55f26 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Thu, 27 Feb 2025 19:46:18 +0100 Subject: [PATCH 07/10] added unit tests and improved the code --- .../StartChatScreenModels.swift | 4 +- .../StartChatScreenViewModel.swift | 71 +++++++++++++------ .../View/JoinRoomByAddressView.swift | 2 +- .../Sources/StartChatViewModelTests.swift | 37 ++++++++++ 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift index 9a9dea6516..9c989feb73 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift @@ -12,7 +12,7 @@ enum StartChatScreenErrorType: Error { case unknown } -enum StartChatScreenViewModelAction { +enum StartChatScreenViewModelAction: Equatable { case close case createRoom case openRoom(withIdentifier: String) @@ -56,7 +56,7 @@ enum StartChatScreenViewAction { case openRoomDirectorySearch } -enum JoinByAddressState { +enum JoinByAddressState: Equatable { case example case invalidAddress case addressNotFound diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index cadf68db96..3204532f22 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -103,40 +103,62 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie context.$viewState .map(\.bindings.roomAddress) - .debounceTextQueriesAndRemoveDuplicates() - .sink { [weak self] roomAddress in + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in guard let self else { return } - state.joinByAddressState = .example internalRoomAddressState = .example - - guard !roomAddress.isEmpty, - isRoomAliasFormatValid(alias: roomAddress) else { - internalRoomAddressState = .invalidAddress + } + .store(in: &cancellables) + + context.$viewState + .map(\.bindings.roomAddress) + .debounce(for: .milliseconds(250), scheduler: DispatchQueue.main) + .removeDuplicates() + .sink { [weak self] roomAddress in + guard let self else { return } - - resolveAliasTask = Task { [weak self] in - guard let self else { - return - } - defer { resolveAliasTask = nil } - - guard case let .success(resolved) = await userSession.clientProxy.resolveRoomAlias(roomAddress) else { - internalRoomAddressState = .addressNotFound - return - } - - let result = JoinByAddressState.addressFound(address: roomAddress, roomID: resolved.roomId) - internalRoomAddressState = result - state.joinByAddressState = result - } + resolveRoomAddress(roomAddress) } .store(in: &cancellables) } + private func resolveRoomAddress(_ roomAddress: String) { + guard !roomAddress.isEmpty, + isRoomAliasFormatValid(alias: roomAddress) else { + internalRoomAddressState = .invalidAddress + resolveAliasTask = nil + return + } + + resolveAliasTask = Task { [weak self] in + guard let self else { + return + } + defer { resolveAliasTask = nil } + + guard case let .success(resolved) = await userSession.clientProxy.resolveRoomAlias(roomAddress) else { + if Task.isCancelled { + return + } + internalRoomAddressState = .addressNotFound + return + } + + guard !Task.isCancelled else { + return + } + + let result = JoinByAddressState.addressFound(address: roomAddress, roomID: resolved.roomId) + internalRoomAddressState = result + state.joinByAddressState = result + } + } + // periphery:ignore - auto cancels when reassigned @CancellableTask private var fetchUsersTask: Task? @@ -193,6 +215,9 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie hideLoadingIndicator() joinRoomByAddress() } + } else if internalRoomAddressState == .example { + resolveRoomAddress(state.bindings.roomAddress) + joinRoomByAddress() } else { state.joinByAddressState = internalRoomAddressState } diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index dfecb5627e..82404432b0 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -24,7 +24,7 @@ struct JoinRoomByAddressView: View { case .addressNotFound: L10n.screenStartChatJoinRoomByAddressRoomNotFound case .addressFound: - L10n.screenStartChatJoinRoomByAddressRoomNotFound + L10n.screenStartChatJoinRoomByAddressRoomFound case .invalidAddress: L10n.screenStartChatJoinRoomByAddressInvalidAddress } diff --git a/UnitTests/Sources/StartChatViewModelTests.swift b/UnitTests/Sources/StartChatViewModelTests.swift index b88821e499..d38871c85f 100644 --- a/UnitTests/Sources/StartChatViewModelTests.swift +++ b/UnitTests/Sources/StartChatViewModelTests.swift @@ -45,6 +45,43 @@ class StartChatScreenViewModelTests: XCTestCase { XCTAssertTrue(userDiscoveryService.searchProfilesWithCalled) } + func testJoinRoomByAddress() async throws { + clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "id", servers: [])) + viewModel.context.roomAddress = "#room:example.com" + + let deferredViewState = deferFulfillment(viewModel.context.$viewState) { viewState in + viewState.joinByAddressState == .addressFound(address: "#room:example.com", roomID: "id") + } + try await deferredViewState.fulfill() + + let deferredAction = deferFulfillment(viewModel.actions) { action in + action == .openRoom(withIdentifier: "id") + } + context.send(viewAction: .joinRoomByAddress) + try await deferredAction.fulfill() + } + + func testJoinRoomByAddressFailsBecauseInvalid() async throws { + viewModel.context.roomAddress = ":" + + let deferred = deferFulfillment(viewModel.context.$viewState) { viewState in + viewState.joinByAddressState == .invalidAddress + } + context.send(viewAction: .joinRoomByAddress) + try await deferred.fulfill() + } + + func testJoinRoomByAddressFailsBecauseNotFound() async throws { + clientProxy.resolveRoomAliasReturnValue = .failure(.failedResolvingRoomAlias) + viewModel.context.roomAddress = "#room:example.com" + + let deferred = deferFulfillment(viewModel.context.$viewState) { viewState in + viewState.joinByAddressState == .addressNotFound + } + context.send(viewAction: .joinRoomByAddress) + try await deferred.fulfill() + } + // MARK: - Private private func assertSearchResults(toBe count: Int) { From 0bec634814876865c396379b15d23fae19db44bb Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 28 Feb 2025 11:10:27 +0100 Subject: [PATCH 08/10] updated strings --- .../Localizations/en-US.lproj/Localizable.strings | 2 +- .../Resources/Localizations/en.lproj/Localizable.strings | 2 +- ElementX/Sources/Generated/Strings.swift | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings b/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings index 67b1fb9c78..e681ac4f30 100644 --- a/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings @@ -480,6 +480,7 @@ "screen_security_and_privacy_room_publishing_section_header" = "Room publishing"; "screen_security_and_privacy_room_visibility_section_footer" = "Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.\nThe address is also required to make the room visible in %1$@ public room directory."; "screen_security_and_privacy_title" = "Security & privacy"; +"screen_start_chat_join_room_by_address_action" = "Join room by address"; "screen_start_chat_join_room_by_address_invalid_address" = "Not a valid address"; "screen_start_chat_join_room_by_address_placeholder" = "Enter..."; "screen_start_chat_join_room_by_address_room_found" = "Matching room found"; @@ -488,7 +489,6 @@ "screen_timeline_item_menu_send_failure_changed_identity" = "Message not sent because %1$@’s verified identity has changed."; "screen_timeline_item_menu_send_failure_unsigned_device" = "Message not sent because %1$@ has not verified all devices."; "screen_timeline_item_menu_send_failure_you_unsigned_device" = "Message not sent because you have not verified one or more of your devices."; -"screen.start_chat.join_room_by_address_action" = "Join room by address"; "screen_account_provider_form_hint" = "Homeserver address"; "screen_account_provider_form_notice" = "Enter a search term or a domain address."; "screen_account_provider_form_subtitle" = "Search for a company, community, or private server."; diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index d42cde4222..e335a6de67 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -480,6 +480,7 @@ "screen_security_and_privacy_room_publishing_section_header" = "Room publishing"; "screen_security_and_privacy_room_visibility_section_footer" = "Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.\nThe address is also required to make the room visible in %1$@ public room directory."; "screen_security_and_privacy_title" = "Security & privacy"; +"screen_start_chat_join_room_by_address_action" = "Join room by address"; "screen_start_chat_join_room_by_address_invalid_address" = "Not a valid address"; "screen_start_chat_join_room_by_address_placeholder" = "Enter..."; "screen_start_chat_join_room_by_address_room_found" = "Matching room found"; @@ -488,7 +489,6 @@ "screen_timeline_item_menu_send_failure_changed_identity" = "Message not sent because %1$@’s verified identity has changed."; "screen_timeline_item_menu_send_failure_unsigned_device" = "Message not sent because %1$@ has not verified all devices."; "screen_timeline_item_menu_send_failure_you_unsigned_device" = "Message not sent because you have not verified one or more of your devices."; -"screen.start_chat.join_room_by_address_action" = "Join room by address"; "screen_account_provider_form_hint" = "Homeserver address"; "screen_account_provider_form_notice" = "Enter a search term or a domain address."; "screen_account_provider_form_subtitle" = "Search for a company, community, or private server."; diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 6b32fed3bd..95dfd6fd31 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -2460,6 +2460,8 @@ internal enum L10n { internal static var screenSignoutSaveRecoveryKeyTitle: String { return L10n.tr("Localizable", "screen_signout_save_recovery_key_title") } /// An error occurred when trying to start a chat internal static var screenStartChatErrorStartingChat: String { return L10n.tr("Localizable", "screen_start_chat_error_starting_chat") } + /// Join room by address + internal static var screenStartChatJoinRoomByAddressAction: String { return L10n.tr("Localizable", "screen_start_chat_join_room_by_address_action") } /// Not a valid address internal static var screenStartChatJoinRoomByAddressInvalidAddress: String { return L10n.tr("Localizable", "screen_start_chat_join_room_by_address_invalid_address") } /// Enter... @@ -2874,13 +2876,6 @@ internal enum L10n { /// You internal static var you: String { return L10n.tr("Localizable", "common.you") } } - - internal enum Screen { - internal enum StartChat { - /// Join room by address - internal static var joinRoomByAddressAction: String { return L10n.tr("Localizable", "screen.start_chat.join_room_by_address_action") } - } - } } // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces From a012cad4652a236e7edb7e52d2ffc6681fec1ca9 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 28 Feb 2025 12:04:53 +0100 Subject: [PATCH 09/10] some pr suggestions: - moving the file - changing the name of the action - reintroduce the debounce text queries - add comments --- ElementX.xcodeproj/project.pbxproj | 2 +- .../Styles}/AuthenticationTextFieldStyle.swift | 13 +++++++------ .../StartChatScreenCoordinator.swift | 2 +- .../StartChatScreen/StartChatScreenModels.swift | 2 +- .../StartChatScreen/StartChatScreenViewModel.swift | 11 ++++++----- UnitTests/Sources/StartChatViewModelTests.swift | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) rename ElementX/Sources/{Screens/Authentication => Other/SwiftUI/Styles}/AuthenticationTextFieldStyle.swift (98%) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index ef2d616b11..4d7c98d4c2 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -5763,6 +5763,7 @@ E6E1D07163F8752D62DA4A93 /* Styles */ = { isa = PBXGroup; children = ( + CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */, 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */, ); path = Styles; @@ -5795,7 +5796,6 @@ E74CD7681375AD2EAA34D66B /* Authentication */ = { isa = PBXGroup; children = ( - CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */, 92390F9FA98255440A6BF5F8 /* OIDCAuthenticationPresenter.swift */, 9E6D88E8AFFBF2C1D589C0FA /* UIConstants.swift */, 90F48FEF84016ED42A94BA24 /* LoginScreen */, diff --git a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift b/ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift similarity index 98% rename from ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift rename to ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift index 2487bc841f..8f4f17b28f 100644 --- a/ElementX/Sources/Screens/Authentication/AuthenticationTextFieldStyle.swift +++ b/ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift @@ -157,7 +157,12 @@ struct AuthenticationTextFieldStyle: TextFieldStyle { } if let footerText { - HStack(spacing: 4) { + Label { + footerText + .tint(.compound.textLinkExternal) + .font(.compound.bodySM) + .foregroundColor(footerTextColor) + } icon: { switch state { case .success: CompoundIcon(\.checkCircleSolid, size: .xSmall, relativeTo: .compound.bodySM) @@ -168,12 +173,8 @@ struct AuthenticationTextFieldStyle: TextFieldStyle { case .default: EmptyView() } - - footerText - .tint(.compound.textLinkExternal) - .font(.compound.bodySM) - .foregroundColor(footerTextColor) } + .labelStyle(.custom(spacing: 4, alignment: .top)) .padding(.horizontal, 16) } } diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift index eb7497a970..59de3b6ae3 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenCoordinator.swift @@ -62,7 +62,7 @@ final class StartChatScreenCoordinator: CoordinatorProtocol { case .createRoom: // before creating a room we select the users we would like to invite in that room presentInviteUsersScreen() - case .openRoom(let identifier): + case .showRoom(let identifier): actionsSubject.send(.openRoom(withIdentifier: identifier)) case .openRoomDirectorySearch: actionsSubject.send(.openRoomDirectorySearch) diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift index 9c989feb73..af71a3fac5 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenModels.swift @@ -15,7 +15,7 @@ enum StartChatScreenErrorType: Error { enum StartChatScreenViewModelAction: Equatable { case close case createRoom - case openRoom(withIdentifier: String) + case showRoom(withIdentifier: String) case openRoomDirectorySearch } diff --git a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift index 3204532f22..5f5c6c8d37 100644 --- a/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift +++ b/ElementX/Sources/Screens/StartChatScreen/StartChatScreenViewModel.swift @@ -64,7 +64,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie switch currentDirectRoom { case .success(.some(let roomId)): hideLoadingIndicator() - actionsSubject.send(.openRoom(withIdentifier: roomId)) + actionsSubject.send(.showRoom(withIdentifier: roomId)) case .success: hideLoadingIndicator() state.bindings.selectedUserToInvite = user @@ -116,8 +116,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie context.$viewState .map(\.bindings.roomAddress) - .debounce(for: .milliseconds(250), scheduler: DispatchQueue.main) - .removeDuplicates() + .debounceTextQueriesAndRemoveDuplicates() .sink { [weak self] roomAddress in guard let self else { return @@ -191,7 +190,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie switch await userSession.clientProxy.createDirectRoom(with: user.userID, expectedRoomName: user.displayName) { case .success(let roomId): analytics.trackCreatedRoom(isDM: true) - actionsSubject.send(.openRoom(withIdentifier: roomId)) + actionsSubject.send(.showRoom(withIdentifier: roomId)) case .failure: displayError() } @@ -206,7 +205,7 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie private func joinRoomByAddress() { if case let .addressFound(lastTestedAddress, roomID) = internalRoomAddressState, lastTestedAddress == state.bindings.roomAddress { - actionsSubject.send(.openRoom(withIdentifier: roomID)) + actionsSubject.send(.showRoom(withIdentifier: roomID)) } else if let resolveAliasTask { // If the task is still running we wait for it to complete and we check the state again showLoadingIndicator(delay: .milliseconds(250)) @@ -216,9 +215,11 @@ class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenVie joinRoomByAddress() } } else if internalRoomAddressState == .example { + // If we are in the example state internally, this means that the task has not started yet so we start it, and the check the state again resolveRoomAddress(state.bindings.roomAddress) joinRoomByAddress() } else { + // In any other case we just use the internal state state.joinByAddressState = internalRoomAddressState } } diff --git a/UnitTests/Sources/StartChatViewModelTests.swift b/UnitTests/Sources/StartChatViewModelTests.swift index d38871c85f..3b194459d5 100644 --- a/UnitTests/Sources/StartChatViewModelTests.swift +++ b/UnitTests/Sources/StartChatViewModelTests.swift @@ -55,7 +55,7 @@ class StartChatScreenViewModelTests: XCTestCase { try await deferredViewState.fulfill() let deferredAction = deferFulfillment(viewModel.actions) { action in - action == .openRoom(withIdentifier: "id") + action == .showRoom(withIdentifier: "id") } context.send(viewAction: .joinRoomByAddress) try await deferredAction.fulfill() From 84bf3b8477fa24da9bd44b7abe71d8fff8d9b89e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 28 Feb 2025 12:18:47 +0100 Subject: [PATCH 10/10] renamed the auth text field style to Element updated tests --- ElementX.xcodeproj/project.pbxproj | 8 +-- ...tyle.swift => ElementTextFieldStyle.swift} | 56 +++++++++---------- .../LoginScreen/View/LoginScreen.swift | 4 +- .../View/ServerSelectionScreen.swift | 8 +-- .../View/SoftLogoutScreen.swift | 2 +- .../View/JoinRoomByAddressView.swift | 8 +-- .../test_serverSelection-iPad-en-GB.3.png | 4 +- .../test_serverSelection-iPad-pseudo.3.png | 4 +- ...test_serverSelection-iPhone-16-en-GB.3.png | 4 +- ...est_serverSelection-iPhone-16-pseudo.3.png | 4 +- .../Sources/StartChatViewModelTests.swift | 7 +-- 11 files changed, 54 insertions(+), 55 deletions(-) rename ElementX/Sources/Other/SwiftUI/Styles/{AuthenticationTextFieldStyle.swift => ElementTextFieldStyle.swift} (76%) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 4d7c98d4c2..1968cd1b7c 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -485,7 +485,7 @@ 601AB75BD52B0B4276CEB84A /* SessionVerificationScreenStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161CD412E75F4086F422AE39 /* SessionVerificationScreenStateMachine.swift */; }; 60ED66E63A169E47489348A8 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 886A0A498FA01E8EDD451D05 /* Sentry */; }; 611BEE29B8B622204E1E6B04 /* SecurityAndPrivacyScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97F2F6B6E56055EF173A2DD3 /* SecurityAndPrivacyScreenCoordinator.swift */; }; - 6146996D5C4DDD5DA816FC87 /* AuthenticationTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */; }; + 6146996D5C4DDD5DA816FC87 /* ElementTextFieldStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCACD75595C40EACD6AD4A74 /* ElementTextFieldStyle.swift */; }; 617624A97BDBB75ED3DD8156 /* RoomScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00C7A331B72C0F05C00392F /* RoomScreenViewModelProtocol.swift */; }; 6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */; }; 61941DEE5F3834765770BE01 /* InviteUsersScreenSelectedItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10F32E0B4B83D2A11EE8D011 /* InviteUsersScreenSelectedItem.swift */; }; @@ -2330,7 +2330,7 @@ CC437C491EA6996513B1CEAB /* ElementCallConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementCallConfiguration.swift; sourceTree = ""; }; CC680E0E79D818706CB28CF8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarHeaderView.swift; sourceTree = ""; }; - CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationTextFieldStyle.swift; sourceTree = ""; }; + CCACD75595C40EACD6AD4A74 /* ElementTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementTextFieldStyle.swift; sourceTree = ""; }; CCF71646898A2F720C5BFDF5 /* RoomDirectorySearchScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreenViewModel.swift; sourceTree = ""; }; CD469F7513574341181F7EAA /* ServerSelectionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreen.swift; sourceTree = ""; }; CD6613DE16AD26B3A74DA1F5 /* LocationRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRoomTimelineItemContent.swift; sourceTree = ""; }; @@ -5763,7 +5763,7 @@ E6E1D07163F8752D62DA4A93 /* Styles */ = { isa = PBXGroup; children = ( - CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */, + CCACD75595C40EACD6AD4A74 /* ElementTextFieldStyle.swift */, 89FBFC09F9DAFF1E4BA97849 /* FormButtonStyles.swift */, ); path = Styles; @@ -6911,7 +6911,7 @@ 0E3A2787C6AEC761A81A938A /* AuthenticationStartScreenModels.swift in Sources */, E79B247A6DD28759636317EA /* AuthenticationStartScreenViewModel.swift in Sources */, 874FEFB9D4A4AF447E0E086E /* AuthenticationStartScreenViewModelProtocol.swift in Sources */, - 6146996D5C4DDD5DA816FC87 /* AuthenticationTextFieldStyle.swift in Sources */, + 6146996D5C4DDD5DA816FC87 /* ElementTextFieldStyle.swift in Sources */, 4AAA8606FBA290E23D15422E /* AvatarHeaderView.swift in Sources */, 1621BF6316FFFEF5AE067C77 /* Avatars.swift in Sources */, 7A25D6926A2C01DB8D0D67A5 /* BadgeLabel.swift in Sources */, diff --git a/ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift b/ElementX/Sources/Other/SwiftUI/Styles/ElementTextFieldStyle.swift similarity index 76% rename from ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift rename to ElementX/Sources/Other/SwiftUI/Styles/ElementTextFieldStyle.swift index 8f4f17b28f..207d7da96f 100644 --- a/ElementX/Sources/Other/SwiftUI/Styles/AuthenticationTextFieldStyle.swift +++ b/ElementX/Sources/Other/SwiftUI/Styles/ElementTextFieldStyle.swift @@ -9,31 +9,31 @@ import Compound import SwiftUI import SwiftUIIntrospect -extension TextFieldStyle where Self == AuthenticationTextFieldStyle { - static func authentication(labelText: String? = nil, - footerText: String? = nil, - state: AuthenticationTextFieldStyle.State = .default, - accessibilityIdentifier: String? = nil) -> AuthenticationTextFieldStyle { - AuthenticationTextFieldStyle(labelText: labelText.map(Text.init), - footerText: footerText.map(Text.init), - state: state, - accessibilityIdentifier: accessibilityIdentifier) +extension TextFieldStyle where Self == ElementTextFieldStyle { + static func element(labelText: String? = nil, + footerText: String? = nil, + state: ElementTextFieldStyle.State = .default, + accessibilityIdentifier: String? = nil) -> ElementTextFieldStyle { + ElementTextFieldStyle(labelText: labelText.map(Text.init), + footerText: footerText.map(Text.init), + state: state, + accessibilityIdentifier: accessibilityIdentifier) } @_disfavoredOverload - static func authentication(labelText: Text? = nil, - footerText: Text? = nil, - state: AuthenticationTextFieldStyle.State = .default, - accessibilityIdentifier: String? = nil) -> AuthenticationTextFieldStyle { - AuthenticationTextFieldStyle(labelText: labelText, - footerText: footerText, - state: state, - accessibilityIdentifier: accessibilityIdentifier) + static func element(labelText: Text? = nil, + footerText: Text? = nil, + state: ElementTextFieldStyle.State = .default, + accessibilityIdentifier: String? = nil) -> ElementTextFieldStyle { + ElementTextFieldStyle(labelText: labelText, + footerText: footerText, + state: state, + accessibilityIdentifier: accessibilityIdentifier) } } /// The text field style used in authentication screens. -struct AuthenticationTextFieldStyle: TextFieldStyle { +struct ElementTextFieldStyle: TextFieldStyle { enum State { case success case error @@ -155,7 +155,7 @@ struct AuthenticationTextFieldStyle: TextFieldStyle { attributes: [NSAttributedString.Key.foregroundColor: placeholderColor]) textField.accessibilityIdentifier = accessibilityIdentifier } - + if let footerText { Label { footerText @@ -186,27 +186,27 @@ struct ElementTextFieldStyle_Previews: PreviewProvider, TestablePreview { VStack(spacing: 20) { // Plain text field. TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication()) + .textFieldStyle(.element()) TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication()) + .textFieldStyle(.element()) TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication()) + .textFieldStyle(.element()) .disabled(true) TextField("Placeholder", text: .constant("Web")) - .textFieldStyle(.authentication(state: .error)) + .textFieldStyle(.element(state: .error)) // Text field with labels TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication(labelText: "Label", footerText: "Footer")) + .textFieldStyle(.element(labelText: "Label", footerText: "Footer")) TextField("Placeholder", text: .constant("Input text")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) + .textFieldStyle(.element(labelText: "Title", footerText: "Footer")) TextField("Placeholder", text: .constant("Bad text")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .error)) + .textFieldStyle(.element(labelText: "Title", footerText: "Footer", state: .error)) TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer")) + .textFieldStyle(.element(labelText: "Title", footerText: "Footer")) .disabled(true) TextField("Placeholder", text: .constant("")) - .textFieldStyle(.authentication(labelText: "Title", footerText: "Footer", state: .success)) + .textFieldStyle(.element(labelText: "Title", footerText: "Footer", state: .success)) } .previewLayout(.sizeThatFits) .padding() diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift index 5fbf93dc89..d43b3d9994 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/View/LoginScreen.swift @@ -69,7 +69,7 @@ struct LoginScreen: View { Text(L10n.commonUsername).foregroundColor(.compound.textSecondary) } .focused($isUsernameFocused) - .textFieldStyle(.authentication(accessibilityIdentifier: A11yIdentifiers.loginScreen.emailUsername)) + .textFieldStyle(.element(accessibilityIdentifier: A11yIdentifiers.loginScreen.emailUsername)) .disableAutocorrection(true) .textContentType(.username) .autocapitalization(.none) @@ -84,7 +84,7 @@ struct LoginScreen: View { Text(L10n.commonPassword).foregroundColor(.compound.textSecondary) } .focused($isPasswordFocused) - .textFieldStyle(.authentication(accessibilityIdentifier: A11yIdentifiers.loginScreen.password)) + .textFieldStyle(.element(accessibilityIdentifier: A11yIdentifiers.loginScreen.password)) .textContentType(.password) .submitLabel(.done) .onSubmit(submit) diff --git a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift index cc377936f3..364024b7a6 100644 --- a/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift +++ b/ElementX/Sources/Screens/Authentication/ServerSelectionScreen/View/ServerSelectionScreen.swift @@ -52,10 +52,10 @@ struct ServerSelectionScreen: View { var serverForm: some View { VStack(alignment: .leading, spacing: 24) { TextField(L10n.commonServerUrl, text: $context.homeserverAddress) - .textFieldStyle(.authentication(labelText: Text(L10n.screenChangeServerFormHeader), - footerText: Text(context.viewState.footerMessage), - state: context.viewState.isShowingFooterError ? .error : .default, - accessibilityIdentifier: A11yIdentifiers.changeServerScreen.server)) + .textFieldStyle(.element(labelText: Text(L10n.screenChangeServerFormHeader), + footerText: Text(context.viewState.footerMessage), + state: context.viewState.isShowingFooterError ? .error : .default, + accessibilityIdentifier: A11yIdentifiers.changeServerScreen.server)) .keyboardType(.URL) .autocapitalization(.none) .disableAutocorrection(true) diff --git a/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/View/SoftLogoutScreen.swift b/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/View/SoftLogoutScreen.swift index bdb774401d..f74b9f895e 100644 --- a/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/View/SoftLogoutScreen.swift +++ b/ElementX/Sources/Screens/Authentication/SoftLogoutScreen/View/SoftLogoutScreen.swift @@ -74,7 +74,7 @@ struct SoftLogoutScreen: View { VStack(spacing: 14) { SecureField(L10n.commonPassword, text: $context.password) .focused($isPasswordFocused) - .textFieldStyle(.authentication()) + .textFieldStyle(.element()) .textContentType(.password) .submitLabel(.done) .onSubmit(submit) diff --git a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift index 82404432b0..3a5bde987d 100644 --- a/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift +++ b/ElementX/Sources/Screens/StartChatScreen/View/JoinRoomByAddressView.swift @@ -30,7 +30,7 @@ struct JoinRoomByAddressView: View { } } - private var textFieldState: AuthenticationTextFieldStyle.State { + private var textFieldState: ElementTextFieldStyle.State { switch context.viewState.joinByAddressState { case .addressFound: .success @@ -46,9 +46,9 @@ struct JoinRoomByAddressView: View { VStack(spacing: 24) { TextField(L10n.screenStartChatJoinRoomByAddressPlaceholder, text: $context.roomAddress) - .textFieldStyle(.authentication(labelText: L10n.screenStartChatJoinRoomByAddressAction, - footerText: footerText, - state: textFieldState)) + .textFieldStyle(.element(labelText: L10n.screenStartChatJoinRoomByAddressAction, + footerText: footerText, + state: textFieldState)) .textInputAutocapitalization(.never) .autocorrectionDisabled() .textContentType(.URL) diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png index c6e979c227..d4e2d02003 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-en-GB.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f172de4c7661d7aa39ad580585e82f771be569b6351567b84b5fd2628f67922d -size 124754 +oid sha256:04271dfb4c74bc6c3e66cca976227eeb9f4b3cf0ae59534a91af9fa20cd3934c +size 124757 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png index 6bdcea382f..d447300383 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPad-pseudo.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b078e48fa9aa152fa489dceda0a1647c97092139938aeab8f327bde3244dab7f -size 153056 +oid sha256:c0ceac7d4a575c93b87dfb9d2cf6878d6f9c276e9504407305be628bfdb3724c +size 153065 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png index 9c09aaff9e..b5ed89d184 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-en-GB.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1891577eccb937d0cafaadcce9c5139a89f7df7c5c79fae5e26615bc49204d21 -size 78057 +oid sha256:ba25f9db0d4a15ab35f60a06ddc2e16d0fab7d984dc0d39d5c91898a657ffb8e +size 78089 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png index 50c9504259..db7f394dbb 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/test_serverSelection-iPhone-16-pseudo.3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a027ac57a10e25574278f4377bf140fbbd6eb5dcc134fac78e070dc793e2b828 -size 110877 +oid sha256:ea9f83d65534c2974698209b7d17fe1fc2a974374cc71f0cecccea0740653209 +size 110886 diff --git a/UnitTests/Sources/StartChatViewModelTests.swift b/UnitTests/Sources/StartChatViewModelTests.swift index 3b194459d5..da2162858c 100644 --- a/UnitTests/Sources/StartChatViewModelTests.swift +++ b/UnitTests/Sources/StartChatViewModelTests.swift @@ -47,11 +47,11 @@ class StartChatScreenViewModelTests: XCTestCase { func testJoinRoomByAddress() async throws { clientProxy.resolveRoomAliasReturnValue = .success(.init(roomId: "id", servers: [])) - viewModel.context.roomAddress = "#room:example.com" let deferredViewState = deferFulfillment(viewModel.context.$viewState) { viewState in viewState.joinByAddressState == .addressFound(address: "#room:example.com", roomID: "id") } + viewModel.context.roomAddress = "#room:example.com" try await deferredViewState.fulfill() let deferredAction = deferFulfillment(viewModel.actions) { action in @@ -62,22 +62,21 @@ class StartChatScreenViewModelTests: XCTestCase { } func testJoinRoomByAddressFailsBecauseInvalid() async throws { - viewModel.context.roomAddress = ":" - let deferred = deferFulfillment(viewModel.context.$viewState) { viewState in viewState.joinByAddressState == .invalidAddress } + viewModel.context.roomAddress = ":" context.send(viewAction: .joinRoomByAddress) try await deferred.fulfill() } func testJoinRoomByAddressFailsBecauseNotFound() async throws { clientProxy.resolveRoomAliasReturnValue = .failure(.failedResolvingRoomAlias) - viewModel.context.roomAddress = "#room:example.com" let deferred = deferFulfillment(viewModel.context.$viewState) { viewState in viewState.joinByAddressState == .addressNotFound } + viewModel.context.roomAddress = "#room:example.com" context.send(viewAction: .joinRoomByAddress) try await deferred.fulfill() }