Skip to content

Commit

Permalink
feat: ✨ Support floating control bar
Browse files Browse the repository at this point in the history
  • Loading branch information
viarotel committed Sep 12, 2024
1 parent 47ae53d commit 8807e50
Show file tree
Hide file tree
Showing 29 changed files with 406 additions and 95 deletions.
118 changes: 118 additions & 0 deletions control/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<template>
<el-config-provider :locale="locale">
<div
class="flex items-center bg-primary-100 dark:bg-gray-800 absolute inset-0 h-full"
>
<div class="flex-none h-full">
<el-button
type="primary"
class="!px-3 bg-transparent !border-none !h-full"
plain
@click="handleClose"
>
<el-icon class="">
<ElIconCircleCloseFilled />
</el-icon>
</el-button>
</div>

<div
class="h-4 w-px mx-1 bg-primary-200 dark:bg-primary-800 flex-none"
></div>

<div class="flex-none h-full">
<el-button
type="primary"
text
class="!px-2 !h-full"
icon="Switch"
@click="switchDevice"
>
<span class="mr-2">{{ deviceInfo.$remark || deviceInfo.$name }}</span>
</el-button>
</div>

<div
class="h-4 w-px mx-1 bg-primary-200 dark:bg-primary-800 flex-none"
></div>

<div class="flex-1 w-0 overflow-hidden h-full">
<ControlBar class="!h-full" :device="deviceInfo" />
</div>

<div
class="h-4 w-px mx-1 bg-primary-200 dark:bg-primary-800 flex-none"
></div>

<div class="flex-none h-full app-region-drag">
<el-button type="primary" text class="!px-3 !h-full">
<el-icon class="">
<ElIconRank />
</el-icon>
</el-button>
</div>
</div>
</el-config-provider>
</template>

<script setup>
import ControlBar from '$/components/Device/components/ControlBar/index.vue'
import { i18n } from '$/locales/index.js'
import localeModel from '$/plugins/element-plus/locale.js'
import { useDeviceStore, useThemeStore } from '$/store/index.js'
import { ElMessage } from 'element-plus'
const themeStore = useThemeStore()
const deviceStore = useDeviceStore()
themeStore.init()
onMounted(() => {
window.electron.ipcRenderer.send('control-mounted')
})
const locale = computed(() => {
const i18nLocale = i18n.global.locale.value
const value = localeModel[i18nLocale]
return value
})
const deviceInfo = ref({})
window.electron.ipcRenderer.on('device-change', (event, data) => {
deviceInfo.value = data
})
window.electron.ipcRenderer.on('language-change', (event, data) => {
i18n.global.locale.value = data
})
window.electron.ipcRenderer.on('theme-change', (event, data) => {
themeStore.update(data)
})
function handleClose() {
window.electron.ipcRenderer.send('hide-active-window')
}
const deviceList = ref([])
async function switchDevice(e) {
e.preventDefault()
const data = await deviceStore.getList()
window.electron.ipcRenderer.send('show-device-list', data)
}
</script>

<style lang="postcss">
.app-region-drag {
-webkit-app-region: drag;
}
</style>
44 changes: 44 additions & 0 deletions control/electron/helpers/index.js
Original file line number Diff line number Diff line change
@@ -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)
}
56 changes: 56 additions & 0 deletions control/electron/main.js
Original file line number Diff line number Diff line change
@@ -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))
})
}
13 changes: 13 additions & 0 deletions control/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en" class="">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/logo.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Escrcpy Control</title>
</head>
<body class="overflow-hidden">
<div id="app"></div>
<script type="module" src="./index.js"></script>
</body>
</html>
5 changes: 5 additions & 0 deletions control/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import bootstrap from '../src/bootstrap/index.js'

import App from './App.vue'

bootstrap(App)
13 changes: 13 additions & 0 deletions electron/configs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
19 changes: 19 additions & 0 deletions electron/events/app/index.js
Original file line number Diff line number Diff line change
@@ -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()
})
}
10 changes: 2 additions & 8 deletions electron/events/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
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'
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)
Expand Down
14 changes: 13 additions & 1 deletion electron/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { resolve } from 'node:path'
import { join, resolve } from 'node:path'
import { contextBridge } from 'electron'
import { cloneDeep } from 'lodash-es'

Expand Down Expand Up @@ -56,3 +56,15 @@ export async function executeI18n(mainWindow, value) {
return value
}
}

export function loadPage(win, prefix = '') {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - [email protected]
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'))
}
}
2 changes: 1 addition & 1 deletion electron/helpers/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ if (isEqual(appStore.store, {})) {
}

export default {
...appStore,
...createProxy(appStore, [
'set',
'get',
Expand All @@ -21,7 +22,6 @@ export default {
'onDidAnyChange',
'openInEditor',
]),
...appStore,
getAll: () => appStore.store,
setAll: value => (appStore.store = value),
}
31 changes: 9 additions & 22 deletions electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -51,25 +55,10 @@ contextMenu({
process.env.DIST = path.join(__dirname, '../dist')

let mainWindow
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - [email protected]
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,
Expand All @@ -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(() => {
Expand Down
Loading

0 comments on commit 8807e50

Please sign in to comment.