Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/Threema/SharedUI/Utilities/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 10 kB image not shown  

Quelle  PhotosAccessHelper.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import FileUtility
import Foundation
import MBProgressHUD
import PhotosUI
import ThreemaMacros

let tmpDirectory = "tmpImages/"

final class PhotosAccessHelper: NSObject {
    
    let completion: ([Any], DKImagePickerController?) -> Void
    weak var pickerController: DKImagePickerController?
    weak var parentViewController: UIViewController?
    
    init(completion: @escaping (([Any], DKImagePickerController?) -> Void)) {
        self.completion = completion
        super.init()
    }
    
    func showPicker(viewController: UIViewController, limit: Int) {
        if !PhotosRightsHelper().haveFullAccess() {
            parentViewController = viewController
            let photoLibrary = PHPhotoLibrary.shared()
            var config = PHPickerConfiguration(photoLibrary: photoLibrary)
            config.selectionLimit = limit
            config.preferredAssetRepresentationMode = .current
            config.selection = .ordered
                
            let picker = PHPickerViewController(configuration: config)
            picker.delegate = self
            viewController.present(picker, animated: true)
            
            return
        }
        
        // Show our custom picker if we have full access
        PHPhotoLibrary.requestAuthorization { _ in
            let assetCollectionView = UITableView.appearance(whenContainedInInstancesOf: [DKImagePickerController.self])
            assetCollectionView.backgroundColor = Colors.backgroundGroupedViewController
            
            DispatchQueue.main.async {
                self.pickerController = self.setupDKImagePickerController(limit: limit)
                guard let pickerController = self.pickerController else {
                    return
                }
                viewController.present(pickerController, animated: true, completion: nil)
            }
        }
    }
    
    func setupDKImagePickerController(limit: Int) -> DKImagePickerController {
        let picker = DKImagePickerController()
        picker.assetType = .allAssets
        picker.showsCancelButton = true
        picker.showsEmptyAlbums = false
        picker.allowMultipleTypes = true
        picker.autoDownloadWhenAssetIsInCloud = false
        picker.defaultSelectedAssets = []
        picker.sourceType = .photo
        picker.maxSelectableCount = limit
        picker.UIDelegate = ThreemaImagePickerControllerDefaultUIDelegate()
        picker.allowsLandscape = true
        
        picker.didSelectAsset = didSelectAsset
        picker.didSelectAssets = didSelectAssets
        
        return picker
    }
    
    func didSelectAsset(picker: DKImagePickerController, asset: DKAsset) {
        if asset.isVideo, asset.originalAsset!
            .duration > (MediaConverter.videoMaxDurationInMinutes() + 1) * 60 {
            picker.deselectAsset(asset)
            let errorTitle = #localize("video_too_long_title")
            let errorMessage = String.localizedStringWithFormat(
                #localize("video_too_long_message"),
                MediaConverter.videoMaxDurationInMinutes()
            )
            
            UIAlertTemplate.showOKAlert(owner: picker, title: errorTitle, message: errorMessage)
        }
    }
    
    func didSelectAssets(assets: [DKAsset]) {
        guard let pickerController else {
            return
        }
        completion(assets, pickerController)
    }
    
    static func getTempDir() -> URL {
        let fileUtility = FileUtility.shared!
        let tmpDirURL = fileUtility.appTemporaryUnencryptedDirectory
        
        if fileUtility.fileExists(at: tmpDirURL) == false {
            do {
                try fileUtility.mkDir(
                    at: tmpDirURL,
                    withIntermediateDirectories: true,
                    attributes: nil
                )
            }
            catch {
                DDLogError("Error \(error.localizedDescription)")
            }
        }
        
        return tmpDirURL
    }
    
    static func storeImageToTmpDir(imageData: UIImage) -> URL {
        let tmpDir = getTempDir()
        let fileUtility = FileUtility.shared!
        let fileName = fileUtility.getTemporarySendableFileName(base: "image")
        let fileURL = tmpDir.appendingPathComponent(fileName + ".jpeg")
        let data = MediaConverter.jpegRepresentation(for: imageData)
        
        guard fileUtility.write(contents: data, to: fileURL) else {
            DDLogError("Failed to store image to temporary directory.")
            return fileURL
        }
        
        return fileURL
    }
    
    static func storePDFToTmpDir(pdfData: Data) -> URL {
        let tmpDir = getTempDir()
        let fileUtility = FileUtility.shared!
        let fileName = fileUtility.getTemporarySendableFileName(base: "Scanned-Documents")
        let fileURL = tmpDir.appendingPathComponent(fileName + ".pdf")
        
        guard fileUtility.write(contents: pdfData, to: fileURL) else {
            DDLogError("Failed to store PDF to temporary directory.")
            return fileURL
        }
        
        return fileURL
    }
}

// MARK: - PHPickerViewControllerDelegate

extension PhotosAccessHelper: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        var hud: MBProgressHUD?
        if let view = parentViewController?.view {
            hud = MBProgressHUD(view: view)
            hud?.graceTime = 0.25
            hud?.mode = .indeterminate
            hud?.label.text = #localize("loading_files_takes_time_title")
            DispatchQueue.main.async {
                view.addSubview(hud!)
                hud?.show(animated: true)
                picker.dismiss(animated: true)
            }
        }
        
        DispatchQueue.global(qos: .userInitiated).async {
            var items: [(Int, Any)] = []
            let sema = DispatchSemaphore(value: 0)
            
            for (index, result) in results.enumerated() {
                // Looping live photos have three type identifiers, but in iOS 15.5. only the movie identifier can be
                // loaded.
                if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
                    DispatchQueue.main.async {
                        hud?.detailsLabel.text = #localize("loading_files_takes_time_description")
                    }
                    // Unfortunately the progress object returned here immediately shows 100% progress
                    result.itemProvider
                        .loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { url, error in
                            defer { sema.signal() }
                            let item = self.loadVideo(from: url)
                            items.append((index, item))
                            if let error {
                                DDLogError("Could not load item \(error)")
                            }
                        }
                }
                else if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                    // Unfortunately the progress object returned here immediately shows 100% progress
                    result.itemProvider.loadFileRepresentation(
                        forTypeIdentifier: UTType.image.identifier,
                        completionHandler: { url, error in
                            defer { sema.signal() }
                            let item = self.loadImage(from: url)
                            items.append((index, item))
                            if error != nil {
                                DDLogError("Could not load item \(error!)")
                            }
                        }
                    )
                }
                else if result.itemProvider.hasItemConformingToTypeIdentifier(UTType.rawImage.identifier) {
                    // Unfortunately the progress object returned here immediately shows 100% progress
                    result.itemProvider.loadFileRepresentation(
                        forTypeIdentifier: UTType.rawImage.identifier,
                        completionHandler: { url, error in
                            defer { sema.signal() }
                            let item = self.loadImage(from: url)
                            items.append((index, item))
                            if error != nil {
                                DDLogError("Could not load item \(error!)")
                            }
                        }
                    )
                }
                else {
                    DDLogError(
                        "Tried to load item but item had invalid registeredTypeIdentifiers: \(result.itemProvider.registeredTypeIdentifiers)"
                    )
                }
            }
            for _ in results {
                sema.wait()
            }
            
            let sortedItems = items.sorted {
                $0.0 < $1.0
            }
            
            let onlyItems: [Any] = sortedItems.map { _, item in
                item
            }
            
            DispatchQueue.main.async {
                hud?.hide(animated: true)
                self.completion(onlyItems, nil)
            }
        }
    }
    
    func loadVideo(from url: URL?) -> Any {
        guard let url else {
            return PhotosPickerError.fileNotFound
        }
        
        let tmpDirURL = PhotosAccessHelper.getTempDir()
        let fileUtility = FileUtility.shared!
        let filename = fileUtility.getTemporarySendableFileName(
            base: "video",
            directoryURL: tmpDirURL,
            pathExtension: url.pathExtension
        )
        
        let newURL = tmpDirURL.appendingPathComponent(filename).appendingPathExtension(url.pathExtension)
        
        if !MediaConverter.isVideoDurationValid(at: url) {
            return PhotosPickerError.fileTooLargeForSending
        }
        else {
            do {
                try fileUtility.copy(from: url, to: newURL)
            }
            catch {
                return PhotosPickerError.fileNotFound
            }
            return newURL
        }
    }
    
    func loadImage(from url: URL?) -> Any {
        guard let url else {
            return PhotosPickerError.fileNotFound
        }
        let tmpDirURL = PhotosAccessHelper.getTempDir()
        let fileUtility = FileUtility.shared!
        let filename = FileUtility.shared.getTemporarySendableFileName(
            base: "image",
            directoryURL: tmpDirURL,
            pathExtension: url.pathExtension
        )
        
        let newURL = tmpDirURL.appendingPathComponent(filename).appendingPathExtension(url.pathExtension)
        do {
            try fileUtility.copy(from: url, to: newURL)
        }
        catch {
            DDLogError("Could not load image \(error)")
            return PhotosPickerError.fileNotFound
        }
        return newURL
    }
}

Messung
CHZG
81939288

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.