add desktop api to front
This commit is contained in:
parent
1425513452
commit
4e243151dd
@ -27,7 +27,8 @@
|
||||
"electron-settings": "^4.0.2",
|
||||
"electron-updater": "^4.6.5",
|
||||
"electron-util": "^0.17.2",
|
||||
"electron-window-state": "^5.0.3"
|
||||
"electron-window-state": "^5.0.3",
|
||||
"node-fetch": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/auto-launch": "^5.0.2",
|
||||
|
@ -3,25 +3,26 @@ import electronIsDev from "electron-is-dev";
|
||||
import { createAndShowNotification } from "./notification";
|
||||
import { Server } from "./preload-local-app/types";
|
||||
import settings, { SettingsData } from "./settings";
|
||||
import { loadShortcuts, saveShortcut, setShortcutsEnabled } from "./shortcuts";
|
||||
import { getWindow, hideAppView, showAppView } from "./window";
|
||||
import { loadShortcuts, setShortcutsEnabled } from "./shortcuts";
|
||||
import { getAppView, getWindow, hideAppView, showAppView } from "./window";
|
||||
// import fetch from "node-fetch";
|
||||
|
||||
export function emitMuteToggle() {
|
||||
const mainWindow = getWindow();
|
||||
if (!mainWindow) {
|
||||
const appView = getAppView();
|
||||
if (!appView) {
|
||||
throw new Error("Main window not found");
|
||||
}
|
||||
|
||||
mainWindow.webContents.send("app:on-camera-toggle");
|
||||
appView.webContents.send("app:on-camera-toggle");
|
||||
}
|
||||
|
||||
export function emitCameraToggle() {
|
||||
const mainWindow = getWindow();
|
||||
if (!mainWindow) {
|
||||
const appView = getAppView();
|
||||
if (!appView) {
|
||||
throw new Error("Main window not found");
|
||||
}
|
||||
|
||||
mainWindow.webContents.send("app:on-mute-toggle");
|
||||
appView.webContents.send("app:on-mute-toggle");
|
||||
}
|
||||
|
||||
export default () => {
|
||||
@ -68,7 +69,7 @@ export default () => {
|
||||
|
||||
try {
|
||||
// TODO: add proper test to see if server url is valid and points to a real WA server
|
||||
await fetch(`${server.url}/iframe_api.js`);
|
||||
// await fetch(`${server.url}/iframe_api.js`);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Error("Invalid server url");
|
||||
@ -76,7 +77,7 @@ export default () => {
|
||||
|
||||
const newServer = {
|
||||
...server,
|
||||
_id: `${servers.length + 1}`,
|
||||
_id: `${Date.now()}-${servers.length + 1}`,
|
||||
};
|
||||
servers.push(newServer);
|
||||
settings.set("servers", servers);
|
||||
|
@ -10,4 +10,4 @@ const api: WorkAdventureDesktopApi = {
|
||||
onCameraToggle: (callback) => ipcRenderer.on("app:on-camera-toggle", callback),
|
||||
};
|
||||
|
||||
contextBridge.exposeInMainWorld("WorkAdventureDesktopApi", api);
|
||||
contextBridge.exposeInMainWorld("WAD", api);
|
||||
|
@ -16,4 +16,4 @@ const api: WorkAdventureLocalAppApi = {
|
||||
setShortcutsEnabled: (enabled) => ipcRenderer.invoke("local-app:setShortcutsEnabled", enabled),
|
||||
};
|
||||
|
||||
contextBridge.exposeInMainWorld("WorkAdventureDesktopApi", api);
|
||||
contextBridge.exposeInMainWorld("WAD", api);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { globalShortcut } from "electron";
|
||||
import settings, { SettingsData } from "./settings";
|
||||
import { emitCameraToggle, emitMuteToggle } from "./ipc";
|
||||
import { createAndShowNotification } from "./notification";
|
||||
|
||||
export function setShortcutsEnabled(enabled: boolean) {
|
||||
if (enabled) {
|
||||
@ -16,18 +15,15 @@ export function loadShortcuts() {
|
||||
|
||||
const shortcuts = settings.get("shortcuts");
|
||||
|
||||
// // mute key
|
||||
if (shortcuts?.mute_toggle && shortcuts.mute_toggle.length > 0) {
|
||||
globalShortcut.register(shortcuts.mute_toggle, () => {
|
||||
emitMuteToggle();
|
||||
createAndShowNotification({ body: "Toggled mute" }); // TODO
|
||||
});
|
||||
}
|
||||
|
||||
if (shortcuts?.camera_toggle && shortcuts.camera_toggle.length > 0) {
|
||||
globalShortcut.register(shortcuts.camera_toggle, () => {
|
||||
emitCameraToggle();
|
||||
createAndShowNotification({ body: "Toggled camera" }); // TODO
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,19 @@ export function getAppView() {
|
||||
return appView;
|
||||
}
|
||||
|
||||
function resizeAppView() {
|
||||
if (!mainWindow || !appView) {
|
||||
return;
|
||||
}
|
||||
|
||||
appView.setBounds({
|
||||
x: sidebarWidth,
|
||||
y: 0,
|
||||
width: mainWindow.getBounds().width - sidebarWidth,
|
||||
height: mainWindow.getBounds().height,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createWindow() {
|
||||
// do not re-create window if still existing
|
||||
if (mainWindow) {
|
||||
@ -41,6 +54,7 @@ export async function createWindow() {
|
||||
preload: path.resolve(__dirname, "..", "dist", "preload-local-app", "preload.js"),
|
||||
},
|
||||
});
|
||||
mainWindow.setMenu(null);
|
||||
|
||||
// Let us register listeners on the window, so we can update the state
|
||||
// automatically (the listeners will be removed when the window is closed)
|
||||
@ -74,16 +88,8 @@ export async function createWindow() {
|
||||
preload: path.resolve(__dirname, "..", "dist", "preload-app", "preload.js"),
|
||||
},
|
||||
});
|
||||
appView.setBounds({
|
||||
x: sidebarWidth,
|
||||
y: 0,
|
||||
width: mainWindow.getBounds().width - sidebarWidth,
|
||||
height: mainWindow.getBounds().height,
|
||||
});
|
||||
appView.setAutoResize({
|
||||
width: true,
|
||||
height: true,
|
||||
});
|
||||
resizeAppView();
|
||||
mainWindow.on("resize", resizeAppView);
|
||||
|
||||
mainWindow.once("ready-to-show", () => {
|
||||
mainWindow?.show();
|
||||
@ -91,7 +97,7 @@ export async function createWindow() {
|
||||
// appView?.webContents.openDevTools({
|
||||
// mode: "detach",
|
||||
// });
|
||||
mainWindow?.webContents.openDevTools({ mode: "detach" });
|
||||
// mainWindow?.webContents.openDevTools({ mode: "detach" });
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -843,6 +843,11 @@ crypto-random-string@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
||||
|
||||
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||
@ -1455,6 +1460,14 @@ fd-slicer@~1.1.0:
|
||||
dependencies:
|
||||
pend "~1.2.0"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.1.4.tgz#e8c6567f80ad7fc22fd302e7dcb72bafde9c1717"
|
||||
integrity sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||
@ -1506,6 +1519,13 @@ form-data@^4.0.0:
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
fs-extra@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
|
||||
@ -2246,6 +2266,20 @@ node-addon-api@^1.6.3:
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d"
|
||||
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.0.tgz#59390db4e489184fa35d4b74caf5510e8dfbaf3b"
|
||||
integrity sha512-8xeimMwMItMw8hRrOl3C9/xzU49HV/yE6ORew/l+dxWimO5A4Ra8ld2rerlJvc/O7et5Z1zrWsPX43v1QBjCxw==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
@ -3085,6 +3119,11 @@ verror@^1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965"
|
||||
integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==
|
||||
|
||||
which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
|
@ -23,6 +23,10 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
|
@ -8,6 +8,7 @@
|
||||
const Home = () => import("~/views/Home.svelte");
|
||||
const AddServer = () => import("~/views/AddServer.svelte");
|
||||
const Settings = () => import("~/views/Settings.svelte");
|
||||
const Server = () => import("~/views/Server.svelte");
|
||||
|
||||
let insideElectron = api.desktop;
|
||||
</script>
|
||||
@ -19,6 +20,7 @@
|
||||
<LazyRoute path="/" component={Home} delayMs={500}>Loading ...</LazyRoute>
|
||||
<LazyRoute path="/server/add" component={AddServer} delayMs={500}>Loading ...</LazyRoute>
|
||||
<LazyRoute path="/settings" component={Settings} delayMs={500}>Loading ...</LazyRoute>
|
||||
<LazyRoute path="/server/:id" component={Server} delayMs={500}>Loading ...</LazyRoute>
|
||||
<Route>
|
||||
<h3>404</h3>
|
||||
<p>No Route could be matched.</p>
|
||||
|
@ -9,7 +9,6 @@
|
||||
{title}
|
||||
</label>
|
||||
<slot />
|
||||
<!-- <input class="shadow appearance-none border border-red-500 rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************"> -->
|
||||
{#if description.length > 0}
|
||||
<p class="text-gray-200 text-xs mt-1 italic">{description}</p>
|
||||
{/if}
|
||||
|
@ -1,18 +0,0 @@
|
||||
<script>
|
||||
import { navigate } from "svelte-navigator";
|
||||
import { api } from "~/lib/ipc";
|
||||
|
||||
let to = "/";
|
||||
let clazz = "";
|
||||
|
||||
export { clazz as class, to };
|
||||
|
||||
async function click() {
|
||||
await api.showLocalApp();
|
||||
navigate(to);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click={click} class={`${clazz}`}>
|
||||
<slot />
|
||||
</div>
|
@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { Link } from "svelte-navigator";
|
||||
|
||||
import Link from "~/lib/Link.svelte";
|
||||
import { servers, selectedServer, selectServer, loadServers } from "~/store";
|
||||
import { servers, selectedServer, loadServers } from "~/store";
|
||||
import CogIcon from "~/assets/nes.icons/cog.svg";
|
||||
import { api } from "~/lib/ipc";
|
||||
|
||||
@ -34,17 +34,16 @@
|
||||
<aside class="flex flex-col bg-gray-700 items-center">
|
||||
<div class="flex flex-col mt-4 space-y-4 overflow-y-auto pb-4">
|
||||
{#each $servers as server, i}
|
||||
<div class="flex flex-col items-center justify-center ">
|
||||
<Link to="/server/{server._id}" class="flex flex-col items-center justify-center ">
|
||||
<div
|
||||
class={`w-16 h-16 p-1 rounded-md flex cursor-pointer text-light-50 border-4 border-transparent text-gray-200 hover:text-gray-500`}
|
||||
class:border-gray-400={$selectedServer === server._id}
|
||||
on:click={() => selectServer(server)}
|
||||
>
|
||||
<div class={`flex w-full h-full text-center items-center justify-center rounded-md ${getServerColor(i)}`}>
|
||||
{server.name.slice(0,2).toLocaleUpperCase()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
{/each}
|
||||
</div>
|
||||
<Link
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { WorkAdventureLocalAppApi, SettingsData, Server } from "@wa-preload-local-app";
|
||||
|
||||
export { WorkAdventureLocalAppApi, SettingsData, Server };
|
||||
// TODO fix type
|
||||
export const api = (window as any)?.WorkAdventureDesktopApi as WorkAdventureLocalAppApi;
|
||||
|
||||
export const api = window?.WAD;
|
||||
|
@ -6,11 +6,11 @@ export const newServer = writable<Omit<Server, "_id">>({
|
||||
url: "",
|
||||
});
|
||||
export const servers = writable<Server[]>([]);
|
||||
export const selectedServer = writable<string | undefined>("");
|
||||
export const selectedServer = writable<string>("");
|
||||
|
||||
export async function selectServer(server: Server) {
|
||||
await api.selectServer(server._id);
|
||||
selectedServer.set(server._id);
|
||||
export async function selectServer(serverId: string) {
|
||||
await api.selectServer(serverId);
|
||||
selectedServer.set(serverId);
|
||||
}
|
||||
|
||||
export async function addServer() {
|
||||
@ -20,7 +20,7 @@ export async function addServer() {
|
||||
}
|
||||
newServer.set({ name: "", url: "" });
|
||||
servers.update((s) => [...s, addedServer]);
|
||||
await selectServer(addedServer);
|
||||
await selectServer(addedServer._id);
|
||||
}
|
||||
|
||||
export async function loadServers() {
|
||||
|
25
desktop/local-app/src/views/Server.svelte
Normal file
25
desktop/local-app/src/views/Server.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { useParams } from "svelte-navigator";
|
||||
|
||||
import { selectServer, servers } from "~/store";
|
||||
import { api } from "~/lib/ipc";
|
||||
|
||||
const params = useParams();
|
||||
|
||||
params.subscribe((_params) => {
|
||||
selectServer(_params.id);
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
await selectServer($params.id);
|
||||
});
|
||||
|
||||
onDestroy(async () => {
|
||||
await api.showLocalApp();
|
||||
});
|
||||
|
||||
$: server = $servers.find(({ _id }) => _id === $params.id);
|
||||
</script>
|
||||
|
||||
<div class="hidden m-auto text-gray-400">Server: "{server.name}"</div>
|
7
desktop/local-app/src/window.d.ts
vendored
Normal file
7
desktop/local-app/src/window.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import type { WorkAdventureLocalAppApi } from "@wa-preload-local-app";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
WAD: WorkAdventureLocalAppApi;
|
||||
}
|
||||
}
|
38
front/src/Api/desktop/index.ts
Normal file
38
front/src/Api/desktop/index.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { isSilentStore, requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
class DesktopApi {
|
||||
isSilent: boolean = false;
|
||||
|
||||
init() {
|
||||
if (!window?.WAD?.desktop) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Yipee you are using the desktop app ;)");
|
||||
|
||||
window.WAD.onMuteToggle(() => {
|
||||
if (this.isSilent) return;
|
||||
if (get(requestedMicrophoneState) === true) {
|
||||
requestedMicrophoneState.disableMicrophone();
|
||||
} else {
|
||||
requestedMicrophoneState.enableMicrophone();
|
||||
}
|
||||
});
|
||||
|
||||
window.WAD.onCameraToggle(() => {
|
||||
if (this.isSilent) return;
|
||||
if (get(requestedCameraState) === true) {
|
||||
requestedCameraState.disableWebcam();
|
||||
} else {
|
||||
requestedCameraState.enableWebcam();
|
||||
}
|
||||
});
|
||||
|
||||
isSilentStore.subscribe((value) => {
|
||||
this.isSilent = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const desktopApi = new DesktopApi();
|
@ -182,13 +182,6 @@ const wa = {
|
||||
|
||||
export type WorkAdventureApi = typeof wa;
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
WA: WorkAdventureApi;
|
||||
}
|
||||
let WA: WorkAdventureApi;
|
||||
}
|
||||
|
||||
window.WA = wa;
|
||||
|
||||
window.addEventListener(
|
||||
|
@ -16,6 +16,7 @@ import { coWebsiteManager } from "./WebRtc/CoWebsiteManager";
|
||||
import { localUserStore } from "./Connexion/LocalUserStore";
|
||||
import { ErrorScene } from "./Phaser/Reconnecting/ErrorScene";
|
||||
import { iframeListener } from "./Api/IframeListener";
|
||||
import { desktopApi } from "./Api/desktop/index";
|
||||
import { SelectCharacterMobileScene } from "./Phaser/Login/SelectCharacterMobileScene";
|
||||
import { HdpiManager } from "./Phaser/Services/HdpiManager";
|
||||
import { waScaleManager } from "./Phaser/Services/WaScaleManager";
|
||||
@ -154,6 +155,7 @@ coWebsiteManager.onResize.subscribe(() => {
|
||||
});
|
||||
|
||||
iframeListener.init();
|
||||
desktopApi.init();
|
||||
|
||||
const app = new App({
|
||||
target: HtmlUtils.getElementByIdOrFail("game-overlay"),
|
||||
|
10
front/src/window.d.ts
vendored
Normal file
10
front/src/window.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { WorkAdventureApi } from "./iframe_api";
|
||||
import { WorkAdventureDesktopApi } from "@wa-preload-app";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
WA: WorkAdventureApi;
|
||||
WAD: WorkAdventureDesktopApi;
|
||||
}
|
||||
let WA: WorkAdventureApi;
|
||||
}
|
@ -27,7 +27,10 @@
|
||||
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */
|
||||
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
"paths": {
|
||||
"@wa-preload-app": ["../desktop/electron/src/preload-app/types.ts"],
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
Loading…
Reference in New Issue
Block a user