import Combine import Foundation import UIKit final class FileMiddleware { static let shared = FileMiddleware() private var downloader = DownloadManager() func middleware(state _: AppState, action: AppAction) -> AnyPublisher { switch action { case .conversationAction(.attachmentsUpdated(let attachments)): DispatchQueue.global(qos: .background).async { for attachment in attachments where attachment.localPath == nil { if let remotePath = attachment.remotePath { let localUrl = self.fileFolder.appendingPathComponent(attachment.id) self.downloader.download(from: remotePath, to: localUrl) { error in if error == nil { DispatchQueue.main.async { store.dispatch(.fileAction(.attachmentFileDownloaded(id: attachment.id, localUrl: localUrl))) } } } } } } return Empty().eraseToAnyPublisher() case .fileAction(.attachmentFileDownloaded(let id, let localUrl)): DispatchQueue.global(qos: .background).async { guard let attachment = store.state.conversationsState.currentAttachments.first(where: { $0.id == id }) else { return } switch attachment.type { case .image: if let data = try? Data(contentsOf: localUrl), let image = UIImage(data: data) { image.scaleAndCropImage(toExampleSize: CGSizeMake(Const.attachmentPreviewSize, Const.attachmentPreviewSize)) { img in if let img = img, let data = img.jpegData(compressionQuality: 1.0) { let thumbnailUrl = self.fileFolder.appendingPathComponent("\(id)_thumbnail.jpg") do { try data.write(to: thumbnailUrl) DispatchQueue.main.async { store.dispatch(.fileAction(.attachmentThumbnailCreated(id: id, thumbnailUrl: thumbnailUrl))) } } catch { print("Error writing thumbnail: \(error)") } } } } case .movie: // self.downloadAndMakeThumbnail(for: attachment) break default: break } } return Empty().eraseToAnyPublisher() default: return Empty().eraseToAnyPublisher() } } } private extension FileMiddleware { var fileFolder: URL { // swiftlint:disable:next force_unwrapping let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! return documentsURL.appendingPathComponent(Const.fileFolder) } } private final class DownloadManager { private let urlSession: URLSession init() { let configuration = URLSessionConfiguration.default urlSession = URLSession(configuration: configuration) } func download(from url: URL, to localUrl: URL, completion: @escaping (Error?) -> Void) { let task = urlSession.downloadTask(with: url) { tempLocalUrl, _, error in if let tempLocalUrl = tempLocalUrl, error == nil { do { try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl) completion(nil) } catch let writeError { completion(writeError) } } else { completion(error) } } task.resume() } }