mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-22 01:22:46 +02:00
222f3292a2
# Conflicts: # .github/workflows/ci-build.yml # .github/workflows/ci-tests.yml # .github/workflows/release-alpha.yml # .github/workflows/triage-move-labelled.yml # .github/workflows/triage-priority-bugs.yml # .gitignore # CHANGES.md # Config/AppConfiguration.swift # Config/AppIdentifiers.xcconfig # Config/AppVersion.xcconfig # Config/BuildSettings.swift # Config/CommonConfiguration.swift # Gemfile # Gemfile.lock # IDETemplateMacros.plist # Podfile # Podfile.lock # README.md # Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button.png # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button@2x.png # Riot/Assets/Images.xcassets/Common/reveal_password_button.imageset/reveal_password_button@3x.png # Riot/Assets/Images.xcassets/People/people_floating_action.imageset/Contents.json # Riot/Assets/Images.xcassets/Rooms/rooms_floating_action.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Recovery/secrets_recovery_key.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Recovery/secrets_recovery_passphrase.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Setup/secrets_setup_key.imageset/Contents.json # Riot/Assets/Images.xcassets/Secrets/Setup/secrets_setup_passphrase.imageset/Contents.json # Riot/Assets/Images.xcassets/TabBar/tab_people.imageset/Contents.json # Riot/Assets/Images.xcassets/TabBar/tab_rooms.imageset/Contents.json # Riot/Assets/SharedImages.xcassets/AppIcon.appiconset/Contents.json # Riot/Assets/SharedImages.xcassets/horizontal_logo.imageset/Contents.json # Riot/Assets/ar.lproj/InfoPlist.strings # Riot/Assets/cs.lproj/Vector.strings # Riot/Assets/de.lproj/InfoPlist.strings # Riot/Assets/de.lproj/Localizable.strings # Riot/Assets/de.lproj/Vector.strings # Riot/Assets/en.lproj/Localizable.strings # Riot/Assets/en.lproj/Untranslated.strings # Riot/Assets/en.lproj/Vector.strings # Riot/Assets/es.lproj/InfoPlist.strings # Riot/Assets/es.lproj/Vector.strings # Riot/Assets/et.lproj/InfoPlist.strings # Riot/Assets/et.lproj/Vector.strings # Riot/Assets/fr.lproj/InfoPlist.strings # Riot/Assets/fr.lproj/Vector.strings # Riot/Assets/hu.lproj/InfoPlist.strings # Riot/Assets/hu.lproj/Vector.strings # Riot/Assets/id.lproj/InfoPlist.strings # Riot/Assets/id.lproj/Vector.strings # Riot/Assets/is.lproj/InfoPlist.strings # Riot/Assets/is.lproj/Vector.strings # Riot/Assets/it.lproj/InfoPlist.strings # Riot/Assets/it.lproj/Vector.strings # Riot/Assets/ja.lproj/InfoPlist.strings # Riot/Assets/ja.lproj/Localizable.strings # Riot/Assets/ja.lproj/Vector.strings # Riot/Assets/nl.lproj/InfoPlist.strings # Riot/Assets/nl.lproj/Vector.strings # Riot/Assets/pl.lproj/InfoPlist.strings # Riot/Assets/pl.lproj/Vector.strings # Riot/Assets/pt_BR.lproj/InfoPlist.strings # Riot/Assets/pt_BR.lproj/Vector.strings # Riot/Assets/ru.lproj/InfoPlist.strings # Riot/Assets/ru.lproj/Vector.strings # Riot/Assets/sk.lproj/InfoPlist.strings # Riot/Assets/sk.lproj/Vector.strings # Riot/Assets/sq.lproj/InfoPlist.strings # Riot/Assets/sq.lproj/Vector.strings # Riot/Assets/sv.lproj/InfoPlist.strings # Riot/Assets/sv.lproj/Vector.strings # Riot/Assets/third_party_licenses.html # Riot/Assets/uk.lproj/InfoPlist.strings # Riot/Assets/uk.lproj/Vector.strings # Riot/Assets/zh_Hans.lproj/InfoPlist.strings # Riot/Assets/zh_Hans.lproj/Localizable.strings # Riot/Assets/zh_Hans.lproj/Vector.strings # Riot/Assets/zh_Hant.lproj/Vector.strings # Riot/Categories/MXKRoomBubbleTableViewCell+Riot.h # Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m # Riot/Categories/MXRestClient+Async.swift # Riot/Categories/MXSession+Riot.m # Riot/Categories/NSAttributedString.swift # Riot/Categories/Publisher+Riot.swift # Riot/Categories/RoomBubbleCellData.swift # Riot/Categories/UILabel.swift # Riot/Categories/UIScrollView.swift # Riot/Categories/UIView.swift # Riot/Categories/UIViewController.swift # Riot/Generated/Images.swift # Riot/Generated/Strings.swift # Riot/Generated/UntranslatedStrings.swift # Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift # Riot/Managers/LocalAuthentication/LocalAuthenticationService.swift # Riot/Managers/PushNotification/PushNotificationService.m # Riot/Managers/PushNotification/PushNotificationStore.swift # Riot/Managers/Settings/RiotSettings.swift # Riot/Managers/Settings/Shared/RiotSharedSettings.swift # Riot/Managers/Theme/Themes/DarkTheme.swift # Riot/Managers/Theme/Themes/DefaultTheme.swift # Riot/Managers/UISIAutoReporter/UISIAutoReporter.swift # Riot/Model/HomeserverConfiguration/HomeserverConfigurationBuilder.swift # Riot/Modules/Analytics/Analytics.swift # Riot/Modules/Analytics/AnalyticsUIElement.swift # Riot/Modules/Analytics/DecryptionFailureTracker.m # Riot/Modules/Application/AppCoordinator.swift # Riot/Modules/Application/LegacyAppDelegate.h # Riot/Modules/Application/LegacyAppDelegate.m # Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift # Riot/Modules/Common/Avatar/AvatarView.swift # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m # Riot/Modules/Common/Recents/RecentsViewController.h # Riot/Modules/Common/Recents/RecentsViewController.m # Riot/Modules/Common/Recents/Views/RecentTableViewCell.m # Riot/Modules/Common/SwiftUI/VectorHostingController.swift # Riot/Modules/Common/Toasts/RoundedToastView.swift # Riot/Modules/Common/Toasts/ToastViewState.swift # Riot/Modules/Common/UserIndicators/UserIndicatorPresenter.swift # Riot/Modules/Common/UserIndicators/UserIndicatorStore.swift # Riot/Modules/Common/UserIndicators/ViewPresenters/ToastViewPresenter.swift # Riot/Modules/Common/WebViewController/WebViewViewController.m # Riot/Modules/Communities/Home/GroupHomeViewController.m # Riot/Modules/Communities/Members/GroupParticipantsViewController.m # Riot/Modules/Communities/Rooms/GroupRoomsViewController.m # Riot/Modules/Contacts/ContactsTableViewController.m # Riot/Modules/Contacts/ContactsTableViewController.xib # Riot/Modules/Contacts/Details/ContactDetailsViewController.m # Riot/Modules/Contacts/Views/ContactTableViewCell.m # Riot/Modules/Contacts/Views/ContactTableViewCell.xib # Riot/Modules/ContextMenu/ActionProviders/RoomActionProvider.swift # Riot/Modules/ContextMenu/Services/RoomContextActionService.swift # Riot/Modules/CreateRoom/CreateRoomCoordinator.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsCoordinator.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift # Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift # Riot/Modules/DeepLink/UniversalLinkParameters.swift # Riot/Modules/Favorites/FavouritesViewController.h # Riot/Modules/Favorites/FavouritesViewController.m # Riot/Modules/GlobalSearch/UnifiedSearchViewController.m # Riot/Modules/Home/HomeViewController.m # Riot/Modules/Home/Views/RoomCollectionViewCell.m # Riot/Modules/Integrations/WidgetPicker/WidgetPickerViewController.m # Riot/Modules/Integrations/Widgets/StickerPicker/StickerPickerViewController.m # Riot/Modules/KeyBackup/ManualExport/EncryptionKeysExportPresenter.swift # Riot/Modules/KeyVerification/Common/KeyVerificationCoordinator.swift # Riot/Modules/KeyVerification/Common/Verify/Scanning/KeyVerificationVerifyByScanningViewController.swift # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitCoordinator.swift # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.storyboard # Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewController.swift # Riot/Modules/KeyVerification/User/SessionStatus/UserVerificationSessionStatusViewController.swift # Riot/Modules/LocationSharing/LocationManager.swift # Riot/Modules/LocationSharing/UserLocationService.swift # Riot/Modules/LocationSharing/UserLocationServiceProvider.swift # Riot/Modules/MatrixKit/Categories/NSBundle+MatrixKit.m # Riot/Modules/MatrixKit/Controllers/MXKAccountDetailsViewController.m # Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m # Riot/Modules/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.h # Riot/Modules/MatrixKit/Controllers/MXKViewController.h # Riot/Modules/MatrixKit/Models/Account/MXKAccount.h # Riot/Modules/MatrixKit/Models/Account/MXKAccount.m # Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.h # Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m # Riot/Modules/MatrixKit/Models/Contact/MXKContact.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataWithAppendingMode.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h # Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m # Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m # Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift # Riot/Modules/MatrixKit/Utils/ErrorPresentation/MXKErrorPresentableBuilder.m # Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.h # Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m # Riot/Modules/MatrixKit/Utils/MXKTools.h # Riot/Modules/MatrixKit/Utils/MXKTools.m # Riot/Modules/MatrixKit/Views/Account/MXKAccountTableViewCell.m # Riot/Modules/MatrixKit/Views/MXKTableViewCell/MXKTableViewCellWithLabelAndTextField.xib # Riot/Modules/MatrixKit/Views/MXKTableViewCell/MXKTableViewCellWithTextFieldAndButton.m # Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarView.m # Riot/Modules/MatrixKit/Views/RoomMemberList/MXKRoomMemberTableViewCell.m # Riot/Modules/MediaPicker/MediaPickerViewController.m # Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift # Riot/Modules/MediaPickerV2/MediaPickerPresenter.swift # Riot/Modules/Onboarding/OnboardingCoordinator.swift # Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift # Riot/Modules/Onboarding/OnboardingCoordinatorProtocol.swift # Riot/Modules/People/PeopleViewController.h # Riot/Modules/People/PeopleViewController.m # Riot/Modules/Pills/PillTextAttachment.swift # Riot/Modules/Pills/PillsFormatter.swift # Riot/Modules/QRCode/QRCodeGenerator.swift # Riot/Modules/Room/CellData/RoomBubbleCellData.m # Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift # Riot/Modules/Room/CreationModal/RoomCreationEventsModal/RoomCreationEventsModalCoordinator.swift # Riot/Modules/Room/CreationModal/RoomCreationEventsModal/RoomCreationEventsModalViewModel.swift # Riot/Modules/Room/CreationModal/RoomCreationModalCoordinatorBridgePresenter.swift # Riot/Modules/Room/DataSources/RoomDataSource.m # Riot/Modules/Room/DataSources/RoomDataSource.swift # Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift # Riot/Modules/Room/Files/RoomFilesViewController.m # Riot/Modules/Room/Location/RoomTimelineLocationView.swift # Riot/Modules/Room/Location/RoomTimelineLocationView.xib # Riot/Modules/Room/MXKRoomViewController.h # Riot/Modules/Room/MXKRoomViewController.m # Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.h # Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m # Riot/Modules/Room/Members/RoomParticipantsViewController.h # Riot/Modules/Room/Members/RoomParticipantsViewController.m # Riot/Modules/Room/ParticipantsInviteModal/ContactsPicker/ContactsPickerViewModel.swift # Riot/Modules/Room/RoomCoordinator.swift # Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewState.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/Views/RoomInfoBasicView.swift # Riot/Modules/Room/RoomViewController.m # Riot/Modules/Room/Settings/RoomSettingsViewController.m # Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.xib # Riot/Modules/Room/TimelineCells/Common/MXKRoomBubbleTableViewCell.m # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCell.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCellContentView.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroViewData.swift # Riot/Modules/Room/TimelineCells/RoomMembership/RoomMembershipCollapsedBubbleCell.m # Riot/Modules/Room/TimelineCells/RoomTimelineCellIdentifier.h # Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineCellProvider.m # Riot/Modules/Room/TimelineCells/Styles/Bubble/BubbleRoomTimelineStyle.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailBaseBubbleCell.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailCellContentView.swift # Riot/Modules/Room/TimelineCells/Styles/Bubble/Cells/FileWithoutThumbnail/Common/FileWithoutThumbnailCellContentView.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Clear/RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Encrypted/RoomIncomingEncryptedAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Incoming/Encrypted/RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Clear/RoomOutgoingAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Encrypted/RoomOutgoingEncryptedAttachmentBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/FileAttachment/Outgoing/Encrypted/RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Location/LocationPlainCell.swift # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Poll/PollPlainCell.swift # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/Sticker/RoomSelectedStickerBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Clear/RoomIncomingTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Encrypted/RoomIncomingEncryptedTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Incoming/Encrypted/RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Clear/RoomOutgoingTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Encrypted/RoomOutgoingEncryptedTextMsgBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/Cells/TextMessage/Outgoing/Encrypted/RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.xib # Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineCellProvider.m # Riot/Modules/Room/TimelineCells/Styles/Plain/PlainRoomTimelineStyle.swift # Riot/Modules/Room/TimelineCells/Styles/RoomTimelineStyle.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionActionViewCell.xib # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionViewCell.xib # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsView.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsViewModel.swift # Riot/Modules/Room/TimelineDecorations/Reactions/RoomReactionsViewModelType.swift # Riot/Modules/Room/TimelineDecorations/Threads/Summary/ThreadSummaryView.swift # Riot/Modules/Room/VoiceMessages/VoiceMessageAudioConverter.swift # Riot/Modules/Room/VoiceMessages/VoiceMessageAudioRecorder.swift # Riot/Modules/Room/VoiceMessages/VoiceMessagePlaybackView.swift # Riot/Modules/Room/VoiceMessages/VoiceMessagePlaybackView.xib # Riot/Modules/Room/VoiceMessages/VoiceMessageToolbarView.swift # Riot/Modules/Rooms/RoomsViewController.h # Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.swift # Riot/Modules/Rooms/ShowDirectory/Cells/Room/DirectoryRoomTableViewCell.swift # Riot/Modules/Rooms/ShowDirectory/Cells/Room/DirectoryRoomTableViewCell.xib # Riot/Modules/Rooms/ShowDirectory/PublicRoomsDirectoryViewModel.swift # Riot/Modules/Rooms/ShowDirectory/ShowDirectoryViewController.swift # Riot/Modules/Rooms/ShowDirectory/ShowDirectoryViewModel.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyViewController.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseViewController.swift # Riot/Modules/Secrets/Recover/SecretsRecoveryCoordinator.swift # Riot/Modules/Secrets/Reset/SecretsResetViewController.storyboard # Riot/Modules/Secrets/Reset/SecretsResetViewController.swift # Riot/Modules/Secrets/Setup/RecoveryKey/SecretsSetupRecoveryKeyViewController.swift # Riot/Modules/Secrets/Setup/RecoveryPassphrase/SecretsSetupRecoveryPassphraseViewController.storyboard # Riot/Modules/Secrets/Setup/RecoveryPassphrase/SecretsSetupRecoveryPassphraseViewController.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewController.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModel.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModelType.swift # Riot/Modules/SecureBackup/Setup/SecureBackupSetupCoordinator.swift # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewController.storyboard # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewController.swift # Riot/Modules/SetPinCode/EnterPinCode/EnterPinCodeViewModel.swift # Riot/Modules/SetPinCode/PinCodePreferences.swift # Riot/Modules/SetPinCode/SetPinCoordinator.swift # Riot/Modules/SetPinCode/SetPinCoordinatorBridgePresenter.swift # Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsCoordinator.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsViewController.swift # Riot/Modules/SetPinCode/SetupBiometrics/SetupBiometricsViewModel.swift # Riot/Modules/Settings/DeactivateAccount/DeactivateAccountViewController.m # Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m # Riot/Modules/Settings/Security/SecurityViewController.m # Riot/Modules/Settings/SettingsViewController.m # Riot/Modules/SideMenu/SideMenuCoordinator.swift # Riot/Modules/SideMenu/SideMenuViewModel.swift # Riot/Modules/Spaces/SpaceList/SpaceListViewModel.swift # Riot/Modules/Spaces/SpaceMenu/SpaceMenuPresenter.swift # Riot/Modules/Spaces/SpaceMenu/SpaceMenuViewModel.swift # Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift # Riot/Modules/SplitView/SplitViewCoordinator.swift # Riot/Modules/SplitView/SplitViewCoordinatorType.swift # Riot/Modules/StartChat/StartChatViewController.m # Riot/Modules/TabBar/MasterTabBarController.h # Riot/Modules/TabBar/MasterTabBarController.m # Riot/Modules/TabBar/TabBarCoordinator.swift # Riot/Modules/TabBar/TabBarCoordinatorType.swift # Riot/Modules/Threads/ThreadList/ThreadListViewModel.swift # Riot/SupportingFiles/Info.plist # Riot/SupportingFiles/Riot-Bridging-Header.h # Riot/SupportingFiles/Riot.entitlements # Riot/Utils/EventFormatter+DTCoreTextFix.m # Riot/Utils/EventFormatter.m # Riot/Utils/Tools.h # Riot/Utils/Tools.m # Riot/Utils/URLValidator.swift # Riot/Utils/UniversalLink.h # Riot/Utils/UniversalLink.m # Riot/target.yml # RiotNSE/NotificationService.swift # RiotNSE/RiotNSE.entitlements # RiotNSE/target.yml # RiotShareExtension/Shared/View/ShareViewController.m # RiotShareExtension/SupportingFiles/Info.plist # RiotShareExtension/target.yml # RiotSwiftUI/Modules/AnalyticsPrompt/AnalyticsPromptViewModel.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Coordinator/AnalyticsPromptCoordinator.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Coordinator/AnalyticsPromptStrings.swift # RiotSwiftUI/Modules/AnalyticsPrompt/MockAnalyticsPromptScreenState.swift # RiotSwiftUI/Modules/AnalyticsPrompt/Test/UI/AnalyticsPromptUITests.swift # RiotSwiftUI/Modules/AnalyticsPrompt/View/AnalyticsPrompt.swift # RiotSwiftUI/Modules/AnalyticsPrompt/View/AnalyticsPromptCheckmarkItem.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationHomeserverViewData.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationModels.swift # RiotSwiftUI/Modules/Authentication/Common/AuthenticationServerInfoSection.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationRestClient.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationService.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/AuthenticationState.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginModels.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginParameters.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/LoginWizard.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationParameters.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/RegistrationWizard.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/SessionCreator.swift # RiotSwiftUI/Modules/Authentication/Common/Service/MatrixSDK/ThreePIDModels.swift # RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginModels.swift # RiotSwiftUI/Modules/Authentication/Login/Coordinator/AuthenticationLoginCoordinator.swift # RiotSwiftUI/Modules/Authentication/Login/Test/UI/AuthenticationLoginUITests.swift # RiotSwiftUI/Modules/Authentication/Login/Test/Unit/AuthenticationLoginViewModelTests.swift # RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/Test/UI/AuthenticationReCaptchaUITests.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/View/AuthenticationReCaptchaScreen.swift # RiotSwiftUI/Modules/Authentication/ReCaptcha/View/AuthenticationReCaptchaWebView.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationModels.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationViewModel.swift # RiotSwiftUI/Modules/Authentication/Registration/AuthenticationRegistrationViewModelProtocol.swift # RiotSwiftUI/Modules/Authentication/Registration/Coordinator/AuthenticationRegistrationCoordinator.swift # RiotSwiftUI/Modules/Authentication/Registration/MockAuthenticationRegistrationScreenState.swift # RiotSwiftUI/Modules/Authentication/Registration/Test/UI/AuthenticationRegistrationUITests.swift # RiotSwiftUI/Modules/Authentication/Registration/Test/Unit/AuthenticationRegistrationViewModelTests.swift # RiotSwiftUI/Modules/Authentication/Registration/View/AuthenticationRegistrationScreen.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/AuthenticationServerSelectionModels.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/AuthenticationServerSelectionViewModel.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/MockAuthenticationServerSelectionScreenState.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Test/UI/AuthenticationServerSelectionUITests.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/Test/Unit/AuthenticationServerSelectionViewModelTests.swift # RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift # RiotSwiftUI/Modules/Authentication/Terms/AuthenticationTermsModels.swift # RiotSwiftUI/Modules/Authentication/Terms/AuthenticationTermsViewModel.swift # RiotSwiftUI/Modules/Authentication/Terms/Coordinator/AuthenticationTermsCoordinator.swift # RiotSwiftUI/Modules/Authentication/Terms/MockAuthenticationTermsScreenState.swift # RiotSwiftUI/Modules/Authentication/Terms/Test/UI/AuthenticationTermsUITests.swift # RiotSwiftUI/Modules/Authentication/Terms/View/AuthenticationTermsScreen.swift # RiotSwiftUI/Modules/Authentication/Terms/View/AuthenticationTermsToggleStyle.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/MockAuthenticationVerifyEmailScreenState.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailForm.swift # RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/AuthenticationVerifyMsisdnModels.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/AuthenticationVerifyMsisdnViewModel.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Coordinator/AuthenticationVerifyMsisdnCoordinator.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/MockAuthenticationVerifyMsisdnScreenState.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Test/UI/AuthenticationVerifyMsisdnUITests.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/Test/Unit/AuthenticationVerifyMsisdnViewModelTests.swift # RiotSwiftUI/Modules/Authentication/VerifyMsisdn/View/AuthenticationVerifyMsisdnForm.swift # RiotSwiftUI/Modules/Common/ActivityIndicator/ActivityIndicator.swift # RiotSwiftUI/Modules/Common/ActivityIndicator/ActivityIndicatorModifier.swift # RiotSwiftUI/Modules/Common/Avatar/Service/MatrixSDK/AvatarService.swift # RiotSwiftUI/Modules/Common/Avatar/Service/Mock/MockAvatarService.swift # RiotSwiftUI/Modules/Common/Avatar/View/AvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/View/PlaceholderAvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/View/SpaceAvatarImage.swift # RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarServiceProtocol.swift # RiotSwiftUI/Modules/Common/Avatar/ViewModel/AvatarViewModel.swift # RiotSwiftUI/Modules/Common/Bridging/VectorContentView.swift # RiotSwiftUI/Modules/Common/DependencyInjection/DependencyContainerKey.swift # RiotSwiftUI/Modules/Common/EffectsScene/EffectsScene.swift # RiotSwiftUI/Modules/Common/EffectsScene/EffectsView.swift # RiotSwiftUI/Modules/Common/Extensions/Publisher.swift # RiotSwiftUI/Modules/Common/Mock/MockAppScreens.swift # RiotSwiftUI/Modules/Common/Mock/MockScreenState.swift # RiotSwiftUI/Modules/Common/Mock/ScreenList.swift # RiotSwiftUI/Modules/Common/Mock/ScreenStateInfo.swift # RiotSwiftUI/Modules/Common/Mock/StateRenderer.swift # RiotSwiftUI/Modules/Common/Test/UI/MockScreenTest.swift # RiotSwiftUI/Modules/Common/Test/UI/XCUIApplication+Riot.swift # RiotSwiftUI/Modules/Common/Test/XCTestPublisherExtensions.swift # RiotSwiftUI/Modules/Common/Theme/ThemeIdentifierExtensions.swift # RiotSwiftUI/Modules/Common/Theme/ThemeKey.swift # RiotSwiftUI/Modules/Common/Theme/ThemePublisher.swift # RiotSwiftUI/Modules/Common/Theme/ThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Theme/ThemeUsersColorsExtension.swift # RiotSwiftUI/Modules/Common/Theme/Themes/DarkThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Theme/Themes/DefaultThemeSwiftUI.swift # RiotSwiftUI/Modules/Common/Util/BorderModifier.swift # RiotSwiftUI/Modules/Common/Util/BorderedInputFieldStyle.swift # RiotSwiftUI/Modules/Common/Util/ClearViewModifier.swift # RiotSwiftUI/Modules/Common/Util/InlineTextButton.swift # RiotSwiftUI/Modules/Common/Util/MultilineTextField.swift # RiotSwiftUI/Modules/Common/Util/OptionButton.swift # RiotSwiftUI/Modules/Common/Util/PrimaryActionButtonStyle.swift # RiotSwiftUI/Modules/Common/Util/RadioButton.swift # RiotSwiftUI/Modules/Common/Util/RoundedBorderTextEditor.swift # RiotSwiftUI/Modules/Common/Util/RoundedBorderTextField.swift # RiotSwiftUI/Modules/Common/Util/RoundedCornerShape.swift # RiotSwiftUI/Modules/Common/Util/SafeBindingCollectionEnumerator.swift # RiotSwiftUI/Modules/Common/Util/ScreenTrackerViewModifier.swift # RiotSwiftUI/Modules/Common/Util/SearchBar.swift # RiotSwiftUI/Modules/Common/Util/SecondaryActionButtonStyle.swift # RiotSwiftUI/Modules/Common/Util/StyledText.swift # RiotSwiftUI/Modules/Common/Util/ThemableButton.swift # RiotSwiftUI/Modules/Common/Util/ThemableNavigationBar.swift # RiotSwiftUI/Modules/Common/Util/ThemableTextEditor.swift # RiotSwiftUI/Modules/Common/Util/ThemableTextField.swift # RiotSwiftUI/Modules/Common/Util/WaitOverlay.swift # RiotSwiftUI/Modules/Common/ViewFrameReader/FramePreferenceKey.swift # RiotSwiftUI/Modules/Common/ViewFrameReader/ViewFrameReader.swift # RiotSwiftUI/Modules/Common/ViewModel/StateStoreViewModel.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Coordinator/OnboardingAvatarCoordinator.swift # RiotSwiftUI/Modules/Onboarding/Avatar/MockOnboardingAvatarScreenState.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Test/UI/OnboardingAvatarUITests.swift # RiotSwiftUI/Modules/Onboarding/Avatar/Test/Unit/OnboardingAvatarViewModelTests.swift # RiotSwiftUI/Modules/Onboarding/Celebration/Test/UI/OnboardingCelebrationUITests.swift # RiotSwiftUI/Modules/Onboarding/Celebration/View/OnboardingCelebrationScreen.swift # RiotSwiftUI/Modules/Onboarding/Common/OnboardingIcon.swift # RiotSwiftUI/Modules/Onboarding/Common/OnboardingMetrics.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/OnboardingCongratulationsModels.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/Test/UI/OnboardingCongratulationsUITests.swift # RiotSwiftUI/Modules/Onboarding/Congratulations/View/OnboardingCongratulationsScreen.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/Coordinator/OnboardingDisplayNameCoordinator.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/Test/UI/OnboardingDisplayNameUITests.swift # RiotSwiftUI/Modules/Onboarding/DisplayName/View/OnboardingDisplayNameScreen.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/OnboardingSplashScreenModels.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreen.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreenPage.swift # RiotSwiftUI/Modules/Onboarding/SplashScreen/View/OnboardingSplashScreenPageIndicator.swift # RiotSwiftUI/Modules/Onboarding/UseCase/Coordinator/OnboardingUseCaseSelectionCoordinator.swift # RiotSwiftUI/Modules/Onboarding/UseCase/OnboardingUseCaseModels.swift # RiotSwiftUI/Modules/Onboarding/UseCase/Test/UI/OnboardingUseCaseUITests.swift # RiotSwiftUI/Modules/Onboarding/UseCase/View/OnboardingUseCaseSelectionScreen.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Coordinator/LiveLocationSharingViewerCoordinator.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerModels.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerViewModel.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/LiveLocationSharingViewerViewModelProtocol.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/MockLiveLocationSharingViewerScreenState.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/LiveLocationSharingViewerServiceProtocol.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/MatrixSDK/LiveLocationSharingViewerService.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Service/Mock/MockLiveLocationSharingViewerService.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Test/UI/LiveLocationSharingViewerUITests.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/Test/Unit/LiveLocationSharingViewerViewModelTests.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/View/LiveLocationListItem.swift # RiotSwiftUI/Modules/Room/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift # RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift # RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingViewModel.swift # RiotSwiftUI/Modules/Room/LocationSharing/Service/MatrixSDK/LocationSharingService.swift # RiotSwiftUI/Modules/Room/LocationSharing/Service/Mock/MockLocationSharingService.swift # RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift # RiotSwiftUI/Modules/Room/LocationSharing/Test/Unit/LocationSharingViewModelTests.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingMapView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingMarkerView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingOptionButton.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/LocationSharingView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/MapCreditsView.swift # RiotSwiftUI/Modules/Room/LocationSharing/View/UserLocationAnnotationView.swift # RiotSwiftUI/Modules/Room/NotificationSettings/Coordinator/RoomNotificationSettingsCoordinator.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormItemButtonStyle.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormPickerItem.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionFooter.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/FormSectionHeader.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettings.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/RoomNotificationSettingsHeader.swift # RiotSwiftUI/Modules/Room/NotificationSettings/View/VectorForm.swift # RiotSwiftUI/Modules/Room/NotificationSettings/ViewModel/RoomNotificationSettingsSwiftUIViewModel.swift # RiotSwiftUI/Modules/Room/PollEditForm/Coordinator/PollEditFormCoordinator.swift # RiotSwiftUI/Modules/Room/PollEditForm/PollEditFormScreenState.swift # RiotSwiftUI/Modules/Room/PollEditForm/PollEditFormViewModel.swift # RiotSwiftUI/Modules/Room/PollEditForm/Test/UI/PollEditFormUITests.swift # RiotSwiftUI/Modules/Room/PollEditForm/Test/Unit/PollEditFormViewModelTests.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditForm.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditFormAnswerOptionView.swift # RiotSwiftUI/Modules/Room/PollEditForm/View/PollEditFormTypePicker.swift # RiotSwiftUI/Modules/Room/RoomAccess/Coordinator/RoomAccessCoordinator.swift # RiotSwiftUI/Modules/Room/RoomAccess/Coordinator/RoomAccessCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Coordinator/RoomAccessTypeChooserCoordinator.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/MockRoomAccessTypeChooserScreenState.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/RoomAccessTypeChooserViewModel.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/RoomAccessTypeChooserViewModelProtocol.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/MatrixSDK/RoomAccessTypeChooserService.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/Mock/MockRoomAccessTypeChooserService.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Service/RoomAccessTypeChooserServiceProtocol.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Test/UI/RoomAccessTypeChooserUITests.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/Test/Unit/RoomAccessTypeChooserViewModelTests.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/View/RoomAccessTypeChooser.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomAccessTypeChooser/View/RoomAccessTypeChooserRow.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomRestrictedAccessSpaceChooser/Coordinator/RoomRestrictedAccessSpaceChooserViewProvider.swift # RiotSwiftUI/Modules/Room/RoomAccess/RoomRestrictedAccessSpaceChooser/View/RoomRestrictedAccessSpaceChooserSelector.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/Coordinator/RoomSuggestionCoordinator.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/Coordinator/RoomSuggestionCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/RoomSuggestionSpaceChooser/Coordinator/RoomSuggestionSpaceChooserViewProvider.swift # RiotSwiftUI/Modules/Room/RoomSuggestion/RoomSuggestionSpaceChooser/View/RoomSuggestionSpaceChooserSelector.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Coordinator/RoomUpgradeCoordinator.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/MockRoomUpgradeScreenState.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/RoomUpgradeViewModel.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/RoomUpgradeViewModelProtocol.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/MatrixSDK/RoomUpgradeService.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/Mock/MockRoomUpgradeService.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Service/RoomUpgradeServiceProtocol.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Test/UI/RoomUpgradeUITests.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/Test/Unit/RoomUpgradeViewModelTests.swift # RiotSwiftUI/Modules/Room/RoomUpgrade/View/RoomUpgrade.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Coordinator/StaticLocationViewingCoordinator.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/MockStaticLocationViewingScreenState.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingModels.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingViewModel.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/StaticLocationViewingViewModelProtocol.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Test/UI/StaticLocationViewingUITests.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/Test/Unit/StaticLocationViewingViewModelTests.swift # RiotSwiftUI/Modules/Room/StaticLocationSharingViewer/View/StaticLocationView.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Coordinator/TimelinePollCoordinator.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Coordinator/TimelinePollProvider.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Test/UI/TimelinePollUITests.swift # RiotSwiftUI/Modules/Room/TimelinePoll/Test/Unit/TimelinePollViewModelTests.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollScreenState.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollViewModel.swift # RiotSwiftUI/Modules/Room/TimelinePoll/TimelinePollViewModelProtocol.swift # RiotSwiftUI/Modules/Room/TimelinePoll/View/TimelinePollAnswerOptionButton.swift # RiotSwiftUI/Modules/Room/TimelinePoll/View/TimelinePollView.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinator.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Coordinator/UserSuggestionCoordinatorBridge.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionService.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Service/UserSuggestionServiceProtocol.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Test/UI/UserSuggestionUITests.swift # RiotSwiftUI/Modules/Room/UserSuggestion/Test/Unit/UserSuggestionServiceTests.swift # RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionScreenState.swift # RiotSwiftUI/Modules/Room/UserSuggestion/UserSuggestionViewModel.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionList.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListItem.swift # RiotSwiftUI/Modules/Room/UserSuggestion/View/UserSuggestionListWithInput.swift # RiotSwiftUI/Modules/Settings/Notifications/Coordinator/NotificationSettingsBridgePresenter.swift # RiotSwiftUI/Modules/Settings/Notifications/Coordinator/NotificationSettingsCoordinator.swift # RiotSwiftUI/Modules/Settings/Notifications/Model/NotificationSettingsScreen.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/MatrixSDK/MXNotificationSettingsService.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/Mock/MockNotificationSettingsService.swift # RiotSwiftUI/Modules/Settings/Notifications/Service/NotificationSettingsServiceType.swift # RiotSwiftUI/Modules/Settings/Notifications/View/Chip.swift # RiotSwiftUI/Modules/Settings/Notifications/View/Chips.swift # RiotSwiftUI/Modules/Settings/Notifications/View/ChipsInput.swift # RiotSwiftUI/Modules/Settings/Notifications/View/DefaultNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/FormInputFieldStyle.swift # RiotSwiftUI/Modules/Settings/Notifications/View/MentionsAndKeywordNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/NotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/View/NotificationSettingsKeywords.swift # RiotSwiftUI/Modules/Settings/Notifications/View/OtherNotificationSettings.swift # RiotSwiftUI/Modules/Settings/Notifications/ViewModel/NotificationSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/AddRoomSelector/Coordinator/AddRoomSelectorViewProvider.swift # RiotSwiftUI/Modules/Spaces/AddRoomSelector/View/AddRoomSelector.swift # RiotSwiftUI/Modules/Spaces/LeaveSpace/Coordinator/LeaveSpaceViewProvider.swift # RiotSwiftUI/Modules/Spaces/LeaveSpace/View/LeaveSpace.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Coordinator/MatrixItemChooserCoordinator.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MatrixItemChooserViewModel.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MatrixItemChooserViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/MockMatrixItemChooserScreenState.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/MatrixItemChooserServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/MatrixSDK/MatrixItemChooserService.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Service/Mock/MockMatrixItemChooserService.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Test/UI/MatrixItemChooserUITests.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/Test/Unit/MatrixItemChooserViewModelTests.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooser.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserListRow.swift # RiotSwiftUI/Modules/Spaces/MatrixItemChooser/View/MatrixItemChooserSectionHeader.swift # RiotSwiftUI/Modules/Spaces/RoomAncestorSelector/Coordinator/RoomAncestorSelectorViewProvider.swift # RiotSwiftUI/Modules/Spaces/RoomAncestorSelector/View/RoomAncestorSelector.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/Coordinator/SpaceCreationCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Coordinator/SpaceCreationEmailInvitesCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/MatrixSDK/SpaceCreationEmailInvitesService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/Mock/MockSpaceCreationEmailInvitesService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Service/SpaceCreationEmailInvitesServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Test/UI/SpaceCreationEmailInvitesUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/Test/Unit/SpaceCreationEmailInvitesViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/View/SpaceCreationEmailInvites.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/ViewModel/SpaceCreationEmailInvitesViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationEmailInvites/ViewModel/SpaceCreationEmailInvitesViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMatrixItemChooser/Coordinator/SpaceCreationMatrixItemChooserViewProvider.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMatrixItemChooser/View/SpaceCreationMatrixItemChooser.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Coordinator/SpaceCreationMenuCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Test/UI/SpaceCreationMenuUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/Test/Unit/SpaceCreationMenuViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/View/SpaceCreationMenu.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/ViewModel/SpaceCreationMenuViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationMenu/ViewModel/SpaceCreationMenuViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Coordinator/SpaceCreationPostProcessCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/MatrixSDK/SpaceCreationPostProcessService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/Mock/MockSpaceCreationPostProcessService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Service/SpaceCreationPostProcessServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Test/UI/SpaceCreationPostProcessUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/Test/Unit/SpaceCreationPostProcessViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/View/SpaceCreationPostProcess.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/View/SpaceCreationPostProcessItem.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/ViewModel/SpaceCreationPostProcessViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationPostProcess/ViewModel/SpaceCreationPostProcessViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Coordinator/SpaceCreationRoomsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Service/Mock/MockSpaceCreationRoomsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Test/UI/SpaceCreationRoomsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/Test/Unit/SpaceCreationRoomsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/View/SpaceCreationRooms.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/ViewModel/SpaceCreationRoomsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationRooms/ViewModel/SpaceCreationRoomsViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Coordinator/SpaceCreationSettingsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/MatrixSDK/SpaceCreationSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/Mock/MockSpaceCreationSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Service/SpaceCreationSettingsServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Test/UI/SpaceCreationSettingsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/Test/Unit/SpaceCreationSettingsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/View/SpaceCreationSettings.swift # RiotSwiftUI/Modules/Spaces/SpaceCreation/SpaceCreationSettings/ViewModel/SpaceCreationSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/Coordinator/SpaceSettingsModalCoordinatorBridgePresenter.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Coordinator/SpaceSettingsCoordinator.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/MockSpaceSettingsScreenState.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/MatrixSDK/SpaceSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/Mock/MockSpaceSettingsService.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Service/SpaceSettingsServiceProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModel.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/SpaceSettingsViewModelProtocol.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Test/UI/SpaceSettingsUITests.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/Test/Unit/SpaceSettingsViewModelTests.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettings.swift # RiotSwiftUI/Modules/Spaces/SpaceSettings/SpaceSettings/View/SpaceSettingsOptionListItem.swift # RiotSwiftUI/Modules/Template/SimpleScreenExample/Test/UI/TemplateSimpleScreenUITests.swift # RiotSwiftUI/Modules/Template/SimpleUserProfileExample/Test/UI/TemplateUserProfileUITests.swift # RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomChat/Test/UI/TemplateRoomChatUITests.swift # RiotSwiftUI/Modules/Template/TemplateAdvancedRoomsExample/TemplateRoomList/Test/UI/TemplateRoomListUITests.swift # RiotSwiftUI/RiotSwiftUIApp.swift # RiotSwiftUI/target.yml # RiotSwiftUI/targetUITests.yml # RiotTests/MatrixKitTests/MXKEventFormatter+Tests.h # RiotTests/MatrixKitTests/MXKEventFormatterTests.m # RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift # RiotTests/MatrixKitTests/MatrixKitTests-Bridging-Header.h # RiotTests/Modules/Authentication/AuthenticationServiceTests.swift # RiotTests/OnboardingTests.swift # RiotTests/PillsFormatterTests.swift # RiotTests/target.yml # SiriIntents/IntentHandler.m # SiriIntents/target.yml # Tools/SwiftGen/swiftgen-config.yml # Tools/Templates/buildable/SimpleScreenTemplate/SimpleScreenTemplateViewController.storyboard # fastlane/.env.default # fastlane/Fastfile # project.yml
1892 lines
82 KiB
Objective-C
1892 lines
82 KiB
Objective-C
/*
|
|
Copyright 2016 OpenMarket Ltd
|
|
Copyright 2017 Vector Creations Ltd
|
|
Copyright 2019 New Vector Ltd
|
|
Copyright (c) 2021 BWI GmbH
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#import "AuthInputsView.h"
|
|
|
|
#import "ThemeService.h"
|
|
#import "Tools.h"
|
|
|
|
#import "CountryPickerViewController.h"
|
|
#import "NBPhoneNumberUtil.h"
|
|
|
|
#import "RiotNavigationController.h"
|
|
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
@interface AuthInputsView () <MXKCountryPickerViewControllerDelegate>
|
|
{
|
|
/**
|
|
The current email validation
|
|
*/
|
|
MXK3PID *submittedEmail;
|
|
|
|
/**
|
|
The current msisdn validation
|
|
*/
|
|
MXK3PID *submittedMSISDN;
|
|
UINavigationController *phoneNumberPickerNavigationController;
|
|
CountryPickerViewController *phoneNumberCountryPicker;
|
|
NBPhoneNumber *nbPhoneNumber;
|
|
|
|
/**
|
|
The set of parameters ready to use for a registration.
|
|
*/
|
|
NSDictionary *externalRegistrationParameters;
|
|
}
|
|
|
|
/**
|
|
The current view container displayed at last position.
|
|
*/
|
|
@property (nonatomic) UIView *currentLastContainer;
|
|
|
|
@end
|
|
|
|
@implementation AuthInputsView
|
|
@synthesize softLogoutCredentials;
|
|
|
|
+ (UINib *)nib
|
|
{
|
|
return [UINib nibWithNibName:NSStringFromClass(self)
|
|
bundle:[NSBundle bundleForClass:self]];
|
|
}
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
[super awakeFromNib];
|
|
|
|
_thirdPartyIdentifiersHidden = YES;
|
|
_isThirdPartyIdentifierPending = NO;
|
|
_isSingleSignOnRequired = NO;
|
|
|
|
self.userLoginTextField.placeholder = [VectorL10n authUserIdPlaceholder];
|
|
self.repeatPasswordTextField.placeholder = [VectorL10n authRepeatPasswordPlaceholder];
|
|
self.passWordTextField.placeholder = [VectorL10n authPasswordPlaceholder];
|
|
|
|
// Apply placeholder color
|
|
[self customizeViewRendering];
|
|
}
|
|
|
|
- (void)destroy
|
|
{
|
|
[super destroy];
|
|
|
|
submittedEmail = nil;
|
|
submittedMSISDN = nil;
|
|
}
|
|
|
|
-(void)layoutSubviews
|
|
{
|
|
[super layoutSubviews];
|
|
|
|
if (_currentLastContainer)
|
|
{
|
|
self.currentLastContainer = _currentLastContainer;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Override MXKView
|
|
|
|
-(void)customizeViewRendering
|
|
{
|
|
[super customizeViewRendering];
|
|
|
|
self.repeatPasswordTextField.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
self.userLoginTextField.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
self.passWordTextField.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
|
|
self.emailTextField.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
self.phoneTextField.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
|
|
self.isoCountryCodeLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
self.callingCodeLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
|
|
self.countryCodeButton.tintColor = ThemeService.shared.theme.textSecondaryColor;
|
|
|
|
self.messageLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
|
|
self.messageLabel.numberOfLines = 0;
|
|
|
|
self.userLoginSeparator.backgroundColor = ThemeService.shared.theme.lineBreakColor;
|
|
self.emailSeparator.backgroundColor = ThemeService.shared.theme.lineBreakColor;
|
|
self.phoneSeparator.backgroundColor = ThemeService.shared.theme.lineBreakColor;
|
|
self.passwordSeparator.backgroundColor = ThemeService.shared.theme.lineBreakColor;
|
|
self.repeatPasswordSeparator.backgroundColor = ThemeService.shared.theme.lineBreakColor;
|
|
|
|
[self.ssoButton.layer setCornerRadius:5];
|
|
self.ssoButton.clipsToBounds = YES;
|
|
[self.ssoButton setTitle:[VectorL10n authLoginSingleSignOn] forState:UIControlStateNormal];
|
|
[self.ssoButton setTitle:[VectorL10n authLoginSingleSignOn] forState:UIControlStateHighlighted];
|
|
self.ssoButton.backgroundColor = ThemeService.shared.theme.tintColor;
|
|
|
|
self.recaptchaContainer.backgroundColor = ThemeService.shared.theme.backgroundColor;
|
|
|
|
if (self.userLoginTextField.placeholder)
|
|
{
|
|
self.userLoginTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.userLoginTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
}
|
|
|
|
if (self.repeatPasswordTextField.placeholder)
|
|
{
|
|
self.repeatPasswordTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.repeatPasswordTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
|
|
}
|
|
|
|
if (self.passWordTextField.placeholder)
|
|
{
|
|
self.passWordTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.passWordTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
}
|
|
|
|
if (self.phoneTextField.placeholder)
|
|
{
|
|
self.phoneTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.phoneTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
}
|
|
|
|
if (self.emailTextField.placeholder)
|
|
{
|
|
self.emailTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.emailTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (BOOL)setAuthSession:(MXAuthenticationSession *)authSession withAuthType:(MXKAuthenticationType)authType;
|
|
{
|
|
if (type == MXKAuthenticationTypeLogin || type == MXKAuthenticationTypeRegister)
|
|
{
|
|
// Validate first the provided session
|
|
MXAuthenticationSession *validSession = [self validateAuthenticationSession:authSession];
|
|
|
|
// Cancel email validation if any
|
|
if (submittedEmail)
|
|
{
|
|
[submittedEmail cancelCurrentRequest];
|
|
submittedEmail = nil;
|
|
}
|
|
|
|
// Cancel msisdn validation if any
|
|
if (submittedMSISDN)
|
|
{
|
|
[submittedMSISDN cancelCurrentRequest];
|
|
submittedMSISDN = nil;
|
|
}
|
|
|
|
// Reset external registration parameters
|
|
externalRegistrationParameters = nil;
|
|
|
|
// Reset UI by hidding all items
|
|
[self hideInputsContainer];
|
|
|
|
if ([super setAuthSession:validSession withAuthType:authType])
|
|
{
|
|
if (authType == MXKAuthenticationTypeLogin)
|
|
{
|
|
_isSingleSignOnRequired = NO;
|
|
|
|
if ([self isFlowSupported:kMXLoginFlowTypePassword])
|
|
{
|
|
BOOL showPhoneTextField = BuildSettings.authScreenShowPhoneNumber;
|
|
|
|
self.passWordTextField.returnKeyType = UIReturnKeyDone;
|
|
self.phoneTextField.returnKeyType = UIReturnKeyNext;
|
|
|
|
self.userLoginTextField.placeholder = [VectorL10n authUserIdPlaceholder];
|
|
self.messageLabel.text = [VectorL10n or];
|
|
self.phoneTextField.placeholder = [VectorL10n authPhonePlaceholder];
|
|
|
|
self.userLoginTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.userLoginTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
self.phoneTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.phoneTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
|
|
self.userLoginContainer.hidden = NO;
|
|
self.messageLabel.hidden = !showPhoneTextField;
|
|
self.phoneContainer.hidden = !showPhoneTextField;
|
|
self.passwordContainer.hidden = NO;
|
|
|
|
self.messageLabelTopConstraint.constant = 59;
|
|
|
|
CGFloat phoneContainerTopConstraintConstant = 0.0;
|
|
CGFloat passwordContainerTopConstraintConstant = 0.0;
|
|
|
|
if (showPhoneTextField)
|
|
{
|
|
phoneContainerTopConstraintConstant = 70;
|
|
passwordContainerTopConstraintConstant = 150;
|
|
}
|
|
else
|
|
{
|
|
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
|
|
passwordContainerTopConstraintConstant = deviceOrientation == UIDeviceOrientationPortrait ? 70 : 50;
|
|
}
|
|
|
|
self.phoneContainerTopConstraint.constant = phoneContainerTopConstraintConstant;
|
|
self.passwordContainerTopConstraint.constant = passwordContainerTopConstraintConstant;
|
|
|
|
self.currentLastContainer = self.passwordContainer;
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeCAS]
|
|
|| [self isFlowSupported:kMXLoginFlowTypeSSO])
|
|
{
|
|
|
|
self.ssoButtonContainer.hidden = NO;
|
|
self.currentLastContainer = self.ssoButtonContainer;
|
|
|
|
_isSingleSignOnRequired = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Update the registration inputs layout by hidding third-party ids fields.
|
|
self.thirdPartyIdentifiersHidden = _thirdPartyIdentifiersHidden;
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSString*)validateParameters
|
|
{
|
|
// Consider everything is fine when external registration parameters are ready to use
|
|
if (externalRegistrationParameters)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
// Check the validity of the parameters
|
|
NSString *errorMsg = nil;
|
|
|
|
// Remove whitespace in user login text field
|
|
NSString *userLogin = self.userLoginTextField.text;
|
|
self.userLoginTextField.text = [userLogin stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
|
|
if (type == MXKAuthenticationTypeLogin)
|
|
{
|
|
if ([self isFlowSupported:kMXLoginFlowTypePassword])
|
|
{
|
|
// Check required fields
|
|
if ((!self.userLoginTextField.text.length && !nbPhoneNumber) || !self.passWordTextField.text.length)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid user/password");
|
|
errorMsg = [VectorL10n authInvalidLoginParam];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorMsg = [VectorL10n notSupportedYet];
|
|
}
|
|
}
|
|
else if (type == MXKAuthenticationTypeRegister)
|
|
{
|
|
if (self.isThirdPartyIdentifiersHidden)
|
|
{
|
|
if (!self.userLoginTextField.text.length)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid user name");
|
|
errorMsg = [VectorL10n authInvalidUserName];
|
|
}
|
|
else if (!self.passWordTextField.text.length)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Missing Passwords");
|
|
errorMsg = [VectorL10n authMissingPassword];
|
|
}
|
|
else if (self.passWordTextField.text.length < 6)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid Passwords");
|
|
errorMsg = [VectorL10n authInvalidPassword];
|
|
}
|
|
else if ([self.repeatPasswordTextField.text isEqualToString:self.passWordTextField.text] == NO)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Passwords don't match");
|
|
errorMsg = [VectorL10n authPasswordDontMatch];
|
|
}
|
|
else
|
|
{
|
|
// Check validity of the non empty user name
|
|
NSString *user = self.userLoginTextField.text;
|
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[a-z0-9.\\-_]+$" options:NSRegularExpressionCaseInsensitive error:nil];
|
|
|
|
if ([regex firstMatchInString:user options:0 range:NSMakeRange(0, user.length)] == nil)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid user name");
|
|
errorMsg = [VectorL10n authInvalidUserName];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check email field
|
|
if ([self isFlowSupported:kMXLoginFlowTypeEmailIdentity] && !self.emailTextField.text.length)
|
|
{
|
|
if (self.areAllThirdPartyIdentifiersRequired)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Missing email");
|
|
errorMsg = [VectorL10n authMissingEmail];
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeMSISDN] && !self.phoneTextField.text.length && self.isThirdPartyIdentifierRequired)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Missing email or phone number");
|
|
errorMsg = [VectorL10n authMissingEmailOrPhone];
|
|
}
|
|
}
|
|
|
|
if (!errorMsg)
|
|
{
|
|
// Check phone field
|
|
if ([self isFlowSupported:kMXLoginFlowTypeMSISDN] && !self.phoneTextField.text.length)
|
|
{
|
|
if (self.areAllThirdPartyIdentifiersRequired)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Missing phone");
|
|
errorMsg = [VectorL10n authMissingPhone];
|
|
}
|
|
}
|
|
|
|
if (!errorMsg)
|
|
{
|
|
// Check email/phone validity
|
|
if (self.emailTextField.text.length)
|
|
{
|
|
// Check validity of the non empty email
|
|
if (![MXTools isEmailAddress:self.emailTextField.text])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid email");
|
|
errorMsg = [VectorL10n authInvalidEmail];
|
|
}
|
|
}
|
|
|
|
if (!errorMsg && nbPhoneNumber)
|
|
{
|
|
// Check validity of the non empty phone
|
|
if (![[NBPhoneNumberUtil sharedInstance] isValidNumber:nbPhoneNumber])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Invalid phone number");
|
|
errorMsg = [VectorL10n authInvalidPhone];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return errorMsg;
|
|
}
|
|
|
|
- (void)prepareParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
|
{
|
|
if (callback)
|
|
{
|
|
// Return external registration parameters if any
|
|
if (externalRegistrationParameters)
|
|
{
|
|
// We trigger here a registration based on external inputs. All the required data are handled by the session id.
|
|
MXLogDebug(@"[AuthInputsView] prepareParameters: return external registration parameters");
|
|
callback(externalRegistrationParameters, nil);
|
|
|
|
// CAUTION: Do not reset this dictionary here, it is used later to handle this registration until the end (see [updateAuthSessionWithCompletedStages:didUpdateParameters:])
|
|
|
|
return;
|
|
}
|
|
|
|
// Prepare here parameters dict by checking each required fields.
|
|
NSDictionary *parameters = nil;
|
|
|
|
// Check the validity of the parameters
|
|
NSString *errorMsg = [self validateParameters];
|
|
if (errorMsg)
|
|
{
|
|
if (inputsAlert)
|
|
{
|
|
[inputsAlert dismissViewControllerAnimated:NO completion:nil];
|
|
}
|
|
|
|
inputsAlert = [UIAlertController alertControllerWithTitle:[VectorL10n error] message:errorMsg preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[inputsAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
|
|
self->inputsAlert = nil;
|
|
|
|
}]];
|
|
|
|
[self.delegate authInputsView:self presentAlertController:inputsAlert];
|
|
}
|
|
else
|
|
{
|
|
// Handle here the supported login flow
|
|
if (type == MXKAuthenticationTypeLogin)
|
|
{
|
|
if ([self isFlowSupported:kMXLoginFlowTypePassword])
|
|
{
|
|
// Check whether the user login has been set.
|
|
NSString *user = self.userLoginTextField.text;
|
|
|
|
if (user.length)
|
|
{
|
|
// Check whether user login is an email or a username.
|
|
if ([MXTools isEmailAddress:user])
|
|
{
|
|
parameters = @{
|
|
@"type": kMXLoginFlowTypePassword,
|
|
@"identifier": @{
|
|
@"type": kMXLoginIdentifierTypeThirdParty,
|
|
@"medium": kMX3PIDMediumEmail,
|
|
@"address": user
|
|
},
|
|
@"password": self.passWordTextField.text,
|
|
// Patch: add the old login api parameters for an email address (medium and address),
|
|
// to keep logging in against old HS.
|
|
@"medium": kMX3PIDMediumEmail,
|
|
@"address": user
|
|
};
|
|
}
|
|
else
|
|
{
|
|
parameters = @{
|
|
@"type": kMXLoginFlowTypePassword,
|
|
@"identifier": @{
|
|
@"type": kMXLoginIdentifierTypeUser,
|
|
@"user": user
|
|
},
|
|
@"password": self.passWordTextField.text,
|
|
// Patch: add the old login api parameters for a username (user),
|
|
// to keep logging in against old HS.
|
|
@"user": user
|
|
};
|
|
}
|
|
}
|
|
else if (nbPhoneNumber)
|
|
{
|
|
NSString *countryCode = [[NBPhoneNumberUtil sharedInstance] getRegionCodeForNumber:nbPhoneNumber];
|
|
NSString *e164 = [[NBPhoneNumberUtil sharedInstance] format:nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil];
|
|
NSString *msisdn;
|
|
if ([e164 hasPrefix:@"+"])
|
|
{
|
|
msisdn = [e164 substringFromIndex:1];
|
|
}
|
|
else if ([e164 hasPrefix:@"00"])
|
|
{
|
|
msisdn = [e164 substringFromIndex:2];
|
|
}
|
|
|
|
if (msisdn && countryCode)
|
|
{
|
|
parameters = @{
|
|
@"type": kMXLoginFlowTypePassword,
|
|
@"identifier": @{
|
|
@"type": kMXLoginIdentifierTypePhone,
|
|
@"country": countryCode,
|
|
@"number": msisdn
|
|
},
|
|
@"password": self.passWordTextField.text
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
// For soft logout, pass the device_id currently used
|
|
if (parameters && self.softLogoutCredentials)
|
|
{
|
|
NSMutableDictionary *parametersWithDeviceId = [parameters mutableCopy];
|
|
parametersWithDeviceId[@"device_id"] = self.softLogoutCredentials.deviceId;
|
|
parameters = parametersWithDeviceId;
|
|
}
|
|
|
|
}
|
|
else if (type == MXKAuthenticationTypeRegister)
|
|
{
|
|
// Check whether a phone number has been set, and if it is not handled yet
|
|
if (nbPhoneNumber && ![self isFlowCompleted:kMXLoginFlowTypeMSISDN])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare msisdn stage");
|
|
|
|
// Retrieve the REST client from delegate
|
|
MXRestClient *restClient;
|
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationRestClient:)])
|
|
{
|
|
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
|
|
}
|
|
|
|
if (restClient)
|
|
{
|
|
MXWeakify(self);
|
|
[self checkIdentityServerRequirement:restClient success:^(BOOL identityServerRequired) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
if (identityServerRequired && !restClient.identityServer)
|
|
{
|
|
callback(nil, [NSError errorWithDomain:MXKAuthErrorDomain
|
|
code:0
|
|
userInfo:@{
|
|
NSLocalizedDescriptionKey:[VectorL10n authPhoneIsRequired]
|
|
}]);
|
|
return;
|
|
}
|
|
|
|
// Check whether a second 3pid is available
|
|
self->_isThirdPartyIdentifierPending = (!self.emailContainer.isHidden && self.emailTextField.text.length && ![self isFlowCompleted:kMXLoginFlowTypeEmailIdentity]);
|
|
|
|
// Launch msisdn validation
|
|
NSString *e164 = [[NBPhoneNumberUtil sharedInstance] format:self->nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil];
|
|
NSString *msisdn;
|
|
if ([e164 hasPrefix:@"+"])
|
|
{
|
|
msisdn = [e164 substringFromIndex:1];
|
|
}
|
|
else if ([e164 hasPrefix:@"00"])
|
|
{
|
|
msisdn = [e164 substringFromIndex:2];
|
|
}
|
|
self->submittedMSISDN = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumMSISDN andAddress:msisdn];
|
|
|
|
[self->submittedMSISDN requestValidationTokenWithMatrixRestClient:restClient
|
|
isDuringRegistration:YES
|
|
nextLink:nil
|
|
success:^
|
|
{
|
|
|
|
[self showValidationMSISDNDialogToPrepareParameters:callback];
|
|
|
|
}
|
|
failure:^(NSError *error)
|
|
{
|
|
|
|
MXLogDebug(@"[AuthInputsView] Failed to request msisdn token");
|
|
|
|
// Ignore connection cancellation error
|
|
if (([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Translate the potential MX error.
|
|
MXError *mxError = [[MXError alloc] initWithNSError:error];
|
|
if (mxError && ([mxError.errcode isEqualToString:kMXErrCodeStringThreePIDInUse] || [mxError.errcode isEqualToString:kMXErrCodeStringServerNotTrusted]))
|
|
{
|
|
NSMutableDictionary *userInfo;
|
|
if (error.userInfo)
|
|
{
|
|
userInfo = [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
|
|
}
|
|
else
|
|
{
|
|
userInfo = [NSMutableDictionary dictionary];
|
|
}
|
|
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = nil;
|
|
|
|
if ([mxError.errcode isEqualToString:kMXErrCodeStringThreePIDInUse])
|
|
{
|
|
userInfo[NSLocalizedDescriptionKey] = [VectorL10n authPhoneInUse];
|
|
userInfo[@"error"] = [VectorL10n authPhoneInUse];
|
|
}
|
|
else
|
|
{
|
|
userInfo[NSLocalizedDescriptionKey] = [VectorL10n authUntrustedIdServer];
|
|
userInfo[@"error"] = [VectorL10n authUntrustedIdServer];
|
|
}
|
|
|
|
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
|
|
}
|
|
|
|
callback(nil, error);
|
|
|
|
}];
|
|
|
|
|
|
} failure:^(NSError *error) {
|
|
callback(nil, error);
|
|
}];
|
|
|
|
// Async response
|
|
return;
|
|
}
|
|
MXLogDebug(@"[AuthInputsView] Authentication failed during the msisdn stage");
|
|
}
|
|
// Check whether an email has been set, and if it is not handled yet
|
|
else if (!self.emailContainer.isHidden && self.emailTextField.text.length && ![self isFlowCompleted:kMXLoginFlowTypeEmailIdentity])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare email identity stage");
|
|
|
|
// Retrieve the REST client from delegate
|
|
MXRestClient *restClient;
|
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationRestClient:)])
|
|
{
|
|
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
|
|
}
|
|
|
|
if (restClient)
|
|
{
|
|
MXWeakify(self);
|
|
[self checkIdentityServerRequirement:restClient success:^(BOOL identityServerRequired) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
if (identityServerRequired && !restClient.identityServer)
|
|
{
|
|
callback(nil, [NSError errorWithDomain:MXKAuthErrorDomain
|
|
code:0
|
|
userInfo:@{
|
|
NSLocalizedDescriptionKey:[VectorL10n authEmailIsRequired]
|
|
}]);
|
|
return;
|
|
}
|
|
|
|
// Check whether a second 3pid is available
|
|
self->_isThirdPartyIdentifierPending = (self->nbPhoneNumber && ![self isFlowCompleted:kMXLoginFlowTypeMSISDN]);
|
|
|
|
// Launch email validation
|
|
self->submittedEmail = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumEmail andAddress:self.emailTextField.text];
|
|
|
|
NSString *identityServer = restClient.identityServer;
|
|
|
|
[self->submittedEmail requestValidationTokenWithMatrixRestClient:restClient
|
|
isDuringRegistration:YES
|
|
nextLink:nil
|
|
success:^
|
|
{
|
|
NSMutableDictionary *threepidCreds = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
@"client_secret": self->submittedEmail.clientSecret,
|
|
|
|
@"sid": self->submittedEmail.sid
|
|
}];
|
|
if (identityServer)
|
|
{
|
|
NSURL *identServerURL = [NSURL URLWithString:identityServer];
|
|
threepidCreds[@"id_server"] = identServerURL.host;
|
|
}
|
|
|
|
NSDictionary *parameters;
|
|
parameters = @{
|
|
@"auth": @{
|
|
@"session":self->currentSession.session,
|
|
@"threepid_creds": threepidCreds,
|
|
@"type": kMXLoginFlowTypeEmailIdentity},
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text,
|
|
};
|
|
|
|
[self hideInputsContainer];
|
|
|
|
self.messageLabel.text = [VectorL10n authEmailValidationMessage];
|
|
self.messageLabel.hidden = NO;
|
|
|
|
callback(parameters, nil);
|
|
|
|
}
|
|
failure:^(NSError *error)
|
|
{
|
|
|
|
MXLogDebug(@"[AuthInputsView] Failed to request email token");
|
|
|
|
// Ignore connection cancellation error
|
|
if (([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Translate the potential MX error.
|
|
MXError *mxError = [[MXError alloc] initWithNSError:error];
|
|
if (mxError && ([mxError.errcode isEqualToString:kMXErrCodeStringThreePIDInUse] || [mxError.errcode isEqualToString:kMXErrCodeStringServerNotTrusted]))
|
|
{
|
|
NSMutableDictionary *userInfo;
|
|
if (error.userInfo)
|
|
{
|
|
userInfo = [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
|
|
}
|
|
else
|
|
{
|
|
userInfo = [NSMutableDictionary dictionary];
|
|
}
|
|
|
|
userInfo[NSLocalizedFailureReasonErrorKey] = nil;
|
|
|
|
if ([mxError.errcode isEqualToString:kMXErrCodeStringThreePIDInUse])
|
|
{
|
|
userInfo[NSLocalizedDescriptionKey] = [VectorL10n authEmailInUse];
|
|
userInfo[@"error"] = [VectorL10n authEmailInUse];
|
|
}
|
|
else
|
|
{
|
|
userInfo[NSLocalizedDescriptionKey] = [VectorL10n authUntrustedIdServer];
|
|
userInfo[@"error"] = [VectorL10n authUntrustedIdServer];
|
|
}
|
|
|
|
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
|
|
}
|
|
callback(nil, error);
|
|
|
|
}];
|
|
} failure:^(NSError *error) {
|
|
callback(nil, error);
|
|
}];
|
|
|
|
// Async response
|
|
return;
|
|
}
|
|
MXLogDebug(@"[AuthInputsView] Authentication failed during the email identity stage");
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeRecaptcha] && ![self isFlowCompleted:kMXLoginFlowTypeRecaptcha])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare reCaptcha stage");
|
|
|
|
[self displayRecaptchaForm:^(NSString *response) {
|
|
|
|
if (response.length)
|
|
{
|
|
NSDictionary *parameters = @{
|
|
@"auth": @{
|
|
@"session": self->currentSession.session,
|
|
@"response": response,
|
|
@"type": kMXLoginFlowTypeRecaptcha
|
|
},
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text,
|
|
};
|
|
|
|
callback(parameters, nil);
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] reCaptcha stage failed");
|
|
callback(nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[VectorL10n notSupportedYet]}]);
|
|
}
|
|
|
|
}];
|
|
|
|
// Async response
|
|
return;
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeDummy] && ![self isFlowCompleted:kMXLoginFlowTypeDummy])
|
|
{
|
|
parameters = @{
|
|
@"auth": @{
|
|
@"session":currentSession.session,
|
|
@"type": kMXLoginFlowTypeDummy
|
|
},
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text,
|
|
};
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypePassword] && ![self isFlowCompleted:kMXLoginFlowTypePassword])
|
|
{
|
|
// Note: this use case was not tested yet.
|
|
parameters = @{
|
|
@"auth": @{
|
|
@"session":currentSession.session,
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text,
|
|
@"type": kMXLoginFlowTypePassword
|
|
}
|
|
};
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeTerms] && ![self isFlowCompleted:kMXLoginFlowTypeTerms])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare terms stage");
|
|
|
|
MXWeakify(self);
|
|
[self displayTermsView:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
NSDictionary *parameters = @{
|
|
@"auth": @{
|
|
@"session":self->currentSession.session,
|
|
@"type": kMXLoginFlowTypeTerms
|
|
},
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text
|
|
};
|
|
callback(parameters, nil);
|
|
}];
|
|
|
|
// Async response
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
callback(parameters, nil);
|
|
}
|
|
}
|
|
|
|
- (void)updateAuthSessionWithCompletedStages:(NSArray *)completedStages didUpdateParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
|
{
|
|
if (callback)
|
|
{
|
|
if (currentSession)
|
|
{
|
|
currentSession.completed = completedStages;
|
|
|
|
BOOL isMSISDNFlowCompleted = [self isFlowCompleted:kMXLoginFlowTypeMSISDN];
|
|
BOOL isEmailFlowCompleted = [self isFlowCompleted:kMXLoginFlowTypeEmailIdentity];
|
|
|
|
// Check the supported use cases
|
|
if (isMSISDNFlowCompleted && self.isThirdPartyIdentifierPending)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare a new third-party stage");
|
|
|
|
// Here an email address is available, we add it to the authentication session.
|
|
[self prepareParameters:callback];
|
|
|
|
return;
|
|
}
|
|
else if ((isMSISDNFlowCompleted || isEmailFlowCompleted)
|
|
&& [self isFlowSupported:kMXLoginFlowTypeRecaptcha] && ![self isFlowCompleted:kMXLoginFlowTypeRecaptcha])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Display reCaptcha stage");
|
|
|
|
if (externalRegistrationParameters)
|
|
{
|
|
[self displayRecaptchaForm:^(NSString *response) {
|
|
|
|
if (response.length)
|
|
{
|
|
// We finalize here a registration triggered from external inputs. All the required data are handled by the session id
|
|
NSDictionary *parameters = @{
|
|
@"auth": @{@"session": self->currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha},
|
|
};
|
|
callback (parameters, nil);
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] reCaptcha stage failed");
|
|
callback (nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[VectorL10n notSupportedYet]}]);
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
[self prepareParameters:callback];
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if ([self isFlowSupported:kMXLoginFlowTypeTerms] && ![self isFlowCompleted:kMXLoginFlowTypeTerms])
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Prepare a new terms stage");
|
|
|
|
if (externalRegistrationParameters)
|
|
{
|
|
[self displayTermsView:^{
|
|
|
|
NSDictionary *parameters = @{
|
|
@"auth": @{
|
|
@"session":self->currentSession.session,
|
|
@"type": kMXLoginFlowTypeTerms
|
|
}
|
|
};
|
|
callback(parameters, nil);
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
[self prepareParameters:callback];
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
MXLogDebug(@"[AuthInputsView] updateAuthSessionWithCompletedStages failed");
|
|
callback (nil, [NSError errorWithDomain:MXKAuthErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey:[VectorL10n notSupportedYet]}]);
|
|
}
|
|
}
|
|
|
|
- (BOOL)setExternalRegistrationParameters:(NSDictionary *)registrationParameters
|
|
{
|
|
// Presently we only support a registration based on next_link associated to a successful email validation.
|
|
NSString *homeserverURL;
|
|
NSString *identityURL;
|
|
|
|
// Check the current authentication type
|
|
if (self.authType != MXKAuthenticationTypeRegister)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] setExternalRegistrationParameters failed: wrong auth type");
|
|
return NO;
|
|
}
|
|
|
|
// Retrieve the REST client from delegate
|
|
MXRestClient *restClient;
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationRestClient:)])
|
|
{
|
|
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
|
|
}
|
|
|
|
if (restClient)
|
|
{
|
|
// Sanity check on homeserver
|
|
id hs_url = registrationParameters[@"hs_url"];
|
|
if (hs_url && [hs_url isKindOfClass:NSString.class])
|
|
{
|
|
homeserverURL = hs_url;
|
|
|
|
if ([homeserverURL isEqualToString:restClient.homeserver] == NO)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] setExternalRegistrationParameters failed: wrong homeserver URL");
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
// Sanity check on identity server
|
|
id is_url = registrationParameters[@"is_url"];
|
|
if (is_url && [is_url isKindOfClass:NSString.class])
|
|
{
|
|
identityURL = is_url;
|
|
|
|
if ([identityURL isEqualToString:restClient.identityServer] == NO)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] setExternalRegistrationParameters failed: wrong identity server URL");
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] setExternalRegistrationParameters failed: not supported");
|
|
return NO;
|
|
}
|
|
|
|
// Retrieve other parameters
|
|
NSString *clientSecret;
|
|
NSString *sid;
|
|
NSString *sessionId;
|
|
|
|
id value = registrationParameters[@"client_secret"];
|
|
if (value && [value isKindOfClass:NSString.class])
|
|
{
|
|
clientSecret = value;
|
|
}
|
|
value = registrationParameters[@"sid"];
|
|
if (value && [value isKindOfClass:NSString.class])
|
|
{
|
|
sid = value;
|
|
}
|
|
value = registrationParameters[@"session_id"];
|
|
if (value && [value isKindOfClass:NSString.class])
|
|
{
|
|
sessionId = value;
|
|
}
|
|
|
|
// Check validity of the required parameters
|
|
if (!homeserverURL.length || !clientSecret.length || !sid.length || !sessionId.length)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] setExternalRegistrationParameters failed: wrong parameters");
|
|
return NO;
|
|
}
|
|
|
|
// Prepare the registration parameters (Ready to use)
|
|
|
|
NSMutableDictionary *threepidCreds = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
@"client_secret": clientSecret,
|
|
|
|
@"sid": sid
|
|
}];
|
|
if (identityURL)
|
|
{
|
|
NSURL *identServerURL = [NSURL URLWithString:identityURL];
|
|
threepidCreds[@"id_server"] = identServerURL.host;
|
|
}
|
|
|
|
externalRegistrationParameters = @{
|
|
@"auth": @{
|
|
@"session": sessionId,
|
|
@"threepid_creds": threepidCreds,
|
|
@"type": kMXLoginFlowTypeEmailIdentity
|
|
},
|
|
};
|
|
|
|
// Hide all inputs by default
|
|
[self hideInputsContainer];
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (void)setSoftLogoutCredentials:(MXCredentials *)credentials
|
|
{
|
|
softLogoutCredentials = credentials;
|
|
self.userLoginTextField.text = softLogoutCredentials.userId;
|
|
self.userLoginContainer.hidden = YES;
|
|
self.phoneContainer.hidden = YES;
|
|
|
|
[self displaySoftLogoutMessage];
|
|
}
|
|
|
|
- (void)displaySoftLogoutMessage
|
|
{
|
|
// Take some shortcuts and make some assumptions (Riot uses MXFileStore and MXRealmCryptoStore) to
|
|
// retrieve data to display as quick as possible
|
|
MXRealmCryptoStore *cryptoStore = [[MXRealmCryptoStore alloc] initWithCredentials:self.softLogoutCredentials];
|
|
BOOL keyBackupNeeded = [cryptoStore inboundGroupSessionsToBackup:1].count > 0;
|
|
|
|
MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:softLogoutCredentials];
|
|
[fileStore asyncUsersWithUserIds:@[softLogoutCredentials.userId] success:^(NSArray<MXUser *> * _Nonnull users) {
|
|
|
|
MXUser *myUser = users.firstObject;
|
|
[fileStore close];
|
|
|
|
[self displaySoftLogoutMessageWithUserDisplayname:myUser.displayname andKeyBackupNeeded:keyBackupNeeded];
|
|
|
|
} failure:^(NSError * _Nonnull error) {
|
|
MXLogDebug(@"[AuthInputsView] displaySoftLogoutMessage: Cannot load displayname. Error: %@", error);
|
|
[self displaySoftLogoutMessageWithUserDisplayname:nil andKeyBackupNeeded:keyBackupNeeded];
|
|
}];
|
|
}
|
|
|
|
- (void)displaySoftLogoutMessageWithUserDisplayname:(NSString*)userDisplayname andKeyBackupNeeded:(BOOL)keyBackupNeeded
|
|
{
|
|
// Use messageLabel for this message
|
|
self.messageLabelTopConstraint.constant = 8;
|
|
self.messageLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
|
|
self.messageLabel.hidden = NO;
|
|
|
|
NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:[VectorL10n authSoftlogoutSignIn]
|
|
attributes:@{
|
|
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]
|
|
}];
|
|
|
|
[message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
|
|
|
|
NSString *string = [VectorL10n authSoftlogoutReason:softLogoutCredentials.homeServerName :userDisplayname :softLogoutCredentials.userId];
|
|
[message appendAttributedString:[[NSAttributedString alloc] initWithString:string
|
|
attributes:@{
|
|
NSFontAttributeName: [UIFont systemFontOfSize:14]
|
|
}]];
|
|
|
|
if (keyBackupNeeded)
|
|
{
|
|
[message appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]];
|
|
string = [VectorL10n authSoftlogoutRecoverEncryptionKeys];
|
|
[message appendAttributedString:[[NSAttributedString alloc] initWithString:string
|
|
attributes:@{
|
|
NSFontAttributeName: [UIFont systemFontOfSize:14]
|
|
}]];
|
|
}
|
|
|
|
self.messageLabel.attributedText = message;
|
|
}
|
|
|
|
- (BOOL)areAllRequiredFieldsSet
|
|
{
|
|
// Keep enable the submit button.
|
|
return YES;
|
|
}
|
|
|
|
- (void)dismissKeyboard
|
|
{
|
|
[self.userLoginTextField resignFirstResponder];
|
|
[self.passWordTextField resignFirstResponder];
|
|
[self.emailTextField resignFirstResponder];
|
|
[self.phoneTextField resignFirstResponder];
|
|
[self.repeatPasswordTextField resignFirstResponder];
|
|
|
|
[super dismissKeyboard];
|
|
}
|
|
|
|
- (void)dismissCountryPicker
|
|
{
|
|
[phoneNumberCountryPicker withdrawViewControllerAnimated:YES completion:nil];
|
|
[phoneNumberCountryPicker destroy];
|
|
phoneNumberCountryPicker = nil;
|
|
|
|
[phoneNumberPickerNavigationController dismissViewControllerAnimated:YES completion:nil];
|
|
phoneNumberPickerNavigationController = nil;
|
|
}
|
|
|
|
- (NSString*)userId
|
|
{
|
|
return self.userLoginTextField.text;
|
|
}
|
|
|
|
- (NSString*)password
|
|
{
|
|
return self.passWordTextField.text;
|
|
}
|
|
|
|
- (void)setCurrentLastContainer:(UIView*)currentLastContainer
|
|
{
|
|
_currentLastContainer = currentLastContainer;
|
|
|
|
CGRect frame = _currentLastContainer.frame;
|
|
self.viewHeightConstraint.constant = frame.origin.y + frame.size.height;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (BOOL)areThirdPartyIdentifiersSupported
|
|
{
|
|
return ([self isFlowSupported:kMXLoginFlowTypeEmailIdentity] || [self isFlowSupported:kMXLoginFlowTypeMSISDN]);
|
|
}
|
|
|
|
- (BOOL)isThirdPartyIdentifierRequired
|
|
{
|
|
// Check first whether some 3pids are supported
|
|
if (!self.areThirdPartyIdentifiersSupported)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
// Check whether an account may be created without third-party identifiers.
|
|
for (MXLoginFlow *loginFlow in currentSession.flows)
|
|
{
|
|
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeEmailIdentity] == NSNotFound
|
|
&& [loginFlow.stages indexOfObject:kMXLoginFlowTypeMSISDN] == NSNotFound)
|
|
{
|
|
// There is a flow with no 3pids
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)areAllThirdPartyIdentifiersRequired
|
|
{
|
|
// Check first whether some 3pids are required
|
|
if (!self.isThirdPartyIdentifierRequired)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
BOOL isEmailIdentityFlowSupported = [self isFlowSupported:kMXLoginFlowTypeEmailIdentity];
|
|
BOOL isMSISDNFlowSupported = [self isFlowSupported:kMXLoginFlowTypeMSISDN];
|
|
|
|
for (MXLoginFlow *loginFlow in currentSession.flows)
|
|
{
|
|
if (isEmailIdentityFlowSupported)
|
|
{
|
|
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeEmailIdentity] == NSNotFound)
|
|
{
|
|
return NO;
|
|
}
|
|
else if (isMSISDNFlowSupported)
|
|
{
|
|
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeMSISDN] == NSNotFound)
|
|
{
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
else if (isMSISDNFlowSupported)
|
|
{
|
|
if ([loginFlow.stages indexOfObject:kMXLoginFlowTypeMSISDN] == NSNotFound)
|
|
{
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (void)setThirdPartyIdentifiersHidden:(BOOL)thirdPartyIdentifiersHidden
|
|
{
|
|
[self hideInputsContainer];
|
|
|
|
UIView *lastViewContainer;
|
|
|
|
if (thirdPartyIdentifiersHidden)
|
|
{
|
|
self.passWordTextField.returnKeyType = UIReturnKeyNext;
|
|
|
|
self.userLoginTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:[VectorL10n authUserNamePlaceholder]
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
|
|
self.userLoginContainer.hidden = NO;
|
|
self.passwordContainer.hidden = NO;
|
|
self.repeatPasswordContainer.hidden = NO;
|
|
|
|
self.passwordContainerTopConstraint.constant = 50;
|
|
|
|
lastViewContainer = self.repeatPasswordContainer;
|
|
}
|
|
else
|
|
{
|
|
if ([self isFlowSupported:kMXLoginFlowTypeEmailIdentity])
|
|
{
|
|
if (self.isThirdPartyIdentifierRequired)
|
|
{
|
|
self.emailTextField.placeholder = [VectorL10n authEmailPlaceholder];
|
|
}
|
|
else
|
|
{
|
|
self.emailTextField.placeholder = [VectorL10n authOptionalEmailPlaceholder];
|
|
}
|
|
|
|
self.emailTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.emailTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
|
|
self.emailContainer.hidden = NO;
|
|
|
|
self.messageLabel.hidden = NO;
|
|
self.messageLabel.text = [VectorL10n authAddEmailMessage2];
|
|
|
|
lastViewContainer = self.emailContainer;
|
|
}
|
|
|
|
if ([self isFlowSupported:kMXLoginFlowTypeMSISDN])
|
|
{
|
|
self.phoneTextField.returnKeyType = UIReturnKeyDone;
|
|
|
|
if (self.isThirdPartyIdentifierRequired)
|
|
{
|
|
self.phoneTextField.placeholder = [VectorL10n authPhonePlaceholder];
|
|
}
|
|
else
|
|
{
|
|
self.phoneTextField.placeholder = [VectorL10n authOptionalPhonePlaceholder];
|
|
}
|
|
|
|
self.phoneTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
|
initWithString:self.phoneTextField.placeholder
|
|
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
|
|
|
|
self.phoneContainer.hidden = NO;
|
|
|
|
if (!_emailContainer.isHidden)
|
|
{
|
|
self.emailTextField.returnKeyType = UIReturnKeyNext;
|
|
|
|
self.phoneContainerTopConstraint.constant = 50;
|
|
self.messageLabel.text = [VectorL10n authAddEmailPhoneMessage2];
|
|
}
|
|
else
|
|
{
|
|
self.phoneContainerTopConstraint.constant = 0;
|
|
|
|
self.messageLabel.hidden = NO;
|
|
self.messageLabel.text = [VectorL10n authAddPhoneMessage2];
|
|
}
|
|
|
|
lastViewContainer = self.phoneContainer;
|
|
}
|
|
|
|
if (!self.messageLabel.isHidden)
|
|
{
|
|
[self.messageLabel sizeToFit];
|
|
|
|
CGRect frame = self.messageLabel.frame;
|
|
|
|
CGFloat offset = frame.origin.y + frame.size.height;
|
|
|
|
self.emailContainerTopConstraint.constant = offset;
|
|
self.phoneContainerTopConstraint.constant += offset;
|
|
}
|
|
}
|
|
|
|
self.currentLastContainer = lastViewContainer;
|
|
|
|
_thirdPartyIdentifiersHidden = thirdPartyIdentifiersHidden;
|
|
}
|
|
|
|
- (IBAction)selectPhoneNumberCountry:(id)sender
|
|
{
|
|
if ([self.delegate respondsToSelector:@selector(authInputsView:presentViewController:animated:)])
|
|
{
|
|
phoneNumberCountryPicker = [CountryPickerViewController countryPickerViewController];
|
|
phoneNumberCountryPicker.delegate = self;
|
|
phoneNumberCountryPicker.showCountryCallingCode = YES;
|
|
|
|
phoneNumberPickerNavigationController = [[RiotNavigationController alloc] init];
|
|
|
|
// Set Riot navigation bar colors
|
|
[ThemeService.shared.theme applyStyleOnNavigationBar:phoneNumberPickerNavigationController.navigationBar];
|
|
|
|
[phoneNumberPickerNavigationController pushViewController:phoneNumberCountryPicker animated:NO];
|
|
|
|
UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:AssetImages.backIcon.image style:UIBarButtonItemStylePlain target:self action:@selector(dismissCountryPicker)];
|
|
phoneNumberCountryPicker.navigationItem.leftBarButtonItem = leftBarButtonItem;
|
|
|
|
[self.delegate authInputsView:self presentViewController:phoneNumberPickerNavigationController animated:YES];
|
|
}
|
|
}
|
|
|
|
- (void)setIsoCountryCode:(NSString *)isoCountryCode
|
|
{
|
|
_isoCountryCode = isoCountryCode;
|
|
|
|
NSNumber *callingCode = [[NBPhoneNumberUtil sharedInstance] getCountryCodeForRegion:isoCountryCode];
|
|
|
|
self.callingCodeLabel.text = [NSString stringWithFormat:@"+%@", callingCode.stringValue];
|
|
|
|
self.isoCountryCodeLabel.text = isoCountryCode;
|
|
|
|
// Update displayed phone
|
|
[self textFieldDidChange:self.phoneTextField];
|
|
}
|
|
|
|
- (void)resetThirdPartyIdentifiers
|
|
{
|
|
[self dismissKeyboard];
|
|
|
|
self.emailTextField.text = nil;
|
|
self.phoneTextField.text = nil;
|
|
|
|
nbPhoneNumber = nil;
|
|
}
|
|
|
|
#pragma mark - MXKCountryPickerViewControllerDelegate
|
|
|
|
- (void)countryPickerViewController:(MXKCountryPickerViewController *)countryPickerViewController didSelectCountry:(NSString *)isoCountryCode
|
|
{
|
|
self.isoCountryCode = isoCountryCode;
|
|
|
|
nbPhoneNumber = [[NBPhoneNumberUtil sharedInstance] parse:self.phoneTextField.text defaultRegion:isoCountryCode error:nil];
|
|
[self formatNewPhoneNumber];
|
|
|
|
[self dismissCountryPicker];
|
|
}
|
|
|
|
#pragma mark - UITextField delegate
|
|
|
|
- (void)textFieldDidEndEditing:(UITextField*)textField
|
|
{
|
|
if (textField == self.userLoginTextField && type == MXKAuthenticationTypeLogin)
|
|
{
|
|
if ([MXTools isMatrixUserIdentifier:self.userLoginTextField.text])
|
|
{
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsView:autoDiscoverServerWithDomain:)])
|
|
{
|
|
NSString *domain = [self.userLoginTextField.text componentsSeparatedByString:@":"][1];
|
|
[self.delegate authInputsView:self autoDiscoverServerWithDomain:domain];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
|
{
|
|
if (textField.returnKeyType == UIReturnKeyDone)
|
|
{
|
|
// "Done" key has been pressed
|
|
[textField resignFirstResponder];
|
|
|
|
// Launch authentication now
|
|
[self.delegate authInputsViewDidPressDoneKey:self];
|
|
}
|
|
else
|
|
{
|
|
//"Next" key has been pressed
|
|
if (textField == self.userLoginTextField || textField == self.phoneTextField)
|
|
{
|
|
[self.passWordTextField becomeFirstResponder];
|
|
}
|
|
else if (textField == self.passWordTextField)
|
|
{
|
|
[self.repeatPasswordTextField becomeFirstResponder];
|
|
}
|
|
else if (textField == self.emailTextField)
|
|
{
|
|
[self.phoneTextField becomeFirstResponder];
|
|
}
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - TextField listener
|
|
|
|
- (IBAction)textFieldDidChange:(id)sender
|
|
{
|
|
UITextField* textField = (UITextField*)sender;
|
|
|
|
if (textField == self.phoneTextField)
|
|
{
|
|
nbPhoneNumber = [[NBPhoneNumberUtil sharedInstance] parse:self.phoneTextField.text defaultRegion:self.isoCountryCode error:nil];
|
|
|
|
[self formatNewPhoneNumber];
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)hideInputsContainer
|
|
{
|
|
// Hide all inputs container
|
|
self.userLoginContainer.hidden = YES;
|
|
self.passwordContainer.hidden = YES;
|
|
self.emailContainer.hidden = YES;
|
|
self.phoneContainer.hidden = YES;
|
|
self.repeatPasswordContainer.hidden = YES;
|
|
|
|
// Hide other items
|
|
self.messageLabelTopConstraint.constant = 8;
|
|
self.messageLabel.hidden = YES;
|
|
self.recaptchaContainer.hidden = YES;
|
|
self.termsView.hidden = YES;
|
|
self.ssoButtonContainer.hidden = YES;
|
|
|
|
_currentLastContainer = nil;
|
|
}
|
|
|
|
- (void)formatNewPhoneNumber
|
|
{
|
|
if (nbPhoneNumber)
|
|
{
|
|
NSString *formattedNumber = [[NBPhoneNumberUtil sharedInstance] format:nbPhoneNumber numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:nil];
|
|
NSString *prefix = self.callingCodeLabel.text;
|
|
if ([formattedNumber hasPrefix:prefix])
|
|
{
|
|
// Format the display phone number
|
|
self.phoneTextField.text = [formattedNumber substringFromIndex:prefix.length];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)displayRecaptchaForm:(void (^)(NSString *response))callback
|
|
{
|
|
// Retrieve the site key
|
|
NSString *siteKey;
|
|
|
|
id recaptchaParams = currentSession.params[kMXLoginFlowTypeRecaptcha];
|
|
if (recaptchaParams && [recaptchaParams isKindOfClass:NSDictionary.class])
|
|
{
|
|
NSDictionary *recaptchaParamsDict = (NSDictionary*)recaptchaParams;
|
|
siteKey = recaptchaParamsDict[@"public_key"];
|
|
}
|
|
|
|
// Retrieve the REST client from delegate
|
|
MXRestClient *restClient;
|
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationRestClient:)])
|
|
{
|
|
restClient = [self.delegate authInputsViewThirdPartyIdValidationRestClient:self];
|
|
}
|
|
|
|
// Sanity check
|
|
if (siteKey.length && restClient && callback)
|
|
{
|
|
[self hideInputsContainer];
|
|
|
|
self.messageLabel.hidden = NO;
|
|
self.messageLabel.text = [VectorL10n authRecaptchaMessage];
|
|
|
|
self.recaptchaContainer.hidden = NO;
|
|
self.currentLastContainer = self.recaptchaContainer;
|
|
|
|
// IB does not support WKWebview in a xib before iOS 11
|
|
// So, add it by coding
|
|
|
|
// Do some cleaning/reset before
|
|
for (UIView *view in self.recaptchaContainer.subviews)
|
|
{
|
|
[view removeFromSuperview];
|
|
}
|
|
|
|
MXKAuthenticationRecaptchaWebView *reCaptchaWebView = [MXKAuthenticationRecaptchaWebView new];
|
|
reCaptchaWebView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
[self.recaptchaContainer addSubview:reCaptchaWebView];
|
|
|
|
// Disable the webview scrollView to avoid 2 scrollviews on the same screen
|
|
reCaptchaWebView.scrollView.scrollEnabled = NO;
|
|
|
|
[self.recaptchaContainer addConstraints:
|
|
[NSLayoutConstraint constraintsWithVisualFormat:@"|-[view]-|"
|
|
options:0
|
|
metrics:0
|
|
views:@{
|
|
@"view": reCaptchaWebView
|
|
}
|
|
]
|
|
];
|
|
[self.recaptchaContainer addConstraints:
|
|
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|"
|
|
options:0
|
|
metrics:0
|
|
views:@{
|
|
@"view": reCaptchaWebView
|
|
}
|
|
]
|
|
];
|
|
|
|
|
|
[reCaptchaWebView openRecaptchaWidgetWithSiteKey:siteKey fromHomeServer:restClient.homeserver callback:callback];
|
|
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
// Tell whether a flow type is supported or not by this view.
|
|
- (BOOL)isSupportedFlowType:(MXLoginFlowType)flowType
|
|
{
|
|
if ([flowType isEqualToString:kMXLoginFlowTypePassword])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeEmailIdentity])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeRecaptcha])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeMSISDN])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeDummy])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeTerms])
|
|
{
|
|
return YES;
|
|
}
|
|
else if ([flowType isEqualToString:kMXLoginFlowTypeCAS] || [flowType isEqualToString:kMXLoginFlowTypeSSO])
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (MXAuthenticationSession*)validateAuthenticationSession:(MXAuthenticationSession*)authSession
|
|
{
|
|
// Check whether the listed flows in this authentication session are supported
|
|
NSMutableArray *supportedFlows = [NSMutableArray array];
|
|
|
|
for (MXLoginFlow* flow in authSession.flows)
|
|
{
|
|
// Check whether flow type is defined
|
|
if (flow.type)
|
|
{
|
|
if ([self isSupportedFlowType:flow.type])
|
|
{
|
|
// Check here all stages
|
|
BOOL isSupported = YES;
|
|
if (flow.stages.count)
|
|
{
|
|
for (NSString *stage in flow.stages)
|
|
{
|
|
if ([self isSupportedFlowType:stage] == NO)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] %@: %@ stage is not supported.", (type == MXKAuthenticationTypeLogin ? @"login" : @"register"), stage);
|
|
isSupported = NO;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flow.stages = @[flow.type];
|
|
}
|
|
|
|
if (isSupported)
|
|
{
|
|
[supportedFlows addObject:flow];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] %@: %@ stage is not supported.", (type == MXKAuthenticationTypeLogin ? @"login" : @"register"), flow.type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check here all stages
|
|
BOOL isSupported = YES;
|
|
if (flow.stages.count)
|
|
{
|
|
for (NSString *stage in flow.stages)
|
|
{
|
|
if ([self isSupportedFlowType:stage] == NO)
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] %@: %@ stage is not supported.", (type == MXKAuthenticationTypeLogin ? @"login" : @"register"), stage);
|
|
isSupported = NO;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isSupported)
|
|
{
|
|
[supportedFlows addObject:flow];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (supportedFlows.count)
|
|
{
|
|
if (supportedFlows.count == authSession.flows.count)
|
|
{
|
|
// Return the original session.
|
|
return authSession;
|
|
}
|
|
else
|
|
{
|
|
// Keep only the supported flow.
|
|
MXAuthenticationSession *updatedAuthSession = [[MXAuthenticationSession alloc] init];
|
|
updatedAuthSession.session = authSession.session;
|
|
updatedAuthSession.params = authSession.params;
|
|
updatedAuthSession.flows = supportedFlows;
|
|
return updatedAuthSession;
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (void)showValidationMSISDNDialogToPrepareParameters:(void (^)(NSDictionary *parameters, NSError *error))callback
|
|
{
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
if (inputsAlert)
|
|
{
|
|
[inputsAlert dismissViewControllerAnimated:NO completion:nil];
|
|
}
|
|
|
|
if (inputsAlert)
|
|
{
|
|
[inputsAlert dismissViewControllerAnimated:NO completion:nil];
|
|
}
|
|
|
|
inputsAlert = [UIAlertController alertControllerWithTitle:[VectorL10n authMsisdnValidationTitle] message:[VectorL10n authMsisdnValidationMessage] preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[inputsAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
|
|
if (weakSelf)
|
|
{
|
|
typeof(self) self = weakSelf;
|
|
self->inputsAlert = nil;
|
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewDidCancelOperation:)])
|
|
{
|
|
[self.delegate authInputsViewDidCancelOperation:self];
|
|
}
|
|
}
|
|
|
|
}]];
|
|
|
|
[inputsAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
|
|
|
textField.secureTextEntry = NO;
|
|
textField.placeholder = nil;
|
|
textField.keyboardType = UIKeyboardTypeDecimalPad;
|
|
|
|
}];
|
|
|
|
[inputsAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n submit]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
|
|
if (weakSelf)
|
|
{
|
|
typeof(self) self = weakSelf;
|
|
UITextField *textField = [self->inputsAlert textFields].firstObject;
|
|
NSString *smsCode = textField.text;
|
|
self->inputsAlert = nil;
|
|
|
|
if (smsCode.length)
|
|
{
|
|
[self->submittedMSISDN submitValidationToken:smsCode success:^{
|
|
|
|
// Retrieve the identity service from delegate
|
|
MXIdentityService *identityService;
|
|
|
|
if (self.delegate && [self.delegate respondsToSelector:@selector(authInputsViewThirdPartyIdValidationIdentityService:)])
|
|
{
|
|
identityService = [self.delegate authInputsViewThirdPartyIdValidationIdentityService:self];
|
|
}
|
|
|
|
NSString *identityServer = identityService.identityServer;
|
|
|
|
if (identityServer)
|
|
{
|
|
NSURL *identServerURL = [NSURL URLWithString:identityServer];
|
|
NSDictionary *parameters;
|
|
parameters = @{
|
|
@"auth": @{
|
|
@"session":self->currentSession.session,
|
|
@"threepid_creds": @{
|
|
@"client_secret": self->submittedMSISDN.clientSecret,
|
|
@"id_server": identServerURL.host,
|
|
@"sid": self->submittedMSISDN.sid
|
|
},
|
|
@"type": kMXLoginFlowTypeMSISDN
|
|
},
|
|
@"username": self.userLoginTextField.text,
|
|
@"password": self.passWordTextField.text
|
|
};
|
|
|
|
callback(parameters, nil);
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[AuthInputsView] Failed to retrieve identity server URL");
|
|
}
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
MXLogDebug(@"[AuthInputsView] Failed to submit the sms token");
|
|
|
|
// Ignore connection cancellation error
|
|
if (([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Alert user
|
|
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
|
|
NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
|
|
if (!title)
|
|
{
|
|
if (msg)
|
|
{
|
|
title = msg;
|
|
msg = nil;
|
|
}
|
|
else
|
|
{
|
|
title = [VectorL10n error];
|
|
}
|
|
}
|
|
|
|
self->inputsAlert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[self->inputsAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
|
|
if (weakSelf)
|
|
{
|
|
typeof(self) self = weakSelf;
|
|
self->inputsAlert = nil;
|
|
|
|
// Ask again for the token
|
|
[self showValidationMSISDNDialogToPrepareParameters:callback];
|
|
}
|
|
|
|
}]];
|
|
|
|
[self->inputsAlert mxk_setAccessibilityIdentifier:@"AuthInputsViewErrorAlert"];
|
|
[self.delegate authInputsView:self presentAlertController:self->inputsAlert];
|
|
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
// Ask again for the token
|
|
[self showValidationMSISDNDialogToPrepareParameters:callback];
|
|
}
|
|
}
|
|
|
|
}]];
|
|
|
|
[inputsAlert mxk_setAccessibilityIdentifier:@"AuthInputsViewMsisdnValidationAlert"];
|
|
[self.delegate authInputsView:self presentAlertController:inputsAlert];
|
|
}
|
|
|
|
- (BOOL)displayTermsView:(dispatch_block_t)onAcceptedCallback
|
|
{
|
|
// Extract data
|
|
NSDictionary *loginTermsData = currentSession.params[kMXLoginFlowTypeTerms];
|
|
MXLoginTerms *loginTerms;
|
|
MXJSONModelSetMXJSONModel(loginTerms, MXLoginTerms.class, loginTermsData);
|
|
|
|
if (loginTerms)
|
|
{
|
|
[self hideInputsContainer];
|
|
|
|
self.messageLabel.hidden = NO;
|
|
self.messageLabel.text = [VectorL10n authAcceptPolicies];
|
|
|
|
self.termsView.hidden = NO;
|
|
self.currentLastContainer = self.termsView;
|
|
|
|
self.termsView.delegate = self.delegate;
|
|
[self.termsView displayTermsWithTerms:loginTerms onAccepted:onAcceptedCallback];
|
|
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
#pragma mark - Flow state
|
|
|
|
/**
|
|
Check if a flow (kMXLoginFlowType*) is part of the required flows steps.
|
|
|
|
@param flow the flow type to check.
|
|
@return YES if the the flow must be implemented.
|
|
*/
|
|
- (BOOL)isFlowSupported:(NSString *)flow
|
|
{
|
|
for (MXLoginFlow *loginFlow in currentSession.flows)
|
|
{
|
|
if ([loginFlow.type isEqualToString:flow] || [loginFlow.stages indexOfObject:flow] != NSNotFound)
|
|
{
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
/**
|
|
Check if a flow (kMXLoginFlowType*) has already been completed.
|
|
|
|
@param flow the flow type to check.
|
|
@return YES if the the flow has been completedd.
|
|
*/
|
|
- (BOOL)isFlowCompleted:(NSString *)flow
|
|
{
|
|
if (currentSession.completed && [currentSession.completed indexOfObject:flow] != NSNotFound)
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)checkIdentityServerRequirement:(MXRestClient*)mxRestClient
|
|
success:(void (^)(BOOL identityServerRequired))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
[mxRestClient supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
|
|
|
|
MXLogDebug(@"[AuthInputsView] checkIdentityServerRequirement: %@", matrixVersions.doesServerRequireIdentityServerParam ? @"YES": @"NO");
|
|
success(matrixVersions.doesServerRequireIdentityServerParam);
|
|
|
|
} failure:failure];
|
|
}
|
|
|
|
@end
|