refactor: ♻️ Split Action Bar Function

This commit is contained in:
viarotel 2023-11-02 16:07:42 +08:00
parent 6154ffcfae
commit 99ed1aeef7
10 changed files with 327 additions and 206 deletions

View File

@ -102,8 +102,27 @@ const getEncoders = async (serial) => {
return value return value
} }
const mirror = async (serial, { title, args = '', ...options } = {}) => {
return shell(
`--serial="${serial}" --window-title="${title}" ${args}`,
options,
)
}
const record = async (
serial,
{ title, args = '', savePath, ...options } = {},
) => {
return shell(
`--serial="${serial}" --window-title="${title}" --record="${savePath}" ${args}`,
options,
)
}
export default () => ({ export default () => ({
shell, shell,
execShell, execShell,
getEncoders, getEncoders,
mirror,
record,
}) })

View File

@ -0,0 +1,98 @@
<template>
<div class="" @click="handleInstall(device)">
<slot />
</div>
</template>
<script>
import LoadingIcon from '@/components/Device/ControlBar/LoadingIcon/index.vue'
export default {
props: {
device: {
type: Object,
default: () => ({}),
},
},
data() {
return {}
},
methods: {
preferenceData(...args) {
return this.$store.preference.getData(...args)
},
async handleInstall(device) {
let files = null
try {
files = await this.$electron.ipcRenderer.invoke('show-open-dialog', {
properties: ['openFile', 'multiSelections'],
filters: [
{
name: this.$t('device.control.install.placeholder'),
extensions: ['apk'],
},
],
})
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
if (!files) {
return false
}
const messageEl = this.$message({
message: this.$t('device.control.install.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
let failCount = 0
for (let index = 0; index < files.length; index++) {
const item = files[index]
await this.$adb.install(device.id, item).catch((e) => {
console.warn(e)
++failCount
})
}
messageEl.close()
const totalCount = files.length
const successCount = totalCount - failCount
if (successCount) {
if (totalCount > 1) {
this.$message.success(
this.$t('device.control.install.success', {
deviceName: device.$name,
totalCount,
successCount,
failCount,
}),
)
}
else {
this.$message.success(
this.$t('device.control.install.success.single', {
deviceName: device.$name,
}),
)
}
return
}
this.$message.warning(this.$t('device.control.install.error'))
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,49 @@
<template>
<div class="" @click="handleGnirehtet(device)">
<slot />
</div>
</template>
<script>
import LoadingIcon from '@/components/Device/ControlBar/LoadingIcon/index.vue'
export default {
props: {
device: {
type: Object,
default: () => ({}),
},
},
data() {
return {}
},
methods: {
preferenceData(...args) {
return this.$store.preference.getData(...args)
},
async handleGnirehtet(device) {
const messageEl = this.$message({
message: this.$t('device.control.gnirehtet.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
try {
await this.$gnirehtet.run(device.id)
this.$message.success(this.$t('device.control.gnirehtet.success'))
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
messageEl.close()
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,83 @@
<template>
<div class="" @click="handleScreenCap(device)">
<slot />
</div>
</template>
<script>
import dayjs from 'dayjs'
import LoadingIcon from '@/components/Device/ControlBar/LoadingIcon/index.vue'
export default {
props: {
device: {
type: Object,
default: () => ({}),
},
},
data() {
return {}
},
methods: {
preferenceData(...args) {
return this.$store.preference.getData(...args)
},
async handleScreenCap(device) {
const messageEl = this.$message({
message: this.$t('device.control.capture.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
const fileName = `${device.$remark ? `${device.$remark}-` : ''}${
device.$name
}-${this.$replaceIP(device.id)}-screencap-${dayjs().format(
'YYYY-MM-DD-HH-mm-ss',
)}.png`
const deviceConfig = this.preferenceData(device.id)
const savePath = this.$path.resolve(deviceConfig.savePath, fileName)
try {
await this.$adb.screencap(device.id, { savePath })
this.handleScreencapSuccess(savePath)
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
messageEl.close()
},
async handleScreencapSuccess(savePath) {
try {
await this.$confirm(
this.$t('device.control.capture.success.message'),
this.$t('device.control.capture.success.message.title'),
{
confirmButtonText: this.$t('common.confirm'),
cancelButtonText: this.$t('common.cancel'),
closeOnClickModal: false,
type: 'success',
},
)
await this.$electron.ipcRenderer.invoke(
'show-item-in-folder',
savePath,
)
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
},
},
}
</script>
<style></style>

View File

@ -4,33 +4,51 @@
class="bg-primary-100 dark:bg-gray-800 -my-[8px] flex flex-nowrap overflow-hidden" class="bg-primary-100 dark:bg-gray-800 -my-[8px] flex flex-nowrap overflow-hidden"
title="滚动查看被遮盖的菜单" title="滚动查看被遮盖的菜单"
> >
<el-button <component
:is="item.component || 'div'"
v-for="(item, index) in controlModel" v-for="(item, index) in controlModel"
:key="index" :key="index"
type="primary" class="flex-none"
plain v-bind="{
class="!border-none !mx-0 bg-transparent !rounded-0 flex-none" device,
:disabled="device.$unauthorized" ...(item.command
:title="item.tips ? $t(item.tips) : ''" ? {
@wheel.prevent="onWheel" onClick: () => handleShell(item),
@click="handleClick(item)" }
: {}),
}"
> >
<template #icon> <el-button
<svg-icon v-if="item.svgIcon" :name="item.svgIcon"></svg-icon> type="primary"
<el-icon v-else-if="item.elIcon" class=""> plain
<component :is="item.elIcon" /> class="!border-none !mx-0 bg-transparent !rounded-0"
</el-icon> :disabled="device.$unauthorized"
</template> :title="item.tips ? $t(item.tips) : ''"
{{ $t(item.label) }} @wheel.prevent="onWheel"
</el-button> >
<template #icon>
<svg-icon v-if="item.svgIcon" :name="item.svgIcon"></svg-icon>
<el-icon v-else-if="item.elIcon" class="">
<component :is="item.elIcon" />
</el-icon>
</template>
{{ $t(item.label) }}
</el-button>
</component>
</div> </div>
</template> </template>
<script> <script>
import dayjs from 'dayjs' import Screenshot from './Screenshot/index.vue'
import LoadingIcon from './LoadingIcon/index.vue' import AppInstall from './AppInstall/index.vue'
import Gnirehtet from './Gnirehtet/index.vue'
export default { export default {
components: {
Screenshot,
AppInstall,
Gnirehtet,
},
props: { props: {
device: { device: {
type: Object, type: Object,
@ -75,19 +93,19 @@ export default {
{ {
label: 'device.control.capture', label: 'device.control.capture',
elIcon: 'Crop', elIcon: 'Crop',
handle: this.handleScreenCap, component: 'Screenshot',
tips: '', tips: '',
}, },
{ {
label: 'device.control.install', label: 'device.control.install',
svgIcon: 'install', svgIcon: 'install',
handle: this.handleInstall, component: 'AppInstall',
tips: '', tips: '',
}, },
{ {
label: 'device.control.gnirehtet', label: 'device.control.gnirehtet',
elIcon: 'Link', elIcon: 'Link',
handle: this.handleGnirehtet, component: 'Gnirehtet',
tips: 'device.control.gnirehtet.tips', tips: 'device.control.gnirehtet.tips',
}, },
], ],
@ -99,164 +117,8 @@ export default {
const container = this.$refs.wheelContainer const container = this.$refs.wheelContainer
container.scrollLeft += event.deltaY container.scrollLeft += event.deltaY
}, },
preferenceData(...args) { handleShell(row) {
return this.$store.preference.getData(...args) this.$adb.deviceShell(this.device.id, row.command)
},
async handleGnirehtet(device) {
const messageEl = this.$message({
message: this.$t('device.control.gnirehtet.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
try {
await this.$gnirehtet.run(device.id)
this.$message.success(this.$t('device.control.gnirehtet.success'))
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
messageEl.close()
},
async handleInstall(device) {
let files = null
try {
files = await this.$electron.ipcRenderer.invoke('show-open-dialog', {
properties: ['openFile', 'multiSelections'],
filters: [
{
name: this.$t('device.control.install.placeholder'),
extensions: ['apk'],
},
],
})
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
if (!files) {
return false
}
const messageEl = this.$message({
message: this.$t('device.control.install.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
let failCount = 0
for (let index = 0; index < files.length; index++) {
const item = files[index]
await this.$adb.install(device.id, item).catch((e) => {
console.warn(e)
++failCount
})
}
messageEl.close()
const totalCount = files.length
const successCount = totalCount - failCount
if (successCount) {
if (totalCount > 1) {
this.$message.success(
this.$t('device.control.install.success', {
deviceName: device.$name,
totalCount,
successCount,
failCount,
}),
)
}
else {
this.$message.success(
this.$t('device.control.install.success.single', {
deviceName: device.$name,
}),
)
}
return
}
this.$message.warning(this.$t('device.control.install.error'))
},
handleClick(row) {
if (row.command) {
this.$adb.deviceShell(this.device.id, row.command)
}
else if (row.handle) {
row.handle(this.device)
}
else {
return false
}
},
async handleScreenCap(device) {
const messageEl = this.$message({
message: this.$t('device.control.capture.progress', {
deviceName: device.$name,
}),
icon: LoadingIcon,
duration: 0,
})
const fileName = `${device.$remark ? `${device.$remark}-` : ''}${
device.$name
}-${this.$replaceIP(device.id)}-screencap-${dayjs().format(
'YYYY-MM-DD-HH-mm-ss',
)}.png`
const deviceConfig = this.preferenceData(device.id)
const savePath = this.$path.resolve(deviceConfig.savePath, fileName)
try {
await this.$adb.screencap(device.id, { savePath })
this.handleScreencapSuccess(savePath)
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
messageEl.close()
},
async handleScreencapSuccess(savePath) {
try {
await this.$confirm(
this.$t('device.control.capture.success.message'),
this.$t('device.control.capture.success.message.title'),
{
confirmButtonText: this.$t('common.confirm'),
cancelButtonText: this.$t('common.cancel'),
closeOnClickModal: false,
type: 'success',
},
)
await this.$electron.ipcRenderer.invoke(
'show-item-in-folder',
savePath,
)
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
}
}, },
}, },
} }

View File

@ -297,16 +297,16 @@ export default {
this.toggleRowExpansion(row, true) this.toggleRowExpansion(row, true)
const savePath = this.getRecordPath(row) const savePath = this.getRecordPath(row)
try { try {
const command = `--serial="${row.id}" --window-title="${ await this.$scrcpy.record(row.id, {
row.$remark ? `${row.$remark}-` : '' title: `${row.$remark ? `${row.$remark}-` : ''}${row.$name}-${
}${row.$name}-${row.id}-🎥${this.$t( row.id
'device.record.progress', }-🎥${this.$t('device.record.progress')}...`,
)}..." --record="${savePath}" ${this.scrcpyArgs(row.id)}` savePath,
args: this.scrcpyArgs(row.id),
console.log('handleRecord.command', command) stdout: this.onStdout,
})
await this.$scrcpy.shell(command, { stdout: this.onStdout })
await this.$confirm( await this.$confirm(
this.$t('device.record.success.message'), this.$t('device.record.success.message'),
@ -337,12 +337,13 @@ export default {
this.toggleRowExpansion(row, true) this.toggleRowExpansion(row, true)
try { try {
await this.$scrcpy.shell( await this.$scrcpy.mirror(row.id, {
`--serial="${row.id}" --window-title="${ title: `${row.$remark ? `${row.$remark}-` : ''}${row.$name}-${
row.$remark ? `${row.$remark}-` : '' row.id
}${row.$name}-${row.id}" ${this.scrcpyArgs(row.id)}`, }`,
{ stdout: this.onStdout }, args: this.scrcpyArgs(row.id),
) stdout: this.onStdout,
})
} }
catch (error) { catch (error) {
if (error.message) { if (error.message) {

View File

@ -138,8 +138,8 @@
"preferences.video.bit.placeholder": "Default 4M, equal to 4000000", "preferences.video.bit.placeholder": "Default 4M, equal to 4000000",
"preferences.video.refresh-rate.name": "Frame Rate", "preferences.video.refresh-rate.name": "Frame Rate",
"preferences.video.refresh-rate.placeholder": "Default 60", "preferences.video.refresh-rate.placeholder": "Default 60",
"preferences.video.codec.name": "Video Codec", "preferences.video.video-code.name": "Video Codec",
"preferences.video.codec.placeholder": "Default H.264", "preferences.video.video-code.placeholder": "Default H.264",
"preferences.video.screen-rotation.name": "Rotation", "preferences.video.screen-rotation.name": "Rotation",
"preferences.video.screen-rotation.placeholder": "Default device rotation", "preferences.video.screen-rotation.placeholder": "Default device rotation",
"preferences.video.screen-cropping.name": "Crop", "preferences.video.screen-cropping.name": "Crop",
@ -179,12 +179,21 @@
"preferences.record.format.name": "Format", "preferences.record.format.name": "Format",
"preferences.record.format.placeholder": "Default *.mp4", "preferences.record.format.placeholder": "Default *.mp4",
"preferences.audio.name": "Audio", "preferences.audio.name": "Audio",
"preferences.audio.disable.name": "Disable Audio",
"preferences.audio.disable.placeholder": "Disable audio stream",
"preferences.audio.audio-source.name": "Audio Source",
"preferences.audio.audio-source.placeholder": "Default Device Audio Output",
"preferences.audio.audio-source.tips": "Tip: Selecting 'Microphone' as the source will allow you to record audio.",
"preferences.audio.audio-source.mic": "Microphone",
"preferences.audio.audio-code.name": "Audio Codec",
"preferences.audio.audio-code.placeholder": "Default Opus",
"preferences.audio.audio-bit-rate.name": "Audio Bit Rate",
"preferences.audio.audio-bit-rate.placeholder": "Default 128000bps",
"preferences.audio.audio-bit-rate.tips": "Note: This option does not apply to RAW audio codecs.",
"preferences.audio.audio-buffer.name": "Audio Buffer", "preferences.audio.audio-buffer.name": "Audio Buffer",
"preferences.audio.audio-buffer.placeholder": "Default 0ms", "preferences.audio.audio-buffer.placeholder": "Default 0ms",
"preferences.audio.audio-output-buffer.name": "Audio Output Buffer", "preferences.audio.audio-output-buffer.name": "Audio Output Buffer",
"preferences.audio.audio-output-buffer.placeholder": "Default 5ms", "preferences.audio.audio-output-buffer.placeholder": "Default 5ms",
"preferences.audio.disable.name": "Disable Audio",
"preferences.audio.disable.placeholder": "Disable audio stream",
"preferences.otg.name": "OTG", "preferences.otg.name": "OTG",
"preferences.otg.enable.name": "Enable OTG", "preferences.otg.enable.name": "Enable OTG",
"preferences.otg.enable.placeholder": "Enable or disable OTG", "preferences.otg.enable.placeholder": "Enable or disable OTG",

View File

@ -139,8 +139,8 @@
"preferences.video.bit.placeholder": "默认值为 4M,等同于 4000000", "preferences.video.bit.placeholder": "默认值为 4M,等同于 4000000",
"preferences.video.refresh-rate.name": "刷新率", "preferences.video.refresh-rate.name": "刷新率",
"preferences.video.refresh-rate.placeholder": "默认值为 60", "preferences.video.refresh-rate.placeholder": "默认值为 60",
"preferences.video.codec.name": "视频编码", "preferences.video.video-code.name": "视频编码",
"preferences.video.codec.placeholder": "默认为 H.264", "preferences.video.video-code.placeholder": "默认为 H.264",
"preferences.video.screen-rotation.name": "屏幕旋转", "preferences.video.screen-rotation.name": "屏幕旋转",
"preferences.video.screen-rotation.placeholder": "默认值为设备屏幕旋转角度", "preferences.video.screen-rotation.placeholder": "默认值为设备屏幕旋转角度",
"preferences.video.screen-cropping.name": "屏幕裁剪", "preferences.video.screen-cropping.name": "屏幕裁剪",
@ -186,8 +186,8 @@
"preferences.audio.audio-source.placeholder": "默认为设备音频输出", "preferences.audio.audio-source.placeholder": "默认为设备音频输出",
"preferences.audio.audio-source.tips": "技巧:如果将来源设为麦克风将可以在录制时将声音录制下来", "preferences.audio.audio-source.tips": "技巧:如果将来源设为麦克风将可以在录制时将声音录制下来",
"preferences.audio.audio-source.mic": "麦克风", "preferences.audio.audio-source.mic": "麦克风",
"preferences.audio.audio-codec.name": "音频编", "preferences.audio.audio-code.name": "音频编码",
"preferences.audio.audio-codec.placeholder": "默认为 Opus", "preferences.audio.audio-code.placeholder": "默认为 Opus",
"preferences.audio.audio-bit-rate.name": "音频比特率", "preferences.audio.audio-bit-rate.name": "音频比特率",
"preferences.audio.audio-bit-rate.placeholder": "默认为 128000bps", "preferences.audio.audio-bit-rate.placeholder": "默认为 128000bps",
"preferences.audio.audio-bit-rate.tips": "注意:此选项不适用于 RAW 音频编解码器", "preferences.audio.audio-bit-rate.tips": "注意:此选项不适用于 RAW 音频编解码器",

View File

@ -16,11 +16,11 @@ export default {
], ],
}, },
audioCode: { audioCode: {
label: 'preferences.audio.audio-codec.name', label: 'preferences.audio.audio-code.name',
field: '--audio-code', field: '--audio-code',
type: 'AudioCodecSelect', type: 'AudioCodecSelect',
value: '', value: '',
placeholder: 'preferences.audio.audio-codec.placeholder', placeholder: 'preferences.audio.audio-code.placeholder',
options: [ options: [
{ {
label: 'opus & c2.android.opus.encoder', label: 'opus & c2.android.opus.encoder',

View File

@ -26,11 +26,11 @@ export default {
append: 'fps', append: 'fps',
}, },
videoCode: { videoCode: {
label: 'preferences.video.codec.name', label: 'preferences.video.video-code.name',
field: '--video-code', field: '--video-code',
type: 'VideoCodecSelect', type: 'VideoCodecSelect',
value: '', value: '',
placeholder: 'preferences.video.codec.placeholder', placeholder: 'preferences.video.video-code.placeholder',
options: [ options: [
{ {
label: 'h265 & OMX.qcom.video.encoder.avc', label: 'h265 & OMX.qcom.video.encoder.avc',