Merge commit '1f3f2160661f1d7d3550d53752c66165309e4bd5' into feature/basis_merge_1824

# 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
This commit is contained in:
Frank Rotermund
2022-09-19 11:31:20 +02:00
773 changed files with 15324 additions and 7024 deletions
@@ -0,0 +1,77 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
// MARK: View model
enum ChangePasswordViewModelResult: CustomStringConvertible {
/// Submit with old and new passwords and sign out of all devices option
case submit(oldPassword: String, newPassword: String, signoutAllDevices: Bool)
/// A string representation of the result, ignoring any associated values that could leak PII.
var description: String {
switch self {
case .submit:
return "submit"
}
}
}
// MARK: View
struct ChangePasswordViewState: BindableState {
/// Requirements text for the new password
var passwordRequirements: String
/// View state that can be bound to from SwiftUI.
var bindings: ChangePasswordBindings
/// Whether the user can submit the form: old password and new passwords should be entered
var canSubmit: Bool {
!bindings.oldPassword.isEmpty
&& !bindings.newPassword1.isEmpty
&& !bindings.newPassword2.isEmpty
}
}
struct ChangePasswordBindings {
/// The password input by the user.
var oldPassword: String
/// The new password input by the user.
var newPassword1: String
/// The new password confirmation input by the user.
var newPassword2: String
/// The signout all devices checkbox status
var signoutAllDevices: Bool
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<ChangePasswordErrorType>?
}
enum ChangePasswordViewAction {
/// Send an email to the entered address.
case submit
/// Toggle sign out of all devices
case toggleSignoutAllDevices
}
enum ChangePasswordErrorType: Hashable {
/// An error response from the homeserver.
case mxError(String)
/// User entered new passwords do not match
case passwordsDontMatch
/// An unknown error occurred.
case unknown
}
@@ -0,0 +1,79 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
typealias ChangePasswordViewModelType = StateStoreViewModel<ChangePasswordViewState,
Never,
ChangePasswordViewAction>
class ChangePasswordViewModel: ChangePasswordViewModelType, ChangePasswordViewModelProtocol {
// MARK: - Properties
// MARK: Private
// MARK: Public
var callback: (@MainActor (ChangePasswordViewModelResult) -> Void)?
// MARK: - Setup
init(oldPassword: String = "",
newPassword1: String = "",
newPassword2: String = "",
passwordRequirements: String = "",
signoutAllDevices: Bool = false) {
let bindings = ChangePasswordBindings(oldPassword: oldPassword,
newPassword1: newPassword1,
newPassword2: newPassword2,
signoutAllDevices: signoutAllDevices)
let viewState = ChangePasswordViewState(passwordRequirements: passwordRequirements,
bindings: bindings)
super.init(initialViewState: viewState)
}
// MARK: - Public
override func process(viewAction: ChangePasswordViewAction) {
switch viewAction {
case .submit:
guard state.bindings.newPassword1 == state.bindings.newPassword2 else {
Task { await displayError(.passwordsDontMatch) }
return
}
Task { await callback?(.submit(oldPassword: state.bindings.oldPassword,
newPassword: state.bindings.newPassword1,
signoutAllDevices: state.bindings.signoutAllDevices)) }
case .toggleSignoutAllDevices:
state.bindings.signoutAllDevices.toggle()
}
}
@MainActor func displayError(_ type: ChangePasswordErrorType) {
switch type {
case .mxError(let message):
state.bindings.alertInfo = AlertInfo(id: type,
title: VectorL10n.error,
message: message)
case .passwordsDontMatch:
state.bindings.alertInfo = AlertInfo(id: type,
title: VectorL10n.error,
message: VectorL10n.authPasswordDontMatch)
case .unknown:
state.bindings.alertInfo = AlertInfo(id: type)
}
}
}
@@ -0,0 +1,26 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
protocol ChangePasswordViewModelProtocol {
var callback: (@MainActor (ChangePasswordViewModelResult) -> Void)? { get set }
var context: ChangePasswordViewModelType.Context { get }
/// Display an error to the user.
@MainActor func displayError(_ type: ChangePasswordErrorType)
}
@@ -0,0 +1,97 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh Threads Threads ThreadList
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
import MatrixSDK
@objc protocol ChangePasswordCoordinatorBridgePresenterDelegate {
func changePasswordCoordinatorBridgePresenterDidCancel(_ bridgePresenter: ChangePasswordCoordinatorBridgePresenter)
func changePasswordCoordinatorBridgePresenterDidComplete(_ bridgePresenter: ChangePasswordCoordinatorBridgePresenter)
}
/// ChangePasswordCoordinatorBridgePresenter enables to start ChangePasswordCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed
/// once the underlying Coordinator has been integrated by another Coordinator.
@objcMembers
final class ChangePasswordCoordinatorBridgePresenter: NSObject {
// MARK: - Constants
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var coordinator: ChangePasswordCoordinator?
// MARK: Public
weak var delegate: ChangePasswordCoordinatorBridgePresenterDelegate?
// MARK: - Setup
/// Initializer
/// - Parameters:
/// - session: Session instance
init(session: MXSession) {
self.session = session
super.init()
}
// MARK: - Public
func present(from viewController: UIViewController, animated: Bool) {
let params = ChangePasswordCoordinatorParameters(restClient: self.session.matrixRestClient)
let changePasswordCoordinator = ChangePasswordCoordinator(parameters: params)
changePasswordCoordinator.callback = { [weak self] in
guard let self = self else { return }
self.delegate?.changePasswordCoordinatorBridgePresenterDidComplete(self)
}
let presentable = changePasswordCoordinator.toPresentable()
let navController = RiotNavigationController(rootViewController: presentable.toPresentable())
navController.navigationBar.topItem?.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(cancelTapped))
navController.isModalInPresentation = true
viewController.present(navController, animated: animated, completion: nil)
changePasswordCoordinator.start()
self.coordinator = changePasswordCoordinator
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
// Dismiss modal
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
completion?()
}
}
@objc
private func cancelTapped() {
delegate?.changePasswordCoordinatorBridgePresenterDidCancel(self)
}
}
@@ -0,0 +1,141 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
import CommonKit
struct ChangePasswordCoordinatorParameters {
let restClient: MXRestClient
}
final class ChangePasswordCoordinator: Coordinator, Presentable {
// MARK: - Properties
// MARK: Private
private let parameters: ChangePasswordCoordinatorParameters
private let changePasswordHostingController: VectorHostingController
private var changePasswordViewModel: ChangePasswordViewModelProtocol
private let passwordValidator = PasswordValidator(withRules: [
.minLength(8),
.containUppercaseLetter,
.containLowercaseLetter,
.containNumber,
.containSymbol
])
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
private var loadingIndicator: UserIndicator?
private var currentTask: Task<Void, Error>? {
willSet {
currentTask?.cancel()
}
}
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
var callback: (@MainActor () -> Void)?
// MARK: - Setup
init(parameters: ChangePasswordCoordinatorParameters) {
self.parameters = parameters
let requirements = passwordValidator.description(with: VectorL10n.passwordValidationInfoHeader)
let viewModel = ChangePasswordViewModel(passwordRequirements: requirements)
let view = ChangePasswordScreen(viewModel: viewModel.context)
changePasswordViewModel = viewModel
changePasswordHostingController = VectorHostingController(rootView: view)
changePasswordHostingController.vc_removeBackTitle()
changePasswordHostingController.enableNavigationBarScrollEdgeAppearance = true
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: changePasswordHostingController)
}
// MARK: - Public
func start() {
MXLog.debug("[ChangePasswordCoordinator] did start.")
Task { await setupViewModel() }
}
func toPresentable() -> UIViewController {
return self.changePasswordHostingController
}
// MARK: - Private
/// Set up the view model. This method is extracted from `start()` so it can run on the `MainActor`.
@MainActor private func setupViewModel() {
changePasswordViewModel.callback = { [weak self] result in
guard let self = self else { return }
switch result {
case .submit(let oldPassword, let newPassword, let signoutAllDevices):
MXLog.debug("[ChangePasswordCoordinator] ChangePasswordViewModel did complete with result: submit.")
self.changePassword(from: oldPassword, to: newPassword, signoutAllDevices: signoutAllDevices)
}
}
}
/// Show an activity indicator whilst loading.
@MainActor private func startLoading() {
loadingIndicator = indicatorPresenter.present(.loading(label: VectorL10n.loading, isInteractionBlocking: true))
}
/// Hide the currently displayed activity indicator.
@MainActor private func stopLoading() {
loadingIndicator = nil
}
/// Submits a reset password request with signing out of all devices option
@MainActor private func changePassword(from oldPassword: String, to newPassword: String, signoutAllDevices: Bool) {
startLoading()
currentTask = Task { [weak self] in
do {
try passwordValidator.validate(password: newPassword)
try await parameters.restClient.changePassword(from: oldPassword, to: newPassword, logoutDevices: signoutAllDevices)
guard !Task.isCancelled else { return }
self?.stopLoading()
self?.callback?()
} catch {
self?.stopLoading()
self?.handleError(error)
}
}
}
/// Processes an error to either update the flow or display it to the user.
@MainActor private func handleError(_ error: Error) {
if let mxError = MXError(nsError: error as NSError) {
changePasswordViewModel.displayError(.mxError(mxError.error))
return
}
if let error = error as? PasswordValidatorError {
changePasswordViewModel.displayError(.mxError(error.localizedDescription))
} else {
changePasswordViewModel.displayError(.unknown)
}
}
}
@@ -0,0 +1,62 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import SwiftUI
/// Using an enum for the screen allows you define the different state cases with
/// the relevant associated data for each case.
enum MockChangePasswordScreenState: MockScreenState, CaseIterable {
// A case for each state you want to represent
// with specific, minimal associated data that will allow you
// mock that screen.
case allEmpty
case cannotSubmit
case canSubmit
case canSubmitAndSignoutAllDevicesChecked
/// The associated screen
var screenType: Any.Type {
ChangePasswordScreen.self
}
/// Generate the view struct for the screen state.
var screenView: ([Any], AnyView) {
let viewModel: ChangePasswordViewModel
switch self {
case .allEmpty:
viewModel = ChangePasswordViewModel()
case .cannotSubmit:
viewModel = ChangePasswordViewModel(oldPassword: "12345678",
newPassword1: "87654321")
case .canSubmit:
viewModel = ChangePasswordViewModel(oldPassword: "12345678",
newPassword1: "87654321",
newPassword2: "87654321")
case .canSubmitAndSignoutAllDevicesChecked:
viewModel = ChangePasswordViewModel(oldPassword: "12345678",
newPassword1: "87654321",
newPassword2: "87654321",
signoutAllDevices: true)
}
// can simulate service and viewModel actions here if needs be.
return (
[viewModel], AnyView(ChangePasswordScreen(viewModel: viewModel.context))
)
}
}
@@ -0,0 +1,129 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import XCTest
import RiotSwiftUI
class ChangePasswordUITests: MockScreenTestCase {
func testAllEmpty() {
app.goToScreenWithIdentifier(MockChangePasswordScreenState.allEmpty.title)
XCTAssertTrue(app.staticTexts["titleLabel"].exists, "The title should be shown.")
XCTAssertTrue(app.staticTexts["passwordRequirementsLabel"].exists, "The password requirements label should be shown.")
let oldPasswordTextField = app.secureTextFields["oldPasswordTextField"]
XCTAssertTrue(oldPasswordTextField.exists, "The text field should be shown.")
XCTAssertEqual(oldPasswordTextField.label, "Old password", "The text field should be showing the placeholder before text is input.")
let newPasswordTextField1 = app.secureTextFields["newPasswordTextField1"]
XCTAssertTrue(newPasswordTextField1.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField1.label, "New password", "The text field should be showing the placeholder before text is input.")
let newPasswordTextField2 = app.secureTextFields["newPasswordTextField2"]
XCTAssertTrue(newPasswordTextField2.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField2.label, "Confirm password", "The text field should be showing the placeholder before text is input.")
let submitButton = app.buttons["submitButton"]
XCTAssertTrue(submitButton.exists, "The submit button should be shown.")
XCTAssertFalse(submitButton.isEnabled, "The submit button should be disabled when not able to submit.")
let signoutAllDevicesToggle = app.switches["signoutAllDevicesToggle"]
XCTAssertTrue(signoutAllDevicesToggle.exists, "Sign out all devices toggle should exist")
XCTAssertFalse(signoutAllDevicesToggle.isOn, "Sign out all devices should be unchecked")
}
func testCannotSubmit() {
app.goToScreenWithIdentifier(MockChangePasswordScreenState.cannotSubmit.title)
XCTAssertTrue(app.staticTexts["titleLabel"].exists, "The title should be shown.")
XCTAssertTrue(app.staticTexts["passwordRequirementsLabel"].exists, "The password requirements label should be shown.")
let oldPasswordTextField = app.secureTextFields["oldPasswordTextField"]
XCTAssertTrue(oldPasswordTextField.exists, "The text field should be shown.")
XCTAssertEqual(oldPasswordTextField.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField1 = app.secureTextFields["newPasswordTextField1"]
XCTAssertTrue(newPasswordTextField1.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField1.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField2 = app.secureTextFields["newPasswordTextField2"]
XCTAssertTrue(newPasswordTextField2.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField2.label, "Confirm password", "The text field should be showing the placeholder before text is input.")
let submitButton = app.buttons["submitButton"]
XCTAssertTrue(submitButton.exists, "The submit button should be shown.")
XCTAssertFalse(submitButton.isEnabled, "The submit button should be disabled when not able to submit.")
let signoutAllDevicesToggle = app.switches["signoutAllDevicesToggle"]
XCTAssertTrue(signoutAllDevicesToggle.exists, "Sign out all devices toggle should exist")
XCTAssertFalse(signoutAllDevicesToggle.isOn, "Sign out all devices should be unchecked")
}
func testCanSubmit() {
app.goToScreenWithIdentifier(MockChangePasswordScreenState.canSubmit.title)
XCTAssertTrue(app.staticTexts["titleLabel"].exists, "The title should be shown.")
XCTAssertTrue(app.staticTexts["passwordRequirementsLabel"].exists, "The password requirements label should be shown.")
let oldPasswordTextField = app.secureTextFields["oldPasswordTextField"]
XCTAssertTrue(oldPasswordTextField.exists, "The text field should be shown.")
XCTAssertEqual(oldPasswordTextField.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField1 = app.secureTextFields["newPasswordTextField1"]
XCTAssertTrue(newPasswordTextField1.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField1.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField2 = app.secureTextFields["newPasswordTextField2"]
XCTAssertTrue(newPasswordTextField2.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField2.value as? String, "••••••••", "The text field should show the entered password secretly.")
let submitButton = app.buttons["submitButton"]
XCTAssertTrue(submitButton.exists, "The submit button should be shown.")
XCTAssertTrue(submitButton.isEnabled, "The submit button should be enabled when able to submit.")
let signoutAllDevicesToggle = app.switches["signoutAllDevicesToggle"]
XCTAssertTrue(signoutAllDevicesToggle.exists, "Sign out all devices toggle should exist")
XCTAssertFalse(signoutAllDevicesToggle.isOn, "Sign out all devices should be unchecked")
}
func testCanSubmitAndSignoutAllDevicesChecked() {
app.goToScreenWithIdentifier(MockChangePasswordScreenState.canSubmitAndSignoutAllDevicesChecked.title)
XCTAssertTrue(app.staticTexts["titleLabel"].exists, "The title should be shown.")
XCTAssertTrue(app.staticTexts["passwordRequirementsLabel"].exists, "The password requirements label should be shown.")
let oldPasswordTextField = app.secureTextFields["oldPasswordTextField"]
XCTAssertTrue(oldPasswordTextField.exists, "The text field should be shown.")
XCTAssertEqual(oldPasswordTextField.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField1 = app.secureTextFields["newPasswordTextField1"]
XCTAssertTrue(newPasswordTextField1.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField1.value as? String, "••••••••", "The text field should show the entered password secretly.")
let newPasswordTextField2 = app.secureTextFields["newPasswordTextField2"]
XCTAssertTrue(newPasswordTextField2.exists, "The text field should be shown.")
XCTAssertEqual(newPasswordTextField2.value as? String, "••••••••", "The text field should show the entered password secretly.")
let submitButton = app.buttons["submitButton"]
XCTAssertTrue(submitButton.exists, "The submit button should be shown.")
XCTAssertTrue(submitButton.isEnabled, "The submit button should be enabled when able to submit.")
let signoutAllDevicesToggle = app.switches["signoutAllDevicesToggle"]
XCTAssertTrue(signoutAllDevicesToggle.exists, "Sign out all devices toggle should exist")
XCTAssertTrue(signoutAllDevicesToggle.isOn, "Sign out all devices should be checked")
}
}
@@ -0,0 +1,50 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import XCTest
@testable import RiotSwiftUI
class ChangePasswordViewModelTests: XCTestCase {
@MainActor func testEmptyState() async {
let viewModel = ChangePasswordViewModel()
let context = viewModel.context
// Given an empty view model
XCTAssert(context.oldPassword.isEmpty, "The view model should start with an empty old password.")
XCTAssert(context.newPassword1.isEmpty, "The view model should start with an empty new password 1.")
XCTAssert(context.newPassword2.isEmpty, "The view model should start with an empty new password 2.")
XCTAssertFalse(context.viewState.canSubmit, "The view model should not be able to submit.")
XCTAssertFalse(context.signoutAllDevices, "The view model should start with sign out of all devices unchecked.")
}
@MainActor func testValidState() async {
let viewModel = ChangePasswordViewModel(oldPassword: "12345678",
newPassword1: "87654321",
newPassword2: "87654321",
signoutAllDevices: true)
let context = viewModel.context
// Given a filled view model in valid state
XCTAssertFalse(context.oldPassword.isEmpty, "The view model should start with an empty old password.")
XCTAssertFalse(context.newPassword1.isEmpty, "The view model should start with an empty new password 1.")
XCTAssertFalse(context.newPassword2.isEmpty, "The view model should start with an empty new password 2.")
XCTAssertTrue(context.viewState.canSubmit, "The view model should be able to submit.")
XCTAssertTrue(context.signoutAllDevices, "Sign out of all devices should be checked.")
}
}
@@ -0,0 +1,143 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
struct ChangePasswordScreen: View {
// MARK: - Properties
// MARK: Private
@Environment(\.theme) private var theme
enum Field { case oldPassword, newPassword1, newPassword2 }
@State private var focusedField: Field?
// MARK: Public
@ObservedObject var viewModel: ChangePasswordViewModel.Context
// MARK: Views
var body: some View {
ScrollView {
VStack(spacing: 0) {
header
.padding(.top, 16)
.padding(.bottom, 36)
form
}
.readableFrame()
.padding(.horizontal, 16)
}
.background(theme.colors.background.ignoresSafeArea())
.alert(item: $viewModel.alertInfo) { $0.alert }
.accentColor(theme.colors.accent)
}
/// The title and icon at the top of the screen.
var header: some View {
VStack(spacing: 8) {
OnboardingIconImage(image: Asset.Images.authenticationPasswordIcon)
.padding(.bottom, 16)
Text(VectorL10n.settingsChangePassword)
.font(theme.fonts.title2B)
.multilineTextAlignment(.center)
.foregroundColor(theme.colors.primaryContent)
.accessibilityIdentifier("titleLabel")
}
}
/// The text fields and submit button.
var form: some View {
VStack(alignment: .leading, spacing: 12) {
RoundedBorderTextField(placeHolder: VectorL10n.settingsOldPassword,
text: $viewModel.oldPassword,
isFirstResponder: focusedField == .oldPassword,
configuration: UIKitTextInputConfiguration(returnKeyType: .next,
isSecureTextEntry: true),
onCommit: { focusedField = .newPassword1 })
.accessibilityIdentifier("oldPasswordTextField")
RoundedBorderTextField(placeHolder: VectorL10n.settingsNewPassword,
text: $viewModel.newPassword1,
isFirstResponder: focusedField == .newPassword1,
configuration: UIKitTextInputConfiguration(returnKeyType: .next,
isSecureTextEntry: true),
onCommit: { focusedField = .newPassword2 })
.accessibilityIdentifier("newPasswordTextField1")
RoundedBorderTextField(placeHolder: VectorL10n.settingsConfirmPassword,
text: $viewModel.newPassword2,
isFirstResponder: focusedField == .newPassword2,
configuration: UIKitTextInputConfiguration(returnKeyType: .done,
isSecureTextEntry: true),
onCommit: submit)
.accessibilityIdentifier("newPasswordTextField2")
HStack(alignment: .center, spacing: 8) {
Toggle(VectorL10n.authenticationChoosePasswordSignoutAllDevices, isOn: $viewModel.signoutAllDevices)
.toggleStyle(AuthenticationTermsToggleStyle())
.accessibilityIdentifier("signoutAllDevicesToggle")
Text(VectorL10n.authenticationChoosePasswordSignoutAllDevices)
.foregroundColor(theme.colors.secondaryContent)
}
.onTapGesture(perform: toggleSignoutAllDevices)
.padding(.top, 8)
Text(viewModel.viewState.passwordRequirements)
.font(theme.fonts.body)
.multilineTextAlignment(.leading)
.foregroundColor(theme.colors.secondaryContent)
.accessibilityIdentifier("passwordRequirementsLabel")
.padding(.top, 8)
.padding(.bottom, 16)
Button(action: submit) {
Text(VectorL10n.save)
}
.buttonStyle(PrimaryActionButtonStyle())
.disabled(!viewModel.viewState.canSubmit)
.accessibilityIdentifier("submitButton")
}
}
/// Sends the `submit` view action if viewModel.viewState.canSubmit.
func submit() {
guard viewModel.viewState.canSubmit else { return }
viewModel.send(viewAction: .submit)
}
/// Sends the `toggleSignoutAllDevices` view action.
func toggleSignoutAllDevices() {
viewModel.send(viewAction: .toggleSignoutAllDevices)
}
}
// MARK: - Previews
struct ChangePasswordScreen_Previews: PreviewProvider {
static let stateRenderer = MockChangePasswordScreenState.stateRenderer
static var previews: some View {
stateRenderer.screenGroup(addNavigation: true)
.navigationViewStyle(.stack)
stateRenderer.screenGroup(addNavigation: true)
.navigationViewStyle(.stack)
.theme(.dark).preferredColorScheme(.dark)
}
}
@@ -15,7 +15,6 @@
//
import Foundation
@available(iOS 14.0, *)
@objc protocol NotificationSettingsCoordinatorBridgePresenterDelegate {
func notificationSettingsCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: NotificationSettingsCoordinatorBridgePresenter)
}
@@ -24,7 +23,6 @@ import Foundation
/// This bridge is used while waiting for global usage of coordinator pattern.
/// It breaks the Coordinator abstraction and it has been introduced for Objective-C compatibility (mainly for integration in legacy view controllers).
/// Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
@available(iOS 14.0, *)
@objcMembers
final class NotificationSettingsCoordinatorBridgePresenter: NSObject {
@@ -82,7 +80,6 @@ final class NotificationSettingsCoordinatorBridgePresenter: NSObject {
}
// MARK: - NotificationSettingsCoordinatorDelegate
@available(iOS 14.0, *)
extension NotificationSettingsCoordinatorBridgePresenter: NotificationSettingsCoordinatorDelegate {
func notificationSettingsCoordinatorDidComplete(_ coordinator: NotificationSettingsCoordinatorType) {
self.delegate?.notificationSettingsCoordinatorBridgePresenterDelegateDidComplete(self)
@@ -91,7 +88,6 @@ extension NotificationSettingsCoordinatorBridgePresenter: NotificationSettingsCo
// MARK: - UIAdaptivePresentationControllerDelegate
@available(iOS 14.0, *)
extension NotificationSettingsCoordinatorBridgePresenter: UIAdaptivePresentationControllerDelegate {
func notificationSettingsCoordinatorDidComplete(_ presentationController: UIPresentationController) {
@@ -17,7 +17,6 @@
import Foundation
import SwiftUI
@available(iOS 14.0, *)
final class NotificationSettingsCoordinator: NotificationSettingsCoordinatorType {
// MARK: - Properties
@@ -66,7 +65,6 @@ final class NotificationSettingsCoordinator: NotificationSettingsCoordinatorType
}
// MARK: - NotificationSettingsViewModelCoordinatorDelegate
@available(iOS 14.0, *)
extension NotificationSettingsCoordinator: NotificationSettingsViewModelCoordinatorDelegate {
func notificationSettingsViewModelDidComplete(_ viewModel: NotificationSettingsViewModelType) {
self.delegate?.notificationSettingsCoordinatorDidComplete(self)
@@ -17,7 +17,6 @@
import Foundation
import Combine
@available(iOS 14.0, *)
class MXNotificationSettingsService: NotificationSettingsServiceType {
private let session: MXSession
@@ -17,7 +17,6 @@
import Foundation
import Combine
@available(iOS 14.0, *)
class MockNotificationSettingsService: NotificationSettingsServiceType, ObservableObject {
static let example = MockNotificationSettingsService()
@@ -18,7 +18,6 @@ import Foundation
import Combine
/// A service for changing notification settings and keywords
@available(iOS 14.0, *)
protocol NotificationSettingsServiceType {
/// Publisher of all push rules.
var rulesPublisher: AnyPublisher<[NotificationPushRuleType], Never> { get }
@@ -18,7 +18,6 @@ import SwiftUI
/// A single rounded rect chip to be rendered within `Chips` collection
@available(iOS 14.0, *)
struct Chip: View {
@Environment(\.isEnabled) var isEnabled
@@ -62,7 +61,6 @@ struct Chip: View {
}
}
@available(iOS 14.0, *)
struct Chip_Previews: PreviewProvider {
static var previews: some View {
Group {
@@ -17,7 +17,6 @@
import SwiftUI
/// Renders multiple chips in a flow layout.
@available(iOS 14.0, *)
struct Chips: View {
@State private var frame: CGRect = CGRect.zero
@@ -75,7 +74,6 @@ struct Chips: View {
}
}
@available(iOS 14.0, *)
struct Chips_Previews: PreviewProvider {
static var chips: [String] = ["Chip1", "Chip2", "Chip3", "Chip4", "Chip5", "Chip6"]
static var previews: some View {
@@ -17,7 +17,6 @@
import SwiftUI
/// Renders an input field and a collection of chips.
@available(iOS 14.0, *)
struct ChipsInput: View {
@Environment(\.theme) var theme: ThemeSwiftUI
@@ -47,7 +46,6 @@ struct ChipsInput: View {
}
}
@available(iOS 14.0, *)
struct ChipsInput_Previews: PreviewProvider {
static var chips = Set<String>(["Website", "Element", "Design", "Matrix/Element"])
static var previews: some View {
@@ -16,7 +16,6 @@
import SwiftUI
@available(iOS 14.0, *)
struct DefaultNotificationSettings: View {
@ObservedObject var viewModel: NotificationSettingsViewModel
@@ -28,7 +27,6 @@ struct DefaultNotificationSettings: View {
}
}
@available(iOS 14.0, *)
struct DefaultNotifications_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
@@ -18,7 +18,6 @@ import Foundation
import SwiftUI
/// An input field style for forms.
@available(iOS 14.0, *)
struct FormInputFieldStyle: TextFieldStyle {
@Environment(\.theme) var theme: ThemeSwiftUI
@@ -26,7 +25,7 @@ struct FormInputFieldStyle: TextFieldStyle {
private var textColor: Color {
if !isEnabled {
return theme.colors.quarterlyContent
return theme.colors.quaternaryContent
}
return theme.colors.primaryContent
}
@@ -49,7 +48,6 @@ struct FormInputFieldStyle: TextFieldStyle {
}
@available(iOS 14.0, *)
struct FormInputFieldStyle_Previews: PreviewProvider {
static var previews: some View {
Group {
@@ -16,7 +16,6 @@
import SwiftUI
@available(iOS 14.0, *)
struct MentionsAndKeywordNotificationSettings: View {
@ObservedObject var viewModel: NotificationSettingsViewModel
@@ -39,7 +38,6 @@ struct MentionsAndKeywordNotificationSettings: View {
}
}
@available(iOS 14.0, *)
struct MentionsAndKeywords_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
@@ -20,7 +20,6 @@ import SwiftUI
///
/// Also renders an optional bottom section.
/// Used in the case of keywords, for the keyword chips and input.
@available(iOS 14.0, *)
struct NotificationSettings<BottomSection: View>: View {
@ObservedObject var viewModel: NotificationSettingsViewModel
@@ -45,14 +44,12 @@ struct NotificationSettings<BottomSection: View>: View {
}
}
@available(iOS 14.0, *)
extension NotificationSettings where BottomSection == EmptyView {
init(viewModel: NotificationSettingsViewModel) {
self.init(viewModel: viewModel, bottomSection: nil)
}
}
@available(iOS 14.0, *)
struct NotificationSettings_Previews: PreviewProvider {
static var previews: some View {
Group {
@@ -17,7 +17,6 @@
import SwiftUI
/// Renders the keywords input, driven by 'NotificationSettingsViewModel'.
@available(iOS 14.0, *)
struct NotificationSettingsKeywords: View {
@ObservedObject var viewModel: NotificationSettingsViewModel
var body: some View {
@@ -32,7 +31,6 @@ struct NotificationSettingsKeywords: View {
}
}
@available(iOS 14.0, *)
struct Keywords_Previews: PreviewProvider {
static let viewModel = NotificationSettingsViewModel(
notificationSettingsService: MockNotificationSettingsService.example,
@@ -16,7 +16,6 @@
import SwiftUI
@available(iOS 14.0, *)
struct OtherNotificationSettings: View {
@ObservedObject var viewModel: NotificationSettingsViewModel
@@ -27,7 +26,6 @@ struct OtherNotificationSettings: View {
}
}
@available(iOS 14.0, *)
struct OtherNotifications_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
@@ -20,7 +20,6 @@ import Foundation
import Combine
import SwiftUI
@available(iOS 14.0, *)
final class NotificationSettingsViewModel: NotificationSettingsViewModelType, ObservableObject {
// MARK: - Properties