feat: add help tooltip

This commit is contained in:
AkiChase 2025-03-12 17:26:55 +08:00
parent 2573356b8c
commit b1f5960306
12 changed files with 119 additions and 52 deletions

View File

@ -18,6 +18,7 @@ import {
getDeviceScreenSize,
adbConnect,
getCurClientInfo,
adbRestartServer,
} from "../tools/invoke";
import {
NH4,
@ -34,6 +35,7 @@ import {
useDialog,
useMessage,
NInputGroup,
NSpace,
} from "naive-ui";
import { CloseCircle, InformationCircle, Refresh } from "@vicons/ionicons5";
import { UnlistenFn, listen } from "@tauri-apps/api/event";
@ -47,6 +49,7 @@ import {
import { LogicalSize, getCurrentWindow } from "@tauri-apps/api/window";
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
import ButtonWithTip from "./common/ButtonWithTip.vue";
import { NonReactiveStore } from "../store/noneReactiveStore";
const { t } = useI18n();
const dialog = useDialog();
@ -328,6 +331,21 @@ async function refreshDevices() {
store.hideLoading();
}
async function restartAdb() {
if (NonReactiveStore.mem.adbUnavailableMsgIns !== null) {
message.error(t("pages.Device.adbUnavailable"));
return;
}
store.showLoading();
try {
await adbRestartServer();
} catch (e) {
message.error(t("pages.Device.adbRestartError"));
console.error(e);
}
store.hideLoading();
}
async function connectDevice() {
if (!wireless_address.value) {
message.error(t("pages.Device.inputWirelessAddress"));
@ -437,15 +455,24 @@ function closeWS() {
<NH4 style="margin: 20px 0" prefix="bar">{{
$t("pages.Device.availableDevice")
}}</NH4>
<ButtonWithTip
tertiary
circle
type="primary"
@click="refreshDevices"
style="margin-right: 20px"
:tip="$t('pages.Device.btnRefresh')"
:icon="Refresh"
/>
<NSpace>
<ButtonWithTip
tertiary
circle
type="primary"
@click="refreshDevices"
:tip="$t('pages.Device.btnRefresh')"
:icon="Refresh"
/>
<ButtonWithTip
tertiary
circle
type="error"
@click="restartAdb"
:tip="$t('pages.Device.btnReStart')"
:icon="Refresh"
/>
</NSpace>
</NFlex>
<NDataTable
max-height="120"

View File

@ -4,9 +4,11 @@ import { useGlobalStore } from "../store/global";
import { MessageReactive, useMessage } from "naive-ui";
import { ScreenStream } from "../tools/screenStream";
import { NonReactiveStore } from "../store/noneReactiveStore";
import { useI18n } from "vue-i18n";
const store = useGlobalStore();
const message = useMessage();
const { t } = useI18n();
const streamImg = ref<HTMLImageElement | null>(null);
@ -14,16 +16,22 @@ let msgReactive: MessageReactive | null = null;
function connectScreenStream() {
if (streamImg.value) {
const ss = new ScreenStream(streamImg.value, NonReactiveStore.mem.screenStreamClientId);
const ss = new ScreenStream(
streamImg.value,
NonReactiveStore.mem.screenStreamClientId
);
ss.connect(
store.screenStream.address,
() => {},
() => {
msgReactive = message.error("投屏连接失败。关闭此信息将尝试重新连接", {
duration: 0,
closable: true,
onClose: () => connectScreenStream(),
});
msgReactive = message.error(
t("pages.Setting.Mask.screenStream.connectError"),
{
duration: 0,
closable: true,
onClose: () => connectScreenStream(),
}
);
}
);
}

View File

@ -1,12 +1,12 @@
<script setup lang="ts">
import { NFlex, NH4, NButton, NIcon, NP, NCheckbox } from "naive-ui";
import { LogoGithub, Planet } from "@vicons/ionicons5";
import { open } from "@tauri-apps/plugin-shell";
import { getVersion } from "@tauri-apps/api/app";
import { onMounted, ref } from "vue";
import { useGlobalStore } from "../../store/global";
import { LocalStore } from "../../store/localStore";
import { useCheckUpdate } from "../../tools/hooks";
import { openWebsite } from "../../tools/tools";
const store = useGlobalStore();
const checkUpdate = useCheckUpdate();
@ -16,10 +16,6 @@ onMounted(async () => {
appVersion.value = await getVersion();
});
function opendWebsite(url: string) {
open(url);
}
async function onClickCheckUpdate() {
store.showLoading();
await checkUpdate();
@ -34,7 +30,7 @@ async function onClickCheckUpdate() {
<NFlex :size="30">
<NButton
text
@click="opendWebsite('https://github.com/AkiChase/scrcpy-mask')"
@click="openWebsite('https://github.com/AkiChase/scrcpy-mask')"
>
<template #icon>
<NIcon><LogoGithub /> </NIcon>
@ -43,7 +39,7 @@ async function onClickCheckUpdate() {
</NButton>
<NButton
text
@click="opendWebsite('https://space.bilibili.com/440760180')"
@click="openWebsite('https://space.bilibili.com/440760180')"
>
<template #icon>
<NIcon
@ -63,7 +59,7 @@ async function onClickCheckUpdate() {
</template>
BiliBili
</NButton>
<NButton text @click="opendWebsite('https://www.akichase.top/')">
<NButton text @click="openWebsite('https://www.akichase.top/')">
<template #icon>
<NIcon><Planet /> </NIcon>
</template>

View File

@ -7,9 +7,7 @@ import {
NFormItemGi,
NInputNumber,
FormRules,
NButton,
NFlex,
NIcon,
FormInst,
useMessage,
NSlider,
@ -22,11 +20,13 @@ import {
LogicalSize,
getCurrentWindow,
} from "@tauri-apps/api/window";
import { SettingsOutline } from "@vicons/ionicons5";
import { Help, SettingsOutline } from "@vicons/ionicons5";
import { useGlobalStore } from "../../store/global";
import { useI18n } from "vue-i18n";
import { LocalStore } from "../../store/localStore";
import { NonReactiveStore } from "../../store/noneReactiveStore";
import ButtonWithTip from "../common/ButtonWithTip.vue";
import { openWebsite } from "../../tools/tools";
const { t } = useI18n();
const store = useGlobalStore();
@ -154,17 +154,14 @@ async function adjustWindowMaskArea() {
>
<NFlex justify="space-between" align="center">
<NH4 prefix="bar">{{ $t("pages.Setting.Mask.areaAdjust") }}</NH4>
<NButton
<ButtonWithTip
tertiary
circle
type="primary"
@click="handleAdjustClick"
style="margin-right: 20px"
>
<template #icon>
<NIcon><SettingsOutline /></NIcon>
</template>
</NButton>
:tip="$t('pages.Setting.Mask.btnAreaAdjustTip')"
:icon="SettingsOutline"
/>
</NFlex>
<NGrid :cols="2" :x-gap="24">
<NFormItemGi label="X" path="posX">
@ -226,8 +223,17 @@ async function adjustWindowMaskArea() {
/>
</NFormItemGi>
</NGrid>
<NH4 prefix="bar">ScreenStream</NH4>
<NFlex justify="space-between" align="center">
<NH4 prefix="bar">ScreenStream</NH4>
<ButtonWithTip
tertiary
circle
type="primary"
@click="openWebsite('https://github.com/dkrivoruchko/ScreenStream')"
:tip="$t('pages.Setting.Mask.screenStream.btnHelp')"
:icon="Help"
/>
</NFlex>
<NFormItem
:label="$t('pages.Setting.Mask.screenStream.enable')"
label-placement="left"

View File

@ -7,6 +7,7 @@ import { NTabs, NTabPane, NSpin } from "naive-ui";
import { useGlobalStore } from "../../store/global";
import SettingTab from "./SettingTab.vue";
// TODO Switch back to landscape size when entering Settings and Devices screen
const store = useGlobalStore();
</script>

View File

@ -30,6 +30,7 @@ div#app {
}
.n-spin-container {
background-color: var(--bg-color);
@include common.flexFullHeight;
.n-spin-content {
@include common.flexFullHeight;

View File

@ -38,7 +38,10 @@
"adbConnectError": "Wireless connection failed",
"rotation": "Device rotation {0}°",
"btnShutdown": "Shutdown control",
"btnRefresh": "Refresh"
"btnRefresh": "Refresh",
"btnReStart": "Restart ADB",
"adbRestartError": "ADB Restart Failed",
"adbUnavailable": "ADB Unavailable"
},
"Mask": {
"keyconfigException": "The key mapping config is abnormal, please delete this config",
@ -97,8 +100,11 @@
"screenStream": {
"enable": "Enable mirror",
"address": "Screen mirror address",
"addressPlaceholder": "Please enter the ScreenStream screen mirror address"
}
"addressPlaceholder": "Please enter the ScreenStream screen mirror address",
"connectError": "ScreenStream connection failed. Closing this message will attempt to reconnect",
"btnHelp": "ScreenStream is an Android screen mirror app with 0.5-1s screen delay, only as a complementary solution to Scrcpy Mask's screen mirror (click to open its project homepage)"
},
"btnAreaAdjustTip": "Setting the mask area"
},
"Basic": {
"language": "Language",
@ -282,5 +288,6 @@
"open": "Connected to external control server",
"close": "External control connection disconnected",
"error": "Something was wrong, the exter connection is closed"
}
},
"screenStream": {}
}

View File

@ -38,7 +38,10 @@
"adbConnectError": "无线连接失败",
"rotation": "设备旋转 {0}°",
"btnShutdown": "关闭控制",
"btnRefresh": "刷新"
"btnRefresh": "刷新",
"btnReStart": "重启ABD",
"adbRestartError": "ADB 重启失败",
"adbUnavailable": "ADB 不可用"
},
"Mask": {
"keyconfigException": "按键方案异常,请删除此方案",
@ -97,8 +100,11 @@
"screenStream": {
"enable": "启用投屏",
"address": "投屏地址",
"addressPlaceholder": "请输入 ScreenStream 投屏地址"
}
"addressPlaceholder": "请输入 ScreenStream 投屏地址",
"connectError": "ScreenStream 投屏连接失败。关闭此信息将尝试重新连接",
"btnHelp": "ScreenStream 是一款安卓投屏App存在0.5-1s的画面延迟仅作为 Scrcpy Mask 的投屏补充方案(点击打开其项目主页)"
},
"btnAreaAdjustTip": "设置蒙版区域"
},
"Basic": {
"language": "语言",
@ -282,5 +288,6 @@
"open": "已连接到外部控制服务端",
"close": "外部控制连接断开",
"error": "未知错误,外部控制连接断开"
}
},
"screenStream": {}
}

View File

@ -1,8 +1,10 @@
import { MessageReactive } from "naive-ui";
import { LocalStore } from "./localStore";
interface MemType {
screenStreamClientId: string;
keyInputFlag: boolean;
adbUnavailableMsgIns: MessageReactive | null;
}
interface LocalType {
@ -19,6 +21,7 @@ export class NonReactiveStore {
static mem: MemType = {
screenStreamClientId: "",
keyInputFlag: false,
adbUnavailableMsgIns: null,
};
static local: LocalType = {

View File

@ -1,13 +1,13 @@
import { getVersion } from "@tauri-apps/api/app";
import { MessageReactive, useDialog, useMessage } from "naive-ui";
import { useDialog, useMessage } from "naive-ui";
import { h } from "vue";
import { useI18n } from "vue-i18n";
import { fetch } from "@tauri-apps/plugin-http";
import { compareVersion } from "./tools";
import { checkAdbAvailable } from "./invoke";
import { NonReactiveStore } from "../store/noneReactiveStore";
// TODO use markdown to render update info
// TODO check screen stream available
function renderUpdateInfo(content: string) {
const pList = content.split("\r\n").map((line: string) => h("p", line));
@ -56,22 +56,24 @@ export function useCheckUpdate() {
};
}
let checkAdbMessage: MessageReactive | null = null;
export function useCheckAdb() {
const message = useMessage();
const { t } = useI18n();
return async function checkAdb() {
try {
if (checkAdbMessage) {
checkAdbMessage.destroy();
checkAdbMessage = null;
if (NonReactiveStore.mem.adbUnavailableMsgIns) {
NonReactiveStore.mem.adbUnavailableMsgIns.destroy();
NonReactiveStore.mem.adbUnavailableMsgIns = null;
}
await checkAdbAvailable();
} catch (e) {
checkAdbMessage = message.error(t("pages.Mask.checkAdb", [e]), {
duration: 0,
});
NonReactiveStore.mem.adbUnavailableMsgIns = message.error(
t("pages.Mask.checkAdb", [e]),
{
duration: 0,
}
);
}
};
}

View File

@ -9,6 +9,10 @@ export async function adbDevices(): Promise<Device[]> {
return await invoke("adb_devices");
}
export async function adbRestartServer(): Promise<void> {
return await invoke("adb_restart_server");
}
export async function forwardServerPort(
id: string,
scid: string,

View File

@ -1,4 +1,5 @@
import { getCurrentWindow, LogicalSize } from "@tauri-apps/api/window";
import { open as shellOpen } from "@tauri-apps/plugin-shell";
export function compareVersion(v1: string, v2: string) {
const [x1, y1, z1] = v1.split(".");
@ -36,3 +37,7 @@ export async function cleanAfterimage() {
await appWindow.setSize(newSize);
await appWindow.setSize(oldSize);
}
export function openWebsite(url: string) {
shellOpen(url);
}