import AVFoundation import Combine import Foundation import Photos import UIKit final class SharingMiddleware { static let shared = SharingMiddleware() func middleware(state: AppState, action: AppAction) -> AnyPublisher { switch action { // MARK: - Camera and Gallery Access case .sharingAction(.checkCameraAccess): return Deferred { Future { promise in let status = AVCaptureDevice.authorizationStatus(for: .video) switch status { case .authorized: promise(.success(.sharingAction(.setCameraAccess(true)))) case .notDetermined: AVCaptureDevice.requestAccess(for: .video) { granted in promise(.success(.sharingAction(.setCameraAccess(granted)))) } case .denied, .restricted: promise(.success(.sharingAction(.setCameraAccess(false)))) @unknown default: promise(.success(.sharingAction(.setCameraAccess(false)))) } } } .eraseToAnyPublisher() case .sharingAction(.checkGalleryAccess): return Deferred { Future { promise in let status = PHPhotoLibrary.authorizationStatus() switch status { case .authorized, .limited: promise(.success(.sharingAction(.setGalleryAccess(true)))) case .notDetermined: PHPhotoLibrary.requestAuthorization { status in promise(.success(.sharingAction(.setGalleryAccess(status == .authorized)))) } case .denied, .restricted: promise(.success(.sharingAction(.setGalleryAccess(false)))) @unknown default: promise(.success(.sharingAction(.setGalleryAccess(false)))) } } } .eraseToAnyPublisher() case .fileAction(.itemsFromGalleryFetched(let items)): return Just(.sharingAction(.galleryItemsUpdated(items: items))) .eraseToAnyPublisher() // MARK: - Sharing case .sharingAction(.shareMedia(let ids)): return Deferred { Future { promise in let items = state.sharingState.galleryItems.filter { ids.contains($0.id) } promise(.success(.fileAction(.copyGalleryItemsForUploading(items: items)))) } } .eraseToAnyPublisher() case .fileAction(.itemsCopiedForUploading(let newMessageIds, let localNames)): if let chat = state.conversationsState.currentChat { return Just(.conversationAction(.sendMediaMessages( from: chat.account, to: chat.participant, messagesIds: newMessageIds, localFilesNames: localNames ))) .eraseToAnyPublisher() } else { return Empty().eraseToAnyPublisher() } case .sharingAction(.cameraCaptured(let media, let type)): return Deferred { Future { promise in if let (id, localName) = FileProcessing.shared.copyCameraCapturedForUploading(media: media, type: type) { promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: [id], localNames: [localName]))) ) } else { promise(.success(.info("SharingMiddleware: camera's captured file didn't copied"))) } } } .eraseToAnyPublisher() case .sharingAction(.shareLocation(let lat, let lon)): if let chat = state.conversationsState.currentChat { let msg = "geo:\(lat),\(lon)" return Just(.conversationAction(.sendMessage(from: chat.account, to: chat.participant, body: msg))) .eraseToAnyPublisher() } else { return Empty().eraseToAnyPublisher() } case .sharingAction(.shareDocuments(let data, let extensions)): return Deferred { Future { promise in let ids = FileProcessing.shared.copyDocumentsForUploading(data: data, extensions: extensions) promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: ids.map { $0.0 }, localNames: ids.map { $0.1 }))) ) } } .eraseToAnyPublisher() case .sharingAction(.shareContact(let jid)): if let chat = state.conversationsState.currentChat { let msg = "contact:\(jid)" return Just(.conversationAction(.sendMessage(from: chat.account, to: chat.participant, body: msg))) .eraseToAnyPublisher() } else { return Empty().eraseToAnyPublisher() } default: return Empty().eraseToAnyPublisher() } } }