setup electron multi-window architecture (#102)
* prototype with two windows * use deps in separate window render process * enhance autoplay into desktop overlay * fix: autoplay window not applying tailwind styles
This commit was merged in pull request #102.
This commit is contained in:
+112
-4
@@ -1,4 +1,4 @@
|
||||
import { app, BrowserWindow, ipcMain, session, shell } from 'electron';
|
||||
import { app, BrowserWindow, ipcMain, screen, session, shell } from 'electron';
|
||||
import path from 'node:path';
|
||||
import started from 'electron-squirrel-startup';
|
||||
import { updateElectronApp, UpdateSourceType } from 'update-electron-app';
|
||||
@@ -22,9 +22,12 @@ if (process.platform === 'darwin' && !app.isPackaged) {
|
||||
app.dock?.setIcon(path.join(__dirname, '../../assets/icon.png'));
|
||||
}
|
||||
|
||||
let mainWindow: BrowserWindow | null = null;
|
||||
let autoplayWindow: BrowserWindow | null = null;
|
||||
let huddleWindow: BrowserWindow | null = null;
|
||||
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
resizable: true,
|
||||
@@ -35,7 +38,6 @@ const createWindow = () => {
|
||||
},
|
||||
});
|
||||
|
||||
// and load the index.html of the app.
|
||||
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
||||
mainWindow.webContents.openDevTools();
|
||||
@@ -44,8 +46,80 @@ const createWindow = () => {
|
||||
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`),
|
||||
);
|
||||
}
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
};
|
||||
|
||||
const createAutoplayWindow = () => {
|
||||
if (autoplayWindow) return;
|
||||
|
||||
autoplayWindow = new BrowserWindow({
|
||||
width: 320,
|
||||
height: 88,
|
||||
resizable: false,
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
skipTaskbar: true,
|
||||
focusable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
},
|
||||
});
|
||||
|
||||
if (AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL) {
|
||||
autoplayWindow.loadURL(AUTOPLAY_WINDOW_VITE_DEV_SERVER_URL);
|
||||
} else {
|
||||
autoplayWindow.loadFile(
|
||||
path.join(__dirname, `../renderer/${AUTOPLAY_WINDOW_VITE_NAME}/index.html`),
|
||||
);
|
||||
}
|
||||
|
||||
autoplayWindow.on('closed', () => {
|
||||
autoplayWindow = null;
|
||||
});
|
||||
};
|
||||
|
||||
const createHuddleWindow = () => {
|
||||
if (huddleWindow) {
|
||||
huddleWindow.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
huddleWindow = new BrowserWindow({
|
||||
width: 1024,
|
||||
height: 768,
|
||||
resizable: true,
|
||||
fullscreenable: true,
|
||||
frame: true,
|
||||
title: 'Huddle',
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
},
|
||||
});
|
||||
|
||||
if (HUDDLE_WINDOW_VITE_DEV_SERVER_URL) {
|
||||
huddleWindow.loadURL(HUDDLE_WINDOW_VITE_DEV_SERVER_URL);
|
||||
} else {
|
||||
huddleWindow.loadFile(
|
||||
path.join(__dirname, `../renderer/${HUDDLE_WINDOW_VITE_NAME}/index.html`),
|
||||
);
|
||||
}
|
||||
|
||||
huddleWindow.on('closed', () => {
|
||||
huddleWindow = null;
|
||||
});
|
||||
};
|
||||
|
||||
function positionAutoplayWindow() {
|
||||
if (!autoplayWindow) return;
|
||||
const { width } = screen.getPrimaryDisplay().workAreaSize;
|
||||
const [winW] = autoplayWindow.getSize();
|
||||
autoplayWindow.setPosition(width - winW - 16, 16);
|
||||
}
|
||||
|
||||
// Window control IPC handlers
|
||||
ipcMain.on('window:minimize', (event) => {
|
||||
BrowserWindow.fromWebContents(event.sender)?.minimize();
|
||||
@@ -66,6 +140,39 @@ ipcMain.on('window:fullscreen', (event) => {
|
||||
if (win) win.setFullScreen(!win.isFullScreen());
|
||||
});
|
||||
|
||||
// Secondary window IPC handlers
|
||||
ipcMain.on('window:open-huddle', () => {
|
||||
createHuddleWindow();
|
||||
});
|
||||
ipcMain.on('window:close-huddle', () => {
|
||||
huddleWindow?.close();
|
||||
});
|
||||
|
||||
// Autoplay IPC handlers
|
||||
ipcMain.on('autoplay:play', (_event, payload) => {
|
||||
if (!autoplayWindow) createAutoplayWindow();
|
||||
if (!autoplayWindow) return;
|
||||
|
||||
const isVideo = typeof payload?.mimeType === 'string' && payload.mimeType.startsWith('video/');
|
||||
autoplayWindow.setSize(320, isVideo ? 260 : 88);
|
||||
positionAutoplayWindow();
|
||||
|
||||
autoplayWindow.webContents.send('autoplay:play', payload);
|
||||
autoplayWindow.showInactive();
|
||||
});
|
||||
|
||||
ipcMain.on('autoplay:dismiss', () => {
|
||||
autoplayWindow?.hide();
|
||||
});
|
||||
|
||||
ipcMain.on('autoplay:navigate', (_event, data) => {
|
||||
autoplayWindow?.hide();
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('autoplay:navigate', data);
|
||||
mainWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Link metadata ---
|
||||
|
||||
const metadataCache = new Map<string, LinkMetadata>();
|
||||
@@ -212,6 +319,7 @@ app.on('ready', () => {
|
||||
);
|
||||
|
||||
createWindow();
|
||||
createAutoplayWindow();
|
||||
});
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
|
||||
Reference in New Issue
Block a user