diff --git a/README.md b/README.md index 1fbd81b..ec3d78b 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,13 @@ 4. 按下 `Ctrl` + `Shift` + `I` 进入开发者工具,并查看是否有任何报错信息。 5. 如果有报错,请截图并在 [反馈问题](https://github.com/viarotel-org/escrcpy/issues) 页面中提交您的问题。 +### macOS 关闭窗口选择最小化到托盘后顶部右侧状态栏找不到图标 + +> 这个一般是状态栏图标过多导致无法展示 Escrcpy 的图标 推荐用以下工具解决 + +- [iBar](https://www.better365.cn/ibar.html) +- [Bartender](https://www.macbartender.com/) + ## 获得帮助 > 因为是开源项目 全靠爱发电 所以支持有限 更新节奏不固定 diff --git a/electron/events/tray/index.js b/electron/events/tray/index.js index 15c1470..4139a8e 100644 --- a/electron/events/tray/index.js +++ b/electron/events/tray/index.js @@ -10,14 +10,31 @@ export default (mainWindow) => { tray.destroy() tray = null } + + if (process.platform === 'darwin') { + app.dock.show() + } + mainWindow.show() return true } + const hideApp = () => { + if (process.platform === 'darwin') { + app.dock.hide() + } + + mainWindow.hide() + + return true + } + const quitApp = () => { app.isQuiting = true + app.quit() + return true } @@ -27,7 +44,7 @@ export default (mainWindow) => { return true } else if (response === 1) { - mainWindow.hide() + hideApp() tray = new Tray(trayPath) diff --git a/electron/exposes/adbkit/index.js b/electron/exposes/adbkit/index.js index 74a6349..36e66f3 100644 --- a/electron/exposes/adbkit/index.js +++ b/electron/exposes/adbkit/index.js @@ -20,10 +20,6 @@ window.addEventListener('beforeunload', () => { appStore.onDidChange('scrcpy.global.adbPath', async (value, oldValue) => { console.log('onDidChange.scrcpy.global.adbPath', value) - if (!value) { - return false - } - if (value === oldValue) { return false } @@ -37,7 +33,7 @@ appStore.onDidChange('scrcpy.global.adbPath', async (value, oldValue) => { client = null } - client = Adb.createClient({ bin: value }) + client = Adb.createClient({ bin: value || adbPath }) }) const shell = async command => exec(`${adbPath} ${command}`) diff --git a/electron/exposes/scrcpy/index.js b/electron/exposes/scrcpy/index.js index 90be756..f3ee288 100644 --- a/electron/exposes/scrcpy/index.js +++ b/electron/exposes/scrcpy/index.js @@ -4,10 +4,11 @@ import { adbPath, scrcpyPath } from '@electron/configs/index.js' const shell = async (command, { stdout, stderr } = {}) => { const spawnPath = appStore.get('scrcpy.global.scrcpyPath') || scrcpyPath + const ADB = appStore.get('scrcpy.global.adbPath') || adbPath const args = command.split(' ') const scrcpyProcess = spawn(spawnPath, args, { - env: { ...process.env, ADB: adbPath }, + env: { ...process.env, ADB }, shell: true, }) diff --git a/electron/main.js b/electron/main.js index 664d56c..14d5033 100644 --- a/electron/main.js +++ b/electron/main.js @@ -37,8 +37,13 @@ function createWindow() { } mainWindow = new BrowserWindow({ + // 这里设置的图标仅在开发模式生效,打包后将使用应用程序图标 + ...(!app.isPackaged + ? { + icon, + } + : {}), show: false, - icon, width: 1000, height: 700, minWidth: 1000, @@ -85,12 +90,20 @@ app.on('window-all-closed', () => { mainWindow = null }) +// 仅 macOS 有这个事件 app.on('activate', () => { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow() } + + if (app.isHidden()) { + app.show() + app.focus() + } + + if (!app.dock.isVisible()) { + app.dock.show() + } }) app.whenReady().then(() => { diff --git a/electron/resources/extra/tray-raw.png b/electron/resources/extra/tray-raw.png new file mode 100644 index 0000000..ae63d41 Binary files /dev/null and b/electron/resources/extra/tray-raw.png differ diff --git a/electron/resources/extra/trayTemplate.png b/electron/resources/extra/trayTemplate.png index 939860b..d10c981 100644 Binary files a/electron/resources/extra/trayTemplate.png and b/electron/resources/extra/trayTemplate.png differ diff --git a/electron/resources/extra/trayTemplate@2x.png b/electron/resources/extra/trayTemplate@2x.png index fc8b6a5..f6ed3d5 100644 Binary files a/electron/resources/extra/trayTemplate@2x.png and b/electron/resources/extra/trayTemplate@2x.png differ diff --git a/electron/resources/extra/trayTemplate@4x.png b/electron/resources/extra/trayTemplate@4x.png index 51c62f5..6707958 100644 Binary files a/electron/resources/extra/trayTemplate@4x.png and b/electron/resources/extra/trayTemplate@4x.png differ diff --git a/src/App.vue b/src/App.vue index 80e4f08..8dcd5bf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -25,6 +25,11 @@ export default { Preference, About, }, + provide() { + return { + $app: this, + } + }, data() { return { tabsModel: [ @@ -42,6 +47,7 @@ export default { }, ], activeTab: 'Device', + renderTab: '', rendered: true, } }, @@ -80,15 +86,20 @@ export default { ) }, isRender(item) { - if (this.activeTab === item.prop) { + if (this.renderTab === item.prop) { return this.rendered } + return true }, - async reRender() { + async reRender(other) { + this.renderTab = other || this.activeTab + this.rendered = false await this.$nextTick() this.rendered = true + + this.renderTab = '' }, async onTabChange(prop) { switch (prop) { diff --git a/src/components/Device/index.vue b/src/components/Device/index.vue index 272e5c7..3a38828 100644 --- a/src/components/Device/index.vue +++ b/src/components/Device/index.vue @@ -36,11 +36,11 @@ type="primary" :icon="loading ? '' : 'Refresh'" :loading="loading" - @click="getDeviceData" + @click="handleRefresh" > 刷新设备 - + 重启服务 @@ -172,6 +172,7 @@ export default { ControlBar, Remark, }, + inject: ['$app'], data() { const adbCache = storage.get('adbCache') || {} return { @@ -216,6 +217,35 @@ export default { scrcpyArgs(...args) { return this.$store.scrcpy.getStringConfig(...args) }, + handleRefresh() { + this.getDeviceData({ resetResolve: true }) + }, + async handleReset(depType = 'scrcpy') { + try { + await this.$confirm( + ` +
通常情况下,这可能是因为更新 Escrcpy 后,缓存的依赖配置不兼容所导致的,是否重置依赖配置?
+
注意:重置后,之前保存的依赖配置将会被清除,因此建议在执行重置操作之前备份您的配置。
+ `, + '操作失败', + { + dangerouslyUseHTMLString: true, + confirmButtonText: '重置依赖配置', + cancelButtonText: '取消', + closeOnClickModal: false, + type: 'warning', + }, + ) + this.$store.scrcpy.resetDeps(depType) + this.$app.reRender('Preference') + this.$message.success('操作成功,请重新尝试。') + } + catch (error) { + if (error.message) { + console.warn(error.message) + } + } + }, onStdout() {}, toggleRowExpansion(...params) { this.$refs.elTable.toggleRowExpansion(...params) @@ -269,6 +299,8 @@ export default { if (error.message) { this.$message.warning(error.message) } + + this.handleReset() } row.$recordLoading = false }, @@ -289,6 +321,7 @@ export default { if (error.message) { this.$message.warning(error.message) } + this.handleReset() } row.$loading = false }, @@ -310,7 +343,7 @@ export default { onPairSuccess() { this.handleConnect() }, - handleReset() { + handleRestart() { this.$electron.ipcRenderer.send('restart-app') }, async handleConnect() { @@ -326,7 +359,7 @@ export default { storage.set('adbCache', this.formData) } catch (error) { - this.handleError(error.message) + this.handleError(error?.message || error?.cause?.message || error) } this.connectLoading = false }, @@ -339,7 +372,8 @@ export default {
1. IP地址或端口号错误
2. 设备未与当前电脑配对成功
3. 电脑网络和提供的设备网络IP不在同一个局域网中
-
4. 其他未知错误
+
4. adb 依赖路径错误
+
5. 其他未知错误
`, '连接设备失败', { @@ -371,7 +405,7 @@ export default { row.$stopLoading = false }, - async getDeviceData() { + async getDeviceData({ resetResolve = false } = {}) { this.loading = true await sleep(500) try { @@ -392,6 +426,10 @@ export default { this.$message.warning(error?.message || error?.cause?.message) } this.deviceList = [] + + if (resetResolve) { + this.handleReset('adb') + } } this.loading = false this.loadingText = '正在获取设备列表...' diff --git a/src/components/Preference/index.vue b/src/components/Preference/index.vue index a1ea1e7..16be38a 100644 --- a/src/components/Preference/index.vue +++ b/src/components/Preference/index.vue @@ -191,6 +191,7 @@ import { useScrcpyStore } from '@/store/index.js' import LoadingIcon from '@/components/Device/ControlBar/LoadingIcon/index.vue' export default { + inject: ['$app'], data() { const scrcpyStore = useScrcpyStore() diff --git a/src/store/scrcpy/index.js b/src/store/scrcpy/index.js index 21c725b..228cf5d 100644 --- a/src/store/scrcpy/index.js +++ b/src/store/scrcpy/index.js @@ -5,6 +5,8 @@ import { replaceIP } from '@/utils/index.js' const $appStore = window.appStore +const { adbPath, scrcpyPath } = window.electron?.configs || {} + function mergeConfig(object, sources, { debug = false } = {}) { const customizer = (objValue, srcValue) => { if (debug) { @@ -89,6 +91,21 @@ export const useScrcpyStore = defineStore({ this.init() }, + resetDeps(type) { + switch (type) { + case 'adb': + $appStore.set('scrcpy.global.adbPath', '') + break + case 'scrcpy': + $appStore.set('scrcpy.global.scrcpyPath', '') + break + default: + $appStore.set('scrcpy.global.adbPath', '') + $appStore.set('scrcpy.global.scrcpyPath', '') + break + } + this.init() + }, setScope(value) { this.scope = replaceIP(value) $appStore.set('scrcpy.scope', this.scope) @@ -127,7 +144,20 @@ export const useScrcpyStore = defineStore({ return value }, setConfig(data, scope = this.scope) { - $appStore.set(`scrcpy.${replaceIP(scope)}`, { ...data }) + const cloneData = cloneDeep(data) + + // console.log('adbPath', adbPath) + // console.log('scrcpyPath', scrcpyPath) + + if (data.adbPath === adbPath) { + delete cloneData.adbPath + } + + if (data.scrcpyPath === scrcpyPath) { + delete cloneData.scrcpyPath + } + + $appStore.set(`scrcpy.${replaceIP(scope)}`, cloneData) this.init(scope) }, diff --git a/src/store/scrcpy/model/custom/index.js b/src/store/scrcpy/model/custom/index.js index e6e5fd3..42872e3 100644 --- a/src/store/scrcpy/model/custom/index.js +++ b/src/store/scrcpy/model/custom/index.js @@ -17,9 +17,9 @@ export default () => { type: 'input.path', value: adbPath, tips: '用于连接设备的 adb 的地址,注意:该选项不受针对于单个设备配置的影响', - placeholder: '请选择 adb', + placeholder: '请设置 adb 路径', properties: ['openFile'], - filters: [{ name: '请选择 adb', extensions: ['*'] }], + filters: [{ name: '请设置 adb 路径', extensions: ['*'] }], }, { label: 'scrcpy 路径', @@ -27,9 +27,9 @@ export default () => { type: 'input.path', value: scrcpyPath, tips: '用于控制设备的 scrcpy 的地址,注意:该选项不受针对于单个设备配置的影响', - placeholder: '请选择 scrcpy', + placeholder: '请设置 scrcpy 路径', properties: ['openFile'], - filters: [{ name: '请选择 scrcpy', extensions: ['*'] }], + filters: [{ name: '请设置 scrcpy 路径', extensions: ['*'] }], }, ] }