refactor(electron): global caller

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-09-24 20:16:42 +08:00
parent ff4d0af262
commit 8f1efb256f
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
5 changed files with 55 additions and 40 deletions

View File

@ -1,4 +1,4 @@
import { callGlobalContextMethod } from "@follow/shared/bridge"
import { callWindowExpose } from "@follow/shared/bridge"
import { dialog } from "electron"
import { getMainWindow } from "~/window"
@ -17,6 +17,7 @@ export const clearAllData = async () => {
message: t("dialog.clearAllData"),
buttons: [t("dialog.yes"), t("dialog.no")],
})
const caller = callWindowExpose(win)
if (result.response === 1) {
return
@ -36,11 +37,12 @@ export const clearAllData = async () => {
"cookies",
],
})
callGlobalContextMethod(win, "toast.success", ["App data reset successfully"])
caller.toast.success("App data reset successfully")
// reload the app
win.reload()
} catch (error: any) {
callGlobalContextMethod(win, "toast.error", [`Error resetting app data: ${error.message}`])
caller.toast.error(`Error resetting app data: ${error.message}`)
}
}

View File

@ -1,7 +1,7 @@
import path from "node:path"
import { getRendererHandlers } from "@egoist/tipc/main"
import { callGlobalContextMethod } from "@follow/shared/bridge"
import { callWindowExpose } from "@follow/shared/bridge"
import type { BrowserWindow } from "electron"
import { app, clipboard, dialog, screen } from "electron"
@ -199,13 +199,17 @@ export const appRoute = {
await downloadFile(input, result.filePath).catch((err) => {
const senderWindow = (sender as Sender).getOwnerBrowserWindow()
if (!senderWindow) return
callGlobalContextMethod(senderWindow, "toast.error", ["Download failed!"])
callWindowExpose(senderWindow).toast.error("Download failed!", {
duration: 1000,
})
throw err
})
const senderWindow = (sender as Sender).getOwnerBrowserWindow()
if (!senderWindow) return
callGlobalContextMethod(senderWindow, "toast.success", ["Download success!"])
callWindowExpose(senderWindow).toast.success("Download success!", {
duration: 1000,
})
}),
getAppPath: t.procedure.action(async () => app.getAppPath()),

View File

@ -2,7 +2,7 @@ import fs from "node:fs"
import { createRequire } from "node:module"
import path from "node:path"
import { callGlobalContextMethod } from "@follow/shared/bridge"
import { callWindowExpose } from "@follow/shared/bridge"
import { app, BrowserWindow } from "electron"
import { MsEdgeTTS, OUTPUT_FORMAT } from "msedge-tts"
@ -54,12 +54,9 @@ export const readerRoute = {
if (!window) {
return
}
callGlobalContextMethod(window, "toast.error", [
error.message,
{
duration: 1000,
},
])
callWindowExpose(window).toast.error(error.message, {
duration: 1000,
})
}
}),
@ -70,12 +67,9 @@ export const readerRoute = {
}
await tts.setMetadata(input, OUTPUT_FORMAT.WEBM_24KHZ_16BIT_MONO_OPUS).catch((error) => {
callGlobalContextMethod(window, "toast.error", [
error.message,
{
duration: 1000,
},
])
callWindowExpose(window).toast.error(error.message, {
duration: 1000,
})
})
}),

View File

@ -2,7 +2,7 @@ import path from "node:path"
import { fileURLToPath } from "node:url"
import { is } from "@electron-toolkit/utils"
import { callGlobalContextMethod } from "@follow/shared/bridge"
import { callWindowExpose } from "@follow/shared/bridge"
import { imageRefererMatches } from "@follow/shared/image"
import type { BrowserWindowConstructorOptions } from "electron"
import { BrowserWindow, screen, shell } from "electron"
@ -219,7 +219,8 @@ export const createMainWindow = () => {
window.hide()
}
callGlobalContextMethod(window, "electronClose")
const caller = callWindowExpose(window)
caller.electronClose()
} else {
windows.mainWindow = null
}
@ -228,11 +229,13 @@ export const createMainWindow = () => {
window.on("show", () => {
cancelPollingUpdateUnreadCount()
callGlobalContextMethod(window, "electronShow")
const caller = callWindowExpose(window)
caller.electronShow()
})
window.on("hide", async () => {
const settings = await callGlobalContextMethod(window, "getUISettings")
const caller = callWindowExpose(window)
const settings = await caller.getUISettings()
if (settings.showDockBadge) {
pollingUpdateUnreadCount()
@ -247,7 +250,8 @@ export const createSettingWindow = (path?: string) => {
// if we open a new window then the state between the two windows will be out of sync.
if (windows.mainWindow && windows.mainWindow.isVisible()) {
windows.mainWindow.show()
callGlobalContextMethod(windows.mainWindow, "showSetting", [path])
callWindowExpose(windows.mainWindow).showSetting(path)
return
}
if (windows.settingWindow) {

View File

@ -4,6 +4,7 @@ import type { toast } from "sonner"
import type { GeneralSettings, UISettings } from "./interface/settings"
const PREFIX = "__follow"
interface RenderGlobalContext {
showSetting: (path?: string) => void
getGeneralSettings: () => GeneralSettings
@ -19,22 +20,32 @@ export const registerGlobalContext = (context: RenderGlobalContext) => {
globalThis[PREFIX] = context
}
export function callGlobalContextMethod<T extends keyof RenderGlobalContext>(
window: BrowserWindow,
method: T,
function createProxy<T extends RenderGlobalContext>(window: BrowserWindow, path: string[] = []): T {
return new Proxy((() => {}) as any, {
get(_, prop: string) {
const newPath = [...path, prop]
// @ts-expect-error
args: Parameters<RenderGlobalContext[T]> = [] as any,
): Promise<ReturnType<RenderGlobalContext[T]>>
export function callGlobalContextMethod(window: BrowserWindow, method: string, args?: any[]): void
return createProxy(window, newPath)
},
apply(_, __, args: any[]) {
const methodPath = path.join(".")
export function callGlobalContextMethod<T extends keyof RenderGlobalContext>(
window: BrowserWindow,
method: T,
args: Parameters<RenderGlobalContext[T]> = [] as any,
) {
return window.webContents.executeJavaScript(
`globalThis.${PREFIX}.${method}(${args.map((arg) => JSON.stringify(arg)).join(",")})`,
)
return window.webContents.executeJavaScript(
`globalThis.${PREFIX}.${methodPath}(${args.map((arg) => JSON.stringify(arg)).join(",")})`,
)
},
})
}
type AddPromise<T> = T extends (...args: infer A) => Promise<infer R>
? (...args: A) => Promise<R>
: T extends (...args: infer A) => infer R
? (...args: A) => Promise<Awaited<R>>
: any
type Fn<T> = {
[K in keyof T]: AddPromise<T[K]> &
(T[K] extends object ? { [P in keyof T[K]]: AddPromise<T[K][P]> } : never)
}
export function callWindowExpose<T extends RenderGlobalContext>(window: BrowserWindow) {
return createProxy(window) as Fn<T>
}