diff options
| -rw-r--r-- | Hotline/Hotline/HotlineClient.swift | 9 | ||||
| -rw-r--r-- | Hotline/Models/Hotline.swift | 72 | ||||
| -rw-r--r-- | Hotline/macOS/FilesView.swift | 115 | ||||
| -rw-r--r-- | Hotline/macOS/NewsView.swift | 15 |
4 files changed, 133 insertions, 78 deletions
diff --git a/Hotline/Hotline/HotlineClient.swift b/Hotline/Hotline/HotlineClient.swift index 1c72ab0..b30ee11 100644 --- a/Hotline/Hotline/HotlineClient.swift +++ b/Hotline/Hotline/HotlineClient.swift @@ -628,6 +628,15 @@ class HotlineClient: NetSocketDelegate { } } + @MainActor func sendDeleteFile(name fileName: String, path filePath: [String], callback: ((Bool) -> Void)? = nil) { + var t = HotlineTransaction(type: .deleteFile) + t.setFieldString(type: .fileName, val: fileName) + t.setFieldPath(type: .filePath, val: filePath) + self.sendPacket(t) { reply, err in + callback?(err == nil) + } + } + @MainActor func sendGetFileInfo(name fileName: String, path filePath: [String], callback: ((FileDetails?) -> Void)? = nil) { var t = HotlineTransaction(type: .getFileInfo) t.setFieldString(type: .fileName, val: fileName) diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift index 06baf04..ce917cd 100644 --- a/Hotline/Models/Hotline.swift +++ b/Hotline/Models/Hotline.swift @@ -545,14 +545,29 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate { } } - @MainActor func fileDetails(_ fileName: String, path: [String], complete callback: ((FileDetails?) -> Void)? = nil) { + @MainActor func getFileDetails(_ fileName: String, path: [String]) async -> FileDetails? { var fullPath: [String] = [] if path.count > 1 { fullPath = Array(path[0..<path.count-1]) } - self.client.sendGetFileInfo(name: fileName, path: fullPath) { info in - callback?(info) + return await withCheckedContinuation { [weak self] continuation in + self?.client.sendGetFileInfo(name: fileName, path: fullPath) { info in + continuation.resume(returning: info) + } + } + } + + @MainActor func deleteFile(_ fileName: String, path: [String]) async -> Bool { + var fullPath: [String] = [] + if path.count > 1 { + fullPath = Array(path[0..<path.count-1]) + } + + return await withCheckedContinuation { [weak self] continuation in + self?.client.sendDeleteFile(name: fileName, path: fullPath) { success in + continuation.resume(returning: success) + } } } @@ -611,57 +626,6 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileClientDelegate { } } -// @MainActor func previewFile(_ fileName: String, path: [String], addTransfer: Bool = false, complete callback: ((TransferInfo, Data) -> Void)? = nil) { -// var fullPath: [String] = [] -// if path.count > 1 { -// fullPath = Array(path[0..<path.count-1]) -// } -// -// self.client.sendDownloadFile(name: fileName, path: fullPath, preview: true, sent: { _ in -// -// }, reply: { [weak self] success, downloadReferenceNumber, downloadTransferSize, downloadFileSize, downloadWaitingCount in -// guard success else { -// return -// } -// -// print("GOT DOWNLOAD REPLY:") -// print("SUCCESS?", success) -// print("TRANSFER SIZE: \(downloadTransferSize.debugDescription)") -// print("FILE SIZE: \(downloadFileSize.debugDescription)") -// print("REFERENCE NUM: \(downloadReferenceNumber.debugDescription)") -// print("WAITING COUNT: \(downloadWaitingCount.debugDescription)") -// -// if -// let self = self, -// let address = self.server?.address, -// let port = self.server?.port, -// let referenceNumber = downloadReferenceNumber, -// let transferSize = downloadTransferSize { -// -// let fileClient = HotlineFileClient(address: address, port: UInt16(port), reference: referenceNumber, size: UInt32(transferSize), type: .preview) -// fileClient.delegate = self -// self.downloads.append(fileClient) -// -// if addTransfer { -// let transfer = TransferInfo(id: referenceNumber, title: fileName, size: UInt(transferSize)) -// transfer.previewCallback = callback -// self.transfers.append(transfer) -// } -// -// fileClient.downloadToMemory() -// -// print("DOWNLOADING TO MEMORY") -//// fileClient.downloadToMemory({ [weak self] fileData in -//// print("DOWNLOADED PREVIEW DATA", fileData?.count) -//// self?.downloads.removeAll { $0.referenceNumber == referenceNumber } -//// callback?(fileData != nil, fileData) -//// }) -// -//// self.downloads.append(fileClient) -// } -// }) -// } - @MainActor func deleteTransfer(id: UInt32) { if let b = self.bannerClient, b.referenceNumber == id { b.cancel() diff --git a/Hotline/macOS/FilesView.swift b/Hotline/macOS/FilesView.swift index a225549..77db291 100644 --- a/Hotline/macOS/FilesView.swift +++ b/Hotline/macOS/FilesView.swift @@ -127,12 +127,51 @@ struct FilesView: View { // let _ = FilePreviewWindowController(info: previewInfo) } + @MainActor private func getFileInfo(_ file: FileInfo) { + Task { + if let fileInfo = await model.getFileDetails(file.name, path: file.path) { + Task { @MainActor in + self.fileDetails = fileInfo + } + } + } + } + + @MainActor private func downloadFile(_ file: FileInfo) { + guard !file.isFolder else { + return + } + + model.downloadFile(file.name, path: file.path) + } + + @MainActor private func previewFile(_ file: FileInfo) { + guard file.isPreviewable else { + return + } + + model.previewFile(file.name, path: file.path) { info in + if let info = info { + openPreviewWindow(info) + } + } + } + + private func deleteFile(_ file: FileInfo) async { + var parentPath: [String] = [] + if file.path.count > 1 { + parentPath = Array(file.path[0..<file.path.count-1]) + } + + if await model.deleteFile(file.name, path: file.path) { + let _ = await model.getFileList(path: parentPath) + } + } + var body: some View { NavigationStack { List(model.files, id: \.self, selection: $selection) { file in FileView(file: file, depth: 0).tag(file.id) -// .environment(self.fileSelection) -// .frame(height: 34) } .environment(\.defaultMinListRowHeight, 34) .listStyle(.inset) @@ -143,7 +182,51 @@ struct FilesView: View { } } .contextMenu(forSelectionType: FileInfo.self) { items in - // ... + let selectedFile = items.first + + Button { + if let s = selectedFile, !s.isFolder { + downloadFile(s) + } + } label: { + Label("Download", systemImage: "arrow.down") + } + .disabled(selectedFile == nil || (selectedFile != nil && selectedFile!.isFolder)) + + Divider() + + Button { + if let s = selectedFile { + getFileInfo(s) + } + } label: { + Label("Get Info", systemImage: "info.circle") + } + .disabled(selectedFile == nil) + + Button { + if let s = selectedFile { + previewFile(s) + } + } label: { + Label("Preview", systemImage: "eye") + } + .disabled(selectedFile == nil || (selectedFile != nil && !selectedFile!.isPreviewable)) + + if model.access?.contains(.canDeleteFiles) == true { + Divider() + + Button { + if let s = selectedFile { + Task { + await deleteFile(s) + } + } + } label: { + Label("Delete", systemImage: "trash") + } + .disabled(selectedFile == nil) + } } primaryAction: { items in guard let clickedFile = items.first else { return @@ -154,7 +237,7 @@ struct FilesView: View { clickedFile.expanded.toggle() } else { - model.downloadFile(clickedFile.name, path: clickedFile.path) + downloadFile(clickedFile) } } .onKeyPress(.rightArrow) { @@ -173,11 +256,7 @@ struct FilesView: View { } .onKeyPress(.space) { if let s = selection, s.isPreviewable { - model.previewFile(s.name, path: s.path) { info in - if let info = info { - openPreviewWindow(info) - } - } + previewFile(s) return .handled } return .ignored @@ -203,12 +282,8 @@ struct FilesView: View { ToolbarItem(placement: .primaryAction) { Button { - if let s = selection, s.isPreviewable { - model.previewFile(s.name, path: s.path) { info in - if let info = info { - openPreviewWindow(info) - } - } + if let selectedFile = selection, selectedFile.isPreviewable { + previewFile(selectedFile) } } label: { Label("Preview", systemImage: "eye") @@ -219,10 +294,8 @@ struct FilesView: View { ToolbarItem(placement: .primaryAction) { Button { - if let s = selection { - model.fileDetails(s.name, path: s.path) { info in - fileDetails = info - } + if let selectedFile = selection { + getFileInfo(selectedFile) } } label: { Label("Get Info", systemImage: "info.circle") @@ -233,8 +306,8 @@ struct FilesView: View { ToolbarItem(placement: .primaryAction) { Button { - if let s = selection, !s.isFolder { - model.downloadFile(s.name, path: s.path) + if let selectedFile = selection, !selectedFile.isFolder { + downloadFile(selectedFile) } } label: { Label("Download", systemImage: "arrow.down") diff --git a/Hotline/macOS/NewsView.swift b/Hotline/macOS/NewsView.swift index ed5d969..6f24193 100644 --- a/Hotline/macOS/NewsView.swift +++ b/Hotline/macOS/NewsView.swift @@ -121,16 +121,15 @@ struct NewsView: View { ToolbarItem(placement: .primaryAction) { Button { + loading = true if let selectionPath = selection?.path { Task { - loading = true await model.getNewsList(at: selectionPath) loading = false } } else { Task { - loading = true await model.getNewsList() loading = false } @@ -153,7 +152,17 @@ struct NewsView: View { .listStyle(.inset) .alternatingRowBackgrounds(.enabled) .contextMenu(forSelectionType: NewsInfo.self) { items in - // ... + let selectedItem = items.first + + Button { + if selectedItem?.type == .article { + replyOpen = true + } + } label: { + Label("Reply to \(selectedItem?.articleUsername ?? "Post")", systemImage: "arrowshape.turn.up.left") + } + .disabled(selectedItem == nil || selectedItem?.type != .article) + } primaryAction: { items in guard let clickedNews = items.first else { return |