mirror of
https://github.com/AkiChase/scrcpy-mask
synced 2025-04-21 04:25:13 +08:00
feat(sidebar): add tooltip for sidebar button
This commit is contained in:
parent
6eac5c8875
commit
3bb71df47e
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Sidebar from "./components/Sidebar.vue";
|
import Sidebar from "./components/sidebar/Sidebar.vue";
|
||||||
import Header from "./components/Header.vue";
|
import Header from "./components/Header.vue";
|
||||||
import {
|
import {
|
||||||
darkTheme,
|
darkTheme,
|
||||||
|
@ -1,209 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
import {
|
|
||||||
GameControllerOutline,
|
|
||||||
LogoAndroid,
|
|
||||||
SettingsOutline,
|
|
||||||
ReturnDownBackOutline,
|
|
||||||
VolumeHighOutline,
|
|
||||||
VolumeLowOutline,
|
|
||||||
StopOutline,
|
|
||||||
ListOutline,
|
|
||||||
BulbOutline,
|
|
||||||
Bulb,
|
|
||||||
} from "@vicons/ionicons5";
|
|
||||||
import { Keyboard24Regular } from "@vicons/fluent";
|
|
||||||
import { NIcon, useMessage } from "naive-ui";
|
|
||||||
import { useGlobalStore } from "../store/global";
|
|
||||||
import { sendSetScreenPowerMode } from "../frontcommand/controlMsg";
|
|
||||||
import { AndroidKeycode } from "../frontcommand/android";
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import { SendKeyAction, sendKey } from "../frontcommand/scrcpyMaskCmd";
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const store = useGlobalStore();
|
|
||||||
const message = useMessage();
|
|
||||||
|
|
||||||
const nextScreenPowerMode = ref(0);
|
|
||||||
|
|
||||||
function nav(name: string) {
|
|
||||||
router.replace({ name });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendKeyCodeToDevice(code: AndroidKeycode) {
|
|
||||||
if (store.controledDevice) {
|
|
||||||
await sendKey({
|
|
||||||
action: SendKeyAction.Default,
|
|
||||||
keycode: code,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
message.error(t("sidebar.noControledDevice"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function changeScreenPowerMode() {
|
|
||||||
if (store.controledDevice) {
|
|
||||||
sendSetScreenPowerMode({ mode: nextScreenPowerMode.value });
|
|
||||||
nextScreenPowerMode.value = nextScreenPowerMode.value ? 0 : 2;
|
|
||||||
} else {
|
|
||||||
message.error(t("sidebar.noControledDevice"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="sidebar">
|
|
||||||
<div data-tauri-drag-region class="logo">S M</div>
|
|
||||||
<div class="module">
|
|
||||||
<div :class="{ active: route.name == 'mask' }" @click="nav('mask')">
|
|
||||||
<NIcon>
|
|
||||||
<GameControllerOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div :class="{ active: route.name == 'device' }" @click="nav('device')">
|
|
||||||
<NIcon>
|
|
||||||
<LogoAndroid />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
:class="{ active: route.name == 'keyboard' }"
|
|
||||||
@click="nav('keyboard')"
|
|
||||||
>
|
|
||||||
<NIcon>
|
|
||||||
<Keyboard24Regular />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div :class="{ active: route.name == 'setting' }" @click="nav('setting')">
|
|
||||||
<NIcon>
|
|
||||||
<SettingsOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-tauri-drag-region class="drag"></div>
|
|
||||||
<div class="nav">
|
|
||||||
<div @click="changeScreenPowerMode">
|
|
||||||
<NIcon>
|
|
||||||
<Bulb v-if="nextScreenPowerMode" />
|
|
||||||
<BulbOutline v-else />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_UP)">
|
|
||||||
<NIcon>
|
|
||||||
<VolumeHighOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_DOWN)">
|
|
||||||
<NIcon>
|
|
||||||
<VolumeLowOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_BACK)">
|
|
||||||
<NIcon>
|
|
||||||
<ReturnDownBackOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_HOME)">
|
|
||||||
<NIcon>
|
|
||||||
<StopOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_APP_SWITCH)">
|
|
||||||
<NIcon>
|
|
||||||
<ListOutline />
|
|
||||||
</NIcon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.sidebar {
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: 10px 0 0 10px;
|
|
||||||
grid-area: sidebar;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 30px;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--light-color);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag{
|
|
||||||
flex-grow: 1;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
flex-shrink: 0;
|
|
||||||
height: 50px;
|
|
||||||
color: var(--gray-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 28px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--primary-hover-color);
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
&:active {
|
|
||||||
color: var(--primary-pressed-color);
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div.active {
|
|
||||||
color: var(--primary-color);
|
|
||||||
border-left: 3px solid var(--primary-color);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav {
|
|
||||||
color: var(--light-color);
|
|
||||||
font-size: 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-shrink: 0;
|
|
||||||
& > div {
|
|
||||||
height: 40px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--primary-hover-color);
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
&:active {
|
|
||||||
color: var(--primary-pressed-color);
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
40
src/components/sidebar/FuncButton.vue
Normal file
40
src/components/sidebar/FuncButton.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { NIcon, NTooltip } from "naive-ui";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
icon: Object;
|
||||||
|
tip: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="btn-content">
|
||||||
|
<NTooltip trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<NIcon><component :is="props.icon" /></NIcon>
|
||||||
|
</template>
|
||||||
|
{{ props.tip }}
|
||||||
|
</NTooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.btn-content {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--primary-hover-color);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
color: var(--primary-pressed-color);
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
63
src/components/sidebar/ModuleNav.vue
Normal file
63
src/components/sidebar/ModuleNav.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { NIcon, NTooltip } from "naive-ui";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
name: string;
|
||||||
|
icon: Object;
|
||||||
|
tip: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
function nav(name: string) {
|
||||||
|
router.replace({ name });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="{
|
||||||
|
'nav-active': route.name === props.name,
|
||||||
|
'nav-content': true,
|
||||||
|
}"
|
||||||
|
@click="nav(props.name)"
|
||||||
|
>
|
||||||
|
<NTooltip trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<NIcon><component :is="props.icon" /></NIcon>
|
||||||
|
</template>
|
||||||
|
{{ props.tip }}
|
||||||
|
</NTooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-content {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 50px;
|
||||||
|
color: var(--gray-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 28px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--primary-hover-color);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
color: var(--primary-pressed-color);
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-active {
|
||||||
|
color: var(--primary-color);
|
||||||
|
border-left: 3px solid var(--primary-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
154
src/components/sidebar/Sidebar.vue
Normal file
154
src/components/sidebar/Sidebar.vue
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
GameControllerOutline,
|
||||||
|
LogoAndroid,
|
||||||
|
SettingsOutline,
|
||||||
|
ReturnDownBackOutline,
|
||||||
|
VolumeHighOutline,
|
||||||
|
VolumeLowOutline,
|
||||||
|
StopOutline,
|
||||||
|
ListOutline,
|
||||||
|
BulbOutline,
|
||||||
|
Bulb,
|
||||||
|
} from "@vicons/ionicons5";
|
||||||
|
import { Keyboard24Regular } from "@vicons/fluent";
|
||||||
|
import { useMessage } from "naive-ui";
|
||||||
|
import { useGlobalStore } from "../../store/global";
|
||||||
|
import { sendSetScreenPowerMode } from "../../frontcommand/controlMsg";
|
||||||
|
import { AndroidKeycode } from "../../frontcommand/android";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { SendKeyAction, sendKey } from "../../frontcommand/scrcpyMaskCmd";
|
||||||
|
import ModuleNav from "./ModuleNav.vue";
|
||||||
|
import FuncButton from "./FuncButton.vue";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useGlobalStore();
|
||||||
|
const message = useMessage();
|
||||||
|
|
||||||
|
const nextScreenPowerMode = ref(0);
|
||||||
|
|
||||||
|
async function sendKeyCodeToDevice(code: AndroidKeycode) {
|
||||||
|
if (store.controledDevice) {
|
||||||
|
await sendKey({
|
||||||
|
action: SendKeyAction.Default,
|
||||||
|
keycode: code,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error(t("sidebar.noControledDevice"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeScreenPowerMode() {
|
||||||
|
if (store.controledDevice) {
|
||||||
|
sendSetScreenPowerMode({ mode: nextScreenPowerMode.value });
|
||||||
|
nextScreenPowerMode.value = nextScreenPowerMode.value ? 0 : 2;
|
||||||
|
} else {
|
||||||
|
message.error(t("sidebar.noControledDevice"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="sidebar">
|
||||||
|
<div data-tauri-drag-region class="logo">S M</div>
|
||||||
|
<div class="module-nav">
|
||||||
|
<ModuleNav
|
||||||
|
name="mask"
|
||||||
|
:icon="GameControllerOutline"
|
||||||
|
:tip="t('sidebar.tip.mask')"
|
||||||
|
/>
|
||||||
|
<ModuleNav
|
||||||
|
name="device"
|
||||||
|
:icon="LogoAndroid"
|
||||||
|
:tip="t('sidebar.tip.device')"
|
||||||
|
/>
|
||||||
|
<ModuleNav
|
||||||
|
name="keyboard"
|
||||||
|
:icon="Keyboard24Regular"
|
||||||
|
:tip="t('sidebar.tip.keyboard')"
|
||||||
|
/>
|
||||||
|
<ModuleNav
|
||||||
|
name="setting"
|
||||||
|
:icon="SettingsOutline"
|
||||||
|
:tip="t('sidebar.tip.setting')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div data-tauri-drag-region class="drag" />
|
||||||
|
<div class="func-btn">
|
||||||
|
<FuncButton
|
||||||
|
@click="changeScreenPowerMode"
|
||||||
|
:tip="nextScreenPowerMode? t('sidebar.tip.screenPowerModeOff'): t('sidebar.tip.screenPowerModeOn')"
|
||||||
|
:icon="nextScreenPowerMode ? Bulb : BulbOutline"
|
||||||
|
/>
|
||||||
|
<FuncButton
|
||||||
|
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_UP)"
|
||||||
|
:tip="t('sidebar.tip.volumeUp')"
|
||||||
|
:icon="VolumeHighOutline"
|
||||||
|
/>
|
||||||
|
<FuncButton
|
||||||
|
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_DOWN)"
|
||||||
|
:tip="t('sidebar.tip.volumeDown')"
|
||||||
|
:icon="VolumeLowOutline"
|
||||||
|
/>
|
||||||
|
<FuncButton
|
||||||
|
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_BACK)"
|
||||||
|
:tip="t('sidebar.tip.back')"
|
||||||
|
:icon="ReturnDownBackOutline"
|
||||||
|
/>
|
||||||
|
<FuncButton
|
||||||
|
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_HOME)"
|
||||||
|
:tip="t('sidebar.tip.home')"
|
||||||
|
:icon="StopOutline"
|
||||||
|
/>
|
||||||
|
<FuncButton
|
||||||
|
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_APP_SWITCH)"
|
||||||
|
:tip="t('sidebar.tip.appSwitch')"
|
||||||
|
:icon="ListOutline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sidebar {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 10px 0 0 10px;
|
||||||
|
grid-area: sidebar;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 30px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--light-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.func-btn {
|
||||||
|
color: var(--light-color);
|
||||||
|
font-size: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -282,7 +282,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"noControledDevice": "No devices are controlled"
|
"noControledDevice": "No devices are controlled",
|
||||||
|
"tip": {
|
||||||
|
"mask": "Mask",
|
||||||
|
"device": "Device",
|
||||||
|
"keyboard": "Key mapping",
|
||||||
|
"setting": "Setting",
|
||||||
|
"screenPowerModeOff": "Screen off",
|
||||||
|
"screenPowerModeOn": "Screen on",
|
||||||
|
"volumeUp": "Volume up",
|
||||||
|
"volumeDown": "Volume down",
|
||||||
|
"back": "Back",
|
||||||
|
"home": "Home",
|
||||||
|
"appSwitch": "App switch"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"websocket": {
|
"websocket": {
|
||||||
"open": "Connected to external control server",
|
"open": "Connected to external control server",
|
||||||
|
@ -282,7 +282,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"noControledDevice": "未控制任何设备"
|
"noControledDevice": "未控制任何设备",
|
||||||
|
"tip": {
|
||||||
|
"mask": "蒙版",
|
||||||
|
"device": "设备",
|
||||||
|
"keyboard": "按键映射",
|
||||||
|
"setting": "设置",
|
||||||
|
"screenPowerModeOff": "息屏",
|
||||||
|
"screenPowerModeOn": "亮屏",
|
||||||
|
"volumeUp": "增加音量",
|
||||||
|
"volumeDown": "减少音量",
|
||||||
|
"back": "返回",
|
||||||
|
"home": "主页",
|
||||||
|
"appSwitch": "最近任务"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"websocket": {
|
"websocket": {
|
||||||
"open": "已连接到外部控制服务端",
|
"open": "已连接到外部控制服务端",
|
||||||
|
Loading…
Reference in New Issue
Block a user