element-ios/Riot/Modules/Camera/CameraPresenter.swift

132 lines
4.6 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
@objc protocol CameraPresenterDelegate: AnyObject {
func cameraPresenter(_ presenter: CameraPresenter, didSelectImage image: UIImage)
func cameraPresenter(_ presenter: CameraPresenter, didSelectVideoAt url: URL)
func cameraPresenterDidCancel(_ cameraPresenter: CameraPresenter)
}
/// CameraPresenter enables to present native camera
@objc final class CameraPresenter: NSObject {
// MARK: - Properties
// MARK: Private
private let cameraAccessManager: CameraAccessManager
private let cameraAccessAlertPresenter: CameraAccessAlertPresenter
private weak var presentingViewController: UIViewController?
private weak var cameraViewController: UIViewController?
private var mediaUTIs: [MXKUTI] = []
// MARK: Public
@objc weak var delegate: CameraPresenterDelegate?
// MARK: - Setup
override init() {
self.cameraAccessManager = CameraAccessManager()
self.cameraAccessAlertPresenter = CameraAccessAlertPresenter()
super.init()
}
// MARK: - Public
@objc func presentCamera(from presentingViewController: UIViewController, with mediaUTIs: [MXKUTI], animated: Bool) {
self.presentingViewController = presentingViewController
self.mediaUTIs = mediaUTIs
self.checkCameraPermissionAndPresentCamera(animated: animated)
}
@objc func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let cameraViewController = self.cameraViewController else {
return
}
cameraViewController.dismiss(animated: animated, completion: completion)
}
// MARK: - Private
private func checkCameraPermissionAndPresentCamera(animated: Bool) {
guard let presentingViewController = self.presentingViewController else {
return
}
guard self.cameraAccessManager.isCameraAvailable else {
self.cameraAccessAlertPresenter.presentCameraUnavailableAlert(from: presentingViewController, animated: animated)
return
}
self.cameraAccessManager.askAndRequestCameraAccessIfNeeded { (granted) in
if granted {
self.presentCameraController(animated: animated)
} else {
self.cameraAccessAlertPresenter.presentPermissionDeniedAlert(from: presentingViewController, animated: animated)
}
}
}
private func presentCameraController(animated: Bool) {
guard let presentingViewController = self.presentingViewController else {
return
}
guard let cameraViewController = self.buildCameraViewController() else {
return
}
presentingViewController.present(cameraViewController, animated: true, completion: nil)
self.cameraViewController = cameraViewController
}
private func buildCameraViewController() -> UIViewController? {
guard UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) else {
return nil
}
let mediaTypes = self.mediaUTIs.map { (uti) -> String in
return uti.rawValue
}
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = UIImagePickerController.SourceType.camera
imagePickerController.mediaTypes = mediaTypes
imagePickerController.videoQuality = .typeHigh
imagePickerController.allowsEditing = false
return imagePickerController
}
}
// MARK: - UIImagePickerControllerDelegate
extension CameraPresenter: UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let videoURL = info[.mediaURL] as? URL {
self.delegate?.cameraPresenter(self, didSelectVideoAt: videoURL)
} else if let image = (info[.editedImage] ?? info[.originalImage]) as? UIImage {
self.delegate?.cameraPresenter(self, didSelectImage: image)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.delegate?.cameraPresenterDidCancel(self)
}
}
// MARK: - UINavigationControllerDelegate
extension CameraPresenter: UINavigationControllerDelegate {
}