From 8807e5041399acd228ee739c610778272e431bdd Mon Sep 17 00:00:00 2001 From: viarotel Date: Thu, 12 Sep 2024 19:11:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20Support=20floating=20contro?= =?UTF-8?q?l=20bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- control/App.vue | 118 ++++++++++++++++++ control/electron/helpers/index.js | 44 +++++++ control/electron/main.js | 56 +++++++++ control/index.html | 13 ++ control/index.js | 5 + electron/configs/index.js | 13 ++ electron/events/app/index.js | 19 +++ electron/events/index.js | 10 +- electron/helpers/index.js | 14 ++- electron/helpers/store.js | 2 +- electron/main.js | 31 ++--- eslint.config.js | 1 + jsconfig.json | 3 +- src/bootstrap/default/index.js | 48 +++++++ src/bootstrap/index.js | 3 + .../Device/components/ControlBar/index.vue | 2 +- .../Device/components/MirrorAction/index.vue | 4 + .../MoreDropdown/components/Custom/index.vue | 5 + .../MoreDropdown/components/Record/index.vue | 3 + src/components/Device/index.vue | 2 +- .../components/SelectLanguage/index.vue | 1 + src/components/Preference/index.vue | 1 + src/locales/languages/en-US.json | 2 + src/locales/languages/zh-CN.json | 2 + src/locales/languages/zh-TW.json | 2 + src/main.js | 45 +------ src/store/preference/model/common/index.js | 7 ++ src/utils/device/index.js | 10 ++ vite.config.js | 35 +++--- 29 files changed, 406 insertions(+), 95 deletions(-) create mode 100644 control/App.vue create mode 100644 control/electron/helpers/index.js create mode 100644 control/electron/main.js create mode 100644 control/index.html create mode 100644 control/index.js create mode 100644 electron/events/app/index.js create mode 100644 src/bootstrap/default/index.js create mode 100644 src/bootstrap/index.js diff --git a/control/App.vue b/control/App.vue new file mode 100644 index 0000000..967be4f --- /dev/null +++ b/control/App.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/control/electron/helpers/index.js b/control/electron/helpers/index.js new file mode 100644 index 0000000..69742ab --- /dev/null +++ b/control/electron/helpers/index.js @@ -0,0 +1,44 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { BrowserWindow } from 'electron' +import { getLogoPath } from '$electron/configs/index.js' +import { sleep } from '$renderer/utils/index.js' +import { loadPage } from '$electron/helpers/index.js' + +export function initControlWindow(mainWindow) { + const __dirname = path.dirname(fileURLToPath(import.meta.url)) + + const controlWindow = new BrowserWindow({ + icon: getLogoPath(), + width: 500, + minWidth: 500, + height: 30, + maxHeight: 30, + frame: false, + show: false, + autoHideMenuBar: true, + alwaysOnTop: true, + skipTaskbar: true, + webPreferences: { + preload: path.join(__dirname, 'preload.mjs'), + nodeIntegration: true, + sandbox: false, + spellcheck: false, + }, + }) + + controlWindow.customId = 'control' + + loadPage(controlWindow, 'control/') + + return controlWindow +} + +export async function openControlWindow(win, data, args = {}) { + if (args.sleep) { + await sleep(args.sleep) + } + + win.show() + win.webContents.send('device-change', data) +} diff --git a/control/electron/main.js b/control/electron/main.js new file mode 100644 index 0000000..943a0d4 --- /dev/null +++ b/control/electron/main.js @@ -0,0 +1,56 @@ +import { BrowserWindow, ipcMain, Menu } from 'electron' +import { initControlWindow, openControlWindow } from './helpers/index.js' + +export default (mainWindow) => { + let controlWindow + + ipcMain.on('open-control-window', (event, data) => { + controlWindow = BrowserWindow.getAllWindows().find( + win => win.customId === 'control', + ) + + if (!controlWindow) { + controlWindow = initControlWindow(mainWindow) + + ipcMain.on('control-mounted', () => { + openControlWindow(controlWindow, data) + }) + + return false + } + + openControlWindow(controlWindow, data) + }) + + ipcMain.on('language-change', (event, data) => { + if (controlWindow) { + controlWindow.webContents.send('language-change', data) + } + }) + + ipcMain.on('theme-change', (event, data) => { + if (controlWindow) { + controlWindow.webContents.send('theme-change', data) + } + }) + + ipcMain.on('show-device-list', (event, deviceList) => { + const template = deviceList.map((item) => { + let label = item.$remark || item.$name + + if (item.$wifi) { + label += ` (WIFI)` + } + + return { + label, + click: () => { + openControlWindow(controlWindow, item) + }, + } + }) + + const menu = Menu.buildFromTemplate(template) + menu.popup(BrowserWindow.fromWebContents(event.sender)) + }) +} diff --git a/control/index.html b/control/index.html new file mode 100644 index 0000000..cafae59 --- /dev/null +++ b/control/index.html @@ -0,0 +1,13 @@ + + + + + + + Escrcpy Control + + +
+ + + diff --git a/control/index.js b/control/index.js new file mode 100644 index 0000000..193213e --- /dev/null +++ b/control/index.js @@ -0,0 +1,5 @@ +import bootstrap from '../src/bootstrap/index.js' + +import App from './App.vue' + +bootstrap(App) diff --git a/electron/configs/index.js b/electron/configs/index.js index b867766..bc0e946 100644 --- a/electron/configs/index.js +++ b/electron/configs/index.js @@ -22,3 +22,16 @@ export const trayPath : extraResolve('common/tray/icon.png') export const logPath = process.env.LOG_PATH + +export function getLogoPath() { + let icon = logoPath + + if (process.platform === 'win32') { + icon = icoLogoPath + } + else if (process.platform === 'darwin') { + icon = icnsLogoPath + } + + return logoPath +} diff --git a/electron/events/app/index.js b/electron/events/app/index.js new file mode 100644 index 0000000..ccbf141 --- /dev/null +++ b/electron/events/app/index.js @@ -0,0 +1,19 @@ +import { app, BrowserWindow, ipcMain } from 'electron' + +export default () => { + ipcMain.on('restart-app', () => { + app.isQuiting = true + app.relaunch() + app.quit() + }) + + ipcMain.on('close-active-window', (event) => { + const win = BrowserWindow.getFocusedWindow() + win.close() + }) + + ipcMain.on('hide-active-window', (event) => { + const win = BrowserWindow.getFocusedWindow() + win.hide() + }) +} diff --git a/electron/events/index.js b/electron/events/index.js index faa2399..50670ab 100644 --- a/electron/events/index.js +++ b/electron/events/index.js @@ -1,5 +1,4 @@ -import { app, ipcMain } from 'electron' - +import appEvents from './app/index.js' import handles from './handles/index.js' import shortcuts from './shortcuts/index.js' import theme from './theme/index.js' @@ -7,12 +6,7 @@ import tray from './tray/index.js' import updater from './updater/index.js' export default (mainWindow) => { - ipcMain.on('restart-app', () => { - app.isQuiting = true - app.relaunch() - app.quit() - }) - + appEvents(mainWindow) handles(mainWindow) updater(mainWindow) tray(mainWindow) diff --git a/electron/helpers/index.js b/electron/helpers/index.js index 9068ed7..30393a9 100644 --- a/electron/helpers/index.js +++ b/electron/helpers/index.js @@ -1,4 +1,4 @@ -import { resolve } from 'node:path' +import { join, resolve } from 'node:path' import { contextBridge } from 'electron' import { cloneDeep } from 'lodash-es' @@ -56,3 +56,15 @@ export async function executeI18n(mainWindow, value) { return value } } + +export function loadPage(win, prefix = '') { + // 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x + const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL + + if (VITE_DEV_SERVER_URL) { + win.loadURL(join(VITE_DEV_SERVER_URL, prefix)) + } + else { + win.loadFile(join(process.env.DIST, prefix, 'index.html')) + } +} diff --git a/electron/helpers/store.js b/electron/helpers/store.js index 90a0da2..afd8d8c 100644 --- a/electron/helpers/store.js +++ b/electron/helpers/store.js @@ -10,6 +10,7 @@ if (isEqual(appStore.store, {})) { } export default { + ...appStore, ...createProxy(appStore, [ 'set', 'get', @@ -21,7 +22,6 @@ export default { 'onDidAnyChange', 'openInEditor', ]), - ...appStore, getAll: () => appStore.store, setAll: value => (appStore.store = value), } diff --git a/electron/main.js b/electron/main.js index e3e3018..a98ca51 100644 --- a/electron/main.js +++ b/electron/main.js @@ -12,10 +12,14 @@ import log from './helpers/log.js' import './helpers/console.js' import appStore from './helpers/store.js' -import { icnsLogoPath, icoLogoPath, logoPath } from './configs/index.js' +import { getLogoPath } from './configs/index.js' import events from './events/index.js' +import control from '$control/electron/main.js' + +import { loadPage } from './helpers/index.js' + const require = createRequire(import.meta.url) const __dirname = path.dirname(fileURLToPath(import.meta.url)) @@ -51,25 +55,10 @@ contextMenu({ process.env.DIST = path.join(__dirname, '../dist') let mainWindow -// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x -const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL function createWindow() { - let icon = logoPath - - if (process.platform === 'win32') { - icon = icoLogoPath - } else if (process.platform === 'darwin') { - icon = icnsLogoPath - } - mainWindow = new BrowserWindow({ - // 这里设置的图标仅在开发模式生效,打包后将使用应用程序图标 - ...(!isPackaged - ? { - icon, - } - : {}), + icon: getLogoPath(), show: false, width: 1200, height: 800, @@ -96,13 +85,11 @@ function createWindow() { return { action: 'deny' } }) - if (VITE_DEV_SERVER_URL) { - mainWindow.loadURL(VITE_DEV_SERVER_URL) - } else { - mainWindow.loadFile(path.join(process.env.DIST, 'index.html')) - } + loadPage(mainWindow) events(mainWindow) + + control(mainWindow) } app.whenReady().then(() => { diff --git a/eslint.config.js b/eslint.config.js index cef1e1d..3fe4230 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -63,6 +63,7 @@ export default antfu( 'unicorn/consistent-function-scoping': 'off', 'regexp/no-unused-capturing-group': 'off', 'regexp/no-dupe-disjunctions': 'off', + 'perfectionist/sort-imports': 'off', }, }, ) diff --git a/jsconfig.json b/jsconfig.json index 142b780..22a7e49 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -5,7 +5,8 @@ "$/*": ["src/*"], "$root/*": ["*"], "$electron/*": ["electron/*"], - "$renderer/*": ["src/*"] + "$renderer/*": ["src/*"], + "$control/*": ["control/*"] } }, "exclude": ["node_modules", "dist", "dist-electron", "dist-release"], diff --git a/src/bootstrap/default/index.js b/src/bootstrap/default/index.js new file mode 100644 index 0000000..d863e29 --- /dev/null +++ b/src/bootstrap/default/index.js @@ -0,0 +1,48 @@ +import { createApp, toRaw } from 'vue' + +import icons from '$/icons/index.js' + +import { i18n, t } from '$/locales/index.js' + +import plugins from '$/plugins/index.js' + +import store from '$/store/index.js' + +import { replaceIP, restoreIP } from '$/utils/index.js' + +import '$/utils/console.js' + +import 'virtual:uno.css' +import '$/styles/index.js' + +export default (App) => { + const app = createApp(App) + + app.use(store) + + app.use(plugins) + + app.use(icons) + + app.use(i18n) + window.t = t + + app.config.globalProperties.$path = window.nodePath + app.config.globalProperties.$appStore = window.appStore + app.config.globalProperties.$appLog = window.appLog + app.config.globalProperties.$electron = window.electron + + app.config.globalProperties.$adb = window.adbkit + app.config.globalProperties.$scrcpy = window.scrcpy + app.config.globalProperties.$gnirehtet = window.gnirehtet + + app.config.globalProperties.$replaceIP = replaceIP + app.config.globalProperties.$restoreIP = restoreIP + + app.config.globalProperties.$toRaw = toRaw + + app.mount('#app').$nextTick(() => { + // Remove Preload scripts loading + postMessage({ payload: 'removeLoading' }, '*') + }) +} diff --git a/src/bootstrap/index.js b/src/bootstrap/index.js new file mode 100644 index 0000000..8b6bfaa --- /dev/null +++ b/src/bootstrap/index.js @@ -0,0 +1,3 @@ +import bootstrap from './default/index.js' + +export default bootstrap diff --git a/src/components/Device/components/ControlBar/index.vue b/src/components/Device/components/ControlBar/index.vue index e57ff96..f82a8d0 100644 --- a/src/components/Device/components/ControlBar/index.vue +++ b/src/components/Device/components/ControlBar/index.vue @@ -1,6 +1,6 @@