add: settings page

This commit is contained in:
2026-02-05 00:00:29 +08:00
parent f7a881358f
commit e862f8deec
18 changed files with 345 additions and 121 deletions

View File

@@ -5,6 +5,22 @@
// @ts-ignore: Unused imports
import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime";
export function GetAutoAccept(): $CancellablePromise<boolean> {
return $Call.ByID(2605668438);
}
export function GetHostName(): $CancellablePromise<string> {
return $Call.ByID(972342140);
}
export function GetID(): $CancellablePromise<string> {
return $Call.ByID(4240411568);
}
export function GetSaveHistory(): $CancellablePromise<boolean> {
return $Call.ByID(2178923392);
}
export function GetSavePath(): $CancellablePromise<string> {
return $Call.ByID(4081533263);
}
@@ -16,6 +32,18 @@ export function Save(): $CancellablePromise<void> {
return $Call.ByID(3089450934);
}
export function SetAutoAccept(autoAccept: boolean): $CancellablePromise<void> {
return $Call.ByID(3371961138, autoAccept);
}
export function SetHostName(hostName: string): $CancellablePromise<void> {
return $Call.ByID(1580131496, hostName);
}
export function SetSaveHistory(saveHistory: boolean): $CancellablePromise<void> {
return $Call.ByID(3779587628, saveHistory);
}
/**
* SetSavePath 修改配置
*/

View File

@@ -46,11 +46,6 @@ export class Peer {
* Port 是文件传输服务的监听端口。
*/
"port": number;
/**
* IsOnline 标记该端点当前是否活跃 (UI 渲染用)。
*/
"is_online": boolean;
"os": OS;
/** Creates a new Peer instance. */
@@ -67,9 +62,6 @@ export class Peer {
if (!("port" in $$source)) {
this["port"] = 0;
}
if (!("is_online" in $$source)) {
this["is_online"] = false;
}
if (!("os" in $$source)) {
this["os"] = OS.$zero;
}

View File

@@ -13,10 +13,6 @@ export function GetID(): $CancellablePromise<string> {
return $Call.ByID(1539451205);
}
export function GetName(): $CancellablePromise<string> {
return $Call.ByID(1578367131);
}
export function GetPeerByIP(ip: string): $CancellablePromise<$models.Peer | null> {
return $Call.ByID(1626825408, ip).then(($result: any) => {
return $$createType1($result);

View File

@@ -45,6 +45,10 @@ export function GetTransferList(): $CancellablePromise<($models.Transfer | null)
});
}
export function LoadHistory(): $CancellablePromise<void> {
return $Call.ByID(2987999795);
}
export function NotifyTransferListUpdate(): $CancellablePromise<void> {
return $Call.ByID(1220032142);
}
@@ -57,6 +61,10 @@ export function ResolvePendingRequest(id: string, accept: boolean, savePath: str
return $Call.ByID(207902967, id, accept, savePath);
}
export function SaveHistory(): $CancellablePromise<void> {
return $Call.ByID(713135400);
}
export function SendFile(target: discovery$0.Peer | null, targetIP: string, filePath: string): $CancellablePromise<void> {
return $Call.ByID(2954589433, target, targetIP, filePath);
}

View File

@@ -8,9 +8,4 @@ import MainLayout from "./components/MainLayout.vue";
</v-app>
</template>
<style>
body,
#app {
font-family: "Noto Sans", "Roboto", "Segoe UI", sans-serif !important;
}
</style>
<style></style>

View File

@@ -7,11 +7,22 @@ import { Transfer } from "../../bindings/mesh-drop/internal/transfer";
import { GetPeers } from "../../bindings/mesh-drop/internal/discovery/service";
import { Events } from "@wailsio/runtime";
import { GetTransferList } from "../../bindings/mesh-drop/internal/transfer/service";
import {
GetSavePath,
SetSavePath,
GetHostName,
SetHostName,
GetAutoAccept,
SetAutoAccept,
GetSaveHistory,
SetSaveHistory,
} from "../../bindings/mesh-drop/internal/config/config";
import { Dialogs } from "@wailsio/runtime";
const peers = ref<Peer[]>([]);
const transferList = ref<Transfer[]>([]);
const activeKey = ref("discover");
const drawer = ref(true); // Control drawer visibility
const drawer = ref(true);
const isMobile = ref(false);
// 监听窗口大小变化更新 isMobile
@@ -26,6 +37,12 @@ onMounted(async () => {
if (isMobile.value) {
drawer.value = false;
}
// 加载配置
savePath.value = await GetSavePath();
hostName.value = await GetHostName();
autoAccept.value = await GetAutoAccept();
saveHistory.value = await GetSaveHistory();
});
const checkMobile = () => {
@@ -73,8 +90,34 @@ const menuItems = computed(() => [
icon: "mdi-inbox",
badge: pendingCount.value > 0 ? pendingCount.value : null,
},
{
title: "Settings",
value: "settings",
icon: "mdi-cog",
},
]);
// --- 设置 ---
const savePath = ref("");
const changeSavePath = async () => {
const opts: Dialogs.OpenFileDialogOptions = {
Title: "Select Save Path",
CanChooseDirectories: true,
CanChooseFiles: false,
AllowsMultipleSelection: false,
};
const path = await Dialogs.OpenFile(opts);
if (path && typeof path === "string") {
await SetSavePath(path);
savePath.value = path;
}
};
const hostName = ref("");
const autoAccept = ref(false);
const saveHistory = ref(false);
// --- 操作 ---
const handleMenuClick = (key: string) => {
@@ -87,17 +130,17 @@ const handleMenuClick = (key: string) => {
<template>
<v-layout>
<!-- App Bar for Mobile -->
<!-- 小屏幕抽屉 -->
<v-app-bar v-if="isMobile" border flat>
<v-toolbar-title class="text-primary font-weight-bold"
>Mesh Drop</v-toolbar-title
>
<template v-slot:append>
<template #append>
<v-btn icon="mdi-menu" @click="drawer = !drawer"></v-btn>
</template>
</v-app-bar>
<!-- Navigation Drawer -->
<!-- 导航抽屉 -->
<v-navigation-drawer v-model="drawer" :permanent="!isMobile">
<div class="pa-4" v-if="!isMobile">
<div class="text-h6 text-primary font-weight-bold">Mesh Drop</div>
@@ -113,7 +156,7 @@ const handleMenuClick = (key: string) => {
rounded="xl"
color="primary"
>
<template v-slot:prepend>
<template #prepend>
<v-icon :icon="item.icon"></v-icon>
</template>
@@ -131,10 +174,10 @@ const handleMenuClick = (key: string) => {
</v-list>
</v-navigation-drawer>
<!-- Main Content -->
<!-- 主内容 -->
<v-main>
<v-container fluid class="pa-4">
<!-- Discover View -->
<!-- 发现视图 -->
<div v-show="activeKey === 'discover'">
<div v-if="peers.length > 0" class="peer-grid">
<div v-for="peer in peers" :key="peer.id">
@@ -160,7 +203,7 @@ const handleMenuClick = (key: string) => {
</div>
</div>
<!-- Transfers View -->
<!-- 传输视图 -->
<div v-show="activeKey === 'transfers'">
<div v-if="transferList.length > 0">
<TransferItem
@@ -177,6 +220,69 @@ const handleMenuClick = (key: string) => {
<div class="text-grey">No transfers yet</div>
</div>
</div>
<!-- 设置视图 -->
<div v-show="activeKey === 'settings'">
<v-list lines="one" bg-color="transparent">
<v-list-item title="Save Path" :subtitle="savePath">
<template #prepend>
<v-icon icon="mdi-folder-download"></v-icon>
</template>
<template #append>
<v-btn
variant="text"
color="primary"
@click="changeSavePath"
prepend-icon="mdi-pencil"
>
Change
</v-btn>
</template>
</v-list-item>
<v-list-item title="HostName">
<template #prepend>
<v-icon icon="mdi-laptop"></v-icon>
</template>
<template #append
><v-text-field
clearable
variant="underlined"
v-model="hostName"
width="200"
@update:modelValue="SetHostName"
></v-text-field
></template>
</v-list-item>
<v-list-item title="Save History">
<template #prepend>
<v-icon icon="mdi-history"></v-icon>
</template>
<template #append
><v-switch
v-model="saveHistory"
color="primary"
inset
hide-details
@update:modelValue="SetSaveHistory(saveHistory)"
></v-switch
></template>
</v-list-item>
<v-list-item title="Auto Accept">
<template #prepend>
<v-icon icon="mdi-content-save"></v-icon>
</template>
<template #append
><v-switch
v-model="autoAccept"
color="primary"
inset
hide-details
@update:modelValue="SetAutoAccept(autoAccept)"
></v-switch
></template>
</v-list-item>
</v-list>
</div>
</v-container>
</v-main>
</v-layout>

View File

@@ -208,14 +208,14 @@ const handleSendFiles = () => {
<template>
<v-card hover link class="peer-card pa-2">
<template v-slot:title>
<template #title>
<div class="d-flex align-center">
<v-icon :icon="osIcon" size="24" class="mr-2"></v-icon>
<span class="text-subtitle-1 font-weight-bold">{{ peer.name }}</span>
</div>
</template>
<template v-slot:text>
<template #text>
<div class="d-flex align-center flex-wrap ga-2 mt-2">
<v-icon icon="mdi-web" size="20" class="text-medium-emphasis"></v-icon>
@@ -241,9 +241,9 @@ const handleSendFiles = () => {
</div>
</template>
<template v-slot:actions>
<template #actions>
<v-menu>
<template v-slot:activator="{ props }">
<template #activator="{ props }">
<v-btn
v-bind="props"
block
@@ -252,10 +252,10 @@ const handleSendFiles = () => {
:disabled="ips.length === 0"
append-icon="mdi-chevron-down"
>
<template v-slot:prepend>
<template #prepend>
<v-icon icon="mdi-send"></v-icon>
</template>
Send...
Send
</v-btn>
</template>
<v-list>
@@ -265,7 +265,7 @@ const handleSendFiles = () => {
:value="item.value"
@click="handleAction(item.value)"
>
<template v-slot:prepend>
<template #prepend>
<v-icon :icon="item.icon"></v-icon>
</template>
<v-list-item-title>{{ item.title }}</v-list-item-title>
@@ -312,7 +312,7 @@ const handleSendFiles = () => {
:subtitle="file.path"
lines="two"
>
<template v-slot:append>
<template #append>
<v-btn
icon="mdi-delete"
size="small"

View File

@@ -261,29 +261,16 @@ const canAccept = computed(() => {
<v-btn
v-if="canAccept"
color="success"
icon="mdi-check"
icon="mdi-content-save"
@click="acceptTransfer"
></v-btn>
<v-menu v-if="canAccept && props.transfer.content_type !== 'text'">
<template v-slot:activator="{ props }">
<v-btn
color="success"
icon="mdi-chevron-down"
v-bind="props"
></v-btn>
</template>
<v-list>
<v-list-item
v-for="(item, index) in dropdownItems"
:key="index"
:value="item.value"
@click="handleSelect(item.value)"
>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn
v-if="canAccept"
color="success"
icon="mdi-folder-arrow-right"
@click="acceptToFolder"
></v-btn>
<v-btn
v-if="canAccept"