Implements attachment uploading
This commit is contained in:
@@ -47,12 +47,11 @@ struct MessageEntryView: View
|
||||
Button("Send") {
|
||||
viewModel.sendDraft(to: selectedConversation)
|
||||
}
|
||||
.disabled(viewModel.draftText.isEmpty)
|
||||
.disabled(viewModel.draftText.isEmpty && viewModel.uploadedAttachmentGUIDs.isEmpty)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
.padding(10.0)
|
||||
}
|
||||
|
||||
.onChange(of: selectedConversation) { oldValue, newValue in
|
||||
if oldValue?.id != newValue?.id {
|
||||
viewModel.draftText = ""
|
||||
@@ -69,20 +68,61 @@ struct MessageEntryView: View
|
||||
var attachments: [OutgoingAttachment] = []
|
||||
var isDropTargeted: Bool = false
|
||||
|
||||
var uploadedAttachmentGUIDs: Set<String> {
|
||||
attachments.reduce(Set<String>()) { partialResult, attachment in
|
||||
switch attachment.state {
|
||||
case .uploaded(let guid): partialResult.union([ guid ])
|
||||
default: partialResult
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let client = XPCClient()
|
||||
private var uploadGuidToAttachmentId: [String: String] = [:]
|
||||
private var signalTask: Task<Void, Never>? = nil
|
||||
|
||||
init() {
|
||||
signalTask = Task { [weak self] in
|
||||
guard let self else { return }
|
||||
for await signal in client.eventStream() {
|
||||
switch signal {
|
||||
case .attachmentUploaded(let uploadGuid, let attachmentGuid):
|
||||
// Mark local attachment as uploaded when the daemon confirms
|
||||
await MainActor.run {
|
||||
if let localId = self.uploadGuidToAttachmentId[uploadGuid],
|
||||
let idx = self.attachments.firstIndex(where: { $0.id == localId }) {
|
||||
self.attachments[idx].state = .uploaded(attachmentGuid)
|
||||
self.uploadGuidToAttachmentId.removeValue(forKey: uploadGuid)
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit { signalTask?.cancel() }
|
||||
|
||||
func sendDraft(to convo: Display.Conversation?) {
|
||||
guard let convo else { return }
|
||||
guard !draftText.isEmpty else { return }
|
||||
guard !(draftText.isEmpty && uploadedAttachmentGUIDs.isEmpty) else { return }
|
||||
|
||||
let messageText = self.draftText
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
let transferGuids = self.uploadedAttachmentGUIDs
|
||||
|
||||
self.draftText = ""
|
||||
self.attachments = []
|
||||
|
||||
Task {
|
||||
let xpc = XPCClient()
|
||||
|
||||
do {
|
||||
try await xpc.sendMessage(conversationId: convo.id, message: messageText)
|
||||
try await client.sendMessage(
|
||||
conversationId: convo.id,
|
||||
message: messageText,
|
||||
transferGuids: transferGuids
|
||||
)
|
||||
} catch {
|
||||
print("Sending error: \(error)")
|
||||
}
|
||||
@@ -123,7 +163,37 @@ struct MessageEntryView: View
|
||||
|
||||
private func stageAndAppend(url: URL) {
|
||||
guard let att = AttachmentManager.shared.stageIfImage(url: url) else { return }
|
||||
Task { @MainActor in attachments.append(att) }
|
||||
Task { @MainActor in
|
||||
attachments.append(att)
|
||||
startUploadIfNeeded(for: att.id)
|
||||
}
|
||||
}
|
||||
|
||||
private func startUploadIfNeeded(for attachmentId: String) {
|
||||
guard let idx = attachments.firstIndex(where: { $0.id == attachmentId }) else { return }
|
||||
|
||||
let attachment = attachments[idx]
|
||||
switch attachment.state {
|
||||
case .staged, .failed:
|
||||
attachments[idx].state = .uploading(progress: 0.0)
|
||||
|
||||
Task {
|
||||
do {
|
||||
let guid = try await client.uploadAttachment(path: attachment.stagedURL.path)
|
||||
await MainActor.run {
|
||||
self.uploadGuidToAttachmentId[guid] = attachmentId
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
if let i = self.attachments.firstIndex(where: { $0.id == attachmentId }) {
|
||||
self.attachments[i].state = .failed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +243,8 @@ struct MessageEntryView: View
|
||||
}
|
||||
}
|
||||
|
||||
struct AttachmentThumbnail: View {
|
||||
struct AttachmentThumbnail: View
|
||||
{
|
||||
let attachment: OutgoingAttachment
|
||||
|
||||
var body: some View {
|
||||
|
||||
Reference in New Issue
Block a user