fix(stage-tamagotchi): shouldnt implement onboarding window like that
This commit is contained in:
@@ -109,7 +109,11 @@ app.whenReady().then(async () => {
|
||||
|
||||
const devtoolsMarkdownStressWindow = injeca.provide('windows:devtools:markdown-stress', () => setupDevtoolsWindow())
|
||||
|
||||
const onboardingWindow = injeca.provide('windows:onboarding', () => setupOnboardingWindowManager())
|
||||
const onboardingWindowManager = injeca.provide('windows:onboarding', {
|
||||
dependsOn: { serverChannel, i18n },
|
||||
build: ({ dependsOn }) => setupOnboardingWindowManager(dependsOn),
|
||||
})
|
||||
|
||||
const noticeWindow = injeca.provide('windows:notice', {
|
||||
dependsOn: { i18n, serverChannel },
|
||||
build: ({ dependsOn }) => setupNoticeWindowManager(dependsOn),
|
||||
@@ -136,7 +140,7 @@ app.whenReady().then(async () => {
|
||||
})
|
||||
|
||||
const mainWindow = injeca.provide('windows:main', {
|
||||
dependsOn: { settingsWindow, chatWindow, widgetsManager, noticeWindow, beatSync, autoUpdater, serverChannel, mcpStdioManager, i18n },
|
||||
dependsOn: { settingsWindow, chatWindow, widgetsManager, noticeWindow, beatSync, autoUpdater, serverChannel, mcpStdioManager, i18n, onboardingWindowManager },
|
||||
build: async ({ dependsOn }) => setupMainWindow(dependsOn),
|
||||
})
|
||||
|
||||
@@ -151,16 +155,10 @@ app.whenReady().then(async () => {
|
||||
})
|
||||
|
||||
injeca.invoke({
|
||||
dependsOn: { mainWindow, tray, serverChannel, pluginHost, mcpStdioManager },
|
||||
dependsOn: { mainWindow, tray, serverChannel, pluginHost, mcpStdioManager, onboardingWindow: onboardingWindowManager },
|
||||
callback: noop,
|
||||
})
|
||||
|
||||
// Show onboarding window if not completed
|
||||
injeca.invoke({
|
||||
dependsOn: { onboardingWindow },
|
||||
callback: ({ onboardingWindow }) => { onboardingWindow.showIfNeeded() },
|
||||
})
|
||||
|
||||
injeca.start().catch(err => console.error(err))
|
||||
|
||||
// Lifecycle
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { createContext } from '@moeru/eventa/adapters/electron/main'
|
||||
|
||||
import type { OnboardingWindowManager } from '../../../windows/onboarding'
|
||||
|
||||
import { defineInvokeHandler } from '@moeru/eventa'
|
||||
|
||||
import { electronOpenOnboarding } from '../../../../shared/eventa'
|
||||
|
||||
export function createOnboardingService(params: {
|
||||
context: ReturnType<typeof createContext>['context']
|
||||
onboardingWindowManager: OnboardingWindowManager
|
||||
}) {
|
||||
defineInvokeHandler(params.context, electronOpenOnboarding, async () => {
|
||||
await params.onboardingWindowManager.getAndToggleWindow()
|
||||
})
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import electronUpdater from 'electron-updater'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import { useLogg } from '@guiiai/logg'
|
||||
import { defineInvokeHandler } from '@moeru/eventa'
|
||||
import { errorMessageFrom } from '@moeru/std'
|
||||
import { errorMessageFrom, tryCatch } from '@moeru/std'
|
||||
import { committerDate } from '~build/git'
|
||||
import { app } from 'electron'
|
||||
import { Semaphore } from 'es-toolkit'
|
||||
@@ -146,10 +146,7 @@ export function createAutoUpdaterService(params: { context: MainContext, window:
|
||||
if (window.isDestroyed())
|
||||
return
|
||||
|
||||
try {
|
||||
context.emit(electronAutoUpdaterStateChanged, state)
|
||||
}
|
||||
catch {}
|
||||
tryCatch(() => context.emit(electronAutoUpdaterStateChanged, state))
|
||||
})
|
||||
|
||||
const cleanups: Array<() => void> = [unsubscribe]
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { ServerChannel } from '../../services/airi/channel-server'
|
||||
import type { McpStdioManager } from '../../services/airi/mcp-servers'
|
||||
import type { AutoUpdater } from '../../services/electron/auto-updater'
|
||||
import type { NoticeWindowManager } from '../notice'
|
||||
import type { OnboardingWindowManager } from '../onboarding'
|
||||
import type { WidgetsWindowManager } from '../widgets'
|
||||
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
@@ -54,6 +55,7 @@ export async function setupMainWindow(params: {
|
||||
serverChannel: ServerChannel
|
||||
mcpStdioManager: McpStdioManager
|
||||
i18n: I18n
|
||||
onboardingWindowManager: OnboardingWindowManager
|
||||
}) {
|
||||
const {
|
||||
setup: setupConfig,
|
||||
@@ -167,6 +169,7 @@ export async function setupMainWindow(params: {
|
||||
serverChannel: params.serverChannel,
|
||||
mcpStdioManager: params.mcpStdioManager,
|
||||
i18n: params.i18n,
|
||||
onboardingWindowManager: params.onboardingWindowManager,
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { ServerChannel } from '../../../services/airi/channel-server'
|
||||
import type { McpStdioManager } from '../../../services/airi/mcp-servers'
|
||||
import type { AutoUpdater } from '../../../services/electron/auto-updater'
|
||||
import type { NoticeWindowManager } from '../../notice'
|
||||
import type { OnboardingWindowManager } from '../../onboarding'
|
||||
import type { WidgetsWindowManager } from '../../widgets'
|
||||
|
||||
import { defineInvokeHandler } from '@moeru/eventa'
|
||||
@@ -13,6 +14,7 @@ import { ipcMain } from 'electron'
|
||||
|
||||
import { electronOpenChat, electronOpenMainDevtools, electronOpenSettings, noticeWindowEventa } from '../../../../shared/eventa'
|
||||
import { createMcpServersService } from '../../../services/airi/mcp-servers'
|
||||
import { createOnboardingService } from '../../../services/airi/onboarding'
|
||||
import { createWidgetsService } from '../../../services/airi/widgets'
|
||||
import { createAutoUpdaterService } from '../../../services/electron'
|
||||
import { toggleWindowShow } from '../../shared'
|
||||
@@ -28,6 +30,7 @@ export async function setupMainWindowElectronInvokes(params: {
|
||||
serverChannel: ServerChannel
|
||||
mcpStdioManager: McpStdioManager
|
||||
i18n: I18n
|
||||
onboardingWindowManager: OnboardingWindowManager
|
||||
}) {
|
||||
// TODO: once we refactored eventa to support window-namespaced contexts,
|
||||
// we can remove the setMaxListeners call below since eventa will be able to dispatch and
|
||||
@@ -40,6 +43,7 @@ export async function setupMainWindowElectronInvokes(params: {
|
||||
createWidgetsService({ context, widgetsManager: params.widgetsManager, window: params.window })
|
||||
createAutoUpdaterService({ context, window: params.window, service: params.autoUpdater })
|
||||
createMcpServersService({ context, manager: params.mcpStdioManager })
|
||||
createOnboardingService({ context, onboardingWindowManager: params.onboardingWindowManager })
|
||||
|
||||
defineInvokeHandler(context, electronOpenMainDevtools, () => params.window.webContents.openDevTools({ mode: 'detach' }))
|
||||
defineInvokeHandler(context, electronOpenSettings, async () => toggleWindowShow(await params.settingsWindow()))
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import type { I18n } from '../../libs/i18n'
|
||||
import type { ServerChannel } from '../../services/airi/channel-server'
|
||||
|
||||
import { join, resolve } from 'node:path'
|
||||
|
||||
import { defineInvokeHandler } from '@moeru/eventa'
|
||||
@@ -6,43 +9,33 @@ import { BrowserWindow, ipcMain, shell } from 'electron'
|
||||
|
||||
import icon from '../../../../resources/icon.png?asset'
|
||||
|
||||
import { electronOnboardingClose, electronOnboardingCompleted, electronOnboardingSkipped, electronOpenOnboarding } from '../../../shared/eventa'
|
||||
import { electronOnboardingClose, electronOnboardingCompleted, electronOnboardingSkipped } from '../../../shared/eventa'
|
||||
import { baseUrl, getElectronMainDirname, load, withHashRoute } from '../../libs/electron/location'
|
||||
import { createReusableWindow } from '../../libs/electron/window-manager'
|
||||
import { toggleWindowShow } from '../shared'
|
||||
import { setupBaseWindowElectronInvokes } from '../shared/window'
|
||||
|
||||
export interface OnboardingWindowManager {
|
||||
getWindow: () => BrowserWindow | null
|
||||
showIfNeeded: () => Promise<boolean>
|
||||
close: () => void
|
||||
markCompleted: () => void
|
||||
markSkipped: () => void
|
||||
getWindow: () => Promise<BrowserWindow>
|
||||
getAndToggleWindow: () => Promise<BrowserWindow>
|
||||
}
|
||||
|
||||
export function setupOnboardingWindowManager(): OnboardingWindowManager {
|
||||
let window: BrowserWindow | undefined
|
||||
export function setupOnboardingWindowManager(params: {
|
||||
serverChannel: ServerChannel
|
||||
i18n: I18n
|
||||
}): OnboardingWindowManager {
|
||||
async function getOnboardingWindow(getWindow: () => Promise<BrowserWindow>) {
|
||||
const window = await getWindow()
|
||||
await toggleWindowShow(window)
|
||||
|
||||
const close = () => {
|
||||
if (window && !window.isDestroyed()) {
|
||||
window.close()
|
||||
}
|
||||
return window
|
||||
}
|
||||
|
||||
const markCompleted = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
const markSkipped = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
const createWindow = async () => {
|
||||
if (window && !window.isDestroyed()) {
|
||||
return window
|
||||
}
|
||||
|
||||
const reusableWindow = createReusableWindow(async () => {
|
||||
const newWindow = new BrowserWindow({
|
||||
title: 'Welcome to AIRI',
|
||||
width: 500,
|
||||
height: 700,
|
||||
width: 1200,
|
||||
height: 600,
|
||||
minWidth: 400,
|
||||
minHeight: 500,
|
||||
show: false,
|
||||
@@ -64,43 +57,26 @@ export function setupOnboardingWindowManager(): OnboardingWindowManager {
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
newWindow.on('closed', () => {
|
||||
window = undefined
|
||||
})
|
||||
// TODO: once we refactored eventa to support window-namespaced contexts,
|
||||
// we can remove the setMaxListeners call below since eventa will be able to dispatch and
|
||||
// manage events within eventa's context system.
|
||||
ipcMain.setMaxListeners(0)
|
||||
|
||||
const { context } = createContext(ipcMain, newWindow)
|
||||
|
||||
defineInvokeHandler(context, electronOnboardingClose, async () => newWindow.close())
|
||||
defineInvokeHandler(context, electronOnboardingCompleted, async () => newWindow.close())
|
||||
defineInvokeHandler(context, electronOnboardingSkipped, async () => newWindow.close())
|
||||
|
||||
await setupBaseWindowElectronInvokes({ context, window: newWindow, i18n: params.i18n, serverChannel: params.serverChannel })
|
||||
|
||||
await load(newWindow, withHashRoute(baseUrl(resolve(getElectronMainDirname(), '..', 'renderer')), '/onboarding'))
|
||||
|
||||
// Setup IPC handlers for this window
|
||||
const { context } = createContext(ipcMain, newWindow)
|
||||
|
||||
defineInvokeHandler(context, electronOnboardingClose, () => close())
|
||||
defineInvokeHandler(context, electronOnboardingCompleted, () => markCompleted())
|
||||
defineInvokeHandler(context, electronOnboardingSkipped, () => markSkipped())
|
||||
defineInvokeHandler(context, electronOpenOnboarding, async () => {
|
||||
await showIfNeeded()
|
||||
return true
|
||||
})
|
||||
|
||||
window = newWindow
|
||||
return newWindow
|
||||
}
|
||||
|
||||
async function showIfNeeded() {
|
||||
if (window && !window.isDestroyed()) {
|
||||
window.show()
|
||||
window.focus()
|
||||
return true
|
||||
}
|
||||
|
||||
await createWindow()
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
getWindow: () => window ?? null,
|
||||
showIfNeeded,
|
||||
close,
|
||||
markCompleted,
|
||||
markSkipped,
|
||||
getWindow: async () => reusableWindow.getWindow(),
|
||||
getAndToggleWindow: async () => await getOnboardingWindow(reusableWindow.getWindow),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
electronGetServerChannelConfig,
|
||||
electronMcpCallTool,
|
||||
electronMcpListTools,
|
||||
electronOpenOnboarding,
|
||||
electronOpenSettings,
|
||||
electronPluginInspect,
|
||||
electronPluginList,
|
||||
@@ -75,6 +76,7 @@ const reportPluginCapability = useElectronEventaInvoke(electronPluginUpdateCapab
|
||||
const listMcpTools = useElectronEventaInvoke(electronMcpListTools)
|
||||
const callMcpTool = useElectronEventaInvoke(electronMcpCallTool)
|
||||
const setLocale = useElectronEventaInvoke(i18nSetLocale)
|
||||
const openOnboarding = useElectronEventaInvoke(electronOpenOnboarding)
|
||||
|
||||
// NOTICE: register plugin host bridge during setup to avoid race with pages using it in immediate watchers.
|
||||
pluginHostInspectorStore.setBridge({
|
||||
@@ -145,6 +147,12 @@ watch(themeColorsHueDynamic, () => {
|
||||
document.documentElement.classList.toggle('dynamic-hue', themeColorsHueDynamic.value)
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => onboardingStore.shouldShowSetup, () => {
|
||||
if (onboardingStore.shouldShowSetup) {
|
||||
openOnboarding()
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
onUnmounted(() => {
|
||||
contextBridgeStore.dispose()
|
||||
clearMcpToolBridge()
|
||||
|
||||
@@ -210,7 +210,7 @@ export const widgetsUpdateEvent = defineEventa<{ id: string, componentProps?: Re
|
||||
export const electronOnboardingClose = defineInvokeEventa('eventa:invoke:electron:windows:onboarding:close')
|
||||
export const electronOnboardingCompleted = defineInvokeEventa('eventa:invoke:electron:windows:onboarding:completed')
|
||||
export const electronOnboardingSkipped = defineInvokeEventa('eventa:invoke:electron:windows:onboarding:skipped')
|
||||
export const electronOpenOnboarding = defineInvokeEventa<boolean>('eventa:invoke:electron:windows:onboarding:open')
|
||||
export const electronOpenOnboarding = defineInvokeEventa('eventa:invoke:electron:windows:onboarding:open')
|
||||
|
||||
export const i18nSetLocale = defineInvokeEventa<void, Locale>('eventa:invoke:electron:i18n:set-locale')
|
||||
export const i18nGetLocale = defineInvokeEventa<Locale>('eventa:invoke:electron:i18n:get-locale')
|
||||
|
||||
Reference in New Issue
Block a user