From 68533dad317c632dd45df7707d07dbe4a6003306 Mon Sep 17 00:00:00 2001 From: nite Date: Wed, 4 Feb 2026 15:06:41 +0800 Subject: [PATCH] add: cancel transfer --- README.md | 3 +- .../mesh-drop/internal/transfer/service.ts | 11 + frontend/src/components/MainLayout.vue | 18 +- frontend/src/components/TransferItem.vue | 63 +++- internal/transfer/client.go | 343 ++++++++++++------ internal/transfer/model.go | 5 +- internal/transfer/reader.go | 21 ++ internal/transfer/server.go | 192 +++++----- internal/transfer/service.go | 94 +++++ 9 files changed, 529 insertions(+), 221 deletions(-) create mode 100644 internal/transfer/reader.go create mode 100644 internal/transfer/service.go diff --git a/README.md b/README.md index b81e3bf..0d2f2bd 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ TODO - [x] 文件夹传输 - [x] 多样化图标 - [ ] 加密传输 -- [ ] 取消传输 \ No newline at end of file +- [x] 取消传输 +- [ ] 多文件发送 \ No newline at end of file diff --git a/frontend/bindings/mesh-drop/internal/transfer/service.ts b/frontend/bindings/mesh-drop/internal/transfer/service.ts index 1ab5529..f3bda93 100644 --- a/frontend/bindings/mesh-drop/internal/transfer/service.ts +++ b/frontend/bindings/mesh-drop/internal/transfer/service.ts @@ -13,10 +13,21 @@ import * as discovery$0 from "../discovery/models.js"; // @ts-ignore: Unused imports import * as $models from "./models.js"; +export function CancelTransfer(transferID: string): $CancellablePromise { + return $Call.ByID(900002248, transferID); +} + export function GetPort(): $CancellablePromise { return $Call.ByID(4195335736); } +export function GetTransfer(transferID: string): $CancellablePromise<[$models.Transfer, boolean]> { + return $Call.ByID(1198637268, transferID).then(($result: any) => { + $result[0] = $$createType0($result[0]); + return $result; + }); +} + export function GetTransferList(): $CancellablePromise<$models.Transfer[]> { return $Call.ByID(584162076).then(($result: any) => { return $$createType1($result); diff --git a/frontend/src/components/MainLayout.vue b/frontend/src/components/MainLayout.vue index eda8b9c..044709d 100644 --- a/frontend/src/components/MainLayout.vue +++ b/frontend/src/components/MainLayout.vue @@ -51,9 +51,10 @@ const showMobileMenu = ref(false); const isMobile = ref(false); // 监听窗口大小变化更新 isMobile -onMounted(() => { +onMounted(async () => { checkMobile(); window.addEventListener("resize", checkMobile); + transferList.value = await GetTransferList(); }); const checkMobile = () => { @@ -83,7 +84,12 @@ const menuOptions = computed(() => [ [ "Transfers", pendingCount.value > 0 ? - h(NBadge, { value: pendingCount.value, max: 99, type: "error" }) + h(NBadge, { + style: "display: inline-flex; align-items: center", + value: pendingCount.value, + max: 99, + type: "error", + }) : null, ], ), @@ -124,8 +130,8 @@ const handleSendFile = async (ip: string) => { if (!filePath) return; const peer = await GetPeerByIP(ip); if (!peer) return; - await SendFile(peer, ip, filePath); activeKey.value = "transfers"; + await SendFile(peer, ip, filePath); } catch (e: any) { console.error(e); alert("Failed to send file: " + e); @@ -143,8 +149,8 @@ const handleSendFolder = async (ip: string) => { if (!folderPath) return; const peer = await GetPeerByIP(ip); if (!peer) return; - await SendFolder(peer, ip, folderPath as string); activeKey.value = "transfers"; + await SendFolder(peer, ip, folderPath as string); }; const dialog = useDialog(); @@ -167,8 +173,8 @@ const handleSendText = (ip: string) => { try { const peer = await GetPeerByIP(ip); if (!peer) return; - await SendText(peer, ip, textContent.value); activeKey.value = "transfers"; + await SendText(peer, ip, textContent.value); } catch (e: any) { console.error(e); alert("Failed to send text: " + e); @@ -185,8 +191,8 @@ const handleSendClipboard = async (ip: string) => { } const peer = await GetPeerByIP(ip); if (!peer) return; - await SendText(peer, ip, text); activeKey.value = "transfers"; + await SendText(peer, ip, text); }; const removeTransfer = (id: string) => { diff --git a/frontend/src/components/TransferItem.vue b/frontend/src/components/TransferItem.vue index 5e3b3b0..db83bf6 100644 --- a/frontend/src/components/TransferItem.vue +++ b/frontend/src/components/TransferItem.vue @@ -23,7 +23,10 @@ import { } from "@fortawesome/free-solid-svg-icons"; import { Transfer } from "../../bindings/mesh-drop/internal/transfer"; -import { ResolvePendingRequest } from "../../bindings/mesh-drop/internal/transfer/service"; +import { + ResolvePendingRequest, + CancelTransfer, +} from "../../bindings/mesh-drop/internal/transfer/service"; import { Dialogs, Clipboard } from "@wailsio/runtime"; import { useDialog } from "naive-ui"; @@ -106,6 +109,27 @@ const handleOpen = async () => { }), }); }; + +const canCancel = computed(() => { + if ( + props.transfer.status === "completed" || + props.transfer.status === "error" || + props.transfer.status === "canceled" || + props.transfer.status === "rejected" + ) { + return false; + } + if (props.transfer.type === "send") { + return true; + } else if (props.transfer.type === "receive") { + // 接收端在 pending 状态只能拒绝不能取消 + if (props.transfer.status === "pending") { + return false; + } + return true; + } + return false; +});