diff --git a/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift b/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift index b5cf5c1..88cfffa 100644 --- a/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift +++ b/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift @@ -7,7 +7,6 @@ import UIKit final class SharingMiddleware { static let shared = SharingMiddleware() - // swiftlint:disable:next function_body_length func middleware(state _: AppState, action: AppAction) -> AnyPublisher { switch action { case .sharingAction(.checkCameraAccess): @@ -54,104 +53,200 @@ final class SharingMiddleware { case .sharingAction(.fetchGallery): return Future { promise in - DispatchQueue.global(qos: .background).async { - let fetchOptions = PHFetchOptions() - fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] - let assets = PHAsset.fetchAssets(with: fetchOptions) - - let manager = PHImageManager.default() - let option = PHImageRequestOptions() - option.isSynchronous = true - - var items: [SharingGalleryItem] = [] - let group = DispatchGroup() - assets.enumerateObjects { asset, _, _ in - if asset.mediaType == .image { - group.enter() - manager.requestImage( - for: asset, - targetSize: PHImageManagerMaximumSize, - contentMode: .aspectFill, - options: option - ) { image, _ in - if image != nil { - items.append(.init(id: asset.localIdentifier, type: .photo)) - group.leave() - } - } - } else if asset.mediaType == .video { - group.enter() - manager.requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in - if avAsset != nil { - items.append(.init(id: asset.localIdentifier, type: .video, duration: asset.duration.minAndSec)) - group.leave() - } - } - } - } - group.notify(queue: .main) { - promise(.success(.sharingAction(.galleryFetched(items)))) + let fetchOptions = PHFetchOptions() + fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] + let assets = PHAsset.fetchAssets(with: fetchOptions) + var items: [SharingGalleryItem] = [] + assets.enumerateObjects { asset, _, _ in + if asset.mediaType == .image { + items.append(.init(id: asset.localIdentifier, type: .photo)) + } else if asset.mediaType == .video { + items.append(.init(id: asset.localIdentifier, type: .video)) } } + promise(.success(.sharingAction(.galleryFetched(items)))) } .eraseToAnyPublisher() case .sharingAction(.galleryFetched(let items)): - return Future { promise in - DispatchQueue.global(qos: .background).async { - let ids = items - .filter { $0.thumbnail == nil } - .map { $0.id } - let assets = PHAsset.fetchAssets(withLocalIdentifiers: ids, options: nil) - assets.enumerateObjects { asset, _, _ in - let manager = PHImageManager.default() - if asset.mediaType == .image { - manager.requestImage( - for: asset, - targetSize: PHImageManagerMaximumSize, - contentMode: .aspectFill, - options: nil - ) { image, _ in - image?.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) { image in - if let image { - let data = image.jpegData(compressionQuality: 1.0) ?? Data() - DispatchQueue.main.async { - store.dispatch(.sharingAction(.thumbnailUpdated(data, asset.localIdentifier))) - } - } - } - } - } else if asset.mediaType == .video { - manager.requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in - if let avAsset { - let imageGenerator = AVAssetImageGenerator(asset: avAsset) - imageGenerator.appliesPreferredTrackTransform = true - let time = CMTimeMake(value: 1, timescale: 2) - do { - let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil) - let thumbnail = UIImage(cgImage: imageRef) - thumbnail.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize), completion: { image in - if let image { - let data = image.jpegData(compressionQuality: 1.0) ?? Data() - DispatchQueue.main.async { - store.dispatch(.sharingAction(.thumbnailUpdated(data, asset.localIdentifier))) - } - } - }) - } catch { - print("Failed to create thumbnail image") - } - } - } - } - } - } - promise(.success(.empty)) + DispatchQueue.global(qos: .background).async { + // for item in items { + // switch item.type { + // case .photo: + // self.makePhotoThumbnail(assetId: PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject!) { data in + // if let data { + // DispatchQueue.main.async { + // store.dispatch(.sharingAction(.thumbnailUpdated(data, item.id))) + // } + // } + // } + // + // case .video: + // self.fetchVideo(asset: PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject!) { newItem in + // if let newItem { + // newItems.append(newItem) + // } + // } + // } + // } } - .eraseToAnyPublisher() + return Empty().eraseToAnyPublisher() default: return Empty().eraseToAnyPublisher() } } } + +private extension SharingMiddleware { + func makePhotoThumbnail(asset: PHAsset, completion: @escaping (Data?) -> Void) { + PHImageManager.default().requestImage( + for: asset, + targetSize: PHImageManagerMaximumSize, + contentMode: .aspectFill, + options: nil + ) { _, _ in + // guard let image = image?.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) else { + // completion(nil) + // return + // } + // let data = image.jpegData(compressionQuality: 1.0) ?? Data() + // completion(.init(id: asset.localIdentifier, type: .photo, thumbnail: data)) + completion(.init(id: asset.localIdentifier, type: .photo, thumbnail: Data())) + } + } + + func fetchVideo(asset: PHAsset, completion: @escaping (SharingGalleryItem?) -> Void) { + PHImageManager.default().requestAVAsset(forVideo: asset, options: nil) { _, _, _ in + // if let avAsset { + // let imageGenerator = AVAssetImageGenerator(asset: avAsset) + // imageGenerator.appliesPreferredTrackTransform = true + // let time = CMTimeMake(value: 1, timescale: 2) + // do { + // let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil) + // let thumbnail = UIImage(cgImage: imageRef) + // guard let image = thumbnail.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) else { + // completion(nil) + // return + // } + // let data = image.jpegData(compressionQuality: 1.0) ?? Data() + // completion(.init(id: asset.localIdentifier, type: .video, thumbnail: data, duration: asset.duration.minAndSec)) + // } catch { + // print("Failed to create thumbnail image") + // completion(nil) + // } + // } else { + // completion(nil) + // } + completion(.init(id: asset.localIdentifier, type: .photo, thumbnail: Data())) + } + } +} + +// case .sharingAction(.fetchGallery): +// return Future { promise in +// DispatchQueue.global(qos: .background).async { +// let fetchOptions = PHFetchOptions() +// fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] +// let assets = PHAsset.fetchAssets(with: fetchOptions) +// +// let manager = PHImageManager.default() +// let option = PHImageRequestOptions() +// option.isSynchronous = true +// +// var items: [SharingGalleryItem] = [] +// let group = DispatchGroup() +// assets.enumerateObjects { asset, _, _ in +// if asset.mediaType == .image { +// group.enter() +// manager.requestImage( +// for: asset, +// targetSize: PHImageManagerMaximumSize, +// contentMode: .aspectFill, +// options: option +// ) { image, _ in +// if image != nil { +// items.append(.init(id: asset.localIdentifier, type: .photo)) +// group.leave() +// } +// } +// } else if asset.mediaType == .video { +// group.enter() +// manager.requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in +// if avAsset != nil { +// items.append(.init(id: asset.localIdentifier, type: .video, duration: asset.duration.minAndSec)) +// group.leave() +// } +// } +// } +// } +// group.notify(queue: .main) { +// promise(.success(.sharingAction(.galleryFetched(items)))) +// } +// } +// } +// .eraseToAnyPublisher() +// +// case .sharingAction(.galleryFetched(let items)): +// return Future { promise in +// DispatchQueue.global(qos: .background).async { +// let ids = items +// .filter { $0.thumbnail == nil } +// .map { $0.id } +// let assets = PHAsset.fetchAssets(withLocalIdentifiers: ids, options: nil) +// +// var newItems: [SharingGalleryItem] = [] +// let group = DispatchGroup() +// +// assets.enumerateObjects { asset, _, _ in +// let manager = PHImageManager.default() +// group.enter() +// if asset.mediaType == .image { +// manager.requestImage( +// for: asset, +// targetSize: PHImageManagerMaximumSize, +// contentMode: .aspectFill, +// options: nil +// ) { image, _ in +// image?.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize)) { image in +// if let image { +// let data = image.jpegData(compressionQuality: 1.0) ?? Data() +// newItems.append(.init(id: asset.localIdentifier, type: .photo, thumbnail: data)) +// } +// group.leave() +// } +// } +// } else if asset.mediaType == .video { +// manager.requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in +// if let avAsset { +// let imageGenerator = AVAssetImageGenerator(asset: avAsset) +// imageGenerator.appliesPreferredTrackTransform = true +// let time = CMTimeMake(value: 1, timescale: 2) +// do { +// let imageRef = try imageGenerator.copyCGImage(at: time, actualTime: nil) +// let thumbnail = UIImage(cgImage: imageRef) +// thumbnail.scaleAndCropImage(toExampleSize: CGSize(width: Const.galleryGridSize, height: Const.galleryGridSize), completion: { image in +// if let image { +// let data = image.jpegData(compressionQuality: 1.0) ?? Data() +// newItems.append(.init(id: asset.localIdentifier, type: .video, thumbnail: data, duration: asset.duration.minAndSec)) +// } +// group.leave() +// }) +// } catch { +// print("Failed to create thumbnail image") +// group.leave() +// } +// } else { +// group.leave() +// } +// } +// } else { +// group.leave() +// } +// } +// group.notify(queue: .main) { +// promise(.success(.sharingAction(.thumbnailUpdated(newItems)))) +// } +// } +// } +// .eraseToAnyPublisher() diff --git a/ConversationsClassic/View/UIToolkit/UIImage+Crop.swift b/ConversationsClassic/View/UIToolkit/UIImage+Crop.swift index 4fd8ba1..1bccefd 100644 --- a/ConversationsClassic/View/UIToolkit/UIImage+Crop.swift +++ b/ConversationsClassic/View/UIToolkit/UIImage+Crop.swift @@ -36,9 +36,7 @@ extension UIImage { } let image: UIImage = .init(cgImage: imgRef, scale: self.scale, orientation: self.imageOrientation) - DispatchQueue.main.async { - completion(image) - } + completion(image) } } }