mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-26 03:20:50 +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
1302 lines
53 KiB
Objective-C
1302 lines
53 KiB
Objective-C
/*
|
|
Copyright 2015 OpenMarket Ltd
|
|
Copyright 2017 Vector Creations Ltd
|
|
Copyright (c) 2021 BWI GmbH
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#import "RoomDataSource.h"
|
|
|
|
#import "EventFormatter.h"
|
|
#import "RoomBubbleCellData.h"
|
|
|
|
#import "MXKRoomBubbleTableViewCell+Riot.h"
|
|
#import "AvatarGenerator.h"
|
|
#import "ThemeService.h"
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
#import "MXRoom+Riot.h"
|
|
|
|
const CGFloat kTypingCellHeight = 24;
|
|
|
|
@interface RoomDataSource() <RoomReactionsViewModelDelegate, URLPreviewViewDelegate, ThreadSummaryViewDelegate, MXThreadingServiceDelegate>
|
|
{
|
|
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
|
|
id kThemeServiceDidChangeThemeNotificationObserver;
|
|
}
|
|
|
|
// Observe key verification request changes
|
|
@property (nonatomic, weak) id keyVerificationRequestDidChangeNotificationObserver;
|
|
|
|
// Observe key verification transaction changes
|
|
@property (nonatomic, weak) id keyVerificationTransactionDidChangeNotificationObserver;
|
|
|
|
// Listen to location beacon received
|
|
@property (nonatomic, weak) id beaconInfoSummaryListener;
|
|
|
|
// Listen to location beacon info deletion
|
|
@property (nonatomic, weak) id beaconInfoSummaryDeletionListener;
|
|
|
|
// Timer used to debounce cells refresh
|
|
@property (nonatomic, strong) NSTimer *refreshCellsTimer;
|
|
|
|
@property (nonatomic, weak, readonly) id<RoomDataSourceDelegate> roomDataSourceDelegate;
|
|
|
|
@property(nonatomic, readwrite) RoomEncryptionTrustLevel encryptionTrustLevel;
|
|
|
|
@property (nonatomic, strong) NSMutableSet *failedEventIds;
|
|
|
|
@property (nonatomic) RoomBubbleCellData *roomCreationCellData;
|
|
|
|
@property (nonatomic) BOOL showRoomCreationCell;
|
|
|
|
@property (nonatomic) NSInteger typingCellIndex;
|
|
|
|
@property(nonatomic, readwrite) BOOL isCurrentUserSharingActiveLocation;
|
|
|
|
@end
|
|
|
|
@implementation RoomDataSource
|
|
|
|
- (instancetype)initWithRoomId:(NSString *)roomId andMatrixSession:(MXSession *)matrixSession
|
|
{
|
|
self = [super initWithRoomId:roomId andMatrixSession:matrixSession];
|
|
if (self)
|
|
{
|
|
// Replace default Cell data class
|
|
[self registerCellDataClass:RoomBubbleCellData.class forCellIdentifier:kMXKRoomBubbleCellDataIdentifier];
|
|
|
|
// Replace the event formatter
|
|
[self updateEventFormatter];
|
|
|
|
// Handle timestamp and read receipts display at Vector app level (see [tableView: cellForRowAtIndexPath:])
|
|
self.useCustomDateTimeLabel = YES;
|
|
self.useCustomReceipts = YES;
|
|
self.useCustomUnsentButton = YES;
|
|
|
|
// Set bubble pagination
|
|
self.bubblesPagination = MXKRoomDataSourceBubblesPaginationPerDay;
|
|
|
|
self.markTimelineInitialEvent = NO;
|
|
|
|
self.showBubbleDateTimeOnSelection = YES;
|
|
self.showReactions = YES;
|
|
|
|
// Observe user interface theme change.
|
|
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
|
|
|
// Force room data reload.
|
|
[self updateEventFormatter];
|
|
[self reload];
|
|
|
|
}];
|
|
|
|
[matrixSession.threadingService addDelegate:self];
|
|
|
|
[self registerKeyVerificationRequestNotification];
|
|
[self registerKeyVerificationTransactionNotification];
|
|
[self registerTrustLevelDidChangeNotifications];
|
|
[self registerBeaconInfoSummaryListner];
|
|
|
|
self.encryptionTrustLevel = RoomEncryptionTrustLevelUnknown;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)finalizeInitialization
|
|
{
|
|
[super finalizeInitialization];
|
|
|
|
// Sadly, we need to make sure we have fetched all room members from the HS
|
|
// to be able to display read receipts
|
|
if (![self.mxSession.store hasLoadedAllRoomMembersForRoom:self.roomId])
|
|
{
|
|
[self.room members:^(MXRoomMembers *roomMembers) {
|
|
MXLogDebug(@"[MXKRoomDataSource] finalizeRoomDataSource: All room members have been retrieved");
|
|
|
|
// Refresh the full table
|
|
[self.delegate dataSource:self didCellChange:nil];
|
|
|
|
} failure:^(NSError *error) {
|
|
MXLogDebug(@"[MXKRoomDataSource] finalizeRoomDataSource: Cannot retrieve all room members");
|
|
}];
|
|
}
|
|
|
|
if (self.room.summary.isEncrypted)
|
|
{
|
|
// Make sure we have the trust shield value
|
|
[self.room.summary enableTrustTracking:YES];
|
|
[self fetchEncryptionTrustedLevel];
|
|
}
|
|
|
|
self.showTypingRow = YES;
|
|
|
|
[self updateCurrentUserLocationSharingStatus];
|
|
}
|
|
|
|
- (id<RoomDataSourceDelegate>)roomDataSourceDelegate
|
|
{
|
|
if (!self.delegate || ![self.delegate conformsToProtocol:@protocol(RoomDataSourceDelegate)])
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
return ((id<RoomDataSourceDelegate>)(self.delegate));
|
|
}
|
|
|
|
- (void)updateEventFormatter
|
|
{
|
|
// Set a new event formatter
|
|
// TODO: We should use the same EventFormatter instance for all the rooms of a mxSession.
|
|
self.eventFormatter = [[EventFormatter alloc] initWithMatrixSession:self.mxSession];
|
|
self.eventFormatter.treatMatrixUserIdAsLink = YES;
|
|
self.eventFormatter.treatMatrixRoomIdAsLink = YES;
|
|
self.eventFormatter.treatMatrixRoomAliasAsLink = YES;
|
|
self.eventFormatter.treatMatrixGroupIdAsLink = YES;
|
|
|
|
// Apply the event types filter to display only the wanted event types.
|
|
self.eventFormatter.eventTypesFilterForMessages = [MXKAppSettings standardAppSettings].eventsFilterForMessages;
|
|
}
|
|
|
|
- (void)destroy
|
|
{
|
|
if (kThemeServiceDidChangeThemeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:kThemeServiceDidChangeThemeNotificationObserver];
|
|
kThemeServiceDidChangeThemeNotificationObserver = nil;
|
|
}
|
|
|
|
if (self.keyVerificationRequestDidChangeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self.keyVerificationRequestDidChangeNotificationObserver];
|
|
}
|
|
|
|
if (self.keyVerificationTransactionDidChangeNotificationObserver)
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self.keyVerificationTransactionDidChangeNotificationObserver];
|
|
}
|
|
|
|
[self.mxSession.threadingService removeDelegate:self];
|
|
|
|
if (self.beaconInfoSummaryListener)
|
|
{
|
|
[self.mxSession.aggregations.beaconAggregations removeListener:self.beaconInfoSummaryListener];
|
|
}
|
|
|
|
if (self.beaconInfoSummaryDeletionListener)
|
|
{
|
|
[self.mxSession.aggregations.beaconAggregations removeListener:self.beaconInfoSummaryDeletionListener];
|
|
}
|
|
|
|
[super destroy];
|
|
}
|
|
|
|
- (void)updateCellDataReactions:(id<MXKRoomBubbleCellDataStoring>)cellData forEventId:(NSString*)eventId
|
|
{
|
|
[super updateCellDataReactions:cellData forEventId:eventId];
|
|
|
|
[self setNeedsUpdateAdditionalContentHeightForCellData:cellData];
|
|
}
|
|
|
|
- (void)updateCellData:(MXKRoomBubbleCellData*)cellData withReadReceipts:(NSArray<MXReceiptData*>*)readReceipts forEventId:(NSString*)eventId
|
|
{
|
|
[super updateCellData:cellData withReadReceipts:readReceipts forEventId:eventId];
|
|
|
|
[self setNeedsUpdateAdditionalContentHeightForCellData:cellData];
|
|
}
|
|
|
|
- (CGFloat)cellHeightAtIndex:(NSInteger)index withMaximumWidth:(CGFloat)maxWidth
|
|
{
|
|
if (index == self.typingCellIndex)
|
|
{
|
|
return kTypingCellHeight;
|
|
}
|
|
|
|
// bwi: Messages like avatar change may be filtered from the displayed timeline depending on settings
|
|
DefaultTimelineFilterService *service = [[DefaultTimelineFilterService alloc] init];
|
|
if ([service shouldFilter:[self cellDataAtIndex:index]]) {
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
return [super cellHeightAtIndex:index withMaximumWidth:maxWidth];
|
|
}
|
|
|
|
- (void)setNeedsUpdateAdditionalContentHeightForCellData:(id<MXKRoomBubbleCellDataStoring>)cellData
|
|
{
|
|
RoomBubbleCellData *roomBubbleCellData;
|
|
|
|
if ([cellData isKindOfClass:[RoomBubbleCellData class]])
|
|
{
|
|
roomBubbleCellData = (RoomBubbleCellData*)cellData;
|
|
[roomBubbleCellData setNeedsUpdateAdditionalContentHeight];
|
|
}
|
|
}
|
|
|
|
#pragma mark Encryption trust level
|
|
|
|
- (void)registerTrustLevelDidChangeNotifications
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(roomSummaryDidChange:) name:kMXRoomSummaryDidChangeNotification object:self.room.summary];
|
|
}
|
|
|
|
|
|
- (void)roomSummaryDidChange:(NSNotification*)notification
|
|
{
|
|
if (RiotSettings.shared.enableLiveLocationSharing)
|
|
{
|
|
[self updateCurrentUserLocationSharingStatus];
|
|
}
|
|
|
|
if (!self.room.summary.isEncrypted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
[self fetchEncryptionTrustedLevel];
|
|
}
|
|
|
|
- (void)fetchEncryptionTrustedLevel
|
|
{
|
|
self.encryptionTrustLevel = self.room.summary.roomEncryptionTrustLevel;
|
|
[self.roomDataSourceDelegate roomDataSourceDidUpdateEncryptionTrustLevel:self];
|
|
}
|
|
|
|
- (NSArray *)attachmentsWithThumbnail
|
|
{
|
|
NSMutableArray *attachments = [NSMutableArray array];
|
|
|
|
@synchronized(bubbles)
|
|
{
|
|
for (id<MXKRoomBubbleCellDataStoring> bubbleData in bubbles)
|
|
{
|
|
if (bubbleData.isAttachmentWithThumbnail && bubbleData.attachment.type != MXKAttachmentTypeSticker)
|
|
{
|
|
if (BuildSettings.enableAntivirusScan)
|
|
{
|
|
MXKRoomBubbleCellData *roomBubbleCellData;
|
|
|
|
if ([bubbleData isKindOfClass:MXKRoomBubbleCellData.class])
|
|
{
|
|
roomBubbleCellData = (MXKRoomBubbleCellData*)bubbleData;
|
|
}
|
|
|
|
// Append attchment only if the scan status is trusted
|
|
if (bubbleData.showAntivirusScanStatus && roomBubbleCellData.eventScanForFirstComponent && roomBubbleCellData.eventScanForFirstComponent.antivirusScanStatus != MXAntivirusScanStatusTrusted)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
[attachments addObject:bubbleData.attachment];
|
|
}
|
|
}
|
|
}
|
|
|
|
return attachments;
|
|
}
|
|
|
|
- (BOOL)shouldQueueEventForProcessing:(MXEvent *)event roomState:(MXRoomState *)roomState direction:(MXTimelineDirection)direction
|
|
{
|
|
if (self.threadId)
|
|
{
|
|
// if in a thread, ignore non-root event or events from other threads
|
|
if (![event.eventId isEqualToString:self.threadId] && ![event.threadId isEqualToString:self.threadId])
|
|
{
|
|
// Ignore the event
|
|
return NO;
|
|
}
|
|
// also ignore events related to un-threaded or events from other threads
|
|
if (!event.isInThread && event.relatesTo.eventId)
|
|
{
|
|
MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId
|
|
inRoom:event.roomId];
|
|
if (![relatedEvent.threadId isEqualToString:self.threadId])
|
|
{
|
|
// ignore the event
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
else if (RiotSettings.shared.enableThreads)
|
|
{
|
|
// if not in a thread, ignore all threaded events
|
|
if (event.isInThread)
|
|
{
|
|
// ignore the event
|
|
return NO;
|
|
}
|
|
// also ignore events related to threaded events
|
|
if (event.relatesTo.eventId)
|
|
{
|
|
MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId
|
|
inRoom:event.roomId];
|
|
if (relatedEvent.isInThread)
|
|
{
|
|
// ignore the event
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
|
|
return [super shouldQueueEventForProcessing:event roomState:roomState direction:direction];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
{
|
|
NSInteger count = [super tableView:tableView numberOfRowsInSection:section];
|
|
|
|
if (count)
|
|
{
|
|
// Enable the containsLastMessage flag for the cell data which contains the last message.
|
|
@synchronized(bubbles)
|
|
{
|
|
// Reset first all cell data
|
|
for (RoomBubbleCellData *cellData in bubbles)
|
|
{
|
|
cellData.containsLastMessage = NO;
|
|
cellData.componentIndexOfSentMessageTick = -1;
|
|
}
|
|
|
|
// The cell containing the last message is the last one with an actual display.
|
|
NSInteger index = bubbles.count;
|
|
while (index--)
|
|
{
|
|
RoomBubbleCellData *cellData = bubbles[index];
|
|
if (cellData.attributedTextMessage)
|
|
{
|
|
cellData.containsLastMessage = YES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
[self updateStatusInfo];
|
|
}
|
|
|
|
if (self.showTypingRow && self.currentTypingUsers)
|
|
{
|
|
self.typingCellIndex = bubbles.count;
|
|
return bubbles.count + 1;
|
|
}
|
|
else
|
|
{
|
|
self.typingCellIndex = -1;
|
|
return bubbles.count;
|
|
}
|
|
}
|
|
|
|
if (self.showTypingRow && self.currentTypingUsers)
|
|
{
|
|
self.typingCellIndex = count;
|
|
return count + 1;
|
|
}
|
|
else
|
|
{
|
|
self.typingCellIndex = -1;
|
|
|
|
// leave it as is, if coming as 0 from super
|
|
return count;
|
|
}
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
if (indexPath.row == self.typingCellIndex)
|
|
{
|
|
MessageTypingCell *cell = [tableView dequeueReusableCellWithIdentifier:MessageTypingCell.defaultReuseIdentifier forIndexPath:indexPath];
|
|
[cell updateWithTheme:ThemeService.shared.theme];
|
|
[cell updateTypingUsers:_currentTypingUsers mediaManager:self.mxSession.mediaManager];
|
|
return cell;
|
|
}
|
|
|
|
// Do cell data customization that needs to be done before [MXKRoomBubbleTableViewCell render]
|
|
RoomBubbleCellData *roomBubbleCellData = [self cellDataAtIndex:indexPath.row];
|
|
|
|
// Use the Riot style placeholder
|
|
if (!roomBubbleCellData.senderAvatarPlaceholder)
|
|
{
|
|
roomBubbleCellData.senderAvatarPlaceholder = [AvatarGenerator generateAvatarForMatrixItem:roomBubbleCellData.senderId withDisplayName:roomBubbleCellData.senderDisplayName];
|
|
}
|
|
|
|
[self updateKeyVerificationIfNeededForRoomBubbleCellData:roomBubbleCellData];
|
|
|
|
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
|
|
|
id<RoomTimelineCellDecorator> cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
|
|
|
|
// Finalize cell view customization here
|
|
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
|
|
{
|
|
MXKRoomBubbleTableViewCell *bubbleCell = (MXKRoomBubbleTableViewCell*)cell;
|
|
[self resetAccessibilityForCell:bubbleCell];
|
|
|
|
RoomBubbleCellData *cellData = (RoomBubbleCellData*)bubbleCell.bubbleData;
|
|
NSArray *bubbleComponents = cellData.bubbleComponents;
|
|
|
|
BOOL isCollapsableCellCollapsed = cellData.collapsable && cellData.collapsed;
|
|
|
|
if (BuildSettings.enableLastMessageTimestamp) {
|
|
// Display timestamp of the last message
|
|
if (cellData.containsLastMessage && !isCollapsableCellCollapsed)
|
|
{
|
|
[bubbleCell addTimestampLabelForComponent:cellData.mostRecentComponentIndex];
|
|
}
|
|
} else {
|
|
// Display timestamp of every message
|
|
if (!isCollapsableCellCollapsed)
|
|
{
|
|
[bubbleCell addTimestampLabelForComponent:cellData.mostRecentComponentIndex];
|
|
}
|
|
}
|
|
|
|
// Display timestamp of the message if needed
|
|
[cellDecorator addTimestampLabelIfNeededToCell:bubbleCell cellData:cellData];
|
|
|
|
NSMutableArray *temporaryViews = [NSMutableArray new];
|
|
|
|
// Handle read receipts and read marker display.
|
|
// Ignore the read receipts on the bubble without actual display.
|
|
// Ignore the read receipts on collapsed bubbles
|
|
if ((((self.showBubbleReceipts && cellData.readReceipts.count) || cellData.reactions.count || cellData.hasLink || cellData.hasThreadRoot) && !isCollapsableCellCollapsed) || self.showReadMarker)
|
|
{
|
|
// Read receipts container are inserted here on the right side into the content view.
|
|
// Some vertical whitespaces are added in message text view (see RoomBubbleCellData class) to insert correctly multiple receipts.
|
|
|
|
NSInteger index = 0;
|
|
|
|
for (MXKRoomBubbleComponent *component in bubbleComponents)
|
|
{
|
|
NSString *componentEventId = component.event.eventId;
|
|
|
|
if (component.event.sentState != MXEventSentStateFailed)
|
|
{
|
|
CGFloat bottomPositionY;
|
|
|
|
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:index];
|
|
|
|
if (CGRectEqualToRect(bubbleComponentFrame, CGRectNull) == NO)
|
|
{
|
|
bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
URLPreviewView *urlPreviewView;
|
|
|
|
// Show a URL preview if the component has a link that should be previewed.
|
|
if (component.showURLPreview)
|
|
{
|
|
urlPreviewView = [URLPreviewView instantiate];
|
|
urlPreviewView.preview = component.urlPreviewData;
|
|
urlPreviewView.delegate = self;
|
|
urlPreviewView.tag = index;
|
|
|
|
[temporaryViews addObject:urlPreviewView];
|
|
[cellDecorator addURLPreviewView:urlPreviewView
|
|
toCell:bubbleCell cellData:cellData contentViewPositionY:bottomPositionY];
|
|
}
|
|
|
|
MXAggregatedReactions* reactions = cellData.reactions[componentEventId].aggregatedReactionsWithNonZeroCount;
|
|
|
|
RoomReactionsView *reactionsView;
|
|
|
|
if (!component.event.isRedactedEvent && reactions && !isCollapsableCellCollapsed)
|
|
{
|
|
BOOL showAllReactions = [cellData showAllReactionsForEvent:componentEventId];
|
|
RoomReactionsViewModel *roomReactionsViewModel = [[RoomReactionsViewModel alloc] initWithAggregatedReactions:reactions
|
|
eventId:componentEventId
|
|
showAll:showAllReactions];
|
|
|
|
reactionsView = [RoomReactionsView new];
|
|
reactionsView.viewModel = roomReactionsViewModel;
|
|
reactionsView.tag = index;
|
|
[reactionsView updateWithTheme:ThemeService.shared.theme];
|
|
|
|
roomReactionsViewModel.viewModelDelegate = self;
|
|
|
|
[temporaryViews addObject:reactionsView];
|
|
[cellDecorator addReactionView:reactionsView toCell:bubbleCell
|
|
cellData:cellData contentViewPositionY:bottomPositionY upperDecorationView:urlPreviewView];
|
|
}
|
|
|
|
ThreadSummaryView *threadSummaryView;
|
|
|
|
// display thread summary view if the component has a thread in the room timeline
|
|
if (RiotSettings.shared.enableThreads && component.thread && !self.threadId)
|
|
{
|
|
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread
|
|
session:self.mxSession];
|
|
threadSummaryView.delegate = self;
|
|
threadSummaryView.tag = index;
|
|
|
|
[temporaryViews addObject:threadSummaryView];
|
|
UIView *upperDecorationView = reactionsView ?: urlPreviewView;
|
|
|
|
[cellDecorator addThreadSummaryView:threadSummaryView
|
|
toCell:bubbleCell
|
|
cellData:cellData
|
|
contentViewPositionY:bottomPositionY
|
|
upperDecorationView:upperDecorationView];
|
|
}
|
|
|
|
MXKReceiptSendersContainer* avatarsContainer;
|
|
|
|
// Handle read receipts (if any)
|
|
if (self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed)
|
|
{
|
|
// Get the events receipts by ignoring the current user receipt.
|
|
NSArray* receipts = cellData.readReceipts[component.event.eventId];
|
|
NSMutableArray *roomMembers;
|
|
NSMutableArray *placeholders;
|
|
|
|
// Check whether some receipts are found
|
|
if (receipts.count)
|
|
{
|
|
// Retrieve the corresponding room members
|
|
roomMembers = [[NSMutableArray alloc] initWithCapacity:receipts.count];
|
|
placeholders = [[NSMutableArray alloc] initWithCapacity:receipts.count];
|
|
|
|
for (MXReceiptData* data in receipts)
|
|
{
|
|
MXRoomMember * roomMember = [self.roomState.members memberWithUserId:data.userId];
|
|
if (roomMember)
|
|
{
|
|
[roomMembers addObject:roomMember];
|
|
[placeholders addObject:[AvatarGenerator generateAvatarForMatrixItem:roomMember.userId withDisplayName:roomMember.displayname]];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check whether some receipts are found
|
|
if (roomMembers.count)
|
|
{
|
|
// Define the read receipts container, positioned on the right border of the bubble cell (Note the right margin 6 pts).
|
|
avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - PlainRoomCellLayoutConstants.readReceiptsViewWidth + PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, bottomPositionY + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin, PlainRoomCellLayoutConstants.readReceiptsViewWidth, PlainRoomCellLayoutConstants.readReceiptsViewHeight) andMediaManager:self.mxSession.mediaManager];
|
|
|
|
// Custom avatar display
|
|
avatarsContainer.maxDisplayedAvatars = 5;
|
|
avatarsContainer.avatarMargin = 6;
|
|
|
|
// Set the container tag to be able to retrieve read receipts container from component index (see component selection in MXKRoomBubbleTableViewCell (Vector) category).
|
|
avatarsContainer.tag = index;
|
|
|
|
avatarsContainer.moreLabelTextColor = ThemeService.shared.theme.textPrimaryColor;
|
|
|
|
[avatarsContainer refreshReceiptSenders:roomMembers withPlaceHolders:placeholders andAlignment:ReadReceiptAlignmentRight];
|
|
avatarsContainer.readReceipts = receipts;
|
|
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:cell action:@selector(onReceiptContainerTap:)];
|
|
[tapRecognizer setNumberOfTapsRequired:1];
|
|
[tapRecognizer setNumberOfTouchesRequired:1];
|
|
[avatarsContainer addGestureRecognizer:tapRecognizer];
|
|
avatarsContainer.userInteractionEnabled = YES;
|
|
|
|
avatarsContainer.translatesAutoresizingMaskIntoConstraints = NO;
|
|
avatarsContainer.accessibilityIdentifier = @"readReceiptsContainer";
|
|
|
|
[temporaryViews addObject:avatarsContainer];
|
|
UIView *upperDecorationView = threadSummaryView ?: (reactionsView ?: urlPreviewView);
|
|
|
|
[cellDecorator addReadReceiptsView:avatarsContainer
|
|
toCell:bubbleCell
|
|
cellData:cellData
|
|
contentViewPositionY:bottomPositionY
|
|
upperDecorationView:upperDecorationView];
|
|
}
|
|
}
|
|
|
|
// Check whether the read marker must be displayed here.
|
|
if (self.showReadMarker)
|
|
{
|
|
// The read marker is added into the overlay container.
|
|
// CAUTION: Keep disabled the user interaction on this container to not disturb tap gesture handling.
|
|
bubbleCell.bubbleOverlayContainer.backgroundColor = [UIColor clearColor];
|
|
bubbleCell.bubbleOverlayContainer.alpha = 1;
|
|
bubbleCell.bubbleOverlayContainer.userInteractionEnabled = NO;
|
|
bubbleCell.bubbleOverlayContainer.hidden = NO;
|
|
|
|
if ([componentEventId isEqualToString:self.room.accountData.readMarkerEventId])
|
|
{
|
|
UIView *readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - PlainRoomCellLayoutConstants.readMarkerViewHeight, bubbleCell.bubbleOverlayContainer.frame.size.width, PlainRoomCellLayoutConstants.readMarkerViewHeight)];
|
|
readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor;
|
|
// Hide by default the marker, it will be shown and animated when the cell will be rendered.
|
|
readMarkerView.hidden = YES;
|
|
readMarkerView.tag = index;
|
|
readMarkerView.accessibilityIdentifier = @"readMarker";
|
|
|
|
[cellDecorator addReadMarkerView:readMarkerView
|
|
toCell:bubbleCell
|
|
cellData:cellData
|
|
contentViewPositionY:bottomPositionY];
|
|
}
|
|
}
|
|
}
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
// Update attachmentView bottom constraint to display reactions and read receipts if needed
|
|
|
|
UIView *attachmentView = bubbleCell.attachmentView;
|
|
NSLayoutConstraint *attachmentViewBottomConstraint = bubbleCell.attachViewBottomConstraint;
|
|
|
|
if (attachmentView && temporaryViews.count)
|
|
{
|
|
attachmentViewBottomConstraint.constant = roomBubbleCellData.additionalContentHeight;
|
|
}
|
|
else if (attachmentView)
|
|
{
|
|
[bubbleCell resetAttachmentViewBottomConstraintConstant];
|
|
}
|
|
|
|
// Check whether an event is currently selected: the other messages are then blurred
|
|
if (_selectedEventId)
|
|
{
|
|
[[RoomTimelineConfiguration shared].currentStyle applySelectedStyleIfNeededToCell:bubbleCell cellData:cellData];
|
|
}
|
|
|
|
// Reset the marker if any
|
|
if (bubbleCell.markerView)
|
|
{
|
|
[bubbleCell.markerView removeFromSuperview];
|
|
}
|
|
|
|
// Manage initial event (case of permalink or search result)
|
|
if ((self.timeline.initialEventId && self.markTimelineInitialEvent) || self.highlightedEventId)
|
|
{
|
|
// Check if the cell contains this initial event
|
|
for (NSUInteger index = 0; index < bubbleComponents.count; index++)
|
|
{
|
|
MXKRoomBubbleComponent *component = bubbleComponents[index];
|
|
|
|
if ([component.event.eventId isEqualToString:self.timeline.initialEventId]
|
|
|| [component.event.eventId isEqualToString:self.highlightedEventId])
|
|
{
|
|
// If yes, mark the event
|
|
[bubbleCell markComponent:index];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Auto animate the sticker in case of animated gif
|
|
bubbleCell.isAutoAnimatedGif = (cellData.attachment && cellData.attachment.type == MXKAttachmentTypeSticker);
|
|
|
|
[self applyMaskToAttachmentViewOfBubbleCell: bubbleCell];
|
|
|
|
[self setupAccessibilityForCell:bubbleCell withCellData:cellData];
|
|
|
|
// We are interested only by outgoing messages
|
|
if ([cellData.senderId isEqualToString: self.mxSession.credentials.userId])
|
|
{
|
|
[cellDecorator addSendStatusViewToCell:bubbleCell
|
|
withFailedEventIds:self.failedEventIds];
|
|
}
|
|
|
|
// Make extra cell layout updates if needed
|
|
[self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData];
|
|
}
|
|
|
|
if ([cell conformsToProtocol:@protocol(Themable)])
|
|
{
|
|
id<Themable> cellThemable = (id<Themable>)cell;
|
|
|
|
[cellThemable updateWithTheme:ThemeService.shared.theme];
|
|
}
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (void)updateCellLayoutIfNeeded:(MXKRoomBubbleTableViewCell*)cell withCellData:(MXKRoomBubbleCellData*)cellData {
|
|
|
|
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
|
|
|
|
[timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutIfNeededFor:cell andCellData:cellData];
|
|
}
|
|
|
|
- (RoomBubbleCellData*)roomBubbleCellDataForEventId:(NSString*)eventId
|
|
{
|
|
id<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];
|
|
RoomBubbleCellData *roomBubbleCellData;
|
|
|
|
if ([cellData isKindOfClass:RoomBubbleCellData.class])
|
|
{
|
|
roomBubbleCellData = (RoomBubbleCellData*)cellData;
|
|
}
|
|
|
|
return roomBubbleCellData;
|
|
}
|
|
|
|
- (id<MXKeyVerificationRequest>)keyVerificationRequestFromEventId:(NSString*)eventId
|
|
{
|
|
RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:eventId];
|
|
|
|
return roomBubbleCellData.keyVerification.request;
|
|
}
|
|
|
|
- (void)refreshCellsWithDelay
|
|
{
|
|
if (self.refreshCellsTimer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.refreshCellsTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(refreshCellsTimerFired) userInfo:nil repeats:NO];
|
|
}
|
|
|
|
- (void)refreshCellsTimerFired
|
|
{
|
|
[self refreshCells];
|
|
self.refreshCellsTimer = nil;
|
|
}
|
|
|
|
- (void)refreshCells
|
|
{
|
|
if (self.delegate)
|
|
{
|
|
[self.delegate dataSource:self didCellChange:nil];
|
|
}
|
|
}
|
|
|
|
- (void)registerKeyVerificationRequestNotification
|
|
{
|
|
self.keyVerificationRequestDidChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:MXKeyVerificationRequestDidChangeNotification
|
|
object:nil
|
|
queue:[NSOperationQueue mainQueue]
|
|
usingBlock:^(NSNotification *notification)
|
|
{
|
|
id notificationObject = notification.object;
|
|
|
|
if ([notificationObject isKindOfClass:MXKeyVerificationByDMRequest.class])
|
|
{
|
|
MXKeyVerificationByDMRequest *keyVerificationByDMRequest = (MXKeyVerificationByDMRequest*)notificationObject;
|
|
|
|
if ([keyVerificationByDMRequest.roomId isEqualToString:self.roomId])
|
|
{
|
|
RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:keyVerificationByDMRequest.eventId];
|
|
|
|
roomBubbleCellData.isKeyVerificationOperationPending = NO;
|
|
roomBubbleCellData.keyVerification = nil;
|
|
|
|
if (roomBubbleCellData)
|
|
{
|
|
[self refreshCellsWithDelay];
|
|
}
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)registerKeyVerificationTransactionNotification
|
|
{
|
|
self.keyVerificationTransactionDidChangeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:MXKeyVerificationTransactionDidChangeNotification
|
|
object:nil
|
|
queue:[NSOperationQueue mainQueue]
|
|
usingBlock:^(NSNotification *notification)
|
|
{
|
|
id<MXKeyVerificationTransaction> keyVerificationTransaction = (id<MXKeyVerificationTransaction>)notification.object;
|
|
|
|
if ([keyVerificationTransaction.dmRoomId isEqualToString:self.roomId])
|
|
{
|
|
RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:keyVerificationTransaction.dmEventId];
|
|
|
|
roomBubbleCellData.isKeyVerificationOperationPending = NO;
|
|
roomBubbleCellData.keyVerification = nil;
|
|
|
|
if (roomBubbleCellData)
|
|
{
|
|
[self refreshCellsWithDelay];
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)registerBeaconInfoSummaryListner
|
|
{
|
|
MXWeakify(self);
|
|
self.beaconInfoSummaryListener = [self.mxSession.aggregations.beaconAggregations listenToBeaconInfoSummaryUpdateInRoomWithId:self.roomId handler:^(id<MXBeaconInfoSummaryProtocol> beaconInfoSummary) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
[self updateCurrentUserLocationSharingStatus];
|
|
[self refreshFirstCellWithBeaconInfoSummary:beaconInfoSummary];
|
|
}];
|
|
|
|
self.beaconInfoSummaryDeletionListener = [self.mxSession.aggregations.beaconAggregations listenToBeaconInfoSummaryDeletionInRoomWithId:self.roomId handler:^(NSString * _Nonnull beaconInfoEventId) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
[self updateCurrentUserLocationSharingStatus];
|
|
[self refreshFirstCellWithBeaconInfoSummaryIdentifier:beaconInfoEventId updatedBeaconInfoSummary:nil];
|
|
}];
|
|
}
|
|
|
|
- (void)refreshFirstCellWithBeaconInfoSummary:(id<MXBeaconInfoSummaryProtocol>)beaconInfoSummary
|
|
{
|
|
[self refreshFirstCellWithBeaconInfoSummaryIdentifier:beaconInfoSummary.id updatedBeaconInfoSummary:beaconInfoSummary];
|
|
}
|
|
|
|
- (void)refreshFirstCellWithBeaconInfoSummaryIdentifier:(NSString*)beaconInfoEventId updatedBeaconInfoSummary:(nullable id<MXBeaconInfoSummaryProtocol>)beaconInfoSummary
|
|
{
|
|
NSUInteger cellIndex;
|
|
__block RoomBubbleCellData *roomBubbleCellData;
|
|
|
|
@synchronized (bubbles)
|
|
{
|
|
cellIndex = [bubbles indexOfObjectPassingTest:^BOOL(id<MXKRoomBubbleCellDataStoring> _Nonnull cellData, NSUInteger idx, BOOL * _Nonnull stop) {
|
|
if ([cellData isKindOfClass:[RoomBubbleCellData class]])
|
|
{
|
|
roomBubbleCellData = (RoomBubbleCellData*)cellData;
|
|
if ([roomBubbleCellData.beaconInfoSummary.id isEqualToString:beaconInfoEventId])
|
|
{
|
|
*stop = YES;
|
|
return YES;
|
|
}
|
|
}
|
|
return NO;
|
|
}];
|
|
}
|
|
|
|
if (cellIndex != NSNotFound)
|
|
{
|
|
roomBubbleCellData.beaconInfoSummary = beaconInfoSummary;
|
|
[self refreshCells];
|
|
}
|
|
}
|
|
|
|
- (BOOL)shouldFetchKeyVerificationForEvent:(MXEvent*)event
|
|
{
|
|
if (!event)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
BOOL shouldFetchKeyVerification = NO;
|
|
|
|
switch (event.eventType)
|
|
{
|
|
case MXEventTypeKeyVerificationDone:
|
|
case MXEventTypeKeyVerificationCancel:
|
|
shouldFetchKeyVerification = YES;
|
|
break;
|
|
case MXEventTypeRoomMessage:
|
|
{
|
|
NSString *msgType = event.content[kMXMessageTypeKey];
|
|
|
|
if ([msgType isEqualToString:kMXMessageTypeKeyVerificationRequest])
|
|
{
|
|
shouldFetchKeyVerification = YES;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return shouldFetchKeyVerification;
|
|
}
|
|
|
|
- (void)updateKeyVerificationIfNeededForRoomBubbleCellData:(RoomBubbleCellData*)bubbleCellData
|
|
{
|
|
MXEvent *event = bubbleCellData.getFirstBubbleComponentWithDisplay.event;
|
|
|
|
if (![self shouldFetchKeyVerificationForEvent:event])
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (bubbleCellData.keyVerification != nil || bubbleCellData.isKeyVerificationOperationPending)
|
|
{
|
|
// Key verification already fetched or request is pending do nothing
|
|
return;
|
|
}
|
|
|
|
__block MXHTTPOperation *operation = [self.mxSession.crypto.keyVerificationManager keyVerificationFromKeyVerificationEvent:event
|
|
success:^(MXKeyVerification * _Nonnull keyVerification)
|
|
{
|
|
BOOL shouldRefreshCells = bubbleCellData.isKeyVerificationOperationPending || bubbleCellData.keyVerification == nil;
|
|
|
|
bubbleCellData.keyVerification = keyVerification;
|
|
bubbleCellData.isKeyVerificationOperationPending = NO;
|
|
|
|
if (shouldRefreshCells)
|
|
{
|
|
[self refreshCellsWithDelay];
|
|
}
|
|
|
|
} failure:^(NSError * _Nonnull error) {
|
|
|
|
MXLogDebug(@"[RoomDataSource] updateKeyVerificationIfNeededForRoomBubbleCellData; keyVerificationFromKeyVerificationEvent fails with error: %@", error);
|
|
|
|
bubbleCellData.isKeyVerificationOperationPending = NO;
|
|
}];
|
|
|
|
bubbleCellData.isKeyVerificationOperationPending = !operation;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)setSelectedEventId:(NSString *)selectedEventId
|
|
{
|
|
// Cancel the current selection (if any)
|
|
if (_selectedEventId)
|
|
{
|
|
RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:_selectedEventId];
|
|
cellData.selectedEventId = nil;
|
|
cellData.showTimestampForSelectedComponent = NO;
|
|
}
|
|
|
|
if (selectedEventId.length)
|
|
{
|
|
RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:selectedEventId];
|
|
|
|
cellData.showTimestampForSelectedComponent = self.showBubbleDateTimeOnSelection;
|
|
|
|
if (cellData.collapsed
|
|
&& cellData.nextCollapsableCellData
|
|
&& cellData.tag != RoomBubbleCellDataTagCall)
|
|
{
|
|
// Select nothing for a collased cell but open it
|
|
[self collapseRoomBubble:cellData collapsed:NO];
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
cellData.selectedEventId = selectedEventId;
|
|
}
|
|
}
|
|
|
|
_selectedEventId = selectedEventId;
|
|
}
|
|
|
|
- (Widget *)jitsiWidget
|
|
{
|
|
Widget *jitsiWidget;
|
|
|
|
// Note: Manage only one jitsi widget at a time for the moment
|
|
jitsiWidget = [[WidgetManager sharedManager] widgetsOfTypes:@[kWidgetTypeJitsiV1, kWidgetTypeJitsiV2] inRoom:self.room withRoomState:self.roomState].firstObject;
|
|
|
|
return jitsiWidget;
|
|
}
|
|
|
|
- (void)sendVideo:(NSURL *)videoLocalURL
|
|
success:(void (^)(NSString * _Nonnull))success
|
|
failure:(void (^)(NSError * _Nullable))failure
|
|
{
|
|
AVURLAsset *videoAsset = [AVURLAsset assetWithURL:videoLocalURL];
|
|
UIImage *videoThumbnail = [MXKVideoThumbnailGenerator.shared generateThumbnailFrom:videoLocalURL];
|
|
|
|
[self sendVideoAsset:videoAsset withThumbnail:videoThumbnail success:success failure:failure];
|
|
}
|
|
|
|
- (void)acceptVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure
|
|
{
|
|
id<MXKeyVerificationRequest> keyVerificationRequest = [self keyVerificationRequestFromEventId:eventId];
|
|
|
|
if (!keyVerificationRequest)
|
|
{
|
|
NSError *error;
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
return;
|
|
}
|
|
|
|
[[AppDelegate theDelegate] presentIncomingKeyVerificationRequest:keyVerificationRequest inSession:self.mxSession];
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
}
|
|
|
|
- (void)declineVerificationRequestForEventId:(NSString*)eventId success:(void(^)(void))success failure:(void(^)(NSError*))failure
|
|
{
|
|
id<MXKeyVerificationRequest> keyVerificationRequest = [self keyVerificationRequestFromEventId:eventId];
|
|
|
|
if (!keyVerificationRequest)
|
|
{
|
|
NSError *error;
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
return;
|
|
}
|
|
|
|
RoomBubbleCellData *roomBubbleCellData = [self roomBubbleCellDataForEventId:eventId];
|
|
roomBubbleCellData.isKeyVerificationOperationPending = YES;
|
|
|
|
[self refreshCells];
|
|
|
|
[keyVerificationRequest cancelWithCancelCode:MXTransactionCancelCode.user success:^{
|
|
|
|
// roomBubbleCellData.isKeyVerificationOperationPending will be set to NO by MXKeyVerificationRequestDidChangeNotification notification
|
|
|
|
if (success)
|
|
{
|
|
success();
|
|
}
|
|
|
|
} failure:^(NSError * _Nonnull error) {
|
|
|
|
roomBubbleCellData.isKeyVerificationOperationPending = NO;
|
|
|
|
if (failure)
|
|
{
|
|
failure(error);
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)resetTypingNotification {
|
|
self.currentTypingUsers = nil;
|
|
}
|
|
|
|
#pragma - Accessibility
|
|
|
|
- (void)setupAccessibilityForCell:(MXKRoomBubbleTableViewCell *)cell withCellData:(RoomBubbleCellData*)cellData
|
|
{
|
|
// Set accessibility only on media. Let VoiceOver automatically manages text messages
|
|
if (cellData.attachment)
|
|
{
|
|
NSString *accessibilityLabel = [cellData accessibilityLabel];
|
|
if (cell.messageTextView.text.length)
|
|
{
|
|
// Files are presented as text with link
|
|
cell.messageTextView.accessibilityLabel = accessibilityLabel;
|
|
cell.messageTextView.isAccessibilityElement = YES;
|
|
}
|
|
else
|
|
{
|
|
cell.attachmentView.accessibilityLabel = accessibilityLabel;
|
|
cell.attachmentView.isAccessibilityElement = YES;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)resetAccessibilityForCell:(MXKRoomBubbleTableViewCell *)cell
|
|
{
|
|
cell.messageTextView.accessibilityLabel = nil;
|
|
cell.attachmentView.accessibilityLabel = nil;
|
|
}
|
|
|
|
#pragma mark - MXThreadingServiceDelegate
|
|
|
|
- (void)threadingService:(MXThreadingService *)service didCreateNewThread:(MXThread *)thread direction:(MXTimelineDirection)direction
|
|
{
|
|
if (direction == MXTimelineDirectionBackwards)
|
|
{
|
|
// no need to reload when paginating back
|
|
return;
|
|
}
|
|
|
|
BOOL notify = YES;
|
|
if (self.threadId)
|
|
{
|
|
// no need to notify the thread screen, it'll cause a flickering
|
|
notify = NO;
|
|
}
|
|
NSUInteger count = 0;
|
|
@synchronized (bubbles)
|
|
{
|
|
count = bubbles.count;
|
|
}
|
|
if (count > 0)
|
|
{
|
|
[self reloadNotifying:notify];
|
|
}
|
|
}
|
|
|
|
#pragma mark - RoomReactionsViewModelDelegate
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didAddReaction:(MXReactionCount *)reactionCount forEventId:(NSString *)eventId
|
|
{
|
|
[self addReaction:reactionCount.reaction forEventId:eventId success:^{
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
}];
|
|
}
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didRemoveReaction:(MXReactionCount * _Nonnull)reactionCount forEventId:(NSString * _Nonnull)eventId
|
|
{
|
|
[self removeReaction:reactionCount.reaction forEventId:eventId success:^{
|
|
|
|
} failure:^(NSError *error) {
|
|
|
|
}];
|
|
}
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didShowAllTappedForEventId:(NSString * _Nonnull)eventId
|
|
{
|
|
[self setShowAllReactions:YES forEvent:eventId];
|
|
}
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didShowLessTappedForEventId:(NSString * _Nonnull)eventId
|
|
{
|
|
[self setShowAllReactions:NO forEvent:eventId];
|
|
}
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didTapAddReactionForEventId:(NSString * _Nonnull)eventId
|
|
{
|
|
[self.delegate dataSource:self didRecognizeAction:kMXKRoomBubbleCellTapOnAddReaction inCell:nil userInfo:@{ kMXKRoomBubbleCellEventIdKey: eventId }];
|
|
}
|
|
|
|
- (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId
|
|
{
|
|
id<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];
|
|
if ([cellData isKindOfClass:[RoomBubbleCellData class]])
|
|
{
|
|
RoomBubbleCellData *roomBubbleCellData = (RoomBubbleCellData*)cellData;
|
|
|
|
[roomBubbleCellData setShowAllReactions:showAllReactions forEvent:eventId];
|
|
[self updateCellDataReactions:roomBubbleCellData forEventId:eventId];
|
|
|
|
[self.delegate dataSource:self didCellChange:nil];
|
|
}
|
|
}
|
|
|
|
- (void)roomReactionsViewModel:(RoomReactionsViewModel *)viewModel didLongPressForEventId:(NSString *)eventId
|
|
{
|
|
[self.delegate dataSource:self didRecognizeAction:kMXKRoomBubbleCellLongPressOnReactionView inCell:nil userInfo:@{ kMXKRoomBubbleCellEventIdKey: eventId }];
|
|
}
|
|
|
|
- (void)applyMaskToAttachmentViewOfBubbleCell:(MXKRoomBubbleTableViewCell *)cell
|
|
{
|
|
if (cell.attachmentView)
|
|
{
|
|
cell.attachmentView.layer.cornerRadius = 6;
|
|
cell.attachmentView.layer.masksToBounds = YES;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Message status management
|
|
|
|
- (void)updateStatusInfo
|
|
{
|
|
if (!self.failedEventIds)
|
|
{
|
|
self.failedEventIds = [NSMutableSet new];
|
|
}
|
|
|
|
NSInteger bubbleIndex = bubbles.count;
|
|
while (bubbleIndex--)
|
|
{
|
|
RoomBubbleCellData *cellData = bubbles[bubbleIndex];
|
|
|
|
NSInteger componentIndex = cellData.bubbleComponents.count;
|
|
while (componentIndex--) {
|
|
MXKRoomBubbleComponent *component = cellData.bubbleComponents[componentIndex];
|
|
MXEventSentState eventState = component.event.sentState;
|
|
|
|
if (eventState == MXEventSentStateFailed)
|
|
{
|
|
[self.failedEventIds addObject:component.event.eventId];
|
|
continue;
|
|
}
|
|
|
|
NSArray<MXReceiptData*> *receipts = cellData.readReceipts[component.event.eventId];
|
|
if (receipts.count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (eventState == MXEventSentStateSent)
|
|
{
|
|
cellData.componentIndexOfSentMessageTick = componentIndex;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - URLPreviewViewDelegate
|
|
|
|
- (void)didOpenURLFromPreviewView:(URLPreviewView *)previewView for:(NSString *)eventID in:(NSString *)roomID
|
|
{
|
|
// Use the link stored in the bubble component when opening the URL as we only
|
|
// store the sanitized URL in the preview data which may differ to the message content.
|
|
RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventID];
|
|
MXKRoomBubbleComponent *component = [cellData bubbleComponentWithLinkForEventId:eventID];
|
|
if (!component)
|
|
{
|
|
MXLogError(@"[RoomDataSource] Failed to open link: Unable to find bubble component.")
|
|
return;
|
|
}
|
|
|
|
[UIApplication.sharedApplication vc_open:component.link completionHandler:nil];
|
|
}
|
|
|
|
- (void)didCloseURLPreviewView:(URLPreviewView *)previewView for:(NSString *)eventID in:(NSString *)roomID
|
|
{
|
|
// Remember that the user closed the preview so it isn't shown again.
|
|
[URLPreviewService.shared closePreviewFor:eventID in:roomID];
|
|
|
|
// Get the component to remove the URL preview from.
|
|
RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventID];
|
|
MXKRoomBubbleComponent *component = [cellData bubbleComponentWithLinkForEventId:eventID];
|
|
if (!component)
|
|
{
|
|
MXLogError(@"[RoomDataSource] Failed to close URL preview: Unable to find bubble component.")
|
|
return;
|
|
}
|
|
|
|
// Hide the preview, remove its data and refresh the cells.
|
|
component.showURLPreview = NO;
|
|
component.urlPreviewData = nil;
|
|
|
|
[cellData invalidateLayout];
|
|
|
|
[self refreshCells];
|
|
}
|
|
|
|
#pragma mark - ThreadSummaryViewDelegate
|
|
|
|
- (void)threadSummaryViewTapped:(ThreadSummaryView *)summaryView
|
|
{
|
|
[self.roomDataSourceDelegate roomDataSource:self
|
|
didTapThread:summaryView.thread];
|
|
}
|
|
|
|
#pragma mark - Location sharing
|
|
|
|
- (void)updateCurrentUserLocationSharingStatus
|
|
{
|
|
MXLocationService *locationService = self.mxSession.locationService;
|
|
|
|
NSString *roomId = self.roomId;
|
|
|
|
if (!locationService || !roomId)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BOOL isUserSharingActiveLocation = [locationService isCurrentUserSharingActiveLocationInRoomWithId:roomId];
|
|
|
|
if (isUserSharingActiveLocation != self.isCurrentUserSharingActiveLocation)
|
|
{
|
|
self.isCurrentUserSharingActiveLocation = isUserSharingActiveLocation;
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[self.roomDataSourceDelegate roomDataSourceDidUpdateCurrentUserSharingLocationStatus:self];
|
|
});
|
|
}
|
|
}
|
|
|
|
@end
|