diff --git a/Sources/QuickBloxData/DTO/File/LocalFileDTO.swift b/Sources/QuickBloxData/DTO/File/LocalFileDTO.swift index ad29177..acf36e0 100644 --- a/Sources/QuickBloxData/DTO/File/LocalFileDTO.swift +++ b/Sources/QuickBloxData/DTO/File/LocalFileDTO.swift @@ -20,4 +20,5 @@ public struct LocalFileDTO: DataStringConvertible { public var type: FileType = .file public var data: Data = Data() public var path: FilePath = FilePath() + public var uid: String = "" } diff --git a/Sources/QuickBloxData/DTO/File/RemoteFileDTO.swift b/Sources/QuickBloxData/DTO/File/RemoteFileDTO.swift index 3692aa7..b2d257e 100644 --- a/Sources/QuickBloxData/DTO/File/RemoteFileDTO.swift +++ b/Sources/QuickBloxData/DTO/File/RemoteFileDTO.swift @@ -17,6 +17,7 @@ public struct RemoteFileDTO: DataStringConvertible { public var type: FileType = .file public var data: Data = Data() public var path: FilePath = FilePath() + public var uid: String = "" public var `public`: Bool = false } diff --git a/Sources/QuickBloxData/DTO/Message/LocalMessageDTO.swift b/Sources/QuickBloxData/DTO/Message/LocalMessageDTO.swift index 53a3da2..98b6a6b 100644 --- a/Sources/QuickBloxData/DTO/Message/LocalMessageDTO.swift +++ b/Sources/QuickBloxData/DTO/Message/LocalMessageDTO.swift @@ -35,4 +35,5 @@ public struct LocalFileInfoDTO: Equatable, Identifiable, Hashable { var ext: FileExtension = .json var name: String = "" var path: FilePath = FilePath() + public var uid: String = "" } diff --git a/Sources/QuickBloxData/DTO/Message/RemoteMessageDTO.swift b/Sources/QuickBloxData/DTO/Message/RemoteMessageDTO.swift index d57d77d..cf9183c 100644 --- a/Sources/QuickBloxData/DTO/Message/RemoteMessageDTO.swift +++ b/Sources/QuickBloxData/DTO/Message/RemoteMessageDTO.swift @@ -39,4 +39,5 @@ public struct RemoteFileInfoDTO: Equatable { var name = "" var type = "" var path = "" + var uid = "" } diff --git a/Sources/QuickBloxData/Repository/FilesRepository.swift b/Sources/QuickBloxData/Repository/FilesRepository.swift index 2783d00..b8ab3db 100644 --- a/Sources/QuickBloxData/Repository/FilesRepository.swift +++ b/Sources/QuickBloxData/Repository/FilesRepository.swift @@ -76,6 +76,7 @@ private extension LocalFileDTO { type = value.type data = value.data path = value.path + uid = value.uid } } @@ -85,7 +86,8 @@ private extension File { info = FileInfo(id: value.id, ext: value.ext, name: value.name, - path: value.path) + path: value.path, + uid: value.uid) data = value.data } } @@ -96,7 +98,8 @@ private extension File { info = FileInfo(id: value.id, ext: value.ext, name: value.name, - path: value.path) + path: value.path, + uid: value.uid) data = value.data } } @@ -109,5 +112,6 @@ private extension LocalFileDTO { type = value.info.type path = value.info.path data = value.data + uid = value.info.uid } } diff --git a/Sources/QuickBloxData/Repository/MessagesRepository.swift b/Sources/QuickBloxData/Repository/MessagesRepository.swift index 0297e27..d1798d4 100644 --- a/Sources/QuickBloxData/Repository/MessagesRepository.swift +++ b/Sources/QuickBloxData/Repository/MessagesRepository.swift @@ -44,6 +44,7 @@ extension LocalMessageDTO { fileInfo?.name = new.name fileInfo?.ext = new.ext fileInfo?.path = new.path + fileInfo?.uid = new.uid } } } @@ -68,7 +69,8 @@ private extension RemoteMessageDTO { id: file.id, name: file.name, type: file.ext.type.rawValue, - path: file.path.remote + path: file.path.remote, + uid: file.uid )) } } @@ -105,6 +107,7 @@ extension Message { name: filesInfo.name) } fileInfo?.path.remote = filesInfo.path + fileInfo?.uid = filesInfo.uid } } @@ -126,6 +129,7 @@ extension Message { ext: info.ext, name: info.name) fileInfo?.path = info.path + fileInfo?.uid = info.uid } } } diff --git a/Sources/QuickBloxData/Source/Entity/File.swift b/Sources/QuickBloxData/Source/Entity/File.swift index 2531ae7..b7c8135 100644 --- a/Sources/QuickBloxData/Source/Entity/File.swift +++ b/Sources/QuickBloxData/Source/Entity/File.swift @@ -30,6 +30,7 @@ public struct FileInfo: FileInfoEntity { public var name: String public var type: FileType public var path: FilePath + public var uid: String public init(id: String, ext: FileExtension, @@ -44,6 +45,7 @@ public struct FileInfo: FileInfoEntity { } type = ext.type path = FilePath() + uid = "" } } @@ -52,7 +54,8 @@ public extension FileInfo { self.init(id: value.id, ext: value.ext, name: value.name, - path: FilePath(value.path)) + path: FilePath(value.path), + uid: value.uid) } } diff --git a/Sources/QuickBloxData/Source/Remote/RemoteDataSource.swift b/Sources/QuickBloxData/Source/Remote/RemoteDataSource.swift index dd60fdb..9728212 100644 --- a/Sources/QuickBloxData/Source/Remote/RemoteDataSource.swift +++ b/Sources/QuickBloxData/Source/Remote/RemoteDataSource.swift @@ -556,7 +556,6 @@ extension RemoteDataSource { system.dateSent = Date() system.recipientID = QBSession.current.currentUserID -// await stream.process(system) for id in dto.participantsIds { system.recipientID = UInt(id) ?? 0 @@ -893,6 +892,7 @@ extension RemoteDataSource { let fileName = blob.name ?? "file" let fileId = String(blob.id) + let fileUID = blob.uid ?? "" var fileExtension: FileExtension if let extStr = fileName.components(separatedBy: ".").last, @@ -916,7 +916,8 @@ extension RemoteDataSource { name: fileName, type: fileExtension.type, data: dto.data, - path: filePath) + path: filePath, + uid: fileUID) } catch let nsError as NSError { throw try nsError.convertToRemoteException() } catch { @@ -974,6 +975,7 @@ extension RemoteDataSource { uploaded.name = fileName uploaded.type = fileExtension.type uploaded.path = filePath + uploaded.uid = uuid return uploaded } catch let nsError as NSError { throw try nsError.convertToRemoteException() @@ -982,6 +984,10 @@ extension RemoteDataSource { } } else { var uploaded = try await get(fileWithPath: dto.id) + if uploaded.name.contains("json"), uploaded.ext != .json { + uploaded.name = uploaded.name.replacingOccurrences(of: "json", + with: uploaded.ext.rawValue) + } if dto.name.contains(dto.ext.rawValue) { let fileName = dto.name.replacingOccurrences(of: dto.ext.rawValue, with: "") @@ -1425,7 +1431,8 @@ private extension QBRequest { name: fileName, type: fileExt.type, data: data, - path: filePath) + path: filePath, + uid: uuid ?? "") } static func delete(file id: UInt) async throws { @@ -1645,7 +1652,9 @@ extension QBChatMessage { } attachments = value.filesInfo.compactMap { - return QBChatAttachment($0) + var attachment = QBChatAttachment($0) + attachment["uid"] = $0.uid + return attachment } delayed = value.delayed @@ -1658,15 +1667,26 @@ extension QBChatMessage { private extension RemoteFileInfoDTO { init (_ value: QBChatAttachment) throws { - guard let id = value.id else { - let info = "\(String(describing: QBChatAttachment.self)) id is missing" - throw MapperException.incorrectData(description: info) + if let id = value.id { + self.id = id + } else { + if let urlPath = value.url, let url = URL(string: urlPath) { + self.id = url.lastPathComponent + } + if let uid = value.customParameters?["uid"] { + self.id = uid + } + if let contentType = value["content-type"] { + type = contentType + } } - self.id = id name = value.name ?? "" type = value.type ?? "" path = value.url ?? "" + if let uid = value.customParameters?["uid"] { + self.uid = uid + } } } diff --git a/Sources/QuickBloxDomain/Entity/FileEntity.swift b/Sources/QuickBloxDomain/Entity/FileEntity.swift index 0be481c..b95ed0c 100644 --- a/Sources/QuickBloxDomain/Entity/FileEntity.swift +++ b/Sources/QuickBloxDomain/Entity/FileEntity.swift @@ -28,6 +28,7 @@ public protocol FileInfoEntity: Entity { var name: String { get set } var type: FileType { get set } var path: PathItem { get set } + var uid: String { get set } init(id: String, ext: FileExtension, name: String) } @@ -36,12 +37,13 @@ extension FileInfoEntity { public init(id: String, ext: FileExtension, name: String, - path: PathItem) { + path: PathItem, + uid: String) { self.init(id: id, ext: ext, name: name) self.name = name - self.name = name self.type = ext.type self.path = path + self.uid = uid } } diff --git a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/GroupDialogView.swift b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/GroupDialogView.swift index 915f5b1..c66040d 100644 --- a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/GroupDialogView.swift +++ b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/GroupDialogView.swift @@ -79,9 +79,12 @@ public struct GroupDialogView: View { if action == .play { viewModel.playAudio(data, action: action) tappedMessage = message - } else { + } else if action == .stop { viewModel.stopPlayng() tappedMessage = nil + } else if action == .save { + self.fileUrl = url + isFileExporterPresented = true } } }, onAIFeature: { type, message in @@ -188,9 +191,9 @@ public struct GroupDialogView: View { viewModel.sendStopTyping() viewModel.stopPlayng() isInfoPresented = true - })) - - .sheet(isPresented: $isFileExporterPresented) { + })) + + .sheet(isPresented: $isFileExporterPresented) { if let fileUrl = fileUrl { ActivityViewController(activityItems: [fileUrl.lastPathComponent , fileUrl]) } diff --git a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/InboundAudioMessageRow.swift b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/InboundAudioMessageRow.swift index 0b18433..a143d84 100644 --- a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/InboundAudioMessageRow.swift +++ b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/InboundAudioMessageRow.swift @@ -96,6 +96,13 @@ public struct InboundAudioMessageRow: View { } .fixedSize(horizontal: false, vertical: true) .id(message.id) + .contextMenu { + Button { + save() + } label: { + Label("Save", systemImage: "folder") + } + } } private func play() { @@ -106,6 +113,11 @@ public struct InboundAudioMessageRow: View { onTap(.play, data, url) } } + + private func save() { + guard let url = fileTuple?.url, let data = fileTuple?.data else { return } + onTap(.save, data, url) + } } import QuickBloxData diff --git a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/OutboundAudioMessageRow.swift b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/OutboundAudioMessageRow.swift index eb5949a..feb5474 100644 --- a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/OutboundAudioMessageRow.swift +++ b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/MessageRowView/OutboundAudioMessageRow.swift @@ -89,7 +89,13 @@ public struct OutboundAudioMessageRow: View { } .fixedSize(horizontal: false, vertical: true) .id(message.id) - + .contextMenu { + Button { + save() + } label: { + Label("Save", systemImage: "folder") + } + } } private func play() { @@ -100,6 +106,11 @@ public struct OutboundAudioMessageRow: View { onTap(.play, data, url) } } + + private func save() { + guard let url = fileTuple?.url, let data = fileTuple?.data else { return } + onTap(.save, data, url) + } } import QuickBloxData diff --git a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/PrivateDialogView.swift b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/PrivateDialogView.swift index 045add4..16c5f84 100644 --- a/Sources/QuickBloxUIKit/SwiftUIView/Dialog/PrivateDialogView.swift +++ b/Sources/QuickBloxUIKit/SwiftUIView/Dialog/PrivateDialogView.swift @@ -79,9 +79,12 @@ public struct PrivateDialogView: View { if action == .play { viewModel.playAudio(data, action: action) tappedMessage = message - } else { + } else if action == .stop { viewModel.stopPlayng() tappedMessage = nil + } else if action == .save { + self.fileUrl = url + isFileExporterPresented = true } } }, onAIFeature: { type, message in diff --git a/Sources/QuickBloxUIKit/ViewModel/DialogsViewModel.swift b/Sources/QuickBloxUIKit/ViewModel/DialogsViewModel.swift index 09d4cb6..2ccc1af 100644 --- a/Sources/QuickBloxUIKit/ViewModel/DialogsViewModel.swift +++ b/Sources/QuickBloxUIKit/ViewModel/DialogsViewModel.swift @@ -66,6 +66,7 @@ open class DialogsViewModel: DialogsListProtocol { if dialogId == self?.selectedItem?.id { self?.selectedItem = nil } + self?.dialogToBeDeleted = nil } .store(in: &cancellables)