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
}
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 () => ({
shell,
execShell,
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"
title="滚动查看被遮盖的菜单"
>
<el-button
<component
:is="item.component || 'div'"
v-for="(item, index) in controlModel"
:key="index"
type="primary"
plain
class="!border-none !mx-0 bg-transparent !rounded-0 flex-none"
:disabled="device.$unauthorized"
:title="item.tips ? $t(item.tips) : ''"
@wheel.prevent="onWheel"
@click="handleClick(item)"
class="flex-none"
v-bind="{
device,
...(item.command
? {
onClick: () => handleShell(item),
}
: {}),
}"
>
<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>
<el-button
type="primary"
plain
class="!border-none !mx-0 bg-transparent !rounded-0"
:disabled="device.$unauthorized"
:title="item.tips ? $t(item.tips) : ''"
@wheel.prevent="onWheel"
>
<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>
</template>
<script>
import dayjs from 'dayjs'
import LoadingIcon from './LoadingIcon/index.vue'
import Screenshot from './Screenshot/index.vue'
import AppInstall from './AppInstall/index.vue'
import Gnirehtet from './Gnirehtet/index.vue'
export default {
components: {
Screenshot,
AppInstall,
Gnirehtet,
},
props: {
device: {
type: Object,
@ -75,19 +93,19 @@ export default {
{
label: 'device.control.capture',
elIcon: 'Crop',
handle: this.handleScreenCap,
component: 'Screenshot',
tips: '',
},
{
label: 'device.control.install',
svgIcon: 'install',
handle: this.handleInstall,
component: 'AppInstall',
tips: '',
},
{
label: 'device.control.gnirehtet',
elIcon: 'Link',
handle: this.handleGnirehtet,
component: 'Gnirehtet',
tips: 'device.control.gnirehtet.tips',
},
],
@ -99,164 +117,8 @@ export default {
const container = this.$refs.wheelContainer
container.scrollLeft += event.deltaY
},
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()
},
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)
}
}
handleShell(row) {
this.$adb.deviceShell(this.device.id, row.command)
},
},
}

View File

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

View File

@ -138,8 +138,8 @@
"preferences.video.bit.placeholder": "Default 4M, equal to 4000000",
"preferences.video.refresh-rate.name": "Frame Rate",
"preferences.video.refresh-rate.placeholder": "Default 60",
"preferences.video.codec.name": "Video Codec",
"preferences.video.codec.placeholder": "Default H.264",
"preferences.video.video-code.name": "Video Codec",
"preferences.video.video-code.placeholder": "Default H.264",
"preferences.video.screen-rotation.name": "Rotation",
"preferences.video.screen-rotation.placeholder": "Default device rotation",
"preferences.video.screen-cropping.name": "Crop",
@ -179,12 +179,21 @@
"preferences.record.format.name": "Format",
"preferences.record.format.placeholder": "Default *.mp4",
"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.placeholder": "Default 0ms",
"preferences.audio.audio-output-buffer.name": "Audio Output Buffer",
"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.enable.name": "Enable OTG",
"preferences.otg.enable.placeholder": "Enable or disable OTG",

View File

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

View File

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

View File

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