TSPhotoPickerManager.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. //
  2. // TSPhotoPickerManager.swift
  3. // AIEmoji
  4. //
  5. // Created by 100Years on 2025/2/25.
  6. //
  7. import UIKit
  8. import PhotosUI
  9. import HXPhotoPicker
  10. class TSPhotoPickerManager: NSObject {
  11. lazy var config: PickerConfiguration = {
  12. var config = PickerConfiguration()
  13. config.modalPresentationStyle = .automatic
  14. config.selectOptions = .photo
  15. config.selectMode = .single
  16. config.isSelectedOriginal = true
  17. config.photoList.sort = .desc
  18. config.photoSelectionTapAction = .quickSelect
  19. config.photoList.finishSelectionAfterTakingPhoto = true
  20. config.photoList.isSaveSystemAlbum = false
  21. config.photoList.takePictureCompletionToSelected = true
  22. var cameraConfig = SystemCameraConfiguration()
  23. cameraConfig.allowsEditing = false
  24. config.photoList.cameraType = .system(cameraConfig)
  25. return config
  26. }()
  27. var picker: PhotoPickerController?
  28. lazy var multipleConfig: PickerConfiguration = {
  29. var config = PickerConfiguration()
  30. config.modalPresentationStyle = .automatic
  31. config.selectOptions = .photo
  32. config.selectMode = .multiple
  33. config.maximumSelectedCount = 2
  34. config.isSelectedOriginal = true
  35. config.photoList.sort = .desc
  36. config.photoSelectionTapAction = .preview
  37. config.photoList.finishSelectionAfterTakingPhoto = false
  38. config.photoList.isSaveSystemAlbum = false
  39. config.photoList.takePictureCompletionToSelected = true
  40. var cameraConfig = SystemCameraConfiguration()
  41. cameraConfig.allowsEditing = false
  42. config.photoList.cameraType = .system(cameraConfig)
  43. return config
  44. }()
  45. // MARK: - Properties
  46. private weak var viewController: UIViewController?
  47. private var completionHandler: (([UIImage]) -> Void)?
  48. private var maxSelected:Int = 1
  49. // MARK: - Initializers
  50. init(viewController: UIViewController) {
  51. self.viewController = viewController
  52. }
  53. // MARK: - Public Methods
  54. /// 打开照片选择器,单选一张照片
  55. func pickPhoto(maxSelected:Int = 1,completion: @escaping ([UIImage]) -> Void) {
  56. self.completionHandler = completion
  57. self.maxSelected = maxSelected
  58. // 检查相册权限
  59. checkPhotoLibraryPermission { [weak self] authorized in
  60. guard let self = self else { return }
  61. if authorized {
  62. self.openPhotoPicker()
  63. } else {
  64. self.showPermissionAlert()
  65. }
  66. }
  67. }
  68. // MARK: - Private Methods
  69. /// 检查相册权限
  70. private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
  71. let status = PHPhotoLibrary.authorizationStatus()
  72. switch status {
  73. case .authorized:
  74. completion(true)
  75. case .notDetermined:
  76. PHPhotoLibrary.requestAuthorization { newStatus in
  77. DispatchQueue.main.async {
  78. completion(newStatus == .authorized)
  79. }
  80. }
  81. default:
  82. completion(false)
  83. }
  84. }
  85. /// 打开照片选择器
  86. private func openPhotoPicker() {
  87. var config = config
  88. if maxSelected > 1 {
  89. config = multipleConfig
  90. config.maximumSelectedCount = maxSelected
  91. }
  92. let picker = PhotoPickerController(splitPicker: config)
  93. picker.pickerDelegate = self
  94. picker.autoDismiss = false
  95. viewController?.present(picker, animated: true, completion: nil)
  96. self.picker = picker
  97. }
  98. /// 显示权限提示
  99. private func showPermissionAlert() {
  100. let alert = UIAlertController(
  101. title: "No photos permission".localized,
  102. message: "Please enable photo permission in settings to select photos".localized,
  103. preferredStyle: .alert
  104. )
  105. alert.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
  106. alert.addAction(UIAlertAction(title: "Go to Settings".localized, style: .default) { _ in
  107. if let url = URL(string: UIApplication.openSettingsURLString) {
  108. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  109. }
  110. })
  111. viewController?.present(alert, animated: true, completion: nil)
  112. }
  113. deinit {
  114. debugPrint("♻️♻️♻️ TSPhotoPickerManager -> TSPhotoPickerManager deinit ♻️♻️♻️")
  115. }
  116. func dismissPageVC(){
  117. self.picker?.view.isHidden = true
  118. self.picker?.dismiss(animated: false)
  119. self.picker = nil
  120. }
  121. }
  122. extension TSPhotoPickerManager: PhotoPickerControllerDelegate {
  123. func pickerController(_ pickerController: PhotoPickerController, didFinishSelection result: PickerResult) {
  124. result.getImage(compressionScale: 1.0) { images in
  125. self.completionHandler?(images)
  126. }
  127. }
  128. func pickerController(didCancel pickerController: PhotoPickerController) {
  129. pickerController.dismiss(animated: true, completion: nil)
  130. }
  131. }
  132. //class TSPhotoPickerManager: NSObject {
  133. //
  134. // // MARK: - Properties
  135. // private weak var viewController: UIViewController?
  136. // private var completionHandler: ((UIImage?,PHAsset?) -> Void)?
  137. // private var completionSizeHandler: ((UIImage?,String?) -> Void)?
  138. // private var imagePicker = UIImagePickerController()
  139. // // MARK: - Initializers
  140. // init(viewController: UIViewController) {
  141. // self.viewController = viewController
  142. // }
  143. //
  144. // // MARK: - Public Methods
  145. // /// 打开照片选择器,单选一张照片
  146. // func pickSinglePhoto(completion: @escaping (UIImage?,PHAsset?) -> Void) {
  147. // self.completionHandler = completion
  148. // // 检查相册权限
  149. // checkPhotoLibraryPermission { [weak self] authorized in
  150. // guard let self = self else { return }
  151. // if authorized {
  152. // self.openPhotoPicker()
  153. // } else {
  154. // self.showPermissionAlert()
  155. // }
  156. // }
  157. // }
  158. //
  159. // // MARK: - Private Methods
  160. // /// 检查相册权限
  161. // private func checkPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
  162. // let status = PHPhotoLibrary.authorizationStatus()
  163. // switch status {
  164. // case .authorized:
  165. // completion(true)
  166. // case .notDetermined:
  167. // PHPhotoLibrary.requestAuthorization { newStatus in
  168. // DispatchQueue.main.async {
  169. // completion(newStatus == .authorized)
  170. // }
  171. // }
  172. // default:
  173. // completion(false)
  174. // }
  175. // }
  176. //
  177. // /// 打开照片选择器
  178. // private func openPhotoPicker() {
  179. // TSToastShared.showLoading(containerView: viewController?.view)
  180. // imagePicker = UIImagePickerController()
  181. // imagePicker.sourceType = .photoLibrary
  182. // imagePicker.delegate = self
  183. // imagePicker.mediaTypes = ["public.image"] // 只选择照片
  184. //// imagePicker.modalPresentationStyle = .custom
  185. //// imagePicker.modalTransitionStyle = .crossDissolve
  186. // if #available(iOS 13.0, *) {
  187. // imagePicker.overrideUserInterfaceStyle = .dark
  188. // }
  189. // viewController?.present(imagePicker, animated: true){
  190. // TSToastShared.hideLoading()
  191. // }
  192. //
  193. // kMainAfter(3.0) {
  194. // TSToastShared.hideLoading()
  195. // }
  196. // }
  197. //
  198. // /// 显示权限提示
  199. // private func showPermissionAlert() {
  200. // let alert = UIAlertController(
  201. // title: "No photos permission".localized,
  202. // message: "Please enable photo permission in settings to select photos".localized,
  203. // preferredStyle: .alert
  204. // )
  205. // alert.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel, handler: nil))
  206. // alert.addAction(UIAlertAction(title: "Go to Settings".localized, style: .default) { _ in
  207. // if let url = URL(string: UIApplication.openSettingsURLString) {
  208. // UIApplication.shared.open(url, options: [:], completionHandler: nil)
  209. // }
  210. // })
  211. // viewController?.present(alert, animated: true, completion: nil)
  212. // }
  213. //
  214. // deinit {
  215. // debugPrint("♻️♻️♻️ TSPhotoPickerManager -> TSPhotoPickerManager deinit ♻️♻️♻️")
  216. // }
  217. //}
  218. //
  219. //// MARK: - UIImagePickerControllerDelegate & UINavigationControllerDelegate (iOS 14 以下)
  220. //extension TSPhotoPickerManager: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
  221. // func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  222. //// picker.dismiss(animated: true) {
  223. // if let image = info[.originalImage] as? UIImage {
  224. // self.completionHandler?(image,info[.phAsset] as? PHAsset )
  225. // } else {
  226. // self.completionHandler?(nil,nil)
  227. // }
  228. //// }
  229. //
  230. // if completionSizeHandler == nil {
  231. // picker.dismiss(animated: true, completion: nil)
  232. // }
  233. //
  234. // }
  235. //
  236. // func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
  237. //// self.completionHandler?(nil,nil)
  238. //// if completionSizeHandler == nil {
  239. // picker.dismiss(animated: true, completion: nil)
  240. //// }
  241. // }
  242. //}
  243. //
  244. //
  245. //
  246. //extension TSPhotoPickerManager{
  247. //
  248. // func pickCustomSinglePhoto(completion: @escaping (UIImage?,String?) -> Void) {
  249. // self.completionSizeHandler = completion
  250. // pickSinglePhoto { [weak self] image,phAsset in
  251. // guard let self = self else { return }
  252. // self.completionSizeHandler?(image,nil)
  253. // self.completionSizeHandler = nil
  254. // }
  255. // }
  256. //
  257. // // MARK: - Public Methods
  258. // /// 打开照片选择器,单选一张照片
  259. // func pickSinglePhoto(maxBitSize:Int, completion: @escaping (UIImage?,String?) -> Void) {
  260. // self.completionSizeHandler = completion
  261. //
  262. // let maxmbSize = Int(Double(maxBitSize) / (1024 * 1024))
  263. // pickSinglePhoto { [weak self] image,phAsset in
  264. // guard let self = self else { return }
  265. // if let image = image,let phAsset = phAsset {
  266. // // 方法2:异步获取详细大小(不阻塞主线程)
  267. // TSPhotoSizeHelper.getImageFileSizeAsync(asset: phAsset) {[weak self] size in
  268. // guard let self = self else { return }
  269. //
  270. // let mbSize = Double(size) / (1024 * 1024)
  271. // print("精确大小: \(mbSize) MB,size = \(size)")
  272. // if size > maxBitSize {
  273. // self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize))
  274. // }else{
  275. // self.completionSizeHandler?(image,nil)
  276. // self.completionSizeHandler = nil
  277. //// imagePicker.dismiss(animated: true)
  278. // }
  279. // }
  280. // }else{
  281. // if let image = image {
  282. // if image.isLargerThan(byteSize: maxBitSize) {
  283. // self.completionSizeHandler?(nil,String(format: "Photo must be smaller than %dMB.".localized, maxmbSize))
  284. // }else{
  285. // self.completionSizeHandler?(image,nil)
  286. // self.completionSizeHandler = nil
  287. //// imagePicker.dismiss(animated: true)
  288. // }
  289. // }else{
  290. // self.completionSizeHandler?(nil,nil)
  291. //// imagePicker.dismiss(animated: true)
  292. // }
  293. // }
  294. // }
  295. // }
  296. //
  297. // func dismissPageVC(){
  298. // self.imagePicker.view.isHidden = true
  299. // self.imagePicker.dismiss(animated: true)
  300. // }
  301. //}