mirror of
https://github.com/frappe/books.git
synced 2024-11-08 23:00:56 +00:00
refactor: shift main process stuff out of source
This commit is contained in:
parent
761dd641bf
commit
a596f5dcad
153
main.ts
Normal file
153
main.ts
Normal file
@ -0,0 +1,153 @@
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
protocol,
|
||||
} from 'electron';
|
||||
import Store from 'electron-store';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import path from 'path';
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
|
||||
import { getMainWindowSize } from './main/helpers';
|
||||
import registerAppLifecycleListeners from './main/registerAppLifecycleListeners';
|
||||
import registerAutoUpdaterListeners from './main/registerAutoUpdaterListeners';
|
||||
import registerIpcMainActionListeners from './main/registerIpcMainActionListeners';
|
||||
import registerIpcMainMessageListeners from './main/registerIpcMainMessageListeners';
|
||||
import registerProcessListeners from './main/registerProcessListeners';
|
||||
import { IPC_CHANNELS } from './src/messages';
|
||||
|
||||
export class Main {
|
||||
title: string = 'Frappe Books';
|
||||
icon: string;
|
||||
|
||||
winURL: string = '';
|
||||
isWebpackUrl: boolean = false;
|
||||
checkedForUpdate = false;
|
||||
mainWindow: BrowserWindow | null = null;
|
||||
|
||||
constructor() {
|
||||
this.icon = this.isDevelopment
|
||||
? path.resolve('./build/icon.png')
|
||||
: path.join(__dirname, 'icons', '512x512.png');
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'app', privileges: { secure: true, standard: true } },
|
||||
]);
|
||||
|
||||
if (this.isDevelopment) {
|
||||
autoUpdater.logger = console;
|
||||
}
|
||||
|
||||
Store.initRenderer();
|
||||
|
||||
this.registerListeners();
|
||||
if (this.isMac && this.isDevelopment) {
|
||||
app.dock.setIcon(this.icon);
|
||||
}
|
||||
}
|
||||
|
||||
get isDevelopment() {
|
||||
return process.env.NODE_ENV !== 'production';
|
||||
}
|
||||
|
||||
get isMac() {
|
||||
return process.platform === 'darwin';
|
||||
}
|
||||
|
||||
get isLinux() {
|
||||
return process.platform === 'linux';
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
registerIpcMainMessageListeners(this);
|
||||
registerIpcMainActionListeners(this);
|
||||
registerAutoUpdaterListeners(this);
|
||||
registerAppLifecycleListeners(this);
|
||||
registerProcessListeners(this);
|
||||
}
|
||||
|
||||
getOptions(): BrowserWindowConstructorOptions {
|
||||
const { width, height } = getMainWindowSize();
|
||||
const options: BrowserWindowConstructorOptions = {
|
||||
vibrancy: 'sidebar',
|
||||
transparent: this.isMac,
|
||||
backgroundColor: '#80FFFFFF',
|
||||
width,
|
||||
height,
|
||||
title: this.title,
|
||||
webPreferences: {
|
||||
contextIsolation: false, // TODO: Switch this off
|
||||
nodeIntegration: process.env
|
||||
.ELECTRON_NODE_INTEGRATION as unknown as boolean,
|
||||
},
|
||||
frame: this.isLinux,
|
||||
resizable: true,
|
||||
};
|
||||
if (this.isDevelopment || this.isLinux) {
|
||||
Object.assign(options, { icon: this.icon });
|
||||
}
|
||||
|
||||
if (this.isLinux) {
|
||||
Object.assign(options, {
|
||||
icon: path.join(__dirname, '/icons/512x512.png'),
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
createWindow() {
|
||||
const options = this.getOptions();
|
||||
this.mainWindow = new BrowserWindow(options);
|
||||
|
||||
this.isWebpackUrl = !!process.env.WEBPACK_DEV_SERVER_URL;
|
||||
if (this.isWebpackUrl) {
|
||||
this.loadWebpackDevServerURL();
|
||||
} else {
|
||||
this.loadAppUrl();
|
||||
}
|
||||
|
||||
this.setMainWindowListeners();
|
||||
}
|
||||
|
||||
loadWebpackDevServerURL() {
|
||||
// Load the url of the dev server if in development mode
|
||||
this.winURL = process.env.WEBPACK_DEV_SERVER_URL as string;
|
||||
this.mainWindow!.loadURL(this.winURL);
|
||||
|
||||
if (!process.env.IS_TEST) {
|
||||
this.mainWindow!.webContents.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
loadAppUrl() {
|
||||
createProtocol('app');
|
||||
// Load the index.html when not in development
|
||||
this.winURL = 'app://./index.html';
|
||||
this.mainWindow!.loadURL(this.winURL);
|
||||
}
|
||||
|
||||
setMainWindowListeners() {
|
||||
if (this.mainWindow === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mainWindow.on('closed', () => {
|
||||
this.mainWindow = null;
|
||||
});
|
||||
|
||||
this.mainWindow.webContents.on('did-finish-load', () => {
|
||||
if (this.mainWindow === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mainWindow.webContents.send(IPC_CHANNELS.STORE_ON_WINDOW, {
|
||||
appVersion: app.getVersion(),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new Main();
|
14
main/helpers.ts
Normal file
14
main/helpers.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import electron, { app } from 'electron';
|
||||
|
||||
export function getMainWindowSize() {
|
||||
let height;
|
||||
if (app.isReady()) {
|
||||
const screen = electron.screen;
|
||||
height = screen.getPrimaryDisplay().workAreaSize.height;
|
||||
height = height > 907 ? 907 : height;
|
||||
} else {
|
||||
height = 907;
|
||||
}
|
||||
const width = Math.ceil(1.323 * height);
|
||||
return { height, width };
|
||||
}
|
32
main/registerAppLifecycleListeners.ts
Normal file
32
main/registerAppLifecycleListeners.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { app } from 'electron';
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
|
||||
import { Main } from '../main';
|
||||
|
||||
export default function registerAppLifecycleListeners(main: Main) {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
if (main.mainWindow === null) {
|
||||
main.createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('ready', async () => {
|
||||
if (main.isDevelopment && !process.env.IS_TEST) {
|
||||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
'Vue Devtools failed to install:',
|
||||
(e as Error).toString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
main.createWindow();
|
||||
});
|
||||
}
|
49
main/registerAutoUpdaterListeners.ts
Normal file
49
main/registerAutoUpdaterListeners.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { autoUpdater, UpdateInfo } from 'electron-updater';
|
||||
import { Main } from '../main';
|
||||
import { IPC_CHANNELS } from '../src/messages';
|
||||
|
||||
export default function registerAutoUpdaterListeners(main: Main) {
|
||||
autoUpdater.autoDownload = false;
|
||||
autoUpdater.autoInstallOnAppQuit = false;
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
if (!main.checkedForUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
main.mainWindow!.webContents.send(IPC_CHANNELS.CHECKING_FOR_UPDATE);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', (info: UpdateInfo) => {
|
||||
if (!main.checkedForUpdate) {
|
||||
main.checkedForUpdate = true;
|
||||
}
|
||||
|
||||
main.mainWindow!.webContents.send(
|
||||
IPC_CHANNELS.UPDATE_AVAILABLE,
|
||||
info.version
|
||||
);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
if (!main.checkedForUpdate) {
|
||||
main.checkedForUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
main.mainWindow!.webContents.send(IPC_CHANNELS.UPDATE_NOT_AVAILABLE);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
main.mainWindow!.webContents.send(IPC_CHANNELS.UPDATE_DOWNLOADED);
|
||||
});
|
||||
|
||||
autoUpdater.on('error', (error) => {
|
||||
if (!main.checkedForUpdate) {
|
||||
main.checkedForUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
main.mainWindow!.webContents.send(IPC_CHANNELS.UPDATE_ERROR, error);
|
||||
});
|
||||
}
|
115
main/registerIpcMainActionListeners.ts
Normal file
115
main/registerIpcMainActionListeners.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { dialog, ipcMain } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { Main } from '../main';
|
||||
import { getUrlAndTokenString, sendError } from '../src/contactMothership';
|
||||
import { getLanguageMap } from '../src/getLanguageMap';
|
||||
import { IPC_ACTIONS } from '../src/messages';
|
||||
import saveHtmlAsPdf from '../src/saveHtmlAsPdf';
|
||||
import { getMainWindowSize } from './helpers';
|
||||
|
||||
export default function registerIpcMainActionListeners(main: Main) {
|
||||
ipcMain.handle(IPC_ACTIONS.TOGGLE_MAXIMIZE_CURRENT_WINDOW, (event) => {
|
||||
const maximizing = main.mainWindow!.isMaximized();
|
||||
if (maximizing) {
|
||||
main.mainWindow!.maximize();
|
||||
} else {
|
||||
main.mainWindow!.unmaximize();
|
||||
}
|
||||
return maximizing;
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_OPEN_FILEPATH, async (event, options) => {
|
||||
return await dialog.showOpenDialog(main.mainWindow!, options);
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_SAVE_FILEPATH, async (event, options) => {
|
||||
return await dialog.showSaveDialog(main.mainWindow!, options);
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_PRIMARY_DISPLAY_SIZE, (event) => {
|
||||
return getMainWindowSize();
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_DIALOG_RESPONSE, async (event, options) => {
|
||||
if (main.isDevelopment || main.isLinux) {
|
||||
Object.assign(options, { icon: main.icon });
|
||||
}
|
||||
|
||||
return await dialog.showMessageBox(main.mainWindow!, options);
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.SHOW_ERROR, async (event, { title, content }) => {
|
||||
return await dialog.showErrorBox(title, content);
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
IPC_ACTIONS.SAVE_HTML_AS_PDF,
|
||||
async (event, html, savePath) => {
|
||||
return await saveHtmlAsPdf(html, savePath);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.SAVE_DATA, async (event, data, savePath) => {
|
||||
return await fs.writeFile(savePath, data, { encoding: 'utf-8' });
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.SEND_ERROR, (event, bodyJson) => {
|
||||
sendError(bodyJson);
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.CHECK_FOR_UPDATES, (event, force) => {
|
||||
if (!main.isDevelopment && !main.checkedForUpdate) {
|
||||
autoUpdater.checkForUpdates();
|
||||
} else if (force) {
|
||||
autoUpdater.checkForUpdates();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_LANGUAGE_MAP, async (event, code) => {
|
||||
const obj = { languageMap: {}, success: true, message: '' };
|
||||
try {
|
||||
obj.languageMap = await getLanguageMap(code, main.isDevelopment);
|
||||
} catch (err) {
|
||||
obj.success = false;
|
||||
obj.message = (err as Error).message;
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_FILE, async (event, options) => {
|
||||
const response = {
|
||||
name: '',
|
||||
filePath: '',
|
||||
success: false,
|
||||
data: Buffer.from('', 'utf-8'),
|
||||
canceled: false,
|
||||
};
|
||||
const { filePaths, canceled } = await dialog.showOpenDialog(
|
||||
main.mainWindow!,
|
||||
options
|
||||
);
|
||||
|
||||
response.filePath = filePaths?.[0];
|
||||
response.canceled = canceled;
|
||||
|
||||
if (!response.filePath) {
|
||||
return response;
|
||||
}
|
||||
|
||||
response.success = true;
|
||||
if (canceled) {
|
||||
return response;
|
||||
}
|
||||
|
||||
response.name = path.basename(response.filePath);
|
||||
response.data = await fs.readFile(response.filePath);
|
||||
return response;
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_CREDS, async (event) => {
|
||||
return await getUrlAndTokenString();
|
||||
});
|
||||
}
|
54
main/registerIpcMainMessageListeners.ts
Normal file
54
main/registerIpcMainMessageListeners.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { ipcMain, Menu, shell } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import { Main } from '../main';
|
||||
import { IPC_MESSAGES } from '../src/messages';
|
||||
|
||||
export default function registerIpcMainMessageListeners(main: Main) {
|
||||
ipcMain.on(IPC_MESSAGES.OPEN_MENU, (event) => {
|
||||
if (event.sender === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const menu = Menu.getApplicationMenu();
|
||||
if (menu === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
menu.popup({ window: main.mainWindow! });
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.RELOAD_MAIN_WINDOW, () => {
|
||||
main.mainWindow!.reload();
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.RESIZE_MAIN_WINDOW, (event, size, resizable) => {
|
||||
const [width, height] = size;
|
||||
if (!width || !height) return;
|
||||
main.mainWindow!.setSize(width, height);
|
||||
main.mainWindow!.setResizable(resizable);
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.CLOSE_CURRENT_WINDOW, (event) => {
|
||||
main.mainWindow!.close();
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.MINIMIZE_CURRENT_WINDOW, (event) => {
|
||||
main.mainWindow!.minimize();
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.OPEN_EXTERNAL, (event, link) => {
|
||||
shell.openExternal(link);
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.SHOW_ITEM_IN_FOLDER, (event, filePath) => {
|
||||
return shell.showItemInFolder(filePath);
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.DOWNLOAD_UPDATE, (event) => {
|
||||
autoUpdater.downloadUpdate();
|
||||
});
|
||||
|
||||
ipcMain.on(IPC_MESSAGES.INSTALL_UPDATE, (event) => {
|
||||
autoUpdater.quitAndInstall(true, true);
|
||||
});
|
||||
}
|
18
main/registerProcessListeners.ts
Normal file
18
main/registerProcessListeners.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { app } from 'electron';
|
||||
import { Main } from '../main';
|
||||
|
||||
export default function registerProcessListeners(main: Main) {
|
||||
if (main.isDevelopment) {
|
||||
if (process.platform === 'win32') {
|
||||
process.on('message', (data) => {
|
||||
if (data === 'graceful-exit') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
process.on('SIGTERM', () => {
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
"postuninstall": "electron-builder install-app-deps",
|
||||
"script:translate": "node scripts/generateTranslations.js"
|
||||
},
|
||||
"main": "background.js",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.10.2",
|
||||
"core-js": "^3.19.0",
|
||||
@ -35,6 +34,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/eslint-parser": "^7.16.0",
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@typescript-eslint/eslint-plugin": "^4.15.1",
|
||||
"@typescript-eslint/parser": "^4.15.1",
|
||||
@ -69,11 +69,11 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"engines": {
|
||||
"node": ">=16.13.1 <17",
|
||||
"yarn": "1.22.17"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"gitHooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"target": "es2018",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
|
@ -5,6 +5,7 @@ module.exports = {
|
||||
pluginOptions: {
|
||||
electronBuilder: {
|
||||
nodeIntegration: true,
|
||||
mainProcessFile: 'main.ts',
|
||||
disableMainProcessTypescript: false,
|
||||
mainProcessTypeChecking: true,
|
||||
chainWebpackRendererProcess: (config) => {
|
||||
|
@ -1221,6 +1221,11 @@
|
||||
dependencies:
|
||||
"@types/ms" "*"
|
||||
|
||||
"@types/electron-devtools-installer@^2.2.0":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/electron-devtools-installer/-/electron-devtools-installer-2.2.1.tgz#27cd1e0a612ef070d980555ae32db5898649e813"
|
||||
integrity sha512-V/gyryjHZi27/VeU5JtO89rqqq7w7d+Is0VYNLseARvR6ad7lXi8UCIJI9NraqNmd1NoGYedB1+tm5Q8UySF8A==
|
||||
|
||||
"@types/eslint-scope@^3.7.0":
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.2.tgz#11e96a868c67acf65bf6f11d10bb89ea71d5e473"
|
||||
|
Loading…
Reference in New Issue
Block a user