// // TSPhotoPickerManager.swift // AIEmoji // // Created by 100Years on 2025/2/25. // import UIKit import PhotosUI class TSPhotoPickerManager: NSObject { // MARK: - Properties private weak var viewController: UIViewController? private var completionHandler: ((UIImage?,PHAsset?) -> Void)? private var completionSizeHandler: ((UIImage?,String?) -> Void)? private var imagePicker = UIImagePickerController() // MARK: - Initializers init(viewController: UIViewController) { self.viewController = viewController } // MARK: - Public Methods /// 打开照片选择器,单选一张照片 func pickSinglePhoto(completion: @escaping (UIImage?,PHAsset?) -> Void) { self.completionHandler = completion // 检查相册权限 checkPhotoLibraryPermission { [weak self] authorized in guard let self = self else { return } if authorized { self.openPhotoPicker() } else { self.showPermissionAlert() } } } // MARK: - Private Methods /// 检查相册权限 private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) { let status = PHPhotoLibrary.authorizationStatus() switch status { case .authorized: completion(true) case .notDetermined: PHPhotoLibrary.requestAuthorization { newStatus in DispatchQueue.main.async { completion(newStatus == .authorized) } } default: completion(false) } } /// 打开照片选择器 private func openPhotoPicker() { TSToastShared.showLoading(containerView: viewController?.view) imagePicker = UIImagePickerController() imagePicker.sourceType = .photoLibrary imagePicker.delegate = self imagePicker.mediaTypes = ["public.image"] // 只选择照片 // imagePicker.modalPresentationStyle = .custom // imagePicker.modalTransitionStyle = .crossDissolve if #available(iOS 13.0, *) { imagePicker.overrideUserInterfaceStyle = .dark } viewController?.present(imagePicker, animated: true){ TSToastShared.hideLoading() } } /// 显示权限提示 private func showPermissionAlert() { let alert = UIAlertController( title: "No photos permission".localized, message: "Please enable photo permission in settings to select photos".localized, preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil)) alert.addAction(UIAlertAction(title: "Go to Settings".localized, style: .default) { _ in if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } }) viewController?.present(alert, animated: true, completion: nil) } deinit { debugPrint("♻️♻️♻️ TSPhotoPickerManager -> TSPhotoPickerManager deinit ♻️♻️♻️") } } // MARK: - UIImagePickerControllerDelegate & UINavigationControllerDelegate (iOS 14 以下) extension TSPhotoPickerManager: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { // picker.dismiss(animated: true) { if let image = info[.originalImage] as? UIImage { self.completionHandler?(image,info[.phAsset] as? PHAsset ) } else { self.completionHandler?(nil,nil) } // } if completionSizeHandler == nil { picker.dismiss(animated: true, completion: nil) } } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { // self.completionHandler?(nil,nil) // if completionSizeHandler == nil { picker.dismiss(animated: true, completion: nil) // } } } extension TSPhotoPickerManager{ func pickCustomSinglePhoto(completion: @escaping (UIImage?,String?) -> Void) { self.completionSizeHandler = completion pickSinglePhoto { [weak self] image,phAsset in guard let self = self else { return } self.completionSizeHandler?(image,nil) self.completionSizeHandler = nil } } // MARK: - Public Methods /// 打开照片选择器,单选一张照片 func pickSinglePhoto(maxBitSize:Int, completion: @escaping (UIImage?,String?) -> Void) { self.completionSizeHandler = completion let maxmbSize = Int(Double(maxBitSize) / (1024 * 1024)) pickSinglePhoto { [weak self] image,phAsset in guard let self = self else { return } if let image = image,let phAsset = phAsset { // 方法2:异步获取详细大小(不阻塞主线程) TSPhotoSizeHelper.getImageFileSizeAsync(asset: phAsset) {[weak self] size in guard let self = self else { return } let mbSize = Double(size) / (1024 * 1024) print("精确大小: \(mbSize) MB,size = \(size)") if size > maxBitSize { self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize)) }else{ self.completionSizeHandler?(image,nil) self.completionSizeHandler = nil // imagePicker.dismiss(animated: true) } } }else{ if let image = image { if image.isLargerThan(byteSize: maxBitSize) { self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize)) }else{ self.completionSizeHandler?(image,nil) self.completionSizeHandler = nil // imagePicker.dismiss(animated: true) } }else{ self.completionSizeHandler?(nil,nil) // imagePicker.dismiss(animated: true) } } } } func dismissPageVC(){ self.imagePicker.view.isHidden = true self.imagePicker.dismiss(animated: true) } }