mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-21 09:02:44 +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
2196 lines
75 KiB
Objective-C
2196 lines
75 KiB
Objective-C
/*
|
|
Copyright 2015 OpenMarket Ltd
|
|
Copyright 2017 Vector Creations Ltd
|
|
Copyright 2018 New Vector Ltd
|
|
Copyright 2019 The Matrix.org Foundation C.I.C
|
|
|
|
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 "MXKAccount.h"
|
|
|
|
#import "MXKAccountManager.h"
|
|
#import "MXKRoomDataSourceManager.h"
|
|
#import "MXKEventFormatter.h"
|
|
|
|
#import "MXKTools.h"
|
|
#import "MXKContactManager.h"
|
|
|
|
#import "MXKConstants.h"
|
|
|
|
#import "NSBundle+MatrixKit.h"
|
|
|
|
#import <AFNetworking/AFNetworking.h>
|
|
|
|
#import <MatrixSDK/MXBackgroundModeHandler.h>
|
|
|
|
#import "MXKSwiftHeader.h"
|
|
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
NSString *const kMXKAccountUserInfoDidChangeNotification = @"kMXKAccountUserInfoDidChangeNotification";
|
|
NSString *const kMXKAccountAPNSActivityDidChangeNotification = @"kMXKAccountAPNSActivityDidChangeNotification";
|
|
NSString *const kMXKAccountPushKitActivityDidChangeNotification = @"kMXKAccountPushKitActivityDidChangeNotification";
|
|
|
|
NSString *const kMXKAccountErrorDomain = @"kMXKAccountErrorDomain";
|
|
|
|
static MXKAccountOnCertificateChange _onCertificateChangeBlock;
|
|
/**
|
|
HTTP status codes for error cases on initial sync requests, for which errors will not be propagated to the client.
|
|
*/
|
|
static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
|
|
|
|
@interface MXKAccount ()
|
|
{
|
|
// We will notify user only once on session failure
|
|
BOOL notifyOpenSessionFailure;
|
|
|
|
// The timer used to postpone server sync on failure
|
|
NSTimer* initialServerSyncTimer;
|
|
|
|
// Reachability observer
|
|
id reachabilityObserver;
|
|
|
|
// Session state observer
|
|
id sessionStateObserver;
|
|
|
|
// Handle user's settings change
|
|
id userUpdateListener;
|
|
|
|
// Used for logging application start up
|
|
NSDate *openSessionStartDate;
|
|
|
|
// Event notifications listener
|
|
id notificationCenterListener;
|
|
|
|
// Internal list of ignored rooms
|
|
NSMutableArray* ignoredRooms;
|
|
|
|
// Background sync management
|
|
MXOnBackgroundSyncDone backgroundSyncDone;
|
|
MXOnBackgroundSyncFail backgroundSyncFails;
|
|
NSTimer* backgroundSyncTimer;
|
|
|
|
// Observe UIApplicationSignificantTimeChangeNotification to refresh MXRoomSummaries on time formatting change.
|
|
id UIApplicationSignificantTimeChangeNotificationObserver;
|
|
|
|
// Observe NSCurrentLocaleDidChangeNotification to refresh MXRoomSummaries on time formatting change.
|
|
id NSCurrentLocaleDidChangeNotificationObserver;
|
|
}
|
|
|
|
/// Will be true if the session is not in a pauseable state or we requested for the session to pause but not finished yet. Will be reverted to false again after `resume` called.
|
|
@property (nonatomic, assign, getter=isPauseRequested) BOOL pauseRequested;
|
|
@property (nonatomic, strong) id<MXBackgroundTask> pauseBackgroundTask;
|
|
@property (nonatomic, strong) id<MXBackgroundTask> backgroundSyncBgTask;
|
|
|
|
@end
|
|
|
|
@implementation MXKAccount
|
|
@synthesize mxSession, mxRestClient;
|
|
@synthesize userPresence;
|
|
@synthesize userTintColor;
|
|
@synthesize hideUserPresence;
|
|
|
|
+ (void)load
|
|
{
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
initialSyncSilentErrorsHTTPStatusCodes = @[
|
|
@(504),
|
|
@(522),
|
|
@(524),
|
|
@(599)
|
|
];
|
|
});
|
|
}
|
|
|
|
+ (void)registerOnCertificateChangeBlock:(MXKAccountOnCertificateChange)onCertificateChangeBlock
|
|
{
|
|
_onCertificateChangeBlock = onCertificateChangeBlock;
|
|
}
|
|
|
|
+ (UIColor*)presenceColor:(MXPresence)presence
|
|
{
|
|
switch (presence)
|
|
{
|
|
case MXPresenceOnline:
|
|
return [[MXKAppSettings standardAppSettings] presenceColorForOnlineUser];
|
|
case MXPresenceUnavailable:
|
|
return [[MXKAppSettings standardAppSettings] presenceColorForUnavailableUser];
|
|
case MXPresenceOffline:
|
|
return [[MXKAppSettings standardAppSettings] presenceColorForOfflineUser];
|
|
case MXPresenceUnknown:
|
|
default:
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
- (nonnull instancetype)initWithCredentials:(MXCredentials*)credentials
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
notifyOpenSessionFailure = YES;
|
|
|
|
// Report credentials and alloc REST client.
|
|
_mxCredentials = credentials;
|
|
[self prepareRESTClient];
|
|
|
|
userPresence = MXPresenceUnknown;
|
|
// Refresh device information
|
|
[self loadDeviceInformation:nil failure:nil];
|
|
|
|
[self registerAccountDataDidChangeIdentityServerNotification];
|
|
[self registerIdentityServiceDidChangeAccessTokenNotification];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[self closeSession:NO];
|
|
mxSession = nil;
|
|
|
|
[mxRestClient close];
|
|
mxRestClient = nil;
|
|
}
|
|
|
|
#pragma mark - NSCoding
|
|
|
|
- (id)initWithCoder:(NSCoder *)coder
|
|
{
|
|
self = [super initWithCoder:coder];
|
|
|
|
if (self)
|
|
{
|
|
notifyOpenSessionFailure = YES;
|
|
|
|
[self prepareRESTClient];
|
|
|
|
[self registerAccountDataDidChangeIdentityServerNotification];
|
|
[self registerIdentityServiceDidChangeAccessTokenNotification];
|
|
|
|
userPresence = MXPresenceUnknown;
|
|
// Refresh device information
|
|
[self loadDeviceInformation:nil failure:nil];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
#pragma mark - Properties
|
|
|
|
- (void)setIdentityServerURL:(NSString *)identityServerURL
|
|
{
|
|
if (identityServerURL.length)
|
|
{
|
|
_identityServerURL = identityServerURL;
|
|
self.mxCredentials.identityServer = identityServerURL;
|
|
|
|
// Update services used in MXSession
|
|
[mxSession setIdentityServer:self.mxCredentials.identityServer andAccessToken:self.mxCredentials.identityServerAccessToken];
|
|
}
|
|
else
|
|
{
|
|
_identityServerURL = nil;
|
|
[mxSession setIdentityServer:nil andAccessToken:nil];
|
|
}
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
- (void)setAntivirusServerURL:(NSString *)antivirusServerURL
|
|
{
|
|
_antivirusServerURL = antivirusServerURL;
|
|
// Update the current session if any
|
|
[mxSession setAntivirusServerURL:antivirusServerURL];
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
- (void)setPushGatewayURL:(NSString *)pushGatewayURL
|
|
{
|
|
_pushGatewayURL = pushGatewayURL.length ? pushGatewayURL : nil;
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] setPushGatewayURL: %@", _pushGatewayURL);
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
- (NSString*)userDisplayName
|
|
{
|
|
if (mxSession)
|
|
{
|
|
return mxSession.myUser.displayname;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSString*)userAvatarUrl
|
|
{
|
|
if (mxSession)
|
|
{
|
|
return mxSession.myUser.avatarUrl;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSString*)fullDisplayName
|
|
{
|
|
if (self.userDisplayName.length)
|
|
{
|
|
return [NSString stringWithFormat:@"%@ (%@)", self.userDisplayName, self.mxCredentials.userId];
|
|
}
|
|
else
|
|
{
|
|
return self.mxCredentials.userId;
|
|
}
|
|
}
|
|
|
|
- (NSString*)userStatusMessage
|
|
{
|
|
if (mxSession)
|
|
{
|
|
return mxSession.myUser.statusMsg;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)linkedEmails
|
|
{
|
|
NSMutableArray<NSString *> *linkedEmails = [NSMutableArray array];
|
|
|
|
for (MXThirdPartyIdentifier *threePID in self.threePIDs)
|
|
{
|
|
if ([threePID.medium isEqualToString:kMX3PIDMediumEmail])
|
|
{
|
|
[linkedEmails addObject:threePID.address];
|
|
}
|
|
}
|
|
|
|
return linkedEmails;
|
|
}
|
|
|
|
- (NSArray<NSString *> *)linkedPhoneNumbers
|
|
{
|
|
NSMutableArray<NSString *> *linkedPhoneNumbers = [NSMutableArray array];
|
|
|
|
for (MXThirdPartyIdentifier *threePID in self.threePIDs)
|
|
{
|
|
if ([threePID.medium isEqualToString:kMX3PIDMediumMSISDN])
|
|
{
|
|
[linkedPhoneNumbers addObject:threePID.address];
|
|
}
|
|
}
|
|
|
|
return linkedPhoneNumbers;
|
|
}
|
|
|
|
- (UIColor*)userTintColor
|
|
{
|
|
if (!userTintColor)
|
|
{
|
|
userTintColor = [MXKTools colorWithRGBValue:[self.mxCredentials.userId hash]];
|
|
}
|
|
|
|
return userTintColor;
|
|
}
|
|
|
|
- (BOOL)pushNotificationServiceIsActive
|
|
{
|
|
BOOL pushNotificationServiceIsActive = ([[MXKAccountManager sharedManager] isAPNSAvailable] && self.hasPusherForPushNotifications && mxSession);
|
|
MXLogDebug(@"[MXKAccount][Push] pushNotificationServiceIsActive: %@", @(pushNotificationServiceIsActive));
|
|
|
|
return pushNotificationServiceIsActive;
|
|
}
|
|
|
|
- (void)enablePushNotifications:(BOOL)enable
|
|
success:(void (^)(void))success
|
|
failure:(void (^)(NSError *))failure
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: %@", @(enable));
|
|
|
|
if (enable)
|
|
{
|
|
if ([[MXKAccountManager sharedManager] isAPNSAvailable])
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Enable Push for %@ account", self.mxCredentials.userId);
|
|
|
|
// Create/restore the pusher
|
|
[self enableAPNSPusher:YES success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Enable Push: Success");
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
} failure:^(NSError *error) {
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Enable Push: Error: %@", error);
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Error: Cannot enable Push");
|
|
|
|
NSError *error = [NSError errorWithDomain:kMXKAccountErrorDomain
|
|
code:0
|
|
userInfo:@{
|
|
NSLocalizedDescriptionKey:
|
|
[VectorL10n accountErrorPushNotAllowed]
|
|
}];
|
|
if (failure)
|
|
{
|
|
failure (error);
|
|
}
|
|
}
|
|
}
|
|
else if (self.hasPusherForPushNotifications)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Disable APNS for %@ account", self.mxCredentials.userId);
|
|
|
|
// Delete the pusher, report the new value only on success.
|
|
[self enableAPNSPusher:NO
|
|
success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Disable Push: Success");
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
} failure:^(NSError *error) {
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Disable Push: Error: %@", error);
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (BOOL)isPushKitNotificationActive
|
|
{
|
|
BOOL isPushKitNotificationActive = ([[MXKAccountManager sharedManager] isPushAvailable] && self.hasPusherForPushKitNotifications && mxSession);
|
|
MXLogDebug(@"[MXKAccount][Push] isPushKitNotificationActive: %@", @(isPushKitNotificationActive));
|
|
|
|
return isPushKitNotificationActive;
|
|
}
|
|
|
|
- (void)enablePushKitNotifications:(BOOL)enable
|
|
success:(void (^)(void))success
|
|
failure:(void (^)(NSError *))failure
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: %@", @(enable));
|
|
|
|
if (enable)
|
|
{
|
|
if ([[MXKAccountManager sharedManager] isPushAvailable])
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Enable Push for %@ account", self.mxCredentials.userId);
|
|
|
|
// Create/restore the pusher
|
|
[self enablePushKitPusher:YES success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Enable Push: Success");
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
} failure:^(NSError *error) {
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Enable Push: Error: %@", error);
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Error: Cannot enable Push");
|
|
|
|
NSError *error = [NSError errorWithDomain:kMXKAccountErrorDomain
|
|
code:0
|
|
userInfo:@{
|
|
NSLocalizedDescriptionKey:
|
|
[VectorL10n accountErrorPushNotAllowed]
|
|
}];
|
|
failure (error);
|
|
}
|
|
}
|
|
else if (self.hasPusherForPushKitNotifications)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Disable Push for %@ account", self.mxCredentials.userId);
|
|
|
|
// Delete the pusher, report the new value only on success.
|
|
[self enablePushKitPusher:NO success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Disable Push: Success");
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
} failure:^(NSError *error) {
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: Disable Push: Error: %@", error);
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitNotifications: PushKit is already disabled for %@", self.mxCredentials.userId);
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setEnableInAppNotifications:(BOOL)enableInAppNotifications
|
|
{
|
|
MXLogDebug(@"[MXKAccount] setEnableInAppNotifications: %@", @(enableInAppNotifications));
|
|
|
|
_enableInAppNotifications = enableInAppNotifications;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
- (void)setDisabled:(BOOL)disabled
|
|
{
|
|
if (_disabled != disabled)
|
|
{
|
|
_disabled = disabled;
|
|
|
|
if (_disabled)
|
|
{
|
|
[self deletePusher];
|
|
[self enablePushKitNotifications:NO success:nil failure:nil];
|
|
|
|
// Close session (keep the storage).
|
|
[self closeSession:NO];
|
|
}
|
|
else if (!mxSession)
|
|
{
|
|
// Open a new matrix session
|
|
id<MXStore> store = [[[MXKAccountManager sharedManager].storeClass alloc] init];
|
|
|
|
[self openSessionWithStore:store];
|
|
}
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
}
|
|
|
|
- (void)setWarnedAboutEncryption:(BOOL)warnedAboutEncryption
|
|
{
|
|
_warnedAboutEncryption = warnedAboutEncryption;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
- (NSMutableDictionary<NSString *, id<NSCoding>> *)others
|
|
{
|
|
if(_others == nil)
|
|
{
|
|
_others = [NSMutableDictionary dictionary];
|
|
}
|
|
|
|
return _others;
|
|
}
|
|
|
|
- (void)setPauseRequested:(BOOL)pauseRequested
|
|
{
|
|
if (_pauseRequested != pauseRequested)
|
|
{
|
|
_pauseRequested = pauseRequested;
|
|
|
|
if (_pauseRequested)
|
|
{
|
|
// Make sure the SDK finish its work before the app goes sleeping in background
|
|
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
|
|
if (handler)
|
|
{
|
|
if (!self.pauseBackgroundTask.isRunning)
|
|
{
|
|
self.pauseBackgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask"
|
|
expirationHandler:nil];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[self cancelPauseBackgroundTask];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - Matrix user's profile
|
|
|
|
- (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))success failure:(void (^)(NSError *error))failure
|
|
{
|
|
if (mxSession && mxSession.myUser)
|
|
{
|
|
[mxSession.myUser setDisplayName:displayname
|
|
success:^{
|
|
if (success) {
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}
|
|
failure:failure];
|
|
}
|
|
else if (failure)
|
|
{
|
|
failure ([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: [VectorL10n accountErrorMatrixSessionIsNotOpened]}]);
|
|
}
|
|
}
|
|
|
|
- (void)setUserAvatarUrl:(NSString*)avatarUrl success:(void (^)(void))success failure:(void (^)(NSError *error))failure
|
|
{
|
|
if (mxSession && mxSession.myUser)
|
|
{
|
|
[mxSession.myUser setAvatarUrl:avatarUrl
|
|
success:^{
|
|
if (success) {
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}
|
|
failure:failure];
|
|
}
|
|
else if (failure)
|
|
{
|
|
failure ([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: [VectorL10n accountErrorMatrixSessionIsNotOpened]}]);
|
|
}
|
|
}
|
|
|
|
- (void)changePassword:(NSString*)oldPassword with:(NSString*)newPassword logoutDevices:(BOOL)logoutDevices success:(void (^)(void))success failure:(void (^)(NSError *error))failure
|
|
{
|
|
if (mxSession)
|
|
{
|
|
[mxRestClient changePassword:oldPassword
|
|
with:newPassword
|
|
logoutDevices:logoutDevices
|
|
success:^{
|
|
|
|
if (success) {
|
|
success();
|
|
}
|
|
|
|
}
|
|
failure:failure];
|
|
}
|
|
else if (failure)
|
|
{
|
|
failure ([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: [VectorL10n accountErrorMatrixSessionIsNotOpened]}]);
|
|
}
|
|
}
|
|
|
|
- (void)load3PIDs:(void (^)(void))success failure:(void (^)(NSError *))failure
|
|
{
|
|
|
|
[mxRestClient threePIDs:^(NSArray<MXThirdPartyIdentifier *> *threePIDs2) {
|
|
self->_threePIDs = threePIDs2;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
} failure:^(NSError *error) {
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)loadDeviceInformation:(void (^)(void))success failure:(void (^)(NSError *error))failure
|
|
{
|
|
if (self.mxCredentials.deviceId)
|
|
{
|
|
[mxRestClient deviceByDeviceId:self.mxCredentials.deviceId success:^(MXDevice *device) {
|
|
|
|
self->_device = device;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
_device = nil;
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setUserPresence:(MXPresence)presence andStatusMessage:(NSString *)statusMessage completion:(void (^)(void))completion
|
|
{
|
|
userPresence = presence;
|
|
|
|
if (mxSession && (!hideUserPresence || BuildSettings.bwiPersonalState))
|
|
{
|
|
// Update user presence on server side
|
|
[mxSession.myUser setPresence:userPresence
|
|
andStatusMessage:statusMessage
|
|
success:^{
|
|
MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) succeeded", self.mxCredentials.userId, (unsigned long)self->userPresence);
|
|
if (completion)
|
|
{
|
|
completion();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}
|
|
failure:^(NSError *error) {
|
|
MXLogDebug(@"[MXKAccount] %@: set user presence (%lu) failed", self.mxCredentials.userId, (unsigned long)self->userPresence);
|
|
}];
|
|
}
|
|
else if (hideUserPresence)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] %@: set user presence is disabled.", self.mxCredentials.userId);
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
/**
|
|
Create a matrix session based on the provided store.
|
|
When store data is ready, the live stream is automatically launched by synchronising the session with the server.
|
|
|
|
In case of failure during server sync, the method is reiterated until the data is up-to-date with the server.
|
|
This loop is stopped if you call [MXCAccount closeSession:], it is suspended if you call [MXCAccount pauseInBackgroundTask].
|
|
|
|
@param store the store to use for the session.
|
|
*/
|
|
-(void)openSessionWithStore:(id<MXStore>)store
|
|
{
|
|
// Sanity check
|
|
if (!self.mxCredentials || !mxRestClient)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] Matrix session cannot be created without credentials");
|
|
return;
|
|
}
|
|
|
|
// Close potential session (keep associated store).
|
|
[self closeSession:NO];
|
|
|
|
openSessionStartDate = [NSDate date];
|
|
|
|
// Instantiate new session
|
|
mxSession = [[MXSession alloc] initWithMatrixRestClient:mxRestClient];
|
|
mxSession.preferredSyncPresence = self.preferredSyncPresence;
|
|
|
|
// Check whether an antivirus url is defined.
|
|
if (_antivirusServerURL)
|
|
{
|
|
// Enable the antivirus scanner in the current session.
|
|
[mxSession setAntivirusServerURL:_antivirusServerURL];
|
|
}
|
|
|
|
// Set default MXEvent -> NSString formatter
|
|
MXKEventFormatter *eventFormatter = [[MXKEventFormatter alloc] initWithMatrixSession:self.mxSession];
|
|
eventFormatter.isForSubtitle = YES;
|
|
|
|
// Apply the event types filter to display only the wanted event types.
|
|
eventFormatter.eventTypesFilterForMessages = [MXKAppSettings standardAppSettings].eventsFilterForMessages;
|
|
|
|
mxSession.roomSummaryUpdateDelegate = eventFormatter;
|
|
|
|
// Observe UIApplicationSignificantTimeChangeNotification to refresh to MXRoomSummaries if date/time are shown.
|
|
// UIApplicationSignificantTimeChangeNotification is posted if DST is updated, carrier time is updated
|
|
UIApplicationSignificantTimeChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationSignificantTimeChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
[self onDateTimeFormatUpdate];
|
|
}];
|
|
|
|
|
|
// Observe NSCurrentLocaleDidChangeNotification to refresh MXRoomSummaries if date/time are shown.
|
|
// NSCurrentLocaleDidChangeNotification is triggered when the time swicthes to AM/PM to 24h time format
|
|
NSCurrentLocaleDidChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSCurrentLocaleDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
[self onDateTimeFormatUpdate];
|
|
}];
|
|
|
|
// Force a date refresh for all the last messages.
|
|
[self onDateTimeFormatUpdate];
|
|
|
|
// Register session state observer
|
|
sessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
|
|
// Check whether the concerned session is the associated one
|
|
if (notif.object == self->mxSession)
|
|
{
|
|
[self onMatrixSessionStateChange];
|
|
}
|
|
}];
|
|
|
|
MXWeakify(self);
|
|
|
|
[mxSession setStore:store success:^{
|
|
|
|
// Complete session registration by launching live stream
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
// Validate the availability of local contact sync for any changes to the
|
|
// authorization of contacts access that may have occurred since the last launch.
|
|
// The session is passed in as the contacts manager may not have had a session added yet.
|
|
[MXKContactManager.sharedManager validateSyncLocalContactsStateForSession:self.mxSession];
|
|
|
|
// Refresh pusher state
|
|
[self refreshAPNSPusher];
|
|
[self refreshPushKitPusher];
|
|
|
|
// Launch server sync
|
|
[self launchInitialServerSync];
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
// This cannot happen. Loading of MXFileStore cannot fail.
|
|
MXStrongifyAndReturnIfNil(self);
|
|
self->mxSession = nil;
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self->sessionStateObserver];
|
|
self->sessionStateObserver = nil;
|
|
|
|
}];
|
|
}
|
|
|
|
/**
|
|
Close the matrix session.
|
|
|
|
@param clearStore set YES to delete all store data.
|
|
*/
|
|
- (void)closeSession:(BOOL)clearStore
|
|
{
|
|
MXLogDebug(@"[MXKAccount] closeSession (%u)", clearStore);
|
|
|
|
if (NSCurrentLocaleDidChangeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:NSCurrentLocaleDidChangeNotificationObserver];
|
|
NSCurrentLocaleDidChangeNotificationObserver = nil;
|
|
}
|
|
|
|
if (UIApplicationSignificantTimeChangeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:UIApplicationSignificantTimeChangeNotificationObserver];
|
|
UIApplicationSignificantTimeChangeNotificationObserver = nil;
|
|
}
|
|
|
|
[self removeNotificationListener];
|
|
|
|
if (reachabilityObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
|
reachabilityObserver = nil;
|
|
}
|
|
|
|
if (sessionStateObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:sessionStateObserver];
|
|
sessionStateObserver = nil;
|
|
}
|
|
|
|
[initialServerSyncTimer invalidate];
|
|
initialServerSyncTimer = nil;
|
|
|
|
if (userUpdateListener)
|
|
{
|
|
[mxSession.myUser removeListener:userUpdateListener];
|
|
userUpdateListener = nil;
|
|
}
|
|
|
|
if (mxSession)
|
|
{
|
|
// Reset room data stored in memory
|
|
[MXKRoomDataSourceManager removeSharedManagerForMatrixSession:mxSession];
|
|
|
|
if (clearStore)
|
|
{
|
|
// Force a reload of device keys at the next session start.
|
|
// This will fix potential UISIs other peoples receive for our messages.
|
|
[mxSession.crypto resetDeviceKeys];
|
|
|
|
// Clean other stores
|
|
[mxSession.scanManager deleteAllAntivirusScans];
|
|
[mxSession.aggregations resetData];
|
|
}
|
|
else
|
|
{
|
|
// For recomputing of room summaries as they are a cache of computed data
|
|
[mxSession resetRoomsSummariesLastMessage];
|
|
}
|
|
|
|
// Close session
|
|
[mxSession close];
|
|
|
|
if (clearStore)
|
|
{
|
|
[mxSession.store deleteAllData];
|
|
}
|
|
|
|
mxSession = nil;
|
|
}
|
|
|
|
notifyOpenSessionFailure = YES;
|
|
}
|
|
|
|
- (void)logout:(void (^)(void))completion
|
|
{
|
|
if (!mxSession || !mxSession.matrixRestClient)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] logout: Need to open the closed session to make a logout request");
|
|
id<MXStore> store = [[[MXKAccountManager sharedManager].storeClass alloc] init];
|
|
mxSession = [[MXSession alloc] initWithMatrixRestClient:mxRestClient];
|
|
|
|
MXWeakify(self);
|
|
[mxSession setStore:store success:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
[self logout:completion];
|
|
|
|
} failure:^(NSError *error) {
|
|
completion();
|
|
}];
|
|
return;
|
|
}
|
|
|
|
[self deletePusher];
|
|
[self enablePushKitNotifications:NO success:nil failure:nil];
|
|
|
|
MXHTTPOperation *operation = [mxSession logout:^{
|
|
|
|
[self closeSession:YES];
|
|
if (completion)
|
|
{
|
|
completion();
|
|
}
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
// Close the session even if the logout request failed
|
|
[self closeSession:YES];
|
|
if (completion)
|
|
{
|
|
completion();
|
|
}
|
|
|
|
}];
|
|
|
|
// Do not retry on failure.
|
|
operation.maxNumberOfTries = 1;
|
|
}
|
|
|
|
// Logout locally, do not send server request
|
|
- (void)logoutLocally:(void (^)(void))completion
|
|
{
|
|
[self deletePusher];
|
|
[self enablePushKitNotifications:NO success:nil failure:nil];
|
|
|
|
[mxSession enableCrypto:NO success:^{
|
|
[self closeSession:YES];
|
|
if (completion)
|
|
{
|
|
completion();
|
|
}
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
// Close the session even if the logout request failed
|
|
[self closeSession:YES];
|
|
if (completion)
|
|
{
|
|
completion();
|
|
}
|
|
|
|
}];
|
|
}
|
|
|
|
- (void)logoutSendingServerRequest:(BOOL)sendLogoutServerRequest
|
|
completion:(void (^)(void))completion
|
|
{
|
|
if (sendLogoutServerRequest)
|
|
{
|
|
[self logout:completion];
|
|
}
|
|
else
|
|
{
|
|
[self logoutLocally:completion];
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Soft logout
|
|
|
|
- (void)softLogout
|
|
{
|
|
if (_isSoftLogout)
|
|
{
|
|
// do not close the session if already soft logged out
|
|
// it may break the current logout request and resetting session credentials can cause crashes
|
|
return;
|
|
}
|
|
_isSoftLogout = YES;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
// Stop SDK making requests to the homeserver
|
|
[mxSession close];
|
|
}
|
|
|
|
- (void)hydrateWithCredentials:(MXCredentials*)credentials
|
|
{
|
|
// Sanity check
|
|
if ([self.mxCredentials.userId isEqualToString:credentials.userId])
|
|
{
|
|
_mxCredentials = credentials;
|
|
_isSoftLogout = NO;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
[self prepareRESTClient];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount] hydrateWithCredentials: Error: users ids mismatch: %@ vs %@", credentials.userId, self.mxCredentials.userId);
|
|
}
|
|
}
|
|
|
|
- (void)deletePusher
|
|
{
|
|
if (self.pushNotificationServiceIsActive)
|
|
{
|
|
[self enableAPNSPusher:NO success:nil failure:nil];
|
|
}
|
|
}
|
|
|
|
- (void)pauseInBackgroundTask
|
|
{
|
|
if (mxSession == nil)
|
|
{
|
|
// no session to pause
|
|
return;
|
|
}
|
|
|
|
// mark that we want to pause when possible
|
|
self.pauseRequested = YES;
|
|
|
|
if (mxSession.isPauseable)
|
|
{
|
|
// Pause SDK
|
|
[mxSession pause];
|
|
|
|
// Update user presence
|
|
MXWeakify(self);
|
|
[self setUserPresence:MXPresenceOffline andStatusMessage:self.userStatusMessage completion:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
[self cancelPauseBackgroundTask];
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
// Cancel pending actions
|
|
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
|
reachabilityObserver = nil;
|
|
[initialServerSyncTimer invalidate];
|
|
initialServerSyncTimer = nil;
|
|
|
|
MXLogDebug(@"[MXKAccount] Pause is delayed due to the session state: %@", [MXTools readableSessionState: mxSession.state]);
|
|
}
|
|
}
|
|
|
|
- (void)resume
|
|
{
|
|
if (mxSession == nil)
|
|
{
|
|
// no session to resume
|
|
return;
|
|
}
|
|
|
|
// mark that we don't want to pause anymore
|
|
self.pauseRequested = NO;
|
|
|
|
MXLogVerbose(@"[MXKAccount] resume: with session state: %@", [MXTools readableSessionState:mxSession.state]);
|
|
|
|
[self cancelBackgroundSync];
|
|
|
|
switch (mxSession.state)
|
|
{
|
|
case MXSessionStatePaused:
|
|
case MXSessionStatePauseRequested:
|
|
{
|
|
// Resume SDK and update user presence
|
|
MXWeakify(self);
|
|
[mxSession resume:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
[self setUserPresence:MXPresenceOffline andStatusMessage:self.userStatusMessage completion:nil];
|
|
|
|
[self refreshAPNSPusher];
|
|
[self refreshPushKitPusher];
|
|
}];
|
|
|
|
break;
|
|
}
|
|
case MXSessionStateStoreDataReady:
|
|
case MXSessionStateInitialSyncFailed:
|
|
{
|
|
// The session initialisation was uncompleted, we try to complete it here.
|
|
[self launchInitialServerSync];
|
|
|
|
[self refreshAPNSPusher];
|
|
[self refreshPushKitPusher];
|
|
|
|
break;
|
|
}
|
|
case MXSessionStateSyncInProgress:
|
|
{
|
|
[self refreshAPNSPusher];
|
|
[self refreshPushKitPusher];
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)reload:(BOOL)clearCache
|
|
{
|
|
// close potential session
|
|
[self closeSession:clearCache];
|
|
|
|
if (!_disabled)
|
|
{
|
|
// Open a new matrix session
|
|
id<MXStore> store = [[[MXKAccountManager sharedManager].storeClass alloc] init];
|
|
[self openSessionWithStore:store];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Push notifications
|
|
|
|
// Refresh the APNS pusher state for this account on this device.
|
|
- (void)refreshAPNSPusher
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher");
|
|
|
|
// Check the conditions required to run the pusher
|
|
if (self.pushNotificationServiceIsActive)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher: Refresh APNS pusher for %@ account", self.mxCredentials.userId);
|
|
|
|
// Create/restore the pusher
|
|
[self enableAPNSPusher:YES
|
|
success:nil
|
|
failure:^(NSError *error) {
|
|
MXLogDebug(@"[MXKAccount][Push] ;: Error: %@", error);
|
|
}];
|
|
}
|
|
else if (_hasPusherForPushNotifications)
|
|
{
|
|
if ([MXKAccountManager sharedManager].apnsDeviceToken)
|
|
{
|
|
if (mxSession)
|
|
{
|
|
// Turn off pusher if user denied remote notification.
|
|
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher: Disable APNS pusher for %@ account (notifications are denied)", self.mxCredentials.userId);
|
|
[self enableAPNSPusher:NO success:nil failure:nil];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher: APNS pusher for %@ account is already disabled. Reset _hasPusherForPushNotifications", self.mxCredentials.userId);
|
|
_hasPusherForPushNotifications = NO;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable/Disable the APNS pusher for this account on this device on the homeserver.
|
|
- (void)enableAPNSPusher:(BOOL)enabled success:(void (^)(void))success failure:(void (^)(NSError *))failure
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enableAPNSPusher: %@", @(enabled));
|
|
|
|
#ifdef DEBUG
|
|
NSString *appId = [[NSUserDefaults standardUserDefaults] objectForKey:@"pusherAppIdDev"];
|
|
#else
|
|
NSString *appId = [[NSUserDefaults standardUserDefaults] objectForKey:@"pusherAppIdProd"];
|
|
#endif
|
|
|
|
NSString *locKey = MXKAppSettings.standardAppSettings.notificationBodyLocalizationKey;
|
|
|
|
NSDictionary *pushData = @{
|
|
@"url": self.pushGatewayURL,
|
|
@"format": @"event_id_only",
|
|
@"default_payload": @{@"aps": @{@"mutable-content": @(1), @"alert": @{@"loc-key": locKey, @"loc-args": @[]}}}
|
|
};
|
|
|
|
[self enablePusher:enabled appId:appId token:[MXKAccountManager sharedManager].apnsDeviceToken pushData:pushData success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enableAPNSPusher: Succeeded to update APNS pusher for %@ (%d)", self.mxCredentials.userId, enabled);
|
|
|
|
self->_hasPusherForPushNotifications = enabled;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
// Ignore error if the client try to disable an unknown token
|
|
if (!enabled)
|
|
{
|
|
// Check whether the token was unknown
|
|
MXError *mxError = [[MXError alloc] initWithNSError:error];
|
|
if (mxError && [mxError.errcode isEqualToString:kMXErrCodeStringUnknown])
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enableAPNSPusher: APNS was already disabled for %@!", self.mxCredentials.userId);
|
|
|
|
// Ignore the error
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
|
|
return;
|
|
}
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enableAPNSPusher: Failed to disable APNS %@! (%@)", self.mxCredentials.userId, error);
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enableAPNSPusher: Failed to send APNS token for %@! (%@)", self.mxCredentials.userId, error);
|
|
}
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
}];
|
|
}
|
|
|
|
// Refresh the PushKit pusher state for this account on this device.
|
|
- (void)refreshPushKitPusher
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher");
|
|
|
|
// Check the conditions required to run the pusher
|
|
if (![MXKAppSettings standardAppSettings].allowPushKitPushers)
|
|
{
|
|
// Turn off pusher if PushKit pushers are not allowed
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: Disable PushKit pusher for %@ account (pushers are not allowed)", self.mxCredentials.userId);
|
|
[self enablePushKitPusher:NO success:nil failure:nil];
|
|
}
|
|
else if (self.isPushKitNotificationActive)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: Refresh PushKit pusher for %@ account", self.mxCredentials.userId);
|
|
|
|
// Create/restore the pusher
|
|
[self enablePushKitPusher:YES
|
|
success:nil
|
|
failure:^(NSError *error) {
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: Error: %@", error);
|
|
}];
|
|
}
|
|
else if (self.hasPusherForPushKitNotifications)
|
|
{
|
|
if ([MXKAccountManager sharedManager].pushDeviceToken)
|
|
{
|
|
if (mxSession)
|
|
{
|
|
// Turn off pusher if user denied remote notification.
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: Disable PushKit pusher for %@ account (notifications are denied)", self.mxCredentials.userId);
|
|
[self enablePushKitPusher:NO success:nil failure:nil];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] refreshPushKitPusher: PushKit pusher for %@ account is already disabled. Reset _hasPusherForPushKitNotifications", self.mxCredentials.userId);
|
|
self->_hasPusherForPushKitNotifications = NO;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable/Disable the pusher based on PushKit for this account on this device on the homeserver.
|
|
- (void)enablePushKitPusher:(BOOL)enabled success:(void (^)(void))success failure:(void (^)(NSError *))failure
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: %@", @(enabled));
|
|
|
|
if (enabled && ![MXKAppSettings standardAppSettings].allowPushKitPushers)
|
|
{
|
|
// sanity check, if accidently try to enable the pusher
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Do not enable it because PushKit pushers not allowed");
|
|
if (failure)
|
|
{
|
|
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
NSString *appIdKey;
|
|
#ifdef DEBUG
|
|
appIdKey = @"pushKitAppIdDev";
|
|
#else
|
|
appIdKey = @"pushKitAppIdProd";
|
|
#endif
|
|
|
|
NSString *appId = [[NSUserDefaults standardUserDefaults] objectForKey:appIdKey];
|
|
|
|
NSMutableDictionary *pushData = [NSMutableDictionary dictionaryWithDictionary:@{@"url": self.pushGatewayURL}];
|
|
|
|
NSDictionary *options = [MXKAccountManager sharedManager].pushOptions;
|
|
if (options.count)
|
|
{
|
|
[pushData addEntriesFromDictionary:options];
|
|
}
|
|
|
|
NSData *token = [MXKAccountManager sharedManager].pushDeviceToken;
|
|
if (!token)
|
|
{
|
|
// sanity check, if no token there is no point of calling the endpoint
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Failed to update PushKit pusher to %@ for %@. (token is missing)", @(enabled), self.mxCredentials.userId);
|
|
if (failure)
|
|
{
|
|
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
|
|
}
|
|
return;
|
|
}
|
|
[self enablePusher:enabled appId:appId token:token pushData:pushData success:^{
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Succeeded to update PushKit pusher for %@. Enabled: %@. Token: %@", self.mxCredentials.userId, @(enabled), [MXKTools logForPushToken:token]);
|
|
|
|
self->_hasPusherForPushKitNotifications = enabled;
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
// Ignore error if the client try to disable an unknown token
|
|
if (!enabled)
|
|
{
|
|
// Check whether the token was unknown
|
|
MXError *mxError = [[MXError alloc] initWithNSError:error];
|
|
if (mxError && [mxError.errcode isEqualToString:kMXErrCodeStringUnknown])
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Push was already disabled for %@!", self.mxCredentials.userId);
|
|
|
|
// Ignore the error
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
|
|
return;
|
|
}
|
|
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Failed to disable Push %@! (%@)", self.mxCredentials.userId, error);
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePushKitPusher: Failed to send Push token for %@! (%@)", self.mxCredentials.userId, error);
|
|
}
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountPushKitActivityDidChangeNotification object:self.mxCredentials.userId];
|
|
}];
|
|
}
|
|
|
|
- (void)enablePusher:(BOOL)enabled appId:(NSString*)appId token:(NSData*)token pushData:(NSDictionary*)pushData success:(void (^)(void))success failure:(void (^)(NSError *))failure
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: %@", @(enabled));
|
|
|
|
// Refuse to try & turn push on if we're not logged in, it's nonsensical.
|
|
if (!self.mxCredentials)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: Not setting push token because we're not logged in");
|
|
return;
|
|
}
|
|
|
|
// Check whether the Push Gateway URL has been configured.
|
|
if (!self.pushGatewayURL)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: Not setting pusher because the Push Gateway URL is undefined");
|
|
return;
|
|
}
|
|
|
|
if (!appId)
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: Not setting pusher because pusher app id is undefined");
|
|
return;
|
|
}
|
|
|
|
NSString *appDisplayName = [NSString stringWithFormat:@"%@ (iOS)", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]];
|
|
|
|
NSString *b64Token = [token base64EncodedStringWithOptions:0];
|
|
|
|
NSString *deviceLang = [NSLocale preferredLanguages][0];
|
|
|
|
NSString * profileTag = [[NSUserDefaults standardUserDefaults] valueForKey:@"pusherProfileTag"];
|
|
if (!profileTag)
|
|
{
|
|
profileTag = @"";
|
|
NSString *alphabet = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
unsigned char c = [alphabet characterAtIndex:arc4random() % alphabet.length];
|
|
profileTag = [profileTag stringByAppendingFormat:@"%c", c];
|
|
}
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: Generated fresh profile tag: %@", profileTag);
|
|
[[NSUserDefaults standardUserDefaults] setValue:profileTag forKey:@"pusherProfileTag"];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: Using existing profile tag: %@", profileTag);
|
|
}
|
|
|
|
NSObject *kind = enabled ? @"http" : [NSNull null];
|
|
|
|
// Use the append flag to handle multiple accounts registration.
|
|
BOOL append = NO;
|
|
// Check whether a pusher is running for another account
|
|
NSArray *activeAccounts = [MXKAccountManager sharedManager].activeAccounts;
|
|
for (MXKAccount *account in activeAccounts)
|
|
{
|
|
if (![account.mxCredentials.userId isEqualToString:self.mxCredentials.userId] && account.pushNotificationServiceIsActive)
|
|
{
|
|
append = YES;
|
|
break;
|
|
}
|
|
}
|
|
MXLogDebug(@"[MXKAccount][Push] enablePusher: append flag: %d", append);
|
|
|
|
MXRestClient *restCli = self.mxRestClient;
|
|
|
|
[restCli setPusherWithPushkey:b64Token kind:kind appId:appId appDisplayName:appDisplayName deviceDisplayName:[[UIDevice currentDevice] name] profileTag:profileTag lang:deviceLang data:pushData append:append success:success failure:failure];
|
|
}
|
|
|
|
#pragma mark - InApp notifications
|
|
|
|
- (void)listenToNotifications:(MXOnNotification)onNotification
|
|
{
|
|
// Check conditions required to add notification listener
|
|
if (!mxSession || !onNotification)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Remove existing listener (if any)
|
|
[self removeNotificationListener];
|
|
|
|
// Register on notification center
|
|
notificationCenterListener = [self.mxSession.notificationCenter listenToNotifications:^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule)
|
|
{
|
|
// Apply first the event filter defined in the related room data source
|
|
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self->mxSession];
|
|
[roomDataSourceManager roomDataSourceForRoom:event.roomId create:NO onComplete:^(MXKRoomDataSource *roomDataSource) {
|
|
if (roomDataSource)
|
|
{
|
|
if (!roomDataSource.eventFormatter.eventTypesFilterForMessages || [roomDataSource.eventFormatter.eventTypesFilterForMessages indexOfObject:event.type] != NSNotFound)
|
|
{
|
|
// Check conditions to report this notification
|
|
if (nil == self->ignoredRooms || [self->ignoredRooms indexOfObject:event.roomId] == NSNotFound)
|
|
{
|
|
onNotification(event, roomState, rule);
|
|
}
|
|
}
|
|
}
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (void)removeNotificationListener
|
|
{
|
|
if (notificationCenterListener)
|
|
{
|
|
[self.mxSession.notificationCenter removeListener:notificationCenterListener];
|
|
notificationCenterListener = nil;
|
|
}
|
|
ignoredRooms = nil;
|
|
}
|
|
|
|
- (void)updateNotificationListenerForRoomId:(NSString*)roomID ignore:(BOOL)isIgnored
|
|
{
|
|
if (isIgnored)
|
|
{
|
|
if (!ignoredRooms)
|
|
{
|
|
ignoredRooms = [[NSMutableArray alloc] init];
|
|
}
|
|
[ignoredRooms addObject:roomID];
|
|
}
|
|
else if (ignoredRooms)
|
|
{
|
|
[ignoredRooms removeObject:roomID];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Internals
|
|
|
|
- (void)launchInitialServerSync
|
|
{
|
|
// Complete the session registration when store data is ready.
|
|
|
|
// Cancel potential reachability observer and pending action
|
|
[[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver];
|
|
reachabilityObserver = nil;
|
|
[initialServerSyncTimer invalidate];
|
|
initialServerSyncTimer = nil;
|
|
|
|
// Sanity check
|
|
if (!mxSession || (mxSession.state != MXSessionStateStoreDataReady && mxSession.state != MXSessionStateInitialSyncFailed))
|
|
{
|
|
MXLogDebug(@"[MXKAccount] Initial server sync is applicable only when store data is ready to complete session initialisation");
|
|
return;
|
|
}
|
|
|
|
// Use /sync filter corresponding to current settings and homeserver capabilities
|
|
MXWeakify(self);
|
|
[self buildSyncFilter:^(MXFilterJSONModel *syncFilter) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
// Make sure the filter is compatible with the previously used one
|
|
MXWeakify(self);
|
|
[self checkSyncFilterCompatibility:syncFilter completion:^(BOOL compatible) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
if (!compatible)
|
|
{
|
|
// Else clear the cache
|
|
MXLogDebug(@"[MXKAccount] New /sync filter not compatible with previous one. Clear cache");
|
|
|
|
[self reload:YES];
|
|
return;
|
|
}
|
|
|
|
// Launch mxSession
|
|
MXWeakify(self);
|
|
[self.mxSession startWithSyncFilter:syncFilter onServerSyncDone:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
MXLogDebug(@"[MXKAccount] %@: The session is ready. Matrix SDK session has been started in %0.fms.", self.mxCredentials.userId, [[NSDate date] timeIntervalSinceDate:self->openSessionStartDate] * 1000);
|
|
|
|
[self setUserPresence:MXPresenceOffline andStatusMessage:self.userStatusMessage completion:nil];
|
|
|
|
} failure:^(NSError *error) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
MXLogDebug(@"[MXKAccount] Initial Sync failed. Error: %@", error);
|
|
|
|
BOOL isClientTimeout = [error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorTimedOut;
|
|
NSHTTPURLResponse *httpResponse = [MXHTTPOperation urlResponseFromError:error];
|
|
BOOL isServerTimeout = httpResponse && [initialSyncSilentErrorsHTTPStatusCodes containsObject:@(httpResponse.statusCode)];
|
|
|
|
if (isClientTimeout || isServerTimeout)
|
|
{
|
|
// do not propagate this error to the client
|
|
// the request will be retried or postponed according to the reachability status
|
|
MXLogDebug(@"[MXKAccount] Initial sync failure did not propagated");
|
|
}
|
|
else if (self->notifyOpenSessionFailure && error)
|
|
{
|
|
// Notify MatrixKit user only once
|
|
self->notifyOpenSessionFailure = NO;
|
|
NSString *myUserId = self.mxSession.myUser.userId;
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
|
|
}
|
|
|
|
// Check if it is a network connectivity issue
|
|
AFNetworkReachabilityManager *networkReachabilityManager = [AFNetworkReachabilityManager sharedManager];
|
|
MXLogDebug(@"[MXKAccount] Network reachability: %d", networkReachabilityManager.isReachable);
|
|
|
|
if (networkReachabilityManager.isReachable)
|
|
{
|
|
// The problem is not the network
|
|
// Postpone a new attempt in 10 sec
|
|
self->initialServerSyncTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(launchInitialServerSync) userInfo:self repeats:NO];
|
|
}
|
|
else
|
|
{
|
|
// The device is not connected to the internet, wait for the connection to be up again before retrying
|
|
// Add observer to launch a new attempt according to reachability.
|
|
self->reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
|
|
|
NSNumber *statusItem = note.userInfo[AFNetworkingReachabilityNotificationStatusItem];
|
|
if (statusItem)
|
|
{
|
|
AFNetworkReachabilityStatus reachabilityStatus = statusItem.integerValue;
|
|
if (reachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi || reachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN)
|
|
{
|
|
// New attempt
|
|
[self launchInitialServerSync];
|
|
}
|
|
}
|
|
|
|
}];
|
|
}
|
|
}];
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (void)attemptDeviceDehydrationWithKeyData:(NSData *)keyData
|
|
success:(void (^)(void))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
[self attemptDeviceDehydrationWithKeyData:keyData retry:YES success:success failure:failure];
|
|
}
|
|
|
|
- (void)attemptDeviceDehydrationWithKeyData:(NSData *)keyData
|
|
retry:(BOOL)retry
|
|
success:(void (^)(void))success
|
|
failure:(void (^)(NSError *error))failure
|
|
{
|
|
if (keyData == nil)
|
|
{
|
|
MXLogWarning(@"[MXKAccount] attemptDeviceDehydrationWithRetry: no key provided for device dehydration");
|
|
|
|
if (failure)
|
|
{
|
|
failure(nil);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: starting device dehydration");
|
|
[[MXKAccountManager sharedManager].dehydrationService dehydrateDeviceWithMatrixRestClient:mxRestClient crypto:mxSession.crypto dehydrationKey:keyData success:^(NSString *deviceId) {
|
|
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device successfully dehydrated");
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
} failure:^(NSError *error) {
|
|
if (retry)
|
|
{
|
|
[self attemptDeviceDehydrationWithKeyData:keyData retry:NO success:success failure:failure];
|
|
MXLogError(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@. Retrying.", error);
|
|
}
|
|
else
|
|
{
|
|
MXLogError(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device dehydration failed due to error: %@", error);
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)onMatrixSessionStateChange
|
|
{
|
|
// Check if pause has been requested
|
|
if (self.isPauseRequested && mxSession.isPauseable)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] Apply the pending pause.");
|
|
[self pauseInBackgroundTask];
|
|
return;
|
|
}
|
|
|
|
if (mxSession.state == MXSessionStateRunning)
|
|
{
|
|
// Check whether the session was not already running
|
|
if (!userUpdateListener)
|
|
{
|
|
// Register listener to user's information change
|
|
userUpdateListener = [mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
|
|
// Consider events related to user's presence
|
|
if (event.eventType == MXEventTypePresence)
|
|
{
|
|
self->userPresence = [MXTools presence:event.content[@"presence"]];
|
|
}
|
|
|
|
// Here displayname or other information have been updated, post update notification.
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}];
|
|
|
|
// User information are just up-to-date (`mxSession` is running), post update notification.
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}
|
|
}
|
|
else if (mxSession.state == MXSessionStateStoreDataReady || mxSession.state == MXSessionStateSyncInProgress)
|
|
{
|
|
// Remove listener (if any), this action is required to handle correctly matrix sdk handler reload (see clear cache)
|
|
if (userUpdateListener)
|
|
{
|
|
[mxSession.myUser removeListener:userUpdateListener];
|
|
userUpdateListener = nil;
|
|
}
|
|
else
|
|
{
|
|
// Here the initial server sync is in progress. The session is not running yet, but some user's information are available (from local storage).
|
|
// We post update notification to let observer take into account this user's information even if they may not be up-to-date.
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountUserInfoDidChangeNotification object:self.mxCredentials.userId];
|
|
}
|
|
}
|
|
else if (mxSession.state == MXSessionStatePaused)
|
|
{
|
|
self.pauseRequested = NO;
|
|
}
|
|
}
|
|
|
|
- (void)prepareRESTClient
|
|
{
|
|
if (!self.mxCredentials)
|
|
{
|
|
return;
|
|
}
|
|
MXWeakify(self);
|
|
mxRestClient = [[MXRestClient alloc] initWithCredentials:self.mxCredentials andOnUnrecognizedCertificateBlock:^BOOL(NSData *certificate) {
|
|
MXStrongifyAndReturnValueIfNil(self, NO);
|
|
if (_onCertificateChangeBlock)
|
|
{
|
|
if (_onCertificateChangeBlock (self, certificate))
|
|
{
|
|
// Update the certificate in credentials
|
|
self.mxCredentials.allowedCertificate = certificate;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
|
|
return YES;
|
|
}
|
|
|
|
self.mxCredentials.ignoredCertificate = certificate;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
return NO;
|
|
|
|
} andPersistentTokenDataHandler:^(void (^handler)(NSArray<MXCredentials *> *credentials, void (^completion)(BOOL didUpdateCredentials))) {
|
|
[MXKAccountManager.sharedManager readAndWriteCredentials:handler];
|
|
} andUnauthenticatedHandler:^(MXError *error, BOOL isSoftLogout, BOOL isRefreshTokenAuth, void (^completion)(void)) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
[self handleUnauthenticatedWithError:error isSoftLogout:isSoftLogout isRefreshTokenAuth:isRefreshTokenAuth andCompletion:completion];
|
|
}];
|
|
}
|
|
|
|
- (void)handleUnauthenticatedWithError:(MXError *)error isSoftLogout:(BOOL)isSoftLogout isRefreshTokenAuth:(BOOL)isRefreshTokenAuth andCompletion:(void (^)(void))completion
|
|
{
|
|
|
|
[Analytics.shared trackAuthUnauthenticatedErrorWithSoftLogout:isSoftLogout refreshTokenAuth:isRefreshTokenAuth errorCode:error.errcode errorReason:error.error];
|
|
MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: trackAuthUnauthenticatedErrorWithSoftLogout sent");
|
|
if (isSoftLogout)
|
|
{
|
|
MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: soft logout.");
|
|
[[MXKAccountManager sharedManager] softLogout:self];
|
|
completion();
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccountManager] handleUnauthenticated: hard logout.");
|
|
[[MXKAccountManager sharedManager] removeAccount:self sendLogoutRequest:NO completion:completion];
|
|
}
|
|
}
|
|
|
|
- (void)onDateTimeFormatUpdate
|
|
{
|
|
if ([mxSession.roomSummaryUpdateDelegate isKindOfClass:MXKEventFormatter.class])
|
|
{
|
|
MXKEventFormatter *eventFormatter = (MXKEventFormatter*)mxSession.roomSummaryUpdateDelegate;
|
|
|
|
// Update the date and time formatters
|
|
[eventFormatter initDateTimeFormatters];
|
|
|
|
dispatch_group_t dispatchGroup = dispatch_group_create();
|
|
|
|
for (MXRoom *room in mxSession.rooms)
|
|
{
|
|
MXRoomSummary *summary = room.summary;
|
|
if (summary)
|
|
{
|
|
dispatch_group_enter(dispatchGroup);
|
|
[summary.mxSession eventWithEventId:summary.lastMessage.eventId
|
|
inRoom:summary.roomId
|
|
success:^(MXEvent *event) {
|
|
|
|
if (event)
|
|
{
|
|
if (summary.lastMessage.others == nil)
|
|
{
|
|
summary.lastMessage.others = [NSMutableDictionary dictionary];
|
|
}
|
|
summary.lastMessage.others[@"lastEventDate"] = [eventFormatter dateStringFromEvent:event withTime:YES];
|
|
[self->mxSession.store.roomSummaryStore storeSummary:summary];
|
|
}
|
|
|
|
dispatch_group_leave(dispatchGroup);
|
|
} failure:^(NSError *error) {
|
|
MXLogError(@"[MXKAccount] onDateTimeFormatUpdate: event fetch failed: %@", error);
|
|
dispatch_group_leave(dispatchGroup);
|
|
}];
|
|
}
|
|
}
|
|
|
|
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
|
|
|
// Commit store changes done
|
|
if ([self->mxSession.store respondsToSelector:@selector(commit)])
|
|
{
|
|
[self->mxSession.store commit];
|
|
}
|
|
|
|
// Broadcast the change which concerns all the room summaries.
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kMXRoomSummaryDidChangeNotification object:nil userInfo:nil];
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
- (void)cancelPauseBackgroundTask
|
|
{
|
|
// Cancel background task
|
|
if (self.pauseBackgroundTask.isRunning)
|
|
{
|
|
[self.pauseBackgroundTask stop];
|
|
self.pauseBackgroundTask = nil;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Crypto
|
|
- (void)resetDeviceId
|
|
{
|
|
self.mxCredentials.deviceId = nil;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
#pragma mark - backgroundSync management
|
|
|
|
- (void)cancelBackgroundSync
|
|
{
|
|
if (self.backgroundSyncBgTask.isRunning)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] The background Sync is cancelled.");
|
|
|
|
if (mxSession)
|
|
{
|
|
if (mxSession.state == MXSessionStateBackgroundSyncInProgress)
|
|
{
|
|
[mxSession pause];
|
|
}
|
|
}
|
|
|
|
[self onBackgroundSyncDone:[NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]];
|
|
}
|
|
}
|
|
|
|
- (void)onBackgroundSyncDone:(NSError*)error
|
|
{
|
|
if (backgroundSyncTimer)
|
|
{
|
|
[backgroundSyncTimer invalidate];
|
|
backgroundSyncTimer = nil;
|
|
}
|
|
|
|
if (backgroundSyncFails && error)
|
|
{
|
|
backgroundSyncFails(error);
|
|
}
|
|
|
|
if (backgroundSyncDone && !error)
|
|
{
|
|
backgroundSyncDone();
|
|
}
|
|
|
|
backgroundSyncDone = nil;
|
|
backgroundSyncFails = nil;
|
|
|
|
// End background task
|
|
if (self.backgroundSyncBgTask.isRunning)
|
|
{
|
|
[self.backgroundSyncBgTask stop];
|
|
self.backgroundSyncBgTask = nil;
|
|
}
|
|
}
|
|
|
|
- (void)onBackgroundSyncTimerOut
|
|
{
|
|
[self cancelBackgroundSync];
|
|
}
|
|
|
|
- (void)backgroundSync:(unsigned int)timeout success:(void (^)(void))success failure:(void (^)(NSError *))failure
|
|
{
|
|
// Check whether a background mode handler has been set.
|
|
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
|
|
if (handler)
|
|
{
|
|
// Only work when the application is suspended.
|
|
// Check conditions before launching background sync
|
|
if (mxSession && mxSession.state == MXSessionStatePaused)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] starts a background Sync");
|
|
|
|
backgroundSyncDone = success;
|
|
backgroundSyncFails = failure;
|
|
|
|
MXWeakify(self);
|
|
|
|
self.backgroundSyncBgTask = [handler startBackgroundTaskWithName:@"[MXKAccount] backgroundSync:success:failure:" expirationHandler:^{
|
|
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
MXLogDebug(@"[MXKAccount] the background Sync fails because of the bg task timeout");
|
|
[self cancelBackgroundSync];
|
|
}];
|
|
|
|
// ensure that the backgroundSync will be really done in the expected time
|
|
// the request could be done but the treatment could be long so add a timer to cancel it
|
|
// if it takes too much time
|
|
backgroundSyncTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:(timeout - 1) / 1000]
|
|
interval:0
|
|
target:self
|
|
selector:@selector(onBackgroundSyncTimerOut)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
|
|
[[NSRunLoop mainRunLoop] addTimer:backgroundSyncTimer forMode:NSDefaultRunLoopMode];
|
|
|
|
[mxSession backgroundSync:timeout success:^{
|
|
MXLogDebug(@"[MXKAccount] the background Sync succeeds");
|
|
[self onBackgroundSyncDone:nil];
|
|
|
|
}
|
|
failure:^(NSError* error) {
|
|
|
|
MXLogDebug(@"[MXKAccount] the background Sync fails");
|
|
[self onBackgroundSyncDone:error];
|
|
|
|
}
|
|
|
|
];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount] cannot start background Sync (invalid state %@)", [MXTools readableSessionState:mxSession.state]);
|
|
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[MXKAccount] cannot start background Sync");
|
|
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
|
|
}
|
|
}
|
|
|
|
#pragma mark - Sync filter
|
|
|
|
- (void)supportLazyLoadOfRoomMembers:(void (^)(BOOL supportLazyLoadOfRoomMembers))completion
|
|
{
|
|
void(^onUnsupportedLazyLoadOfRoomMembers)(NSError *) = ^(NSError *error) {
|
|
completion(NO);
|
|
};
|
|
|
|
// Check if the server supports LL sync filter
|
|
MXFilterJSONModel *filter = [self syncFilterWithLazyLoadOfRoomMembers:YES];
|
|
[mxSession.store filterIdForFilter:filter success:^(NSString * _Nullable filterId) {
|
|
|
|
if (filterId)
|
|
{
|
|
// The LL filter is already in the store. The HS supports LL
|
|
completion(YES);
|
|
}
|
|
else
|
|
{
|
|
// Check the Matrix versions supported by the HS
|
|
[self.mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
|
|
|
|
if (matrixVersions.supportLazyLoadMembers)
|
|
{
|
|
// The HS supports LL
|
|
completion(YES);
|
|
}
|
|
else
|
|
{
|
|
onUnsupportedLazyLoadOfRoomMembers(nil);
|
|
}
|
|
|
|
} failure:onUnsupportedLazyLoadOfRoomMembers];
|
|
}
|
|
} failure:onUnsupportedLazyLoadOfRoomMembers];
|
|
}
|
|
|
|
/**
|
|
Build the sync filter according to application settings and HS capability.
|
|
|
|
@param completion the block providing the sync filter to use.
|
|
*/
|
|
- (void)buildSyncFilter:(void (^)(MXFilterJSONModel *syncFilter))completion
|
|
{
|
|
// Check settings
|
|
BOOL syncWithLazyLoadOfRoomMembersSetting = [MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers;
|
|
|
|
if (syncWithLazyLoadOfRoomMembersSetting)
|
|
{
|
|
// Check if the server supports LL sync filter before enabling it
|
|
[self supportLazyLoadOfRoomMembers:^(BOOL supportLazyLoadOfRoomMembers) {
|
|
|
|
if (supportLazyLoadOfRoomMembers)
|
|
{
|
|
completion([self syncFilterWithLazyLoadOfRoomMembers:YES]);
|
|
}
|
|
else
|
|
{
|
|
// No support from the HS
|
|
// Disable the setting. That will avoid to make a request at every startup
|
|
[MXKAppSettings standardAppSettings].syncWithLazyLoadOfRoomMembers = NO;
|
|
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
completion([self syncFilterWithLazyLoadOfRoomMembers:NO]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Compute the sync filter to use according to the device screen size.
|
|
|
|
@param syncWithLazyLoadOfRoomMembers enable LL support.
|
|
@return the sync filter to use.
|
|
*/
|
|
- (MXFilterJSONModel *)syncFilterWithLazyLoadOfRoomMembers:(BOOL)syncWithLazyLoadOfRoomMembers
|
|
{
|
|
MXFilterJSONModel *syncFilter;
|
|
NSUInteger limit = 10;
|
|
|
|
// Define a message limit for /sync requests that is high enough so that
|
|
// a full page of room messages can be displayed without an additional
|
|
// server request.
|
|
|
|
// This limit value depends on the device screen size. So, the rough rule is:
|
|
// - use 10 for small phones (5S/SE)
|
|
// - use 15 for phones (6/6S/7/8)
|
|
// - use 20 for phablets (.Plus/X/XR/XS/XSMax)
|
|
// - use 30 for iPads
|
|
UIUserInterfaceIdiom userInterfaceIdiom = [[UIDevice currentDevice] userInterfaceIdiom];
|
|
if (userInterfaceIdiom == UIUserInterfaceIdiomPhone)
|
|
{
|
|
CGFloat screenHeight = [[UIScreen mainScreen] nativeBounds].size.height;
|
|
if (screenHeight == 1334) // 6/6S/7/8 screen height
|
|
{
|
|
limit = 15;
|
|
}
|
|
else if (screenHeight > 1334)
|
|
{
|
|
limit = 20;
|
|
}
|
|
}
|
|
else if (userInterfaceIdiom == UIUserInterfaceIdiomPad)
|
|
{
|
|
limit = 30;
|
|
}
|
|
|
|
// Set that limit in the filter
|
|
if (syncWithLazyLoadOfRoomMembers)
|
|
{
|
|
syncFilter = [MXFilterJSONModel syncFilterForLazyLoadingWithMessageLimit:limit];
|
|
}
|
|
else
|
|
{
|
|
syncFilter = [MXFilterJSONModel syncFilterWithMessageLimit:limit];
|
|
}
|
|
|
|
// TODO: We could extend the filter to match other settings (self.showAllEventsInRoomHistory,
|
|
// self.eventsFilterForMessages, etc).
|
|
|
|
return syncFilter;
|
|
}
|
|
|
|
|
|
/**
|
|
Check the sync filter we want to use is compatible with the one previously used.
|
|
|
|
@param syncFilter the sync filter to use.
|
|
@param completion the block called to indicated the compatibility.
|
|
*/
|
|
- (void)checkSyncFilterCompatibility:(MXFilterJSONModel*)syncFilter completion:(void (^)(BOOL compatible))completion
|
|
{
|
|
// There is no compatibility issue if no /sync was done before
|
|
if (!mxSession.store.eventStreamToken)
|
|
{
|
|
completion(YES);
|
|
}
|
|
|
|
// Check the filter we want to use is compatible with the one previously used
|
|
else if (!syncFilter && !mxSession.syncFilterId)
|
|
{
|
|
// A nil filter implies a nil mxSession.syncFilterId. So, there is no filter change
|
|
completion(YES);
|
|
}
|
|
else if (!syncFilter || !mxSession.syncFilterId)
|
|
{
|
|
// Change from no filter with using a filter or vice-versa. So, there is a filter change
|
|
MXLogDebug(@"[MXKAccount] checkSyncFilterCompatibility: Incompatible filter. New or old is nil. mxSession.syncFilterId: %@ - syncFilter: %@",
|
|
mxSession.syncFilterId, syncFilter.JSONDictionary);
|
|
completion(NO);
|
|
}
|
|
else if (!mxSession.store.allFilterIds.count)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] There are no filters stored in this session, proceed as if no /sync was done before");
|
|
completion(YES);
|
|
}
|
|
else
|
|
{
|
|
// Check the filter is the one previously set
|
|
// It must be already in the store
|
|
MXWeakify(self);
|
|
[mxSession.store filterIdForFilter:syncFilter success:^(NSString * _Nullable filterId) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
// Note: We could be more tolerant here
|
|
// We could accept filter hot change if the change is limited to the `limit` filter value
|
|
// But we do not have this requirement yet
|
|
BOOL compatible = [filterId isEqualToString:self.mxSession.syncFilterId];
|
|
if (!compatible)
|
|
{
|
|
MXLogDebug(@"[MXKAccount] checkSyncFilterCompatibility: Incompatible filter ids. mxSession.syncFilterId: %@ - store.filterId: %@ - syncFilter: %@",
|
|
self.mxSession.syncFilterId, filterId, syncFilter.JSONDictionary);
|
|
}
|
|
completion(compatible);
|
|
|
|
} failure:^(NSError * _Nullable error) {
|
|
// Should never happen
|
|
completion(NO);
|
|
}];
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Identity server updates
|
|
|
|
- (void)registerAccountDataDidChangeIdentityServerNotification
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAccountDataDidChangeIdentityServerNotification:) name:kMXSessionAccountDataDidChangeIdentityServerNotification object:nil];
|
|
}
|
|
|
|
- (void)handleAccountDataDidChangeIdentityServerNotification:(NSNotification*)notification
|
|
{
|
|
MXSession *mxSession = notification.object;
|
|
if (mxSession == self.mxSession)
|
|
{
|
|
if (![self.mxCredentials.identityServer isEqualToString:self.mxSession.accountDataIdentityServer])
|
|
{
|
|
_identityServerURL = self.mxSession.accountDataIdentityServer;
|
|
self.mxCredentials.identityServer = _identityServerURL;
|
|
self.mxCredentials.identityServerAccessToken = nil;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Identity server Access Token updates
|
|
|
|
- (void)identityService:(MXIdentityService *)identityService didUpdateAccessToken:(NSString *)accessToken
|
|
{
|
|
self.mxCredentials.identityServerAccessToken = accessToken;
|
|
}
|
|
|
|
- (void)registerIdentityServiceDidChangeAccessTokenNotification
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleIdentityServiceDidChangeAccessTokenNotification:) name:MXIdentityServiceDidChangeAccessTokenNotification object:nil];
|
|
}
|
|
|
|
- (void)handleIdentityServiceDidChangeAccessTokenNotification:(NSNotification*)notification
|
|
{
|
|
NSDictionary *userInfo = notification.userInfo;
|
|
|
|
NSString *userId = userInfo[MXIdentityServiceNotificationUserIdKey];
|
|
NSString *identityServer = userInfo[MXIdentityServiceNotificationIdentityServerKey];
|
|
NSString *accessToken = userInfo[MXIdentityServiceNotificationAccessTokenKey];
|
|
|
|
if (userId && identityServer && accessToken && [self.mxCredentials.identityServer isEqualToString:identityServer])
|
|
{
|
|
self.mxCredentials.identityServerAccessToken = accessToken;
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Presence
|
|
|
|
- (void)setPreferredSyncPresence:(MXPresence)preferredSyncPresence
|
|
{
|
|
[super setPreferredSyncPresence:preferredSyncPresence];
|
|
|
|
if (self.mxSession)
|
|
{
|
|
self.mxSession.preferredSyncPresence = preferredSyncPresence;
|
|
[self setUserPresence:MXPresenceOffline andStatusMessage:self.userStatusMessage completion:nil];
|
|
}
|
|
|
|
// Archive updated field
|
|
[[MXKAccountManager sharedManager] saveAccounts];
|
|
}
|
|
|
|
@end
|