Enable screensharing in desktop app (#2042)

* enable screensharing in desktop app

* add source picker

* update dependencies

* improve source picker

* improve source picker

* update thumbnails

* decrease thumbnail size

* revert unnecessary changes in screen sharing store

* fix types and eslint

* fix prettier

* remove unused import
This commit is contained in:
Lukas
2022-04-25 14:46:20 +02:00
committed by GitHub
parent 2412f4076f
commit 1c9caa690a
15 changed files with 650 additions and 632 deletions
+6 -6
View File
@@ -10,7 +10,7 @@ import { setLogLevel } from "./log";
import "./serve"; // prepare custom url scheme
import { loadShortcuts } from "./shortcuts";
function init() {
async function init() {
const appLock = app.requestSingleInstanceLock();
if (!appLock) {
@@ -21,7 +21,7 @@ function init() {
app.on("second-instance", () => {
// re-create window if closed
createWindow();
void createWindow();
const mainWindow = getWindow();
@@ -36,15 +36,15 @@ function init() {
});
// This method will be called when Electron has finished loading
app.whenReady().then(async () => {
await app.whenReady().then(async () => {
await settings.init();
setLogLevel(settings.get("log_level") || "info");
autoUpdater.init();
await autoUpdater.init();
// enable auto launch
updateAutoLaunch();
await updateAutoLaunch();
// load ipc handler
ipc();
@@ -72,7 +72,7 @@ function init() {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
void createWindow();
}
});
+25 -22
View File
@@ -38,32 +38,35 @@ export async function manualRequestUpdateCheck() {
isManualRequestedUpdate = false;
}
function init() {
async function init() {
autoUpdater.logger = log;
autoUpdater.on("update-downloaded", ({ releaseNotes, releaseName }) => {
(async () => {
const dialogOpts = {
type: "question",
buttons: ["Install and Restart", "Install Later"],
defaultId: 0,
title: "WorkAdventure - Update",
message: process.platform === "win32" ? releaseNotes : releaseName,
detail: "A new version has been downloaded. Restart the application to apply the updates.",
};
autoUpdater.on(
"update-downloaded",
({ releaseNotes, releaseName }: { releaseNotes: string; releaseName: string }) => {
void (async () => {
const dialogOpts = {
type: "question",
buttons: ["Install and Restart", "Install Later"],
defaultId: 0,
title: "WorkAdventure - Update",
message: process.platform === "win32" ? releaseNotes : releaseName,
detail: "A new version has been downloaded. Restart the application to apply the updates.",
};
const { response } = await dialog.showMessageBox(dialogOpts);
if (response === 0) {
await sleep(1000);
const { response } = await dialog.showMessageBox(dialogOpts);
if (response === 0) {
await sleep(1000);
autoUpdater.quitAndInstall();
autoUpdater.quitAndInstall();
// Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app.
// app.confirmedExitPrompt = true;
app.quit();
}
})();
});
// Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app.
// app.confirmedExitPrompt = true;
app.quit();
}
})();
}
);
if (process.platform === "linux" && !process.env.APPIMAGE) {
autoUpdater.autoDownload = false;
@@ -85,7 +88,7 @@ function init() {
}
});
checkForUpdates();
await checkForUpdates();
// run update check every hour again
setInterval(() => checkForUpdates, 1000 * 60 * 1);
+12 -4
View File
@@ -1,4 +1,4 @@
import { ipcMain, app } from "electron";
import { ipcMain, app, desktopCapturer } from "electron";
import electronIsDev from "electron-is-dev";
import { createAndShowNotification } from "./notification";
import { Server } from "./preload-local-app/types";
@@ -30,10 +30,18 @@ export default () => {
ipcMain.handle("get-version", () => (electronIsDev ? "dev" : app.getVersion()));
// app ipc
ipcMain.on("app:notify", (event, txt) => {
ipcMain.on("app:notify", (event, txt: string) => {
createAndShowNotification({ body: txt });
});
ipcMain.handle("app:getDesktopCapturerSources", async (event, options: Electron.SourcesOptions) => {
return (await desktopCapturer.getSources(options)).map((source) => ({
id: source.id,
name: source.name,
thumbnailURL: source.thumbnail.toDataURL(),
}));
});
// local-app ipc
ipcMain.handle("local-app:showLocalApp", () => {
hideAppView();
@@ -43,7 +51,7 @@ export default () => {
return settings.get("servers");
});
ipcMain.handle("local-app:selectServer", (event, serverId: string) => {
ipcMain.handle("local-app:selectServer", async (event, serverId: string) => {
const servers = settings.get("servers") || [];
const selectedServer = servers.find((s) => s._id === serverId);
@@ -51,7 +59,7 @@ export default () => {
return new Error("Server not found");
}
showAppView(selectedServer.url);
await showAppView(selectedServer.url);
return true;
});
+1
View File
@@ -15,6 +15,7 @@ function onError(e: Error) {
function onRejection(reason: Error) {
if (reason instanceof Error) {
let _reason = reason;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const errPrototype = Object.getPrototypeOf(reason);
const nameProperty = Object.getOwnPropertyDescriptor(errPrototype, "name");
+1 -1
View File
@@ -2,4 +2,4 @@ import app from "./app";
import log from "./log";
log.init();
app.init();
void app.init();
@@ -8,6 +8,7 @@ const api: WorkAdventureDesktopApi = {
notify: (txt) => ipcRenderer.send("app:notify", txt),
onMuteToggle: (callback) => ipcRenderer.on("app:on-mute-toggle", callback),
onCameraToggle: (callback) => ipcRenderer.on("app:on-camera-toggle", callback),
getDesktopCapturerSources: (options) => ipcRenderer.invoke("app:getDesktopCapturerSources", options),
};
contextBridge.exposeInMainWorld("WAD", api);
+13
View File
@@ -1,3 +1,15 @@
// copy of Electron.SourcesOptions to avoid Electron dependency in front
export interface SourcesOptions {
types: string[];
thumbnailSize?: { height: number; width: number };
}
export interface DesktopCapturerSource {
id: string;
name: string;
thumbnailURL: string;
}
export type WorkAdventureDesktopApi = {
desktop: boolean;
isDevelopment: () => Promise<boolean>;
@@ -5,4 +17,5 @@ export type WorkAdventureDesktopApi = {
notify: (txt: string) => void;
onMuteToggle: (callback: () => void) => void;
onCameraToggle: (callback: () => void) => void;
getDesktopCapturerSources: (options: SourcesOptions) => Promise<DesktopCapturerSource[]>;
};
+3 -3
View File
@@ -36,14 +36,14 @@ export function createTray() {
},
{
label: "Check for updates",
async click() {
await autoUpdater.manualRequestUpdateCheck();
click() {
void autoUpdater.manualRequestUpdateCheck();
},
},
{
label: "Open Logs",
click() {
log.openLog();
void log.openLog();
},
},
{
+2 -2
View File
@@ -115,7 +115,7 @@ export async function createWindow() {
}
}
export function showAppView(url?: string) {
export async function showAppView(url?: string) {
if (!appView) {
throw new Error("App view not found");
}
@@ -130,7 +130,7 @@ export function showAppView(url?: string) {
mainWindow.addBrowserView(appView);
if (url && url !== appViewUrl) {
appView.webContents.loadURL(url);
await appView.webContents.loadURL(url);
appViewUrl = url;
}