mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2024-11-12 01:40:52 +01:00
perf: ✅ Support batch screenshot and other performance optimization
This commit is contained in:
parent
49ae54166a
commit
db9e3e791e
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -49,5 +49,6 @@
|
||||
],
|
||||
"cSpell.words": [
|
||||
"bhsn"
|
||||
]
|
||||
],
|
||||
"common-intellisense.ui": []
|
||||
}
|
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## [1.20.1](https://github.com/viarotel-org/escrcpy/compare/v1.20.0...v1.20.1) (2024-07-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Fix batch text spelling errors ([062c689](https://github.com/viarotel-org/escrcpy/commit/062c689755df5bcc5f8e38605c7f101762d7ada0))
|
||||
|
||||
## [1.20.0](https://github.com/viarotel-org/escrcpy/compare/v1.19.4...v1.20.0) (2024-07-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add batch installation application function ([37ce245](https://github.com/viarotel-org/escrcpy/commit/37ce2457bce9a1b661c6db7162023f53268833f5))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 🚀 Add mouse binding options ([7ee4ba4](https://github.com/viarotel-org/escrcpy/commit/7ee4ba4f2b177e6dbfce85036425b51bfa35ecff))
|
||||
|
||||
## [1.19.4](https://github.com/viarotel-org/escrcpy/compare/v1.19.3...v1.19.4) (2024-07-02)
|
||||
|
||||
|
||||
|
@ -203,7 +203,7 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
||||
15. 支持批量连接历史设备功能 ✅
|
||||
16. 支持使用内置终端执行自定义命令 ✅
|
||||
17. 支持设备自动执行镜像 ✅
|
||||
18. 添加批量安装应用功能 ✅
|
||||
18. 支持常用批量功能 ✅
|
||||
19. 支持更多批量处理功能 🚧
|
||||
20. 支持对设备进行分组 🚧
|
||||
21. 添加文件传输助手功能 🚧
|
||||
|
@ -201,7 +201,7 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
||||
15. Support bulk connecting to historical devices ✅
|
||||
16. Support to use built-in terminals to execute custom commands ✅
|
||||
17. Supports automatic execution of mirror on devices ✅
|
||||
18. Add batch installation application function ✅
|
||||
18. Support common batch processing function ✅
|
||||
19. Support more batch processing functions 🚧
|
||||
20. Support the device to group 🚧
|
||||
21. Add file transmission assistant function 🚧
|
||||
|
32
components.d.ts
vendored
32
components.d.ts
vendored
@ -7,21 +7,11 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
About: typeof import('./src/components/About/index.vue')['default']
|
||||
AppInstall: typeof import('./src/components/Device/components/BatchActions/AppInstall/index.vue')['default']
|
||||
AppSearch: typeof import('./src/components/AppSearch/index.vue')['default']
|
||||
AudioCodecSelect: typeof import('./src/components/Preference/components/AudioCodecSelect/index.vue')['default']
|
||||
BatchActions: typeof import('./src/components/Device/components/BatchActions/index.vue')['default']
|
||||
Camera: typeof import('./src/components/Device/components/MoreDropdown/components/Camera/index.vue')['default']
|
||||
ControlBar: typeof import('./src/components/Device/components/ControlBar/index.vue')['default']
|
||||
Device: typeof import('./src/components/Device/index.vue')['default']
|
||||
DisplaySelect: typeof import('./src/components/Preference/components/DisplaySelect/index.vue')['default']
|
||||
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
@ -44,28 +34,6 @@ declare module 'vue' {
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
FileManage: typeof import('./src/components/Device/components/ControlBar/FileManage/index.vue')['default']
|
||||
Gnirehtet: typeof import('./src/components/Device/components/ControlBar/Gnirehtet/index.vue')['default']
|
||||
KeyboardInjectSelect: typeof import('./src/components/Preference/components/KeyboardInjectSelect/index.vue')['default']
|
||||
LanguageSelect: typeof import('./src/components/Preference/components/LanguageSelect/index.vue')['default']
|
||||
LoadingIcon: typeof import('./src/components/Device/components/LoadingIcon/index.vue')['default']
|
||||
MirrorAction: typeof import('./src/components/Device/components/MirrorAction/index.vue')['default']
|
||||
MirrorGroup: typeof import('./src/components/Device/components/ControlBar/MirrorGroup/index.vue')['default']
|
||||
MoreDropdown: typeof import('./src/components/Device/components/MoreDropdown/index.vue')['default']
|
||||
Otg: typeof import('./src/components/Device/components/MoreDropdown/components/Otg/index.vue')['default']
|
||||
PairDialog: typeof import('./src/components/Device/components/Wireless/PairDialog/index.vue')['default']
|
||||
PathInput: typeof import('./src/components/Preference/components/PathInput/index.vue')['default']
|
||||
Preference: typeof import('./src/components/Preference/index.vue')['default']
|
||||
Record: typeof import('./src/components/Device/components/MoreDropdown/components/Record/index.vue')['default']
|
||||
Remark: typeof import('./src/components/Device/components/Remark/index.vue')['default']
|
||||
Rotation: typeof import('./src/components/Device/components/ControlBar/Rotation/index.vue')['default']
|
||||
Screenshot: typeof import('./src/components/Device/components/ControlBar/Screenshot/index.vue')['default']
|
||||
TerminalAction: typeof import('./src/components/Device/components/TerminalAction/index.vue')['default']
|
||||
TerminalDialog: typeof import('./src/components/Device/components/TerminalAction/components/TerminalDialog/index.vue')['default']
|
||||
VideoCodecSelect: typeof import('./src/components/Preference/components/VideoCodecSelect/index.vue')['default']
|
||||
Volume: typeof import('./src/components/Device/components/ControlBar/Volume/index.vue')['default']
|
||||
Wireless: typeof import('./src/components/Device/components/Wireless/index.vue')['default']
|
||||
WirelessAction: typeof import('./src/components/Device/components/WirelessAction/index.vue')['default']
|
||||
}
|
||||
export interface ComponentCustomProperties {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
|
@ -27,8 +27,6 @@ log.initialize({ preload: true })
|
||||
|
||||
const debug = !!appStore.get('common.debug')
|
||||
|
||||
log.info('Debug Status:', debug)
|
||||
|
||||
if (!debug) {
|
||||
log.warn(
|
||||
'Debug Tips:',
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "escrcpy",
|
||||
"type": "module",
|
||||
"version": "1.19.4",
|
||||
"version": "1.20.1",
|
||||
"private": true,
|
||||
"description": "Scrcpy Powered by Electron",
|
||||
"author": "viarotel",
|
||||
|
@ -33,7 +33,7 @@ import { ElMessageBox } from 'element-plus'
|
||||
import Device from './components/Device/index.vue'
|
||||
import Preference from './components/Preference/index.vue'
|
||||
import About from './components/About/index.vue'
|
||||
import AppSearch from './components/AppSearch/index.vue'
|
||||
import AppSearch from './components/Search/index.vue'
|
||||
|
||||
import { useThemeStore } from '$/store/theme/index.js'
|
||||
import { usePreferenceStore } from '$/store/preference/index.js'
|
||||
|
@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="" @click="handleClick">
|
||||
<slot />
|
||||
<AppInstallProxy ref="appInstallProxyRef" />
|
||||
<ApplicationProxy ref="applicationProxyRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInstallProxy from '$/components/Device/components/ControlBar/AppInstall/index.vue'
|
||||
import ApplicationProxy from '$/components/Device/components/ControlBar/Application/index.vue'
|
||||
import { sleep } from '$/utils'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AppInstallProxy,
|
||||
ApplicationProxy,
|
||||
},
|
||||
props: {
|
||||
devices: {
|
||||
@ -23,7 +23,7 @@ export default {
|
||||
async handleClick() {
|
||||
for (let index = 0; index < this.devices.length; index++) {
|
||||
const item = this.devices[index]
|
||||
await this.$refs.appInstallProxyRef.handleInstall(item)
|
||||
await this.$refs.applicationProxyRef.invoke(item)
|
||||
await sleep(2 * 1000)
|
||||
}
|
||||
},
|
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="" @click="handleClick">
|
||||
<slot />
|
||||
<ScreenshotProxy ref="screenshotProxyRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ScreenshotProxy from '$/components/Device/components/ControlBar/Screenshot/index.vue'
|
||||
import { sleep } from '$/utils'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ScreenshotProxy,
|
||||
},
|
||||
props: {
|
||||
devices: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async handleClick() {
|
||||
for (let index = 0; index < this.devices.length; index++) {
|
||||
const item = this.devices[index]
|
||||
await this.$refs.screenshotProxyRef.invoke(item)
|
||||
await sleep(2 * 1000)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center space-x-2">
|
||||
<component
|
||||
:is="item.component || 'div'"
|
||||
v-for="(item, index) in actionModel"
|
||||
@ -31,7 +31,7 @@
|
||||
<component :is="item.elIcon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
{{ $t('common.batch') }}{{ $t(item.label) }}
|
||||
{{ $t('common.batch') }}-{{ $t(item.label) }}
|
||||
</el-button>
|
||||
</template>
|
||||
</component>
|
||||
@ -39,11 +39,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInstall from './AppInstall/index.vue'
|
||||
import Application from './Application/index.vue'
|
||||
import Screenshot from './Screenshot/index.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AppInstall,
|
||||
Application,
|
||||
Screenshot,
|
||||
},
|
||||
props: {
|
||||
devices: {
|
||||
@ -54,10 +56,15 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
actionModel: [
|
||||
{
|
||||
label: 'device.control.capture',
|
||||
elIcon: 'Crop',
|
||||
component: 'Screenshot',
|
||||
},
|
||||
{
|
||||
label: 'device.control.install',
|
||||
svgIcon: 'install',
|
||||
component: 'AppInstall',
|
||||
component: 'Application',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -5,8 +5,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LoadingIcon from '$/components/Device/components/LoadingIcon/index.vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
device: {
|
||||
@ -18,6 +16,9 @@ export default {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
invoke(...args) {
|
||||
return this.handleInstall(...args)
|
||||
},
|
||||
preferenceData(...args) {
|
||||
return this.$store.preference.getData(...args)
|
||||
},
|
||||
@ -46,13 +47,11 @@ export default {
|
||||
return false
|
||||
}
|
||||
|
||||
const messageEl = this.$message({
|
||||
message: this.$t('device.control.install.progress', {
|
||||
const messageEl = this.$message.loading(
|
||||
this.$t('device.control.install.progress', {
|
||||
deviceName: this.$store.device.getLabel(device),
|
||||
}),
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
)
|
||||
|
||||
let failCount = 0
|
||||
|
@ -1,12 +1,10 @@
|
||||
<template>
|
||||
<div class="" @click="handleScreenCap(device)">
|
||||
<div class="" @click="handleCapture(device)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LoadingIcon from '$/components/Device/components/LoadingIcon/index.vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
device: {
|
||||
@ -18,21 +16,22 @@ export default {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
invoke(...args) {
|
||||
return this.handleCapture(...args)
|
||||
},
|
||||
preferenceData(...args) {
|
||||
return this.$store.preference.getData(...args)
|
||||
},
|
||||
async handleScreenCap(device) {
|
||||
const messageEl = this.$message({
|
||||
message: this.$t('device.control.capture.progress', {
|
||||
async handleCapture(device) {
|
||||
const messageEl = this.$message.loading(
|
||||
this.$t('device.control.capture.progress', {
|
||||
deviceName: this.$store.device.getLabel(device),
|
||||
}),
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
)
|
||||
|
||||
const fileName = this.$store.device.getLabel(
|
||||
device,
|
||||
({ time }) => `screenshot-${time}.png`,
|
||||
({ time }) => `screenshot-${time}.jpg`,
|
||||
)
|
||||
|
||||
const deviceConfig = this.preferenceData(device.id)
|
||||
@ -40,7 +39,7 @@ export default {
|
||||
|
||||
try {
|
||||
await this.$adb.screencap(device.id, { savePath })
|
||||
this.handleScreencapSuccess(savePath)
|
||||
await this.handleSuccess(savePath)
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message) {
|
||||
@ -50,29 +49,12 @@ export default {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
async handleSuccess(savePath) {
|
||||
return this.$message.success(
|
||||
`${this.$t(
|
||||
'device.control.capture.success.message.title',
|
||||
)}: ${savePath}`,
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -66,7 +66,7 @@
|
||||
|
||||
<script>
|
||||
import Screenshot from './Screenshot/index.vue'
|
||||
import AppInstall from './AppInstall/index.vue'
|
||||
import Application from './Application/index.vue'
|
||||
import Gnirehtet from './Gnirehtet/index.vue'
|
||||
import MirrorGroup from './MirrorGroup/index.vue'
|
||||
import Rotation from './Rotation/index.vue'
|
||||
@ -76,7 +76,7 @@ import FileManage from './FileManage/index.vue'
|
||||
export default {
|
||||
components: {
|
||||
Screenshot,
|
||||
AppInstall,
|
||||
Application,
|
||||
Gnirehtet,
|
||||
MirrorGroup,
|
||||
Rotation,
|
||||
@ -142,7 +142,7 @@ export default {
|
||||
{
|
||||
label: 'device.control.install',
|
||||
svgIcon: 'install',
|
||||
component: 'AppInstall',
|
||||
component: 'Application',
|
||||
},
|
||||
{
|
||||
label: 'device.control.file.name',
|
||||
|
@ -51,7 +51,7 @@ export default {
|
||||
|
||||
await recording
|
||||
|
||||
this.onRecordSuccess(savePath)
|
||||
await this.handleSuccess(savePath)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('record.args', args)
|
||||
@ -79,24 +79,10 @@ export default {
|
||||
|
||||
return value
|
||||
},
|
||||
async onRecordSuccess(savePath) {
|
||||
try {
|
||||
await this.$confirm(
|
||||
this.$t('device.record.success.message'),
|
||||
this.$t('device.record.success.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) {
|
||||
console.warn(error)
|
||||
}
|
||||
async handleSuccess(savePath) {
|
||||
return this.$message.success(
|
||||
`${this.$t('device.record.success.title')}: ${savePath}`,
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex items-center flex-none space-x-2 pt-1">
|
||||
<div class="flex items-center flex-none space-x-2 py-1 overflow-x-auto">
|
||||
<Wireless ref="wireless" :reload="getDeviceData" />
|
||||
|
||||
<div class="w-px h-7 !ml-4 !mr-2 bg-gray-200"></div>
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
<BatchActions
|
||||
class="overflow-hidden transition-all"
|
||||
:class="isMultipleRow ? 'h-12 opacity-100 mt-4' : 'h-0 opacity-0 mt-0'"
|
||||
:class="isMultipleRow ? 'h-12 opacity-100 mt-3' : 'h-0 opacity-0 mt-0'"
|
||||
:devices="selectionRows"
|
||||
/>
|
||||
|
||||
@ -68,6 +68,7 @@
|
||||
sortable
|
||||
show-overflow-tooltip
|
||||
align="left"
|
||||
min-width="200"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center">
|
||||
@ -96,7 +97,7 @@
|
||||
<el-table-column
|
||||
v-slot="{ row, $index }"
|
||||
:label="$t('device.control.name')"
|
||||
width="450"
|
||||
width="400"
|
||||
align="left"
|
||||
>
|
||||
<MirrorAction
|
||||
|
@ -208,7 +208,6 @@ import DisplaySelect from './components/DisplaySelect/index.vue'
|
||||
import KeyboardInjectSelect from './components/KeyboardInjectSelect/index.vue'
|
||||
|
||||
import { usePreferenceStore } from '$/store/index.js'
|
||||
import LoadingIcon from '$/components/Device/components/LoadingIcon/index.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -349,11 +348,7 @@ export default {
|
||||
},
|
||||
|
||||
async handleExport() {
|
||||
const messageEl = this.$message({
|
||||
message: this.$t('preferences.config.export.message'),
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
const messageEl = this.$message.loading(this.$t('preferences.config.export.message'))
|
||||
|
||||
try {
|
||||
await this.$electron.ipcRenderer.invoke('show-save-dialog', {
|
||||
|
@ -16,6 +16,7 @@ export default () => {
|
||||
}),
|
||||
useAutoComponents({
|
||||
resolvers,
|
||||
dirs: 'none',
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LoadingIcon',
|
||||
name: 'EleIconLoading',
|
||||
}
|
||||
</script>
|
||||
|
@ -8,12 +8,22 @@ import 'element-plus/theme-chalk/el-message-box.css'
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
import './restyle.css'
|
||||
|
||||
import EleIconLoading from './components/EleIconLoading/index.vue'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
for (const [key, component] of Object.entries(ElementPlusIcons)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
ElMessage.loading = (message, options = {}) =>
|
||||
ElMessage({
|
||||
duration: 0,
|
||||
...options,
|
||||
message,
|
||||
icon: EleIconLoading,
|
||||
})
|
||||
|
||||
app.use(ElMessage)
|
||||
app.use(ElMessageBox)
|
||||
app.use(ElLoading)
|
||||
|
@ -7,6 +7,7 @@ html {
|
||||
@screen sm {
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
|
Loading…
Reference in New Issue
Block a user