diff --git a/ConversationsClassic/AppCore/Actions/SharingActions.swift b/ConversationsClassic/AppCore/Actions/SharingActions.swift index 901358a..6d8d0ee 100644 --- a/ConversationsClassic/AppCore/Actions/SharingActions.swift +++ b/ConversationsClassic/AppCore/Actions/SharingActions.swift @@ -5,7 +5,7 @@ enum SharingAction: Stateable { case shareLocation(lat: Double, lon: Double) case shareContact(jid: String) - case shareDocuments([Data]) + case shareDocuments([Data], [String]) case shareMedia(ids: [String]) case checkCameraAccess diff --git a/ConversationsClassic/AppCore/Files/FileProcessing.swift b/ConversationsClassic/AppCore/Files/FileProcessing.swift index 582682f..9845fac 100644 --- a/ConversationsClassic/AppCore/Files/FileProcessing.swift +++ b/ConversationsClassic/AppCore/Files/FileProcessing.swift @@ -166,6 +166,23 @@ final class FileProcessing { return nil } } + + // This function also creates new id for file from document sharing + func copyDocumentsForUploading(data: [Data], extensions: [String]) -> [(String, String)] { + data.enumerated().compactMap { index, data in + let newMessageId = UUID().uuidString + let fileId = UUID().uuidString + let localName = "\(newMessageId)_\(fileId).\(extensions[index])" + let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName) + do { + try data.write(to: localUrl) + return (newMessageId, localName) + } catch { + print("FileProcessing: Error writing document: \(error)") + return nil + } + } + } } private extension FileProcessing { diff --git a/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift b/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift index e06b5c5..73ad01c 100644 --- a/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift +++ b/ConversationsClassic/AppCore/Middlewares/SharingMiddleware.swift @@ -97,9 +97,13 @@ final class SharingMiddleware { return Empty().eraseToAnyPublisher() } - case .sharingAction(.shareDocuments(let data)): - print("Sharing documents: \(data.count)") - return Empty().eraseToAnyPublisher() + case .sharingAction(.shareDocuments(let data, let extensions)): + return 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 { diff --git a/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift b/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift index 2c134d9..6cbda05 100644 --- a/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift +++ b/ConversationsClassic/View/Screens/Conversation/ConversationMessageContainer.swift @@ -1,5 +1,6 @@ import AVKit import MapKit +import QuickLook import SwiftUI struct ConversationMessageContainer: View { @@ -92,6 +93,14 @@ private struct AttachmentView: View { placeholder } + case .file: + if let file = message.attachmentLocalPath { + DocumentPreview(url: file) + .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize) + } else { + placeholder + } + default: placeholder } @@ -175,3 +184,37 @@ private struct VideoPlayerView: UIViewControllerRepresentable { // Update the controller if needed. } } + +struct DocumentPreview: UIViewControllerRepresentable { + var url: URL + + func makeUIViewController(context: Context) -> QLPreviewController { + let controller = QLPreviewController() + controller.dataSource = context.coordinator + return controller + } + + func updateUIViewController(_: QLPreviewController, context _: Context) { + // Update the controller if needed. + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, QLPreviewControllerDataSource { + var parent: DocumentPreview + + init(_ parent: DocumentPreview) { + self.parent = parent + } + + func numberOfPreviewItems(in _: QLPreviewController) -> Int { + 1 + } + + func previewController(_: QLPreviewController, previewItemAt _: Int) -> QLPreviewItem { + parent.url as QLPreviewItem + } + } +} diff --git a/ConversationsClassic/View/Screens/Sharing/SharingFilesPickerView.swift b/ConversationsClassic/View/Screens/Sharing/SharingFilesPickerView.swift index 3bf6734..5535b02 100644 --- a/ConversationsClassic/View/Screens/Sharing/SharingFilesPickerView.swift +++ b/ConversationsClassic/View/Screens/Sharing/SharingFilesPickerView.swift @@ -6,9 +6,9 @@ struct SharingFilesPickerView: View { var body: some View { DocumentPicker( - completion: { dataArray in + completion: { dataArray, extensionsArray in store.dispatch(.sharingAction(.showSharing(false))) - store.dispatch(.sharingAction(.shareDocuments(dataArray))) + store.dispatch(.sharingAction(.shareDocuments(dataArray, extensionsArray))) }, cancel: { store.dispatch(.sharingAction(.showSharing(false))) @@ -18,7 +18,7 @@ struct SharingFilesPickerView: View { } struct DocumentPicker: UIViewControllerRepresentable { - let completion: ([Data]) -> Void + let completion: ([Data], [String]) -> Void let cancel: () -> Void func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIDocumentPickerViewController { @@ -44,15 +44,17 @@ struct DocumentPicker: UIViewControllerRepresentable { func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt: [URL]) { var dataArray = [Data]() + var extensionArray = [String]() for url in didPickDocumentsAt { do { let data = try Data(contentsOf: url) dataArray.append(data) + extensionArray.append(url.pathExtension) } catch { print("Unable to load data from \(url): \(error)") } } - parent.completion(dataArray) + parent.completion(dataArray, extensionArray) } func documentPickerWasCancelled(_: UIDocumentPickerViewController) {