Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: native window control #161

Merged
merged 5 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@
"arknights"
],
"dependencies": {
"@pyke/vibe": "^0.4.0",
"@tigerconnect/ffi-napi": "4.0.3-tc3",
"@tigerconnect/ref-napi": "4.0.0-tc8",
"axios": "^0.27.2",
"crypto-js": "^4.1.1",
"electron-acrylic-window": "^0.5.11",
"electron-squirrel-startup": "^1.0.0",
"electron-store": "^8.1.0",
"execa": "^5.1.1",
Expand Down
6 changes: 4 additions & 2 deletions packages/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { app, BrowserWindow, shell } from 'electron'
import { release } from 'os'
import { join } from 'path'
import fs from 'fs'
import { spawn } from 'child_process'
import { getPlatform, isInDev } from '@main/utils/os'
import vibe from '@pyke/vibe'

import useDebug from '@main/utils/debug'
import logger from '@main/utils/logger'
import useHooks from '@main/hooks'
import { getPlatform, isInDev } from '@main/utils/os'

// modules
import WindowManager from '@main/windowManager'
Expand Down Expand Up @@ -70,6 +70,8 @@ async function createApp(): Promise<void> {
})
}

vibe.setup(app)

app.whenReady().then(createApp)

app.on('window-all-closed', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/main/windowManager/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ipcMainHandle, ipcMainOn } from '@main/utils/ipc-main'
import type { DialogProperty } from '@type/misc'
import type { BrowserWindow } from 'electron'
import { ipcMain, dialog } from 'electron'
import { getPlatform } from '@main/utils/os'

export default function useController(window: BrowserWindow): void {
ipcMainOn('main.WindowManager:closeWindow', () => {
Expand Down
67 changes: 48 additions & 19 deletions packages/main/windowManager/index.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
import type { BrowserWindowConstructorOptions, BrowserWindow } from 'electron'
import { type BrowserWindowConstructorOptions, BrowserWindow } from 'electron'
import { join } from 'path'
import { Singleton } from '@common/function/singletonDecorator'
import useController from './control'
import useTheme from './theme'
import Storage from '@main/storageManager'
import { getPlatform } from '@main/utils/os'
import type { Module } from '@type/misc'

const createWindow = (options?: BrowserWindowConstructorOptions): BrowserWindow => {
const storage = new Storage()
const module =
getPlatform() === 'windows' && storage.get('theme.acrylic')
? require('electron-acrylic-window')
: require('electron')
const Ctor = module.BrowserWindow
return new Ctor(options)
}
import vibe from '@pyke/vibe'

@Singleton
class WindowManager implements Module {
constructor() {
const storage = new Storage()
this.window_ = createWindow({
transparent: true,
frame: false,
this.window_ = new BrowserWindow({
backgroundColor: '#00000000',
frame: getPlatform() === 'macos',
icon: join(__dirname, '../renderer/assets/icon.png'),
vibrancy:
getPlatform() === 'macos' && storage.get('theme.acrylic')
? 'under-window'
: 'appearance-based',
titleBarOverlay: true,
// frameless和titleBarStyle: 'hidden'同时开,会显示窗口控制按钮
titleBarStyle: 'hidden',
width: 1024,
height: 768,
minWidth: 800,
Expand All @@ -42,6 +31,46 @@ class WindowManager implements Module {
})
useController(this.window_)
useTheme(this.window_)
if (getPlatform() === 'macos') {
this.window_.setTrafficLightPosition({
x: 12,
y: 12,
})
}
if (getPlatform() === 'windows') {
this.window_.setTitleBarOverlay({
color: '#00000000',
symbolColor: '#FFFFFF',
})
}
this.useVibrancy()
}

private useVibrancy() {
const storage = new Storage()
if (getPlatform() === 'macos' && storage.get('theme.acrylic')) {
this.window_.setVibrancy('under-window')
}
if (getPlatform() === 'windows' && storage.get('theme.acrylic')) {
vibe.applyEffect(this.window_, 'unified-acrylic')
}
// if (getPlatform() === 'windows') {
// switch (storage.get('theme.acrylic')) {
// case 'none':
// case false:
// vibe.clearEffects(this.window_)
// break
// case 'acrylic':
// case true:
// vibe.applyEffect(this.window_, 'unified-acrylic')
// break
// case 'blur':
// vibe.applyEffect(this.window_, 'blurbehind')
// break
// default:
// break
// }
// }
}

public get name(): string {
Expand Down
30 changes: 24 additions & 6 deletions packages/main/windowManager/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ipcMainHandle, ipcMainSend } from '@main/utils/ipc-main'
import { nativeTheme, BrowserWindow } from 'electron'
import { getPlatform } from '@main/utils/os'
import Storage from '@main/storageManager'
import vibe from '@pyke/vibe'

export default function useTheme(window: BrowserWindow): void {
const themeEvent = (): void => {
Expand All @@ -11,19 +12,36 @@ export default function useTheme(window: BrowserWindow): void {

ipcMainHandle('main.AppearanceManager:themeUpdated', (event, isDark) => {
const storage = new Storage()
if (getPlatform() === 'windows' && storage.get('theme.acrylic')) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { setVibrancy } = require('electron-acrylic-window')
setVibrancy(window, {
theme: isDark ? 'dark' : 'light',
effect: 'acrylic',
if (getPlatform() === 'windows') {
window.setTitleBarOverlay({
// 无法使用透明的WCO背景色,在反复hover的时候会导致错误的背景色叠加
// https://www.electronjs.org/zh/docs/latest/tutorial/window-customization#%E5%B1%80%E9%99%90%E6%80%A7
// https://github.com/electron/electron/issues/33567
color: isDark ? '#0f0f0f' : '#f0f0f0',
symbolColor: isDark ? '#ffffff' : '#000000',
})
}
if (getPlatform() === 'windows' && storage.get('theme.acrylic')) {
nativeTheme.themeSource = isDark ? 'dark' : 'light'
}
if (getPlatform() === 'macos' && storage.get('theme.acrylic')) {
window.setVibrancy(isDark ? 'dark' : 'light')
}
})

ipcMainHandle('main.AppearanceManager:acrylicUpdated', (event, isAcrylic) => {
if (getPlatform() === 'macos') {
window.setVibrancy(isAcrylic ? 'under-window' : 'appearance-based')
}
if (getPlatform() === 'windows') {
if (isAcrylic) {
vibe.applyEffect(window, 'unified-acrylic')
} else {
vibe.clearEffects(window)
}
}
})

ipcMainHandle('main.WindowManager:loaded', event => {
themeEvent()
ipcMainSend('renderer.WindowManager:loaded')
Expand Down
1 change: 1 addition & 0 deletions packages/renderer/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const commonThemeOverrides: Partial<ThemeCommonVars> = {
errorColorHover: '#ff8f8f',
errorColorPressed: '#ff4747',
errorColorSuppl: '#ff8f8f',
cardColor: 'transparent',
}

const lightThemeOverrides: GlobalThemeOverrides = {
Expand Down
89 changes: 32 additions & 57 deletions packages/renderer/src/components/Setting/Appearance/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ import {
NCard,
} from 'naive-ui'
import useThemeStore from '@/store/theme'
import { getPlatform } from '@/hooks/caller/os'
import { type Platform } from '@type/api/maa'

const themeStore = useThemeStore()

const platform = ref<Platform>('noPlatform')

const themeOptions = [
{
label: '跟随系统',
Expand Down Expand Up @@ -77,102 +82,72 @@ function handleWindowResize() {
bgPreviewWidth.value = window.innerWidth - 700
}

function handleAcrylicChange(value: boolean) {
themeStore.updateAcrylic(value)
window.ipcRenderer.invoke('main.AppearanceManager:acrylicUpdated', value)
}

onMounted(() => {
handleWindowResize()
window.addEventListener('resize', _.throttle(handleWindowResize, 16))
getPlatform().then((p) => {
platform.value = p
})
})
</script>

<template>
<div id="appearance">
<h2 class="title">外观</h2>
<NFormItem label="背景颜色">
<NSelect
:value="themeStore.theme"
:options="themeOptions"
:style="{ width: '200px' }"
@update:value="value => themeStore.updateTheme(value)"
/>
<NSelect :value="themeStore.theme" :options="themeOptions" :style="{ width: '200px' }"
@update:value="value => themeStore.updateTheme(value)" />
</NFormItem>
<NFormItem label="主题色不透明度">
<NSlider
:value="themeStore.themeColorOpacity"
:min="0"
:max="1"
:step="0.01"
:format-tooltip="value => `${Math.floor(value * 100)}%`"
:style="{ width: '300px' }"
@update:value="value => themeStore.updateColorOpacity(value)"
/>
<NSlider :value="themeStore.themeColorOpacity" :min="0" :max="1" :step="0.01"
:format-tooltip="value => `${Math.floor(value * 100)}%`" :style="{ width: '300px' }"
@update:value="value => themeStore.updateColorOpacity(value)" />
</NFormItem>
<NFormItem label="开启亚克力效果(重启应用生效)">
<NSwitch
:value="themeStore.acrylic"
@update:value="value => themeStore.updateAcrylic(value)"
/>
<NFormItem label="开启亚克力效果" v-show="platform === 'macos' || platform === 'windows'">
<NSwitch :value="themeStore.acrylic" @update:value="handleAcrylicChange" />
</NFormItem>
<NDivider />
<NFormItem label="背景随主题变换">
<NSwitch
:value="themeStore.bgFollowTheme"
@update:value="value => themeStore.updateBgFollowTheme(value)"
/>
<NSwitch :value="themeStore.bgFollowTheme"
@update:value="value => themeStore.updateBgFollowTheme(value)" />
</NFormItem>
<NFormItem label="背景图片" :label-style="{ justifyContent: 'center' }">
<div style="margin: 5pt 0">
<NCard>
<NForm :show-feedback="false">
<NFormItem :show-label="false" @click="handleLightBgSelect">
<NImage
class="background-preview"
:width="bgPreviewWidth"
:preview-disabled="true"
:src="themeStore.bgLight.url"
alt="选择图片"
/>
<NImage class="background-preview" :width="bgPreviewWidth" :preview-disabled="true"
:src="themeStore.bgLight.url" alt="选择图片" />
</NFormItem>
<NFormItem label="不透明度" label-placement="left">
<NInputNumber
:value="themeStore.bgLight.opacity"
:min="0"
:max="1"
:step="0.01"
<NInputNumber :value="themeStore.bgLight.opacity" :min="0" :max="1" :step="0.01"
:format="value => `${Math.floor((value ?? 0) * 100)}%`"
:parse="input => Number(input.replace('%', '')) / 100"
@update:value="handleUpdateBgLightOpacity"
/>
@update:value="handleUpdateBgLightOpacity" />
</NFormItem>
</NForm>
</NCard>
</div>
</NFormItem>
<NFormItem
v-show="themeStore.bgFollowTheme"
label="深色背景图片"
:label-style="{ justifyContent: 'center' }"
>
<NFormItem v-show="themeStore.bgFollowTheme" label="深色背景图片"
:label-style="{ justifyContent: 'center' }">
<div style="margin: 5pt 0">
<NCard>
<NForm :show-feedback="false">
<NFormItem :show-label="false" @click="handleDarkBgSelect">
<NImage
class="background-preview"
:width="bgPreviewWidth"
:preview-disabled="true"
:src="themeStore.bgDark.url"
alt="选择图片"
/>
<NImage class="background-preview" :width="bgPreviewWidth" :preview-disabled="true"
:src="themeStore.bgDark.url" alt="选择图片" />
</NFormItem>
<NFormItem label="不透明度">
<NInputNumber
:value="themeStore.bgDark.opacity"
:min="0"
:max="1"
:step="0.01"
<NInputNumber :value="themeStore.bgDark.opacity" :min="0" :max="1" :step="0.01"
:format="value => `${Math.floor((value ?? 0) * 100)}%`"
:parse="input => Number(input.replace('%', '')) / 100"
@update:value="handleUpdateBgDarkOpacity"
/>
@update:value="handleUpdateBgDarkOpacity" />
</NFormItem>
</NForm>
</NCard>
Expand Down
Loading