diff --git a/desktop/package.json b/desktop/package.json index 44783828..a3b929db 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -6,7 +6,7 @@ "license": "SEE LICENSE IN LICENSE.txt", "scripts": { "tsc": "tsup-node ./src/main.ts", - "dev": "tsup-node ./src/main.ts ./src/preload/index.ts --watch --onSuccess 'yarn electron dist/main.js'", + "dev": "tsup-node ./src/main.ts ./src/sidebar/preload.ts ./src/app/preload.js --watch --onSuccess 'yarn electron dist/main.js'", "prod": "tsc && node --max-old-space-size=4096 ./dist/server.js", "runprod": "node --max-old-space-size=4096 ./dist/server.js", "profile": "tsc && node --prof ./dist/server.js", diff --git a/desktop/sidebar/index.html b/desktop/sidebar/index.html new file mode 100644 index 00000000..7621461d --- /dev/null +++ b/desktop/sidebar/index.html @@ -0,0 +1,59 @@ + + + + + WorkAdventure Desktop Demo + + + +
+ + + + \ No newline at end of file diff --git a/desktop/sidebar/index.js b/desktop/sidebar/index.js new file mode 100644 index 00000000..ce9a4334 --- /dev/null +++ b/desktop/sidebar/index.js @@ -0,0 +1,34 @@ +// let muted = false; + +if (window?.WorkAdventureDesktopApi?.desktop) { + (async () => { + const servers = await window.WorkAdventureDesktopApi.getServers(); + servers.forEach((e) => { + const server = document.createElement("div"); + server.innerText = e.name; + server.onclick = () => { + window.WorkAdventureDesktopApi.selectServer(e._id); + }; + document.getElementById("servers").appendChild(server); + }); + })(); +} + +document.getElementById("btn-reload").onclick = () => { + location.reload(); +}; + +// window?.WorkAdventureDesktopApi?.onMutedKeyPress((event) => { +// if (muted) { +// document.getElementById("demo").innerHTML = +// "Ready to speak! Press ctrl-alt-m to mute."; +// } else { +// document.getElementById("demo").innerHTML = +// "Muted! Press ctrl-alt-m to unmute again."; +// } +// muted = !muted; +// }); + +// document.getElementById("btn-api").onclick = () => { +// window.WorkAdventureDesktopApi.notify("Hello from website"); +// }; diff --git a/desktop/src/preload/index.ts b/desktop/src/app/preload.ts similarity index 65% rename from desktop/src/preload/index.ts rename to desktop/src/app/preload.ts index e1381cb8..74bcb048 100644 --- a/desktop/src/preload/index.ts +++ b/desktop/src/app/preload.ts @@ -2,7 +2,7 @@ import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron"; contextBridge.exposeInMainWorld("WorkAdventureDesktopApi", { desktop: true, - notify: (txt: string) => ipcRenderer.send("notify", txt), + notify: (txt: string) => ipcRenderer.send("app:notify", txt), onMutedKeyPress: (callback: (event: IpcRendererEvent) => void) => - ipcRenderer.on("on-muted-key-press", callback), + ipcRenderer.on("app:on-muted-key-press", callback), }); diff --git a/desktop/src/ipc.ts b/desktop/src/ipc.ts index 7d6dc95d..cedc0084 100644 --- a/desktop/src/ipc.ts +++ b/desktop/src/ipc.ts @@ -1,6 +1,7 @@ import { ipcMain } from "electron"; import { createAndShowNotification } from "./notification"; -import { getWindow } from "./window"; +import settings from "./settings"; +import { getAppView, getWindow } from "./window"; export function emitMutedKeyPress() { const mainWindow = getWindow(); @@ -8,11 +9,62 @@ export function emitMutedKeyPress() { throw new Error("Main window not found"); } - mainWindow.webContents.send("on-muted-key-press"); + mainWindow.webContents.send("app:on-muted-key-press"); } export default () => { - ipcMain.on("notify", (event, txt) => { + ipcMain.on("app:notify", (event, txt) => { createAndShowNotification({ body: txt }); }); + + ipcMain.handle("sidebar:getServers", () => { + // TODO: remove + if (!settings.get("servers")) { + settings.set("servers", [ + { + _id: "1", + name: "WA Demo", + url: "https://play.staging.workadventu.re/@/tcm/workadventure/wa-village", + }, + { + _id: "2", + name: "My Server", + url: "http://play.workadventure.localhost/", + }, + ]); + } + + return settings.get("servers", []); + }); + + ipcMain.handle("sidebar:selectServer", (event, serverId: string) => { + const appView = getAppView(); + if (!appView) { + throw new Error("App view not found"); + } + + const servers = settings.get("servers", []); + const selectedServer = servers.find((s) => s._id === serverId); + + if (!selectedServer) { + return new Error("Server not found"); + } + + appView.webContents.loadURL(selectedServer.url); + return true; + }); + + ipcMain.handle( + "sidebar:addServer", + (event, serverName: string, serverUrl: string) => { + const servers = settings.get("servers", []); + servers.push({ + _id: `${servers.length + 1}`, + name: serverName, + url: serverUrl, + }); + settings.set("servers", servers); + return true; + } + ); }; diff --git a/desktop/src/log.ts b/desktop/src/log.ts index 5378115d..5fab521f 100644 --- a/desktop/src/log.ts +++ b/desktop/src/log.ts @@ -1,5 +1,4 @@ import { dialog, shell } from "electron"; -import electronIsDev from "electron-is-dev"; import log from "electron-log"; import settings from "./settings"; @@ -40,18 +39,12 @@ function onRejection(reason: Error) { function init() { const logLevel = settings.get("log_level", "info"); - log.transports.file.level = logLevel; log.transports.console.level = logLevel; + log.transports.file.level = logLevel; // eslint-disable-next-line no-console console.log = log.log.bind(log); - if (!electronIsDev) { - log.transports.file.fileName = "work-adventure.log"; - } else { - console.log("Log file is disabled in dev. Using console output instead."); - } - process.on("uncaughtException", onError); process.on("unhandledRejection", onRejection); } diff --git a/desktop/src/settings.ts b/desktop/src/settings.ts index c19a9979..fb61621c 100644 --- a/desktop/src/settings.ts +++ b/desktop/src/settings.ts @@ -1,9 +1,16 @@ import ElectronLog from "electron-log"; import Settings from "electron-settings"; +type Server = { + _id: string; + name: string; + url: string; +}; + type SettingsData = { log_level: ElectronLog.LogLevel; auto_launch_enabled: boolean; + servers: Server[]; }; let settings: SettingsData; diff --git a/desktop/src/sidebar/preload.ts b/desktop/src/sidebar/preload.ts new file mode 100644 index 00000000..71ba33ed --- /dev/null +++ b/desktop/src/sidebar/preload.ts @@ -0,0 +1,10 @@ +import { contextBridge, ipcRenderer } from "electron"; + +contextBridge.exposeInMainWorld("WorkAdventureDesktopApi", { + desktop: true, + getServers: () => ipcRenderer.invoke("sidebar:getServers"), + selectServer: (serverId: string) => + ipcRenderer.invoke("sidebar:selectServer", serverId), + addServer: (serverName: string, serverUrl: string) => + ipcRenderer.invoke("sidebar:addServer", serverName, serverUrl), +}); diff --git a/desktop/src/tray.ts b/desktop/src/tray.ts index 9396e438..984cdc5b 100644 --- a/desktop/src/tray.ts +++ b/desktop/src/tray.ts @@ -20,7 +20,7 @@ export function createTray() { const trayContextMenu = Menu.buildFromTemplate([ { id: "open", - label: "Open / Close", + label: "Show / Hide", click() { const mainWindow = getWindow(); if (!mainWindow) { diff --git a/desktop/src/window.ts b/desktop/src/window.ts index a8f8babf..7bdb3262 100644 --- a/desktop/src/window.ts +++ b/desktop/src/window.ts @@ -1,17 +1,20 @@ -import { BrowserWindow } from "electron"; -import electronIsDev from "electron-is-dev"; +import { BrowserView, BrowserWindow } from "electron"; import windowStateKeeper from "electron-window-state"; import path from "path"; let mainWindow: BrowserWindow | undefined; +let appView: BrowserView | undefined; -const url = process.env.PLAY_URL; -// "https://play.staging.workadventu.re/@/tcm/workadventure/wa-village"; // TODO +const sidebarWidth = 70; export function getWindow() { return mainWindow; } +export function getAppView() { + return appView; +} + export function createWindow() { // do not re-create window if still existing if (mainWindow) { @@ -32,13 +35,8 @@ export function createWindow() { height: windowState.height, autoHideMenuBar: true, show: false, - title: "WorkAdventure", webPreferences: { - preload: path.join(__dirname, "../dist/preload/index.js"), - // allowRunningInsecureContent: false, - // contextIsolation: true, // TODO: remove in electron 12 - // nodeIntegration: false, - // sandbox: true, + preload: path.join(__dirname, "../dist/sidebar/preload.js"), }, }); @@ -47,18 +45,10 @@ export function createWindow() { // and restore the maximized or full screen state windowState.manage(mainWindow); - mainWindow.on("show", () => { - // TODO - }); - mainWindow.on("closed", () => { mainWindow = undefined; }); - mainWindow.once("ready-to-show", () => { - mainWindow?.show(); - }); - // mainWindow.on('close', async (event) => { // if (!app.confirmedExitPrompt) { // event.preventDefault(); // Prevents the window from closing @@ -77,11 +67,37 @@ export function createWindow() { // } // }); - if (!url || electronIsDev) { - // TODO - mainWindow.loadFile("../test-app/index.html"); - mainWindow.webContents.openDevTools(); - } else { - mainWindow.loadURL(url); // TODO: load app on demand - } + appView = new BrowserView({ + webPreferences: { + preload: path.join(__dirname, "../dist/app/index.js"), + }, + }); + mainWindow.setBrowserView(appView); + appView.setBounds({ + x: sidebarWidth, + y: 0, + width: mainWindow.getBounds().width - sidebarWidth, + height: mainWindow.getBounds().height, + }); + appView.setAutoResize({ + width: true, + height: true, + }); + + mainWindow.once("ready-to-show", () => { + (async () => { + await appView?.webContents.loadURL("https://workadventu.re/"); // TODO: use some splashscreen ? + // appView.webContents.openDevTools({ + // mode: "detach", + // }); + mainWindow?.show(); + // mainWindow?.webContents.openDevTools({ mode: "detach" }); + })(); + }); + + mainWindow.webContents.on("did-finish-load", () => { + mainWindow?.setTitle("WorkAdventure Desktop"); + }); + + mainWindow.loadFile("../sidebar/index.html"); } diff --git a/desktop/test-app/index.html b/desktop/test-app/index.html deleted file mode 100644 index 4ce24a29..00000000 --- a/desktop/test-app/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - WorkAdventure Desktop Demo - - -
Hello World!
- - - - - \ No newline at end of file diff --git a/desktop/test-app/web.js b/desktop/test-app/web.js deleted file mode 100644 index 8495a393..00000000 --- a/desktop/test-app/web.js +++ /dev/null @@ -1,25 +0,0 @@ -let muted = false; - -if (window?.WorkAdventureDesktopApi?.desktop) { - document.getElementById("demo").innerHTML = - "Hello Desktop app! Press ctrl-alt-m to mute."; - - window?.WorkAdventureDesktopApi?.onMutedKeyPress((event) => { - if (muted) { - document.getElementById("demo").innerHTML = - "Ready to speak! Press ctrl-alt-m to mute."; - } else { - document.getElementById("demo").innerHTML = - "Muted! Press ctrl-alt-m to unmute again."; - } - muted = !muted; - }); -} - -document.getElementById("btn-reload").onclick = () => { - location.reload(); -}; - -document.getElementById("btn-api").onclick = () => { - window.WorkAdventureDesktopApi.notify("Hello from website"); -};