From 8028c709d71b273420516987bb003b0401f6e24a Mon Sep 17 00:00:00 2001 From: fmodf Date: Sun, 18 Aug 2024 11:17:58 +0200 Subject: [PATCH] wip --- .../AppData/Store/AttachmentsStore.swift | 146 +++++++++++++++++- .../AppData/Store/ConversationStore.swift | 141 ----------------- .../Attachments/AttachmentPickerScreen.swift | 2 - .../FilesPicker/FilesPickerView.swift | 3 +- .../MediaPicker/CameraCellPreview.swift | 2 +- .../MediaPicker/MediaPickerView.swift | 2 +- 6 files changed, 147 insertions(+), 149 deletions(-) diff --git a/ConversationsClassic/AppData/Store/AttachmentsStore.swift b/ConversationsClassic/AppData/Store/AttachmentsStore.swift index e11f0c3..e776725 100644 --- a/ConversationsClassic/AppData/Store/AttachmentsStore.swift +++ b/ConversationsClassic/AppData/Store/AttachmentsStore.swift @@ -5,9 +5,9 @@ import SwiftUI @MainActor final class AttachmentsStore: ObservableObject { - @Published var cameraAccessGranted = false - @Published var galleryAccessGranted = false - @Published var galleryItems: [GalleryItem] = [] + @Published private(set) var cameraAccessGranted = false + @Published private(set) var galleryAccessGranted = false + @Published private(set) var galleryItems: [GalleryItem] = [] private let client: Client private let roster: Roster @@ -18,6 +18,7 @@ final class AttachmentsStore: ObservableObject { } } +// MARK: - Camera and Gallery access extension AttachmentsStore { func checkCameraAuthorization() async { let status = AVCaptureDevice.authorizationStatus(for: .video) @@ -43,3 +44,142 @@ extension AttachmentsStore { galleryItems = await GalleryItem.fetchAll() } } + +// MARK: - Save outgoing attachments for future uploadings +extension AttachmentsStore { + func sendMedia(_ items: [GalleryItem]) async { + galleryItems = [] + for item in items { + Task { + var message = Message.blank + message.from = roster.bareJid + message.to = roster.contactBareJid + + switch item.type { + case .photo: + guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject else { return } + guard let photo = try? await PHImageManager.default().getPhoto(for: asset) else { return } + guard let data = photo.jpegData(compressionQuality: 1.0) else { return } + let localName = "\(message.id)_\(UUID().uuidString).jpg" + let localUrl = Const.fileFolder.appendingPathComponent(localName) + try? data.write(to: localUrl) + message.contentType = .attachment( + Attachment( + type: .image, + localName: localName, + thumbnailName: nil, + remotePath: nil + ) + ) + try? await message.save() + + case .video: + guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject else { return } + guard let video = try? await PHImageManager.default().getVideo(for: asset) else { return } + // swiftlint:disable:next force_cast + let assetURL = video as! AVURLAsset + let url = assetURL.url + let localName = "\(message.id)_\(UUID().uuidString).mov" + let localUrl = Const.fileFolder.appendingPathComponent(localName) + try? FileManager.default.copyItem(at: url, to: localUrl) + message.contentType = .attachment( + Attachment( + type: .video, + localName: localName, + thumbnailName: nil, + remotePath: nil + ) + ) + try? await message.save() + } + } + } + } + + func sendCaptured(_ data: Data, _ type: GalleryMediaType) async { + galleryItems = [] + // save locally and make message + var message = Message.blank + message.from = roster.bareJid + message.to = roster.contactBareJid + + let localName: String + let msgType: AttachmentType + do { + (localName, msgType) = try await Task { + // local name + let fileId = UUID().uuidString + let localName: String + let msgType: AttachmentType + switch type { + case .photo: + localName = "\(message.id)_\(fileId).jpg" + msgType = .image + + case .video: + localName = "\(message.id)_\(fileId).mov" + msgType = .video + } + + // save + let localUrl = Const.fileFolder.appendingPathComponent(localName) + try data.write(to: localUrl) + return (localName, msgType) + }.value + } catch { + logIt(.error, "Can't save file for uploading: \(error)") + return + } + + // save message + message.contentType = .attachment( + Attachment( + type: msgType, + localName: localName, + thumbnailName: nil, + remotePath: nil + ) + ) + do { + try await message.save() + } catch { + logIt(.error, "Can't save message: \(error)") + return + } + } + + func sendDocuments(_ data: [Data], _ extensions: [String]) async { + galleryItems = [] + for (index, data) in data.enumerated() { + Task { + let newMessageId = UUID().uuidString + let fileId = UUID().uuidString + let localName = "\(newMessageId)_\(fileId).\(extensions[index])" + let localUrl = Const.fileFolder.appendingPathComponent(localName) + do { + try data.write(to: localUrl) + } catch { + print("FileProcessing: Error writing document: \(error)") + return + } + + var message = Message.blank + message.from = roster.bareJid + message.to = roster.contactBareJid + message.contentType = .attachment( + Attachment( + type: localName.attachmentType, + localName: localName, + thumbnailName: nil, + remotePath: nil + ) + ) + do { + try await message.save() + } catch { + print("FileProcessing: Error saving document: \(error)") + } + } + } + } +} diff --git a/ConversationsClassic/AppData/Store/ConversationStore.swift b/ConversationsClassic/AppData/Store/ConversationStore.swift index 68902b8..54c8046 100644 --- a/ConversationsClassic/AppData/Store/ConversationStore.swift +++ b/ConversationsClassic/AppData/Store/ConversationStore.swift @@ -37,147 +37,6 @@ extension ConversationStore { try? await msg.setStatus(.error) } } -} - -extension ConversationStore { - func sendMedia(_ items: [GalleryItem]) async { - for item in items { - Task { - var message = Message.blank - message.from = roster.bareJid - message.to = roster.contactBareJid - - switch item.type { - case .photo: - guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject else { return } - guard let photo = try? await PHImageManager.default().getPhoto(for: asset) else { return } - guard let data = photo.jpegData(compressionQuality: 1.0) else { return } - let localName = "\(message.id)_\(UUID().uuidString).jpg" - let localUrl = Const.fileFolder.appendingPathComponent(localName) - try? data.write(to: localUrl) - message.contentType = .attachment( - Attachment( - type: .image, - localName: localName, - thumbnailName: nil, - remotePath: nil - ) - ) - try? await message.save() - - case .video: - guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [item.id], options: nil).firstObject else { return } - guard let video = try? await PHImageManager.default().getVideo(for: asset) else { return } - // swiftlint:disable:next force_cast - let assetURL = video as! AVURLAsset - let url = assetURL.url - let localName = "\(message.id)_\(UUID().uuidString).mov" - let localUrl = Const.fileFolder.appendingPathComponent(localName) - try? FileManager.default.copyItem(at: url, to: localUrl) - message.contentType = .attachment( - Attachment( - type: .video, - localName: localName, - thumbnailName: nil, - remotePath: nil - ) - ) - try? await message.save() - } - - await upload(message) - } - } - } - - func sendCaptured(_ data: Data, _ type: GalleryMediaType) async { - // save locally and make message - var message = Message.blank - message.from = roster.bareJid - message.to = roster.contactBareJid - - let localName: String - let msgType: AttachmentType - do { - (localName, msgType) = try await Task { - // local name - let fileId = UUID().uuidString - let localName: String - let msgType: AttachmentType - switch type { - case .photo: - localName = "\(message.id)_\(fileId).jpg" - msgType = .image - - case .video: - localName = "\(message.id)_\(fileId).mov" - msgType = .video - } - - // save - let localUrl = Const.fileFolder.appendingPathComponent(localName) - try data.write(to: localUrl) - return (localName, msgType) - }.value - } catch { - logIt(.error, "Can't save file for uploading: \(error)") - return - } - - // save message - message.contentType = .attachment( - Attachment( - type: msgType, - localName: localName, - thumbnailName: nil, - remotePath: nil - ) - ) - do { - try await message.save() - } catch { - logIt(.error, "Can't save message: \(error)") - return - } - - // upload and save - await upload(message) - } - - func sendDocuments(_ data: [Data], _ extensions: [String]) async { - for (index, data) in data.enumerated() { - Task { - let newMessageId = UUID().uuidString - let fileId = UUID().uuidString - let localName = "\(newMessageId)_\(fileId).\(extensions[index])" - let localUrl = Const.fileFolder.appendingPathComponent(localName) - do { - try data.write(to: localUrl) - } catch { - print("FileProcessing: Error writing document: \(error)") - return - } - - var message = Message.blank - message.from = roster.bareJid - message.to = roster.contactBareJid - message.contentType = .attachment( - Attachment( - type: localName.attachmentType, - localName: localName, - thumbnailName: nil, - remotePath: nil - ) - ) - do { - try await message.save() - await upload(message) - } catch { - print("FileProcessing: Error saving document: \(error)") - } - } - } - } func sendContact(_ jidStr: String) async { await sendMessage("contact:\(jidStr)") diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift b/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift index 8f71c07..8c57bd4 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift @@ -9,7 +9,6 @@ enum AttachmentTab: Int, CaseIterable { struct AttachmentPickerScreen: View { @Environment(\.router) var router - @EnvironmentObject var attachments: AttachmentsStore @State private var selectedTab: AttachmentTab = .media @@ -36,7 +35,6 @@ struct AttachmentPickerScreen: View { switch selectedTab { case .media: MediaPickerView() - .environmentObject(attachments) case .files: FilesPickerView() diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift index d041667..2e734b7 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift @@ -4,12 +4,13 @@ import UIKit struct FilesPickerView: View { @Environment(\.router) var router @EnvironmentObject var conversation: ConversationStore + @EnvironmentObject var attachments: AttachmentsStore var body: some View { DocumentPicker( completion: { dataArray, extensionsArray in Task { - await conversation.sendDocuments(dataArray, extensionsArray) + await attachments.sendDocuments(dataArray, extensionsArray) } router.dismissEnvironment() }, diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift index 11fbef0..de3fb50 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift @@ -27,7 +27,7 @@ struct CameraCellPreview: View { router.showScreen(.fullScreenCover) { _ in CameraPicker { data, type in Task { - await conversation.sendCaptured(data, type) + await attachments.sendCaptured(data, type) } router.dismissEnvironment() } diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift index f3b8daf..fc7541b 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift @@ -46,7 +46,7 @@ struct MediaPickerView: View { .onTapGesture { Task { let items = attachments.galleryItems.filter { selectedItems.contains($0.id) } - await conversation.sendMedia(items) + await attachments.sendMedia(items) } router.dismissEnvironment() }