Files
bundesmessenger-ios/Riot/Modules/MediaPicker/SingleImagePickerPresenter.swift
T
JanNiklas Grabowski b298dedc22 chore: update from foss 1.11.19 (MESSENGER-6656)
Merge commit 'f823ab9aae70e8d15ed7cc079210dd9bbbb6c8e1' into feature/foss_update_1_11_19

* commit 'f823ab9aae70e8d15ed7cc079210dd9bbbb6c8e1':
  finish version++
  version++
  comments
  update submodule
  remove obsolete tests
  removed unused code
  update submodule
  fix
  Libolm removal
  update license macro
  update license
  Prepare for new sprint

# Conflicts:
#	Config/AppVersion.xcconfig
#	IDETemplateMacros.plist
#	LICENSE
#	README.md
#	Riot/Categories/MXSession+Riot.m
#	Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
#	Riot/Managers/KeyValueStorage/Extensions/Keychain.swift
#	Riot/Managers/KeyValueStorage/KeyValueStore.swift
#	Riot/Managers/KeyValueStorage/KeychainStore.swift
#	Riot/Managers/KeyValueStorage/MemoryStore.swift
#	Riot/Managers/PushNotification/PushNotificationService.m
#	Riot/Managers/Settings/RiotSettings.swift
#	Riot/Managers/Settings/Shared/RiotSharedSettings.swift
#	Riot/Modules/Analytics/AnalyticsUIElement.swift
#	Riot/Modules/Application/AppCoordinator.swift
#	Riot/Modules/Application/LegacyAppDelegate.h
#	Riot/Modules/Application/LegacyAppDelegate.m
#	Riot/Modules/Authentication/Legacy/AuthenticationViewController.h
#	Riot/Modules/Authentication/Legacy/AuthenticationViewController.m
#	Riot/Modules/Authentication/Legacy/Views/AuthInputsView.h
#	Riot/Modules/Authentication/Legacy/Views/AuthInputsView.m
#	Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
#	Riot/Modules/Common/Recents/RecentsViewController.m
#	Riot/Modules/Common/WebViewController/WebViewViewController.m
#	Riot/Modules/Contacts/Details/ContactDetailsViewController.m
#	Riot/Modules/Contacts/Views/ContactTableViewCell.m
#	Riot/Modules/Favorites/FavouritesViewController.h
#	Riot/Modules/Favorites/FavouritesViewController.m
#	Riot/Modules/GlobalSearch/UnifiedSearchViewController.m
#	Riot/Modules/People/PeopleViewController.h
#	Riot/Modules/People/PeopleViewController.m
#	Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift
#	Riot/Modules/Room/DataSources/RoomDataSource.m
#	Riot/Modules/Room/Files/RoomFilesViewController.m
#	Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m
#	Riot/Modules/Room/Members/RoomParticipantsViewController.m
#	Riot/Modules/Room/RoomViewController.m
#	Riot/Modules/Room/Settings/RoomSettingsViewController.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/RoomTimelineCellIdentifier.h
#	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/PublicRoomsDirectoryViewModel.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/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewController.swift
#	Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModel.swift
#	Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModelType.swift
#	Riot/Modules/SetPinCode/PinCodePreferences.swift
#	Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
#	Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m
#	Riot/Modules/Settings/Security/SecurityViewController.m
#	Riot/Modules/Settings/SettingsViewController.m
#	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/Utils/EventFormatter.m
#	Riot/Utils/HTMLFormatter.swift
#	Riot/Utils/Tools.m
#	RiotNSE/NotificationService.swift
2024-10-18 15:45:54 +02:00

222 lines
9.1 KiB
Swift

/*
Copyright 2019-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import Foundation
import UIKit
import AVFoundation
import PhotosUI
@objc protocol SingleImagePickerPresenterDelegate: AnyObject {
func singleImagePickerPresenter(_ presenter: SingleImagePickerPresenter, didSelectImageData imageData: Data, withUTI uti: MXKUTI?)
func singleImagePickerPresenterDidCancel(_ presenter: SingleImagePickerPresenter)
func singleImagePickerPresenterDidRemoveImage(_ presenter: SingleImagePickerPresenter)
}
/// SingleImagePickerPresenter enables to present an image picker with single selection
@objcMembers
final class SingleImagePickerPresenter: NSObject {
// MARK: - Constants
private enum Constants {
static let jpegCompressionQuality: CGFloat = 1.0
}
// MARK: - Properties
// MARK: Private
private let session: MXSession
private weak var presentingViewController: UIViewController?
private var cameraPresenter: CameraPresenter?
private var mediaPickerPresenter: MediaPickerCoordinatorBridgePresenter?
// MARK: Public
weak var delegate: SingleImagePickerPresenterDelegate?
var allowsRemoveImage = false
// MARK: - Setup
init(session: MXSession) {
self.session = session
}
// MARK: - Public
func present(from presentingViewController: UIViewController,
sourceView: UIView?,
sourceRect: CGRect,
animated: Bool) {
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: VectorL10n.imagePickerActionCamera, style: .default, handler: { _ in
self.presentCamera(animated: animated)
})
let photoLibraryAction = UIAlertAction(title: VectorL10n.imagePickerActionLibrary, style: .default, handler: { _ in
self.presentPhotoLibray(sourceView: sourceView, sourceRect: sourceRect, animated: animated)
})
let cancelAction = UIAlertAction(title: VectorL10n.cancel, style: .cancel)
alert.addAction(cameraAction)
alert.addAction(photoLibraryAction)
// BWI: remove avatars
if BWIBuildSettings.shared.enableRemoveAvatarImage && allowsRemoveImage {
let removePhotoAction = UIAlertAction(title: BWIL10n.imagePickerActionRemovePhoto, style: .destructive, handler: { _ in
self.removeImage()
})
alert.addAction(removePhotoAction)
}
alert.addAction(cancelAction)
if let popoverPresentationController = alert.popoverPresentationController {
popoverPresentationController.sourceView = sourceView
popoverPresentationController.sourceRect = sourceRect
}
presentingViewController.present(alert, animated: animated, completion: nil)
self.presentingViewController = presentingViewController
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
if let cameraPresenter = self.cameraPresenter {
cameraPresenter.dismiss(animated: animated, completion: completion)
} else if let mediaPickerPresenter = self.mediaPickerPresenter {
mediaPickerPresenter.dismiss(animated: animated, completion: completion)
}
}
// MARK: - Private
private func presentCamera(animated: Bool) {
guard let presentingViewController = self.presentingViewController else {
return
}
let cameraPresenter = CameraPresenter()
cameraPresenter.delegate = self
cameraPresenter.presentCamera(from: presentingViewController, with: [.image], animated: animated)
self.cameraPresenter = cameraPresenter
}
private func presentPhotoLibray(sourceView: UIView?, sourceRect: CGRect, animated: Bool) {
guard let presentingViewController = self.presentingViewController else {
return
}
if BWIBuildSettings.shared.useNewPhotosPickerAPI {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = .images
configuration.preferredAssetRepresentationMode = .compatible
configuration.selection = .default
configuration.selectionLimit = 1
configuration.preselectedAssetIdentifiers = []
let pickerViewController = PHPickerViewController(configuration: configuration)
pickerViewController.delegate = self
presentingViewController.present(pickerViewController, animated: true)
} else {
let mediaPickerPresenter = MediaPickerCoordinatorBridgePresenter(session: self.session, mediaUTIs: [.image], allowsMultipleSelection: false)
mediaPickerPresenter.delegate = self
mediaPickerPresenter.present(from: presentingViewController, sourceView: sourceView, sourceRect: sourceRect, animated: animated)
self.mediaPickerPresenter = mediaPickerPresenter
}
}
private func removeImage() {
self.delegate?.singleImagePickerPresenterDidRemoveImage(self)
}
}
// MARK: - CameraPresenterDelegate
extension SingleImagePickerPresenter: CameraPresenterDelegate {
func cameraPresenter(_ cameraPresenter: CameraPresenter, didSelectImage image: UIImage) {
if let imageData = image.jpegData(compressionQuality: Constants.jpegCompressionQuality) {
self.delegate?.singleImagePickerPresenter(self, didSelectImageData: imageData, withUTI: MXKUTI.jpeg)
}
}
func cameraPresenterDidCancel(_ cameraPresenter: CameraPresenter) {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
func cameraPresenter(_ cameraPresenter: CameraPresenter, didSelectVideoAt url: URL) {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
}
// MARK: - MediaPickerCoordinatorBridgePresenterDelegate
extension SingleImagePickerPresenter: MediaPickerCoordinatorBridgePresenterDelegate {
func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectImageData imageData: Data, withUTI uti: MXKUTI?) {
self.delegate?.singleImagePickerPresenter(self, didSelectImageData: imageData, withUTI: uti)
}
func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectVideo videoAsset: AVAsset) {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
func mediaPickerCoordinatorBridgePresenter(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter, didSelectAssets assets: [PHAsset]) {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
func mediaPickerCoordinatorBridgePresenterDidCancel(_ coordinatorBridgePresenter: MediaPickerCoordinatorBridgePresenter) {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
}
// MARK: - PHPickerViewControllerDelegate (BWI)
extension SingleImagePickerPresenter: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
guard let itemProvider = results.first?.itemProvider else {
self.delegate?.singleImagePickerPresenterDidCancel(self)
return
}
// bwi: #5872 workaround for known issue (63426347) selection of images on iOS 15 (simulator)
let heicId = "public.heic"
if itemProvider.registeredTypeIdentifiers.contains(heicId) {
itemProvider.loadDataRepresentation(forTypeIdentifier: heicId) { imageData, error in
DispatchQueue.main.async {
if let imageData = imageData, let image = UIImage(data: imageData), let imageData = image.pngData() {
let uti = MXKUTI(mimeType: "image/png")
self.delegate?.singleImagePickerPresenter(self, didSelectImageData: imageData, withUTI: uti)
} else {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
}
}
} else {
if itemProvider.canLoadObject(ofClass: UIImage.self) {
itemProvider.loadObject(ofClass: UIImage.self) { image, error in
DispatchQueue.main.async {
if let image = image as? UIImage, let imageData = image.pngData() {
let uti = MXKUTI(mimeType: "image/png")
self.delegate?.singleImagePickerPresenter(self, didSelectImageData: imageData, withUTI: uti)
} else {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
}
}
} else {
self.delegate?.singleImagePickerPresenterDidCancel(self)
}
}
}
}