feat(stage-tamagotchi-electron): use eventa for type safe event & invoke

This commit is contained in:
Neko Ayaka
2025-09-11 02:32:21 +08:00
parent 16527bd375
commit 5139d44db1
7 changed files with 652 additions and 133 deletions
+1 -1
View File
@@ -43,7 +43,7 @@
"@tresjs/cientos": "^4.3.1",
"@tresjs/core": "^4.3.6",
"@types/audioworklet": "^0.0.83",
"@unbird/eventa": "^0.0.5",
"@unbird/eventa": "^0.0.8",
"@vueuse/core": "^13.9.0",
"@vueuse/shared": "^13.9.0",
"@xsai-ext/providers-cloud": "catalog:",
@@ -4,11 +4,15 @@ import { fileURLToPath } from 'node:url'
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
import { Format, LogLevel, setGlobalFormat, setGlobalLogLevel } from '@guiiai/logg'
import { app, BrowserWindow, shell } from 'electron'
import { defineInvokeHandler } from '@unbird/eventa'
import { createContext } from '@unbird/eventa/adapters/electron/main'
import { app, BrowserWindow, ipcMain, screen, shell } from 'electron'
import { isMacOS } from 'std-env'
import icon from '../../resources/icon.png?asset'
import { electronCursorPoint, electronStartTrackingCursorPoint } from '../shared/eventa'
setGlobalFormat(Format.Pretty)
setGlobalLogLevel(LogLevel.Log)
@@ -24,8 +28,11 @@ if (/^true$/i.test(env.APP_REMOTE_DEBUG || '')) {
app.dock?.setIcon(icon)
let trackCursorPointInterval: NodeJS.Timeout | undefined
function createWindow(): void {
const mainWindow = new BrowserWindow({
title: 'AIRI',
width: 450.0,
height: 600.0,
show: false,
@@ -40,6 +47,17 @@ function createWindow(): void {
hasShadow: false,
})
const { context } = createContext(ipcMain, mainWindow)
defineInvokeHandler(context, electronStartTrackingCursorPoint, () => {
trackCursorPointInterval = setInterval(() => {
const dipPos = screen.getCursorScreenPoint()
// const pos = screen.dipToScreenPoint(dipPos)
context.emit(electronCursorPoint, dipPos)
// mainWindow.webContents.send(electronCursorPoint.id, dipPos)
}, 32)
})
mainWindow.setAlwaysOnTop(true)
mainWindow.setWindowButtonVisibility(false)
mainWindow.on('ready-to-show', () => mainWindow!.show())
@@ -68,9 +86,7 @@ app.whenReady().then(() => {
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
app.on('browser-window-created', (_, window) => optimizer.watchWindowShortcuts(window))
createWindow()
})
@@ -79,10 +95,11 @@ app.whenReady().then(() => {
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (trackCursorPointInterval) {
clearInterval(trackCursorPointInterval)
}
if (platform !== 'darwin') {
app.quit()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
@@ -2,11 +2,14 @@
import { useDisplayModelsStore } from '@proj-airi/stage-ui/stores/display-models'
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
import { defineInvoke } from '@unbird/eventa'
import { createContext } from '@unbird/eventa/adapters/electron/renderer'
import { storeToRefs } from 'pinia'
import { onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterView } from 'vue-router'
import { electronStartTrackingCursorPoint } from '../shared/eventa'
import { useWindowMode } from './stores/window-controls'
useWindowMode()
@@ -26,6 +29,10 @@ onMounted(async () => {
await displayModelsStore.loadDisplayModelsFromIndexedDB()
await settingsStore.initializeStageModel()
const { context } = createContext(window.electron.ipcRenderer)
const startTrackingCursorPoint = defineInvoke(context, electronStartTrackingCursorPoint)
await startTrackingCursorPoint(undefined)
})
watch(themeColorsHue, () => {
@@ -0,0 +1,17 @@
import { defineEventa, defineInvokeEventa } from '@unbird/eventa'
// TODO: currently, if we use `/shared` path, both web & node tsconfig.json
// will include, while web gets higher priority in including files, this results
// in type error for `electron` module, even for type only import, here the
// `Point` interface cannot be imported directly due to this reason.
//
// We have to find a better way (better without sub-package) to share code between
// main & preload & renderer process.
interface Point {
// Docs: https://electronjs.org/docs/api/structures/point
x: number
y: number
}
export const electronCursorPoint = defineEventa<Point>('electron:eventa:event:cursor-point')
export const electronStartTrackingCursorPoint = defineInvokeEventa('electron:eventa:invoke:start-tracking-cursor-point')
@@ -30,6 +30,11 @@
"src/preload/**/*.ts",
"src/preload/**/*.d.ts",
"src/preload/**/*.tsx",
"src/preload/**/*.vue"
"src/preload/**/*.vue",
"src/shared/**/*.ts",
"src/shared/**/*.d.ts",
"src/shared/**/*.tsx",
"src/shared/**/*.vue"
]
}
@@ -42,6 +42,11 @@
"src/renderer/**/*.ts",
"src/renderer/**/*.d.ts",
"src/renderer/**/*.tsx",
"src/renderer/**/*.vue"
"src/renderer/**/*.vue",
"src/shared/**/*.ts",
"src/shared/**/*.d.ts",
"src/shared/**/*.tsx",
"src/shared/**/*.vue"
]
}
+591 -123
View File
File diff suppressed because it is too large Load Diff