Skip to content

Commit

Permalink
Merge pull request #355 from fperera123/feature/overlay-mode
Browse files Browse the repository at this point in the history
Introduce window modes with overlay and transparent overlay
  • Loading branch information
CrazyMarvin authored Sep 9, 2024
2 parents 1a58877 + 9cc7521 commit 1ee902b
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 99 deletions.
96 changes: 73 additions & 23 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { app, BrowserWindow, ipcMain, shell } from "electron"
import MenuBuilder from "./menu"
import { resolveHtmlPath } from "./util"
import { WindowStateManager, WindowState } from './windowState';
import { WindowModeManager } from "./windowMode";
import { registerWindowHandlers, destroyWindowHandlers } from "./windowHandler";
import { registerLogoutHandler, destroyLogoutHandler } from "./logoutHandler";
import { registerRefreshHandler, destroyRefreshHandler } from "./refreshHandler";
Expand Down Expand Up @@ -44,41 +45,28 @@ const installExtensions = async () => {
.catch(console.log)
}

const windowModeManager = new WindowModeManager('main-window');
const windowMode = windowModeManager.getWindowMode();

const createWindow = async () => {
if (isDebug) {
await installExtensions()
}

const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../../assets')
const windowOptions = getWindowOptions(windowMode);

const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths)
}

mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728,
icon: getAssetPath('icon.png'),
webPreferences: {
webSecurity: false,
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
})

mainWindow.isPrimary = true;
mainWindow = new BrowserWindow(windowOptions);

// 👉 save window state
const defaultWindowState: WindowState = {
width: 1024,
height: 728,
};
const windowStateManager = new WindowStateManager('main', defaultWindowState);
windowStateManager.manage(mainWindow);

if(windowMode !== 'overlayTransparent') {
const windowStateManager = new WindowStateManager('main', defaultWindowState, windowMode);
windowStateManager.manage(mainWindow);
}

mainWindow.loadURL(resolveHtmlPath('index.html'))

Expand Down Expand Up @@ -111,6 +99,66 @@ const createWindow = async () => {
// new AppUpdater()
}

const getWindowOptions = (windowMode: 'overlay' | 'windowed' | 'overlayTransparent'): Electron.BrowserWindowConstructorOptions => {

const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../../assets')

const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths)
}

const baseOptions: Electron.BrowserWindowConstructorOptions = {
show: false,
minWidth: 200,
minHeight: 45,
icon: getAssetPath('icon.png'),
webPreferences: {
webSecurity: false,
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
isPrimary: true,
resizable: true,
movable: true,
};

if (windowMode === 'overlay') {
return {
...baseOptions,
width: 800,
height: 600,
alwaysOnTop: true,
frame: false,
};
}
if (windowMode === 'overlayTransparent') {
return {
...baseOptions,
width: 200,
height: 45,
alwaysOnTop: true,
frame: false,
transparent: true,
resizable: false,
hasShadow: false,
};
}
else if (windowMode === 'windowed') {
return {
...baseOptions,
width: 1024,
height: 728,
frame: true,
};
}

return baseOptions;
}


/**
* Add event listeners...
*/
Expand Down Expand Up @@ -152,3 +200,5 @@ ipcMain.handle('ipc-open-file', async (event, ...args) => {
registerWindowHandlers();
registerLogoutHandler();
registerRefreshHandler();

export const getMainWindow = () => mainWindow;
18 changes: 18 additions & 0 deletions src/main/windowHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BrowserWindow, ipcMain, app } from 'electron';
import path from 'path';
import { resolveHtmlPath } from './util';
import { WindowModeManager } from './windowMode';

interface WindowCache {
[url: string]: BrowserWindow | undefined;
Expand All @@ -9,6 +10,9 @@ interface WindowCache {
export const registerWindowHandlers = () => {
const windowCache: WindowCache = {};

const windowModeManager = new WindowModeManager('main-window');


// 👉 register window handlers
ipcMain.on('open-new-window', (event, url, width, height) => {
// Check if the window for this URL already exists
Expand Down Expand Up @@ -40,9 +44,23 @@ export const registerWindowHandlers = () => {
});

});

ipcMain.on('set-window-mode', (event, mode: 'overlay' | 'windowed') => {
windowModeManager.setWindowMode(mode);

// in order to change window options we need to restart
app.relaunch();
app.exit();
});

ipcMain.handle('get-window-mode', () => {
return windowModeManager.getWindowMode();
});
};

export const destroyWindowHandlers = () => {
// 👉 destroy window handlers
ipcMain.removeAllListeners('open-new-window');
ipcMain.removeAllListeners('set-window-mode');
ipcMain.removeAllListeners('get-window-mode');
};
30 changes: 30 additions & 0 deletions src/main/windowMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { app } from 'electron';
import fs from 'fs';
import path from 'path';

export class WindowModeManager {

private filePath: string;

constructor(private windowName: string) {
const userDataPath = app.getPath('userData');
this.filePath = path.join(userDataPath, `${windowName}-window-mode.json`);
console.log('filePath', this.filePath);
}

getWindowMode(): 'overlay' | 'windowed' | 'overlayTransparent' {
try {
const data = fs.readFileSync(this.filePath, 'utf8');
const parsed = JSON.parse(data);
return parsed.windowMode;
} catch (error) {
return 'windowed';
}
}

setWindowMode(mode: 'overlay' | 'windowed') {
const data = JSON.stringify({ windowMode: mode }, null, 2);
console.log('setWindowMode', this.filePath, data, mode);
fs.writeFileSync(this.filePath, data);
}
}
8 changes: 6 additions & 2 deletions src/main/windowState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export class WindowStateManager {

private state: WindowState;

constructor(private windowName: string, private defaultState: WindowState) {
constructor(private windowName: string, private defaultState: WindowState, private windowMode: 'overlay' | 'overlayTransparent' | 'windowed') {
const userDataPath = app.getPath('userData');
this.stateFilePath = path.join(userDataPath, `${windowName}-window-state.json`);
this.stateFilePath = path.join(userDataPath, `${windowName}-${windowMode}-window-state.json`);
this.state = this.readState();
}

Expand Down Expand Up @@ -61,4 +61,8 @@ export class WindowStateManager {
};
this.saveState(this.state);
}

public getState(): WindowState {
return this.state;
}
}
13 changes: 13 additions & 0 deletions src/renderer/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "@/globals.css"
import "@/custom.css"
import "@/i18n/config"
import { useEffect } from "react"
import { getWindowMode, setLocalStorageWindowMode } from "@/lib/utils";

export default function App() {
const token = useAuthStore((state) => state.token)
Expand All @@ -22,6 +23,18 @@ export default function App() {
};
}, []);


useEffect(() => {
async function fetchAndStoreWindowMode() {
const mode = await getWindowMode();
console.log('fetchWindowMode', mode);

setLocalStorageWindowMode(mode);
}

fetchAndStoreWindowMode();
}, []);

return (
<AnimatePresence>
<RouterProvider router={routes(!!token)} />
Expand Down
16 changes: 16 additions & 0 deletions src/renderer/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,25 @@ const resultUnits: DropdownConfigType[] = [
},
];

const windowModes: DropdownConfigType[] = [
{
label: 'Overlay',
value: 'overlay',
},
{
label: 'Overlay (Transparent)',
value: 'overlayTransparent',
},
{
label: 'Windowed',
value: 'windowed',
},
];

export {
countries,
languages,
themes,
resultUnits,
windowModes,
}
12 changes: 12 additions & 0 deletions src/renderer/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,15 @@
--ring: 12 100% 50%;
}
}

.draggable{
-webkit-app-region: drag;
}

.no-draggable{
-webkit-app-region: no-drag;
}

.overlay-shadow{
text-shadow: 2px 1px 5px rgba(0, 0, 0, 0.8);
}
20 changes: 18 additions & 2 deletions src/renderer/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,24 @@ export async function openFile(type: string, folder: string, group: string, file
await window.electron.ipcRenderer.invoke('ipc-open-file', type, folder, group, filename)
}

export function openNewWindow(path: string, width: number, height: number) {
window.electron.ipcRenderer.sendMessage('open-new-window', path, width, height)
export async function openNewWindow(path: string, width: number, height: number) {
await window.electron.ipcRenderer.sendMessage('open-new-window', path, width, height)
}

export async function setWindowMode(mode: string) {
await window.electron.ipcRenderer.sendMessage('set-window-mode', mode)
}

export async function getWindowMode() {
return await window.electron.ipcRenderer.invoke('get-window-mode')
}

export async function setLocalStorageWindowMode(mode: string) {
await localStorage.setItem('windowMode', mode);
}

export async function getLocalStorageWindowMode(): Promise<string> {
return await localStorage.getItem('windowMode') as string;
}

export async function setRedirectTo (path: string) {
Expand Down
Loading

0 comments on commit 1ee902b

Please sign in to comment.