fix(All): runtime error

This commit is contained in:
AkiChase 2025-03-10 16:02:07 +08:00
parent bac2f316b2
commit db160c86c8
19 changed files with 1645 additions and 510 deletions

View File

@ -12,27 +12,32 @@
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.1.1", "@tauri-apps/api": "2.1.1",
"@tauri-apps/cli": "^2.3.1",
"@tauri-apps/plugin-clipboard-manager": "~2.2.1", "@tauri-apps/plugin-clipboard-manager": "~2.2.1",
"@tauri-apps/plugin-http": "~2", "@tauri-apps/plugin-http": "~2",
"@tauri-apps/plugin-os": "~2", "@tauri-apps/plugin-os": "~2",
"@tauri-apps/plugin-process": "~2", "@tauri-apps/plugin-process": "~2",
"@tauri-apps/plugin-shell": "~2", "@tauri-apps/plugin-shell": "~2",
"@tauri-apps/plugin-store": "~2", "@tauri-apps/plugin-store": "~2",
"naive-ui": "^2.41.0",
"pinia": "^3.0.1", "pinia": "^3.0.1",
"vue": "^3.3.4", "vue": "^3.5.13",
"vue-i18n": "10", "vue-i18n": "10",
"vue-router": "4" "vue-router": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": ">=2.0.0-beta.0", "@tsconfig/node22": "^22.0.0",
"@types/node": "^22.13.9",
"@vicons/fluent": "^0.12.0", "@vicons/fluent": "^0.12.0",
"@vicons/ionicons5": "^0.12.0", "@vicons/ionicons5": "^0.12.0",
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.2.1",
"naive-ui": "^2.38.1", "@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^7.0.2",
"sass": "^1.85.1", "sass": "^1.85.1",
"sass-loader": "^16.0.5", "sass-loader": "^16.0.5",
"typescript": "^5.0.2", "typescript": "~5.8.0",
"vite": "^5.0.0", "vite": "^6.2.1",
"vue-tsc": "^1.8.5" "vite-plugin-vue-devtools": "^7.7.2",
"vue-tsc": "^2.2.8"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -18,27 +18,23 @@ onMounted(async () => {
</script> </script>
<template> <template>
<NConfigProvider :theme="darkTheme" class="container"> <NConfigProvider :theme="darkTheme" class="root">
<NMessageProvider> <NMessageProvider>
<Header />
<NDialogProvider> <NDialogProvider>
<Header />
<RouterView v-slot="{ Component }"> <RouterView v-slot="{ Component }">
<KeepAlive> <KeepAlive>
<Suspense> <component :is="Component" />
<div>
<component :is="Component" />
</div>
</Suspense>
</KeepAlive> </KeepAlive>
</RouterView> </RouterView>
<Sidebar />
</NDialogProvider> </NDialogProvider>
<Sidebar />
</NMessageProvider> </NMessageProvider>
</NConfigProvider> </NConfigProvider>
</template> </template>
<style> <style>
.container { .root {
background-color: transparent; background-color: transparent;
height: 100%; height: 100%;
display: grid; display: grid;

View File

@ -75,7 +75,6 @@ onMounted(async () => {
if (payload.clipboard === lastClipboard) break; if (payload.clipboard === lastClipboard) break;
lastClipboard = payload.clipboard; lastClipboard = payload.clipboard;
writeText(payload.clipboard); writeText(payload.clipboard);
console.log(payload);
break; break;
case "ClipboardSetAck": case "ClipboardSetAck":
break; break;
@ -101,7 +100,7 @@ onMounted(async () => {
} }
break; break;
default: default:
console.log("Unknown reply", payload); console.warn("Unknown reply", payload);
break; break;
} }
} catch (e) { } catch (e) {
@ -360,119 +359,127 @@ function closeWS() {
</script> </script>
<template> <template>
<NScrollbar> <div class="container">
<div class="device"> <NScrollbar>
<NSpin :show="store.showLoadingRef"> <div class="device">
<NH4 prefix="bar">{{ $t("pages.Device.localPort") }}</NH4> <NSpin :show="store.showLoadingRef">
<NInputNumber <NH4 prefix="bar">{{ $t("pages.Device.localPort") }}</NH4>
v-model:value="port" <NInputNumber
:show-button="false" v-model:value="port"
:min="16384" :show-button="false"
:max="49151" :min="16384"
:placeholder="$t('pages.Device.localPortPlaceholder')" :max="49151"
style="max-width: 300px" :placeholder="$t('pages.Device.localPortPlaceholder')"
/> style="max-width: 300px"
<NH4 prefix="bar">{{ $t("pages.Device.wireless") }}</NH4>
<NInputGroup style="max-width: 300px">
<NInput
v-model:value="wireless_address"
clearable
:placeholder="$t('pages.Device.wirelessPlaceholder')"
/> />
<NButton type="primary" @click="connectDevice">{{ <NH4 prefix="bar">{{ $t("pages.Device.wireless") }}</NH4>
$t("pages.Device.connect") <NInputGroup style="max-width: 300px">
}}</NButton> <NInput
</NInputGroup> v-model:value="wireless_address"
<NH4 prefix="bar">{{ $t("pages.Device.externalControl") }}</NH4> clearable
<NInputGroup style="max-width: 300px"> :placeholder="$t('pages.Device.wirelessPlaceholder')"
<NInput />
v-model:value="ws_address" <NButton type="primary" @click="connectDevice">{{
clearable $t("pages.Device.connect")
:placeholder="$t('pages.Device.wsAddress')" }}</NButton>
:disabled="store.externalControlled" </NInputGroup>
/> <NH4 prefix="bar">{{ $t("pages.Device.externalControl") }}</NH4>
<NButton <NInputGroup style="max-width: 300px">
v-if="store.externalControlled" <NInput
type="error" v-model:value="ws_address"
@click="closeWS" clearable
>{{ $t("pages.Device.wsClose") }}</NButton :placeholder="$t('pages.Device.wsAddress')"
> :disabled="store.externalControlled"
<NButton v-else type="primary" @click="connectWS">{{ />
$t("pages.Device.wsConnect") <NButton
}}</NButton> v-if="store.externalControlled"
</NInputGroup> type="error"
<NH4 prefix="bar">{{ $t("pages.Device.controledDevice") }}</NH4> @click="closeWS"
<div class="controled-device-list"> >{{ $t("pages.Device.wsClose") }}</NButton
<NEmpty >
size="small" <NButton v-else type="primary" @click="connectWS">{{
:description="$t('pages.Device.noControledDevice')" $t("pages.Device.wsConnect")
v-if="!store.controledDevice" }}</NButton>
/> </NInputGroup>
<div class="controled-device" v-if="store.controledDevice"> <NH4 prefix="bar">{{ $t("pages.Device.controledDevice") }}</NH4>
<div> <div class="controled-device-list">
{{ store.controledDevice.deviceName }} ({{ <NEmpty
store.controledDevice.deviceID size="small"
}}) :description="$t('pages.Device.noControledDevice')"
</div> v-if="!store.controledDevice"
<div class="device-op"> />
<NTooltip trigger="hover"> <div class="controled-device" v-if="store.controledDevice">
<template #trigger> <div>
<NButton quaternary circle type="info"> {{ store.controledDevice.deviceName }} ({{
<template #icon> store.controledDevice.deviceID
<NIcon><InformationCircle /></NIcon> }})
</template> </div>
</NButton> <div class="device-op">
</template> <NTooltip trigger="hover">
scid: {{ store.controledDevice.scid }} <template #trigger>
</NTooltip> <NButton quaternary circle type="info">
<NButton quaternary circle type="error" @click="shutdownSC()"> <template #icon>
<template #icon> <NIcon><InformationCircle /></NIcon>
<NIcon><CloseCircle /></NIcon> </template>
</template> </NButton>
</NButton> </template>
scid: {{ store.controledDevice.scid }}
</NTooltip>
<NButton quaternary circle type="error" @click="shutdownSC()">
<template #icon>
<NIcon><CloseCircle /></NIcon>
</template>
</NButton>
</div>
</div> </div>
</div> </div>
</div> <NFlex justify="space-between" align="center">
<NFlex justify="space-between" align="center"> <NH4 style="margin: 20px 0" prefix="bar">{{
<NH4 style="margin: 20px 0" prefix="bar">{{ $t("pages.Device.availableDevice")
$t("pages.Device.availableDevice") }}</NH4>
}}</NH4> <NButton
<NButton tertiary
tertiary circle
circle type="primary"
type="primary" @click="refreshDevices"
@click="refreshDevices" style="margin-right: 20px"
style="margin-right: 20px" >
> <template #icon>
<template #icon> <NIcon><Refresh /></NIcon>
<NIcon><Refresh /></NIcon> </template>
</template> </NButton>
</NButton> </NFlex>
</NFlex> <NDataTable
<NDataTable max-height="120"
max-height="120" :columns="tableCols"
:columns="tableCols" :data="availableDevice"
:data="availableDevice" :row-props="tableRowProps"
:row-props="tableRowProps" :pagination="false"
:pagination="false" :bordered="false"
:bordered="false" />
/> <NDropdown
<NDropdown placement="bottom-start"
placement="bottom-start" trigger="manual"
trigger="manual" :x="menuX"
:x="menuX" :y="menuY"
:y="menuY" :options="menuOptions"
:options="menuOptions" :show="showMenu"
:show="showMenu" :on-clickoutside="onMenuClickoutside"
:on-clickoutside="onMenuClickoutside" @select="onMenuSelect"
@select="onMenuSelect" />
/> </NSpin>
</NSpin> </div>
</div> </NScrollbar>
</NScrollbar> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@use "./../css/common.scss";
.container {
@include common.contentContainer;
}
.device { .device {
color: var(--light-color); color: var(--light-color);
background-color: var(--bg-color); background-color: var(--bg-color);

View File

@ -19,7 +19,6 @@ import { getCurrentWindow, PhysicalSize } from "@tauri-apps/api/window";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { checkAdbAvailable } from "../invoke"; import { checkAdbAvailable } from "../invoke";
import { loadPersistentStorage } from "../storeLoader"; import { loadPersistentStorage } from "../storeLoader";
import { load } from "@tauri-apps/plugin-store";
const { t } = useI18n(); const { t } = useI18n();
const store = useGlobalStore(); const store = useGlobalStore();
@ -60,7 +59,7 @@ onActivated(async () => {
onMounted(async () => { onMounted(async () => {
store.screenStreamClientId = genClientId(); store.screenStreamClientId = genClientId();
await loadLocalStore(); loadPersistentStorage(store, t);
store.checkUpdate = checkUpdate; store.checkUpdate = checkUpdate;
if (store.checkUpdateAtStart) checkUpdate(); if (store.checkUpdateAtStart) checkUpdate();
store.checkAdb = checkAdb; store.checkAdb = checkAdb;
@ -102,11 +101,6 @@ function genClientId() {
return result; return result;
} }
async function loadLocalStore() {
const localStore = await load("store.json");
await loadPersistentStorage(localStore, store, t);
}
async function cleanAfterimage() { async function cleanAfterimage() {
// TODO fix oldSize making window large // TODO fix oldSize making window large
const appWindow = getCurrentWindow(); const appWindow = getCurrentWindow();
@ -181,71 +175,81 @@ async function checkUpdate() {
</script> </script>
<template> <template>
<div v-show="!store.controledDevice" class="notice"> <div class="content-container">
<div class="content"> <div v-show="!store.controledDevice" class="notice">
<NDialog <div class="content">
:closable="false" <NDialog
:title="$t('pages.Mask.noControledDevice.title')" :closable="false"
:content="$t('pages.Mask.noControledDevice.content')" :title="$t('pages.Mask.noControledDevice.title')"
:positive-text="$t('pages.Mask.noControledDevice.positiveText')" :content="$t('pages.Mask.noControledDevice.content')"
type="warning" :positive-text="$t('pages.Mask.noControledDevice.positiveText')"
@positive-click="toStartServer" type="warning"
@positive-click="toStartServer"
/>
</div>
</div>
<template v-if="store.keyMappingConfigList.length">
<div @contextmenu.prevent class="mask" id="maskElement"></div>
<ScreenStream
:cid="store.screenStreamClientId"
v-if="
curPageActive && store.controledDevice && store.screenStream.enable
"
/> />
</div> <div
</div> v-if="store.maskButton.show"
<template v-if="store.keyMappingConfigList.length"> :style="'--transparency: ' + store.maskButton.transparency"
<div @contextmenu.prevent class="mask" id="maskElement"></div> class="button-layer"
<ScreenStream
:cid="store.screenStreamClientId"
v-if="curPageActive && store.controledDevice && store.screenStream.enable"
/>
<div
v-if="store.maskButton.show"
:style="'--transparency: ' + store.maskButton.transparency"
class="button-layer"
>
<!-- <div style="position: absolute;height: 100%;width: 1px;background-color: red;left: 50%;"></div>
<div style="position: absolute;width: 100%;height: 1px;background-color: red;top: 56.6%;"></div> -->
<template
v-for="button in store.keyMappingConfigList[store.curKeyMappingIndex]
.list"
> >
<div <!-- <div style="position: absolute;height: 100%;width: 1px;background-color: red;left: 50%;"></div>
v-if="button.type === 'SteeringWheel'" <div style="position: absolute;width: 100%;height: 1px;background-color: red;top: 56.6%;"></div> -->
class="mask-steering-wheel" <template
:style="{ v-for="button in store.keyMappingConfigList[store.curKeyMappingIndex]
left: button.posX - 75 + 'px', .list"
top: button.posY - 75 + 'px',
}"
> >
<div class="wheel-container"> <div
<i /> v-if="button.type === 'SteeringWheel'"
<span>{{ (button as KeySteeringWheel).key.up }}</span> class="mask-steering-wheel"
<i /> :style="{
<span>{{ (button as KeySteeringWheel).key.left }}</span> left: button.posX - 75 + 'px',
<i /> top: button.posY - 75 + 'px',
<span>{{ (button as KeySteeringWheel).key.right }}</span> }"
<i /> >
<span>{{ (button as KeySteeringWheel).key.down }}</span> <div class="wheel-container">
<i /> <i />
<span>{{ (button as KeySteeringWheel).key.up }}</span>
<i />
<span>{{ (button as KeySteeringWheel).key.left }}</span>
<i />
<span>{{ (button as KeySteeringWheel).key.right }}</span>
<i />
<span>{{ (button as KeySteeringWheel).key.down }}</span>
<i />
</div>
</div> </div>
</div> <div
<div v-else
v-else class="mask-button"
class="mask-button" :style="{
:style="{ left: button.posX + 'px',
left: button.posX + 'px', top: button.posY - 14 + 'px',
top: button.posY - 14 + 'px', }"
}" >
> {{ button.type === "Fire" ? "Fire" : button.key }}
{{ button.type === "Fire" ? "Fire" : button.key }} </div>
</div> </template>
</template> </div>
</div> </template>
</template> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@use "../css/common.scss";
.content-container {
@include common.contentContainer;
}
.mask { .mask {
background-color: transparent; background-color: transparent;
overflow: hidden; overflow: hidden;

View File

@ -335,67 +335,78 @@ onBeforeRouteLeave(() => {
</script> </script>
<template> <template>
<ScreenStream <div class="content-container">
:cid="store.screenStreamClientId" <ScreenStream
v-if="curPageActive && store.controledDevice && store.screenStream.enable" :cid="store.screenStreamClientId"
/> v-if="curPageActive && store.controledDevice && store.screenStream.enable"
<div
v-if="store.keyMappingConfigList.length"
id="keyboardElement"
class="keyboard"
@mousedown="handleClick"
@contextmenu.prevent
>
<KeySetting />
<KeyInfo />
<NDropdown
:options="addButtonOptions"
:show="keyboardStore.showButtonAddFlag"
placement="bottom-start"
trigger="manual"
:x="addButtonPos.x"
:y="addButtonPos.y"
@clickoutside="keyboardStore.showButtonAddFlag = false"
@select="onAddButtonSelect"
/> />
<template v-for="(_, index) in store.editKeyMappingList"> <div
<KeySteeringWheel v-if="store.keyMappingConfigList.length"
v-if="store.editKeyMappingList[index].type === 'SteeringWheel'" id="keyboardElement"
:index="index" class="keyboard"
@mousedown="handleClick"
@contextmenu.prevent
>
<KeySetting />
<KeyInfo />
<NDropdown
:options="addButtonOptions"
:show="keyboardStore.showButtonAddFlag"
placement="bottom-start"
trigger="manual"
:x="addButtonPos.x"
:y="addButtonPos.y"
@clickoutside="keyboardStore.showButtonAddFlag = false"
@select="onAddButtonSelect"
/> />
<KeySkill <template v-for="(_, index) in store.editKeyMappingList">
v-else-if=" <KeySteeringWheel
store.editKeyMappingList[index].type === 'DirectionalSkill' || v-if="store.editKeyMappingList[index].type === 'SteeringWheel'"
store.editKeyMappingList[index].type === 'DirectionlessSkill' || :index="index"
store.editKeyMappingList[index].type === 'TriggerWhenPressedSkill' || />
store.editKeyMappingList[index].type === <KeySkill
'TriggerWhenDoublePressedSkill' v-else-if="
" store.editKeyMappingList[index].type === 'DirectionalSkill' ||
:index="index" store.editKeyMappingList[index].type === 'DirectionlessSkill' ||
/> store.editKeyMappingList[index].type ===
<KeyObservation 'TriggerWhenPressedSkill' ||
v-else-if="store.editKeyMappingList[index].type === 'Observation'" store.editKeyMappingList[index].type ===
:index="index" 'TriggerWhenDoublePressedSkill'
/> "
<KeySwipe :index="index"
v-else-if="store.editKeyMappingList[index].type === 'Swipe'" />
:index="index" <KeyObservation
/> v-else-if="store.editKeyMappingList[index].type === 'Observation'"
<KeySight :index="index"
v-else-if="store.editKeyMappingList[index].type === 'Sight'" />
:index="index" <KeySwipe
/> v-else-if="store.editKeyMappingList[index].type === 'Swipe'"
<KeyFire :index="index"
v-else-if="store.editKeyMappingList[index].type === 'Fire'" />
:index="index" <KeySight
/> v-else-if="store.editKeyMappingList[index].type === 'Sight'"
<KeyCommon v-else :index="index" /> :index="index"
</template> />
<KeyFire
v-else-if="store.editKeyMappingList[index].type === 'Fire'"
:index="index"
/>
<KeyCommon v-else :index="index" />
</template>
</div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@use "../../css/common.scss";
.content-container {
@include common.contentContainer;
}
.keyboard { .keyboard {
width: 100%;
height: 100%;
color: var(--light-color); color: var(--light-color);
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
overflow: hidden; overflow: hidden;

View File

@ -19,12 +19,11 @@ import { KeyMappingConfig } from "../../keyMappingConfig";
import { useKeyboardStore } from "../../store/keyboard"; import { useKeyboardStore } from "../../store/keyboard";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { writeText } from "@tauri-apps/plugin-clipboard-manager"; import { writeText } from "@tauri-apps/plugin-clipboard-manager";
import { load } from "@tauri-apps/plugin-store"; import { LocalStore } from "../../store/localStore";
const { t } = useI18n(); const { t } = useI18n();
const store = useGlobalStore(); const store = useGlobalStore();
const keyboardStore = useKeyboardStore(); const keyboardStore = useKeyboardStore();
const localStore = await load("store.json");
const message = useMessage(); const message = useMessage();
const showImportModal = ref(false); const showImportModal = ref(false);
@ -52,12 +51,12 @@ const keySettingPos = ref({ x: 100, y: 100 });
onMounted(async () => { onMounted(async () => {
// loading keySettingPos from local store // loading keySettingPos from local store
let storedPos = await localStore.get<{ x: number; y: number }>( let storedPos = await LocalStore.get<{ x: number; y: number }>(
"keySettingPos" "keySettingPos"
); );
if (storedPos === undefined) { if (storedPos === undefined) {
await localStore.set("keySettingPos", keySettingPos.value); await LocalStore.set("keySettingPos", keySettingPos.value);
storedPos = { x: 100, y: 100 }; storedPos = { x: 100, y: 100 };
} }
// apply keySettingPos // apply keySettingPos
@ -119,7 +118,7 @@ function dragHandler(downEvent: MouseEvent) {
if (moveFlag) { if (moveFlag) {
// move up // move up
target.style.setProperty("cursor", "pointer"); target.style.setProperty("cursor", "pointer");
localStore.set("keySettingPos", keySettingPos.value); LocalStore.set("keySettingPos", keySettingPos.value);
} else { } else {
// click up // click up
if (keyboardStore.editSwipePointsFlag) { if (keyboardStore.editSwipePointsFlag) {
@ -152,7 +151,7 @@ function importKeyMappingConfig() {
store.keyMappingConfigList.push(keyMappingConfig); store.keyMappingConfigList.push(keyMappingConfig);
store.setKeyMappingIndex(store.keyMappingConfigList.length - 1); store.setKeyMappingIndex(store.keyMappingConfigList.length - 1);
showImportModal.value = false; showImportModal.value = false;
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.importSuccess")); message.success(t("pages.KeyBoard.KeySetting.importSuccess"));
} }
@ -172,7 +171,7 @@ async function importDefaultKeyMappingConfig() {
return; return;
} }
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.importDefaultSuccess", [count])); message.success(t("pages.KeyBoard.KeySetting.importDefaultSuccess", [count]));
} }
@ -195,7 +194,7 @@ function createKeyMappingConfig() {
}; };
store.keyMappingConfigList.push(newConfig); store.keyMappingConfigList.push(newConfig);
store.setKeyMappingIndex(store.keyMappingConfigList.length - 1); store.setKeyMappingIndex(store.keyMappingConfigList.length - 1);
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.newConfigSuccess")); message.success(t("pages.KeyBoard.KeySetting.newConfigSuccess"));
} }
@ -218,7 +217,7 @@ function copyCurKeyMappingConfig() {
keyboardStore.activeButtonIndex = -1; keyboardStore.activeButtonIndex = -1;
keyboardStore.activeSteeringWheelButtonKeyIndex = -1; keyboardStore.activeSteeringWheelButtonKeyIndex = -1;
store.setKeyMappingIndex(store.keyMappingConfigList.length - 1); store.setKeyMappingIndex(store.keyMappingConfigList.length - 1);
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.copyConfigSuccess", [newTitle])); message.success(t("pages.KeyBoard.KeySetting.copyConfigSuccess", [newTitle]));
} }
@ -237,7 +236,7 @@ function delCurKeyMappingConfig() {
store.setKeyMappingIndex( store.setKeyMappingIndex(
store.curKeyMappingIndex > 0 ? store.curKeyMappingIndex - 1 : 0 store.curKeyMappingIndex > 0 ? store.curKeyMappingIndex - 1 : 0
); );
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.delSuccess", [title])); message.success(t("pages.KeyBoard.KeySetting.delSuccess", [title]));
} }
@ -246,7 +245,7 @@ function renameKeyMappingConfig() {
showRenameModal.value = false; showRenameModal.value = false;
if (newTitle !== "") { if (newTitle !== "") {
store.keyMappingConfigList[store.curKeyMappingIndex].title = newTitle; store.keyMappingConfigList[store.curKeyMappingIndex].title = newTitle;
localStore.set("keyMappingConfigList", store.keyMappingConfigList); LocalStore.set("keyMappingConfigList", store.keyMappingConfigList);
message.success(t("pages.KeyBoard.KeySetting.renameSuccess", [newTitle])); message.success(t("pages.KeyBoard.KeySetting.renameSuccess", [newTitle]));
} else { } else {
message.error(t("pages.KeyBoard.KeySetting.renameEmpty")); message.error(t("pages.KeyBoard.KeySetting.renameEmpty"));

View File

@ -141,7 +141,6 @@ function swipePointDragHandlue(downEvent: MouseEvent, index: number) {
function swipeTrackClickHandler(event: MouseEvent) { function swipeTrackClickHandler(event: MouseEvent) {
if (event.button !== 0) return; if (event.button !== 0) return;
console.log(event.target, event.currentTarget);
if (event.target !== event.currentTarget) return; if (event.target !== event.currentTarget) return;
keyMapping.value.pos.push({ x: event.clientX - 70, y: event.clientY - 30 }); keyMapping.value.pos.push({ x: event.clientX - 70, y: event.clientY - 30 });
} }

View File

@ -5,10 +5,9 @@ import { open } from "@tauri-apps/plugin-shell";
import { getVersion } from "@tauri-apps/api/app"; import { getVersion } from "@tauri-apps/api/app";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { useGlobalStore } from "../../store/global"; import { useGlobalStore } from "../../store/global";
import { load } from "@tauri-apps/plugin-store"; import { LocalStore } from "../../store/localStore";
const store = useGlobalStore(); const store = useGlobalStore();
const localStore = await load('store.json');
const appVersion = ref(""); const appVersion = ref("");
onMounted(async () => { onMounted(async () => {
@ -73,7 +72,7 @@ async function checkUpdate() {
<NCheckbox <NCheckbox
v-model:checked="store.checkUpdateAtStart" v-model:checked="store.checkUpdateAtStart"
@update:checked=" @update:checked="
localStore.set('checkUpdateAtStart', store.checkUpdateAtStart) LocalStore.set('checkUpdateAtStart', store.checkUpdateAtStart)
" "
>{{ $t("pages.Setting.About.checkUpdateOnStartup") }}</NCheckbox >{{ $t("pages.Setting.About.checkUpdateOnStartup") }}</NCheckbox
> >

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { load } from "@tauri-apps/plugin-store";
import { import {
NH4, NH4,
NButton, NButton,
@ -16,9 +15,9 @@ import i18n, { allLanguage } from "../../i18n";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { setAdbPath } from "../../invoke"; import { setAdbPath } from "../../invoke";
import { useGlobalStore } from "../../store/global"; import { useGlobalStore } from "../../store/global";
import { LocalStore } from "../../store/localStore";
const { t } = useI18n(); const { t } = useI18n();
const localStore = await load("store.json");
const store = useGlobalStore(); const store = useGlobalStore();
const message = useMessage(); const message = useMessage();
@ -34,14 +33,14 @@ const curLanguage = ref("en-US");
const adbPath = ref(""); const adbPath = ref("");
onMounted(async () => { onMounted(async () => {
curLanguage.value = (await localStore.get<string>("language")) ?? "en-US"; curLanguage.value = (await LocalStore.get<string>("language")) ?? "en-US";
adbPath.value = (await localStore.get<string>("adbPath")) ?? ""; adbPath.value = (await LocalStore.get<string>("adbPath")) ?? "";
}); });
function changeLanguage(language: "zh-CN" | "en-US") { function changeLanguage(language: "zh-CN" | "en-US") {
if (language === curLanguage.value) return; if (language === curLanguage.value) return;
curLanguage.value = language; curLanguage.value = language;
localStore.set("language", language); LocalStore.set("language", language);
i18n.global.locale = language; i18n.global.locale = language;
} }
@ -50,12 +49,12 @@ async function adjustAdbPath() {
await setAdbPath(adbPath.value); await setAdbPath(adbPath.value);
message.success(t("pages.Setting.Basic.adbPath.setSuccess")); message.success(t("pages.Setting.Basic.adbPath.setSuccess"));
await store.checkAdb(); await store.checkAdb();
adbPath.value = (await localStore.get<string>("adbPath")) ?? ""; adbPath.value = (await LocalStore.get<string>("adbPath")) ?? "";
store.hideLoading(); store.hideLoading();
} }
function changeClipboardSync() { function changeClipboardSync() {
localStore.set("clipboardSync", store.clipboardSync); LocalStore.set("clipboardSync", store.clipboardSync);
} }
</script> </script>

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { load } from "@tauri-apps/plugin-store";
import { Refresh, TrashBinOutline } from "@vicons/ionicons5"; import { Refresh, TrashBinOutline } from "@vicons/ionicons5";
import { import {
NH4, NH4,
@ -17,9 +16,9 @@ import {
import { relaunch } from "@tauri-apps/plugin-process"; import { relaunch } from "@tauri-apps/plugin-process";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { LocalStore } from "../../store/localStore";
const { t } = useI18n(); const { t } = useI18n();
const localStore = await load("store.json");
const dialog = useDialog(); const dialog = useDialog();
@ -33,7 +32,7 @@ onMounted(async () => {
}); });
async function refreshLocalData() { async function refreshLocalData() {
localStoreEntries.value = await localStore.entries(); localStoreEntries.value = await LocalStore.entries();
} }
function showLocalStore(index: number) { function showLocalStore(index: number) {
@ -54,7 +53,7 @@ function delLocalStore(key?: string) {
positiveText: t("pages.Setting.Data.delLocalStore.dialog.positiveText"), positiveText: t("pages.Setting.Data.delLocalStore.dialog.positiveText"),
negativeText: t("pages.Setting.Data.delLocalStore.dialog.negativeText"), negativeText: t("pages.Setting.Data.delLocalStore.dialog.negativeText"),
onPositiveClick: () => { onPositiveClick: () => {
localStore.delete(key); LocalStore.delete(key);
localStoreEntries.value.splice(curDataIndex, 1); localStoreEntries.value.splice(curDataIndex, 1);
showDataModal.value = false; showDataModal.value = false;
}, },
@ -66,7 +65,7 @@ function delLocalStore(key?: string) {
positiveText: t("pages.Setting.Data.delLocalStore.dialog.positiveText"), positiveText: t("pages.Setting.Data.delLocalStore.dialog.positiveText"),
negativeText: t("pages.Setting.Data.delLocalStore.dialog.negativeText"), negativeText: t("pages.Setting.Data.delLocalStore.dialog.negativeText"),
onPositiveClick: () => { onPositiveClick: () => {
localStore.clear(); LocalStore.clear();
relaunch(); relaunch();
}, },
}); });

View File

@ -24,18 +24,17 @@ import {
PhysicalSize, PhysicalSize,
getCurrentWindow, getCurrentWindow,
} from "@tauri-apps/api/window"; } from "@tauri-apps/api/window";
import { load } from "@tauri-apps/plugin-store";
import { SettingsOutline } from "@vicons/ionicons5"; import { SettingsOutline } from "@vicons/ionicons5";
import { UnlistenFn } from "@tauri-apps/api/event"; import { UnlistenFn } from "@tauri-apps/api/event";
import { useGlobalStore } from "../../store/global"; import { useGlobalStore } from "../../store/global";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { LocalStore } from "../../store/localStore";
let unlistenResize: UnlistenFn = () => {}; let unlistenResize: UnlistenFn = () => {};
let unlistenMove: UnlistenFn = () => {}; let unlistenMove: UnlistenFn = () => {};
let factor = 1; let factor = 1;
const { t } = useI18n(); const { t } = useI18n();
const localStore = await load("store.json");
const store = useGlobalStore(); const store = useGlobalStore();
const message = useMessage(); const message = useMessage();
const formRef = ref<FormInst | null>(null); const formRef = ref<FormInst | null>(null);
@ -105,7 +104,7 @@ function handleAdjustClick(e: MouseEvent) {
formRef.value?.validate((errors) => { formRef.value?.validate((errors) => {
if (!errors) { if (!errors) {
adjustMaskArea().then(() => { adjustMaskArea().then(() => {
localStore.set("maskArea", areaModel.value); LocalStore.set("maskArea", areaModel.value);
message.success(t("pages.Setting.Mask.areaSaved")); message.success(t("pages.Setting.Mask.areaSaved"));
}); });
} else { } else {
@ -140,7 +139,7 @@ onMounted(async () => {
const appWindow = getCurrentWindow(); const appWindow = getCurrentWindow();
factor = await appWindow.scaleFactor(); factor = await appWindow.scaleFactor();
let maskArea = await localStore.get<MaskArea>("maskArea"); let maskArea = await LocalStore.get<MaskArea>("maskArea");
if (maskArea !== undefined) { if (maskArea !== undefined) {
areaModel.value = maskArea; areaModel.value = maskArea;
} }
@ -172,13 +171,13 @@ onUnmounted(() => {
> >
<NCheckbox <NCheckbox
v-model:checked="store.maskButton.show" v-model:checked="store.maskButton.show"
@update:checked="localStore.set('maskButton', store.maskButton)" @update:checked="LocalStore.set('maskButton', store.maskButton)"
/> />
</NFormItem> </NFormItem>
<NFormItem :label="$t('pages.Setting.Mask.opacity')" label-placement="left"> <NFormItem :label="$t('pages.Setting.Mask.opacity')" label-placement="left">
<NSlider <NSlider
v-model:value="store.maskButton.transparency" v-model:value="store.maskButton.transparency"
@update:value="localStore.set('maskButton', store.maskButton)" @update:value="LocalStore.set('maskButton', store.maskButton)"
:min="0" :min="0"
:max="1" :max="1"
:step="0.01" :step="0.01"
@ -243,7 +242,7 @@ onUnmounted(() => {
> >
<NCheckbox <NCheckbox
v-model:checked="store.rotation.enable" v-model:checked="store.rotation.enable"
@update:checked="localStore.set('rotation', store.rotation)" @update:checked="LocalStore.set('rotation', store.rotation)"
/> />
</NFormItem> </NFormItem>
<NGrid :cols="2"> <NGrid :cols="2">
@ -253,7 +252,7 @@ onUnmounted(() => {
> >
<NInputNumber <NInputNumber
v-model:value="store.rotation.verticalLength" v-model:value="store.rotation.verticalLength"
@update:value="localStore.set('rotation', store.rotation)" @update:value="LocalStore.set('rotation', store.rotation)"
:placeholder="$t('pages.Setting.Mask.rotation.verticalLength')" :placeholder="$t('pages.Setting.Mask.rotation.verticalLength')"
/> />
</NFormItemGi> </NFormItemGi>
@ -263,7 +262,7 @@ onUnmounted(() => {
> >
<NInputNumber <NInputNumber
v-model:value="store.rotation.horizontalLength" v-model:value="store.rotation.horizontalLength"
@update:value="localStore.set('rotation', store.rotation)" @update:value="LocalStore.set('rotation', store.rotation)"
:placeholder="$t('pages.Setting.Mask.rotation.horizontalLength')" :placeholder="$t('pages.Setting.Mask.rotation.horizontalLength')"
/> />
</NFormItemGi> </NFormItemGi>
@ -276,7 +275,7 @@ onUnmounted(() => {
> >
<NCheckbox <NCheckbox
v-model:checked="store.screenStream.enable" v-model:checked="store.screenStream.enable"
@update:checked="localStore.set('screenStream', store.screenStream)" @update:checked="LocalStore.set('screenStream', store.screenStream)"
/> />
</NFormItem> </NFormItem>
<NFormItem <NFormItem
@ -285,7 +284,7 @@ onUnmounted(() => {
> >
<NInput <NInput
v-model:value="store.screenStream.address" v-model:value="store.screenStream.address"
@update:value="localStore.set('screenStream', store.screenStream)" @update:value="LocalStore.set('screenStream', store.screenStream)"
clearable clearable
:placeholder="$t('pages.Setting.Mask.screenStream.addressPlaceholder')" :placeholder="$t('pages.Setting.Mask.screenStream.addressPlaceholder')"
/> />

View File

@ -39,10 +39,12 @@ const store = useGlobalStore();
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@use "../../css/common.scss";
.setting { .setting {
@include common.contentContainer;
background-color: var(--content-bg-color); background-color: var(--content-bg-color);
color: var(--light-color); color: var(--light-color);
height: 100%;
overflow-y: auto; overflow-y: auto;
display: flex; display: flex;

5
src/css/common.scss Normal file
View File

@ -0,0 +1,5 @@
@mixin contentContainer {
grid-area: content;
width: 100%;
height: 100%;
}

View File

@ -4,7 +4,6 @@ import { locale } from "@tauri-apps/plugin-os";
import enUS from "./en-US.json"; import enUS from "./en-US.json";
import zhCN from "./zh-CN.json"; import zhCN from "./zh-CN.json";
const localStore = await load("store.json");
export const allLanguage = { export const allLanguage = {
"en-US": { label: "English US", value: enUS }, "en-US": { label: "English US", value: enUS },
@ -18,22 +17,24 @@ const i18n = createI18n({
), ),
}); });
localStore.get<"en-US" | "zh-CN">("language").then((language) => { load("store.json").then((localStore) => {
if (language === undefined) { localStore.get<"en-US" | "zh-CN">("language").then((language) => {
locale().then((lang) => { if (language === undefined) {
if (lang === null) i18n.global.locale = "en-US"; locale().then((lang) => {
else if (lang in allLanguage) { if (lang === null) i18n.global.locale = "en-US";
i18n.global.locale = lang; else if (lang in allLanguage) {
} else { i18n.global.locale = lang;
if (lang.startsWith("zh")) i18n.global.locale = "zh-CN"; } else {
else if (lang.startsWith("en")) i18n.global.locale = "en-US"; if (lang.startsWith("zh")) i18n.global.locale = "zh-CN";
else i18n.global.locale = "en-US"; else if (lang.startsWith("en")) i18n.global.locale = "en-US";
} else i18n.global.locale = "en-US";
}); }
// "en-US" });
} else { // "en-US"
i18n.global.locale = language; } else {
} i18n.global.locale = language;
}
});
}); });
export default i18n; export default i18n;

View File

@ -5,9 +5,7 @@ import {
KeyMappingConfig, KeyMappingConfig,
KeySteeringWheel, KeySteeringWheel,
} from "../keyMappingConfig"; } from "../keyMappingConfig";
import { load } from "@tauri-apps/plugin-store"; import { LocalStore } from "./localStore";
const localStore = await load("store.json");
export const useGlobalStore = defineStore("global", () => { export const useGlobalStore = defineStore("global", () => {
const showLoadingRef = ref(false); const showLoadingRef = ref(false);
@ -48,7 +46,7 @@ export const useGlobalStore = defineStore("global", () => {
keyMappingConfigList.value[curKeyMappingIndex.value].list = keyMappingConfigList.value[curKeyMappingIndex.value].list =
editKeyMappingList.value; editKeyMappingList.value;
localStore.set("keyMappingConfigList", keyMappingConfigList.value); LocalStore.set("keyMappingConfigList", keyMappingConfigList.value);
return true; return true;
} }
@ -63,7 +61,7 @@ export const useGlobalStore = defineStore("global", () => {
function setKeyMappingIndex(index: number) { function setKeyMappingIndex(index: number) {
curKeyMappingIndex.value = index; curKeyMappingIndex.value = index;
resetEditKeyMappingList(); resetEditKeyMappingList();
localStore.set("curKeyMappingIndex", index); LocalStore.set("curKeyMappingIndex", index);
} }
const externalControlled = ref(false); const externalControlled = ref(false);

29
src/store/localStore.ts Normal file
View File

@ -0,0 +1,29 @@
import { load, Store } from "@tauri-apps/plugin-store";
export class LocalStore {
public static store: Store;
static async init() {
this.store = await load("store.json");
}
static async get<T>(key: string): Promise<T | undefined> {
return this.store.get(key);
}
static async set<T>(key: string, value: T) {
return this.store.set(key, value);
}
static async delete(key: string) {
return this.store.delete(key);
}
static async clear() {
return this.store.clear();
}
static async entries(){
return this.store.entries();
}
}

View File

@ -1,22 +1,21 @@
import { Store } from "@tauri-apps/plugin-store";
import { KeyMappingConfig } from "./keyMappingConfig"; import { KeyMappingConfig } from "./keyMappingConfig";
import { useGlobalStore } from "./store/global"; import { useGlobalStore } from "./store/global";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { LocalStore } from "./store/localStore";
let localStore: Store;
let store: ReturnType<typeof useGlobalStore>; let store: ReturnType<typeof useGlobalStore>;
let t: ReturnType<typeof useI18n>["t"]; let t: ReturnType<typeof useI18n>["t"];
async function loadKeyMappingConfigList() { async function loadKeyMappingConfigList() {
// loading keyMappingConfigList from local store // loading keyMappingConfigList from local store
let keyMappingConfigList = await localStore.get<KeyMappingConfig[]>( let keyMappingConfigList = await LocalStore.get<KeyMappingConfig[]>(
"keyMappingConfigList" "keyMappingConfigList"
); );
if (keyMappingConfigList === undefined || keyMappingConfigList.length === 0) { if (keyMappingConfigList === undefined || keyMappingConfigList.length === 0) {
// add empty key mapping config // add empty key mapping config
// unable to get mask element when app is not ready // unable to get mask element when app is not ready
// so we use the stored mask area to get relative size // so we use the stored mask area to get relative size
const maskArea = await localStore.get<{ const maskArea = await LocalStore.get<{
posX: number; posX: number;
posY: number; posY: number;
sizeW: number; sizeW: number;
@ -36,27 +35,27 @@ async function loadKeyMappingConfigList() {
list: [], list: [],
}, },
]; ];
await localStore.set("keyMappingConfigList", keyMappingConfigList); await LocalStore.set("keyMappingConfigList", keyMappingConfigList);
} }
store.keyMappingConfigList = keyMappingConfigList; store.keyMappingConfigList = keyMappingConfigList;
} }
async function loadCurKeyMappingIndex() { async function loadCurKeyMappingIndex() {
// loading curKeyMappingIndex from local store // loading curKeyMappingIndex from local store
let curKeyMappingIndex = await localStore.get<number>("curKeyMappingIndex"); let curKeyMappingIndex = await LocalStore.get<number>("curKeyMappingIndex");
if ( if (
curKeyMappingIndex === undefined || curKeyMappingIndex === undefined ||
curKeyMappingIndex >= store.keyMappingConfigList.length curKeyMappingIndex >= store.keyMappingConfigList.length
) { ) {
curKeyMappingIndex = 0; curKeyMappingIndex = 0;
localStore.set("curKeyMappingIndex", curKeyMappingIndex); LocalStore.set("curKeyMappingIndex", curKeyMappingIndex);
} }
store.curKeyMappingIndex = curKeyMappingIndex; store.curKeyMappingIndex = curKeyMappingIndex;
} }
async function loadMaskButton() { async function loadMaskButton() {
// loading maskButton from local store // loading maskButton from local store
let maskButton = await localStore.get<{ const maskButton = await LocalStore.get<{
show: boolean; show: boolean;
transparency: number; transparency: number;
}>("maskButton"); }>("maskButton");
@ -68,7 +67,7 @@ async function loadMaskButton() {
async function loadCheckUpdateAtStart() { async function loadCheckUpdateAtStart() {
// loading checkUpdateAtStart from local store // loading checkUpdateAtStart from local store
const checkUpdateAtStart = await localStore.get<boolean>( const checkUpdateAtStart = await LocalStore.get<boolean>(
"checkUpdateAtStart" "checkUpdateAtStart"
); );
store.checkUpdateAtStart = checkUpdateAtStart ?? true; store.checkUpdateAtStart = checkUpdateAtStart ?? true;
@ -76,7 +75,7 @@ async function loadCheckUpdateAtStart() {
async function loadRotation() { async function loadRotation() {
// loading rotation from local store // loading rotation from local store
const rotation = await localStore.get<{ const rotation = await LocalStore.get<{
enable: boolean; enable: boolean;
verticalLength: number; verticalLength: number;
horizontalLength: number; horizontalLength: number;
@ -86,7 +85,7 @@ async function loadRotation() {
async function loadScreenStream() { async function loadScreenStream() {
// loading screenStream from local store // loading screenStream from local store
const screenStream = await localStore.get<{ const screenStream = await LocalStore.get<{
enable: boolean; enable: boolean;
address: string; address: string;
}>("screenStream"); }>("screenStream");
@ -95,7 +94,7 @@ async function loadScreenStream() {
async function loadClipboardSync() { async function loadClipboardSync() {
// loading clipboardSync from local store // loading clipboardSync from local store
const clipboardSync = await localStore.get<{ const clipboardSync = await LocalStore.get<{
syncFromDevice: boolean; syncFromDevice: boolean;
pasteFromPC: boolean; pasteFromPC: boolean;
}>("clipboardSync"); }>("clipboardSync");
@ -103,11 +102,11 @@ async function loadClipboardSync() {
} }
export async function loadPersistentStorage( export async function loadPersistentStorage(
theLocalStore: Store,
theStore: ReturnType<typeof useGlobalStore>, theStore: ReturnType<typeof useGlobalStore>,
theT: ReturnType<typeof useI18n>["t"] theT: ReturnType<typeof useI18n>["t"]
) { ) {
localStore = theLocalStore; await LocalStore.init();
store = theStore; store = theStore;
t = theT; t = theT;

View File

@ -51,7 +51,6 @@ async function handleMessage(event: MessageEvent) {
delete msg.type; delete msg.type;
await touch(msg); await touch(msg);
} else if (msg.type === "swipe") { } else if (msg.type === "swipe") {
console.log(msg);
msg.screen = { w: sharedStore.screenSizeW, h: sharedStore.screenSizeH }; msg.screen = { w: sharedStore.screenSizeW, h: sharedStore.screenSizeH };
delete msg.type; delete msg.type;
await swipe(msg); await swipe(msg);