Refactor work environment to use typescript and webpack #10
79
src/Application.ts
Normal file
79
src/Application.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import {app, Menu, shell, Tray} from "electron";
|
||||||
|
import Meta from "./Meta";
|
||||||
|
import Config from "./Config";
|
||||||
|
import Updater from "./Updater";
|
||||||
|
import MainWindow from "./windows/MainWindow";
|
||||||
|
|
||||||
|
export default class Application {
|
||||||
|
private readonly devMode: boolean;
|
||||||
|
private readonly config: Config;
|
||||||
|
private readonly updater: Updater;
|
||||||
|
private readonly mainWindow: MainWindow;
|
||||||
|
private tray?: Tray;
|
||||||
|
|
||||||
|
constructor(devMode: boolean) {
|
||||||
|
this.devMode = devMode;
|
||||||
|
this.config = new Config();
|
||||||
|
this.updater = new Updater(this.config);
|
||||||
|
this.mainWindow = new MainWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start(): Promise<void> {
|
||||||
|
console.log('Starting app');
|
||||||
|
|
||||||
|
this.setupSystemTray();
|
||||||
|
this.mainWindow.setup();
|
||||||
|
this.setupElectronTweaks();
|
||||||
|
|
||||||
|
// Check for updates
|
||||||
|
this.updater.checkAndPromptForUpdates(this.mainWindow.getWindow()).then(() => {
|
||||||
|
console.log('Update check successful.');
|
||||||
|
}).catch(console.error);
|
||||||
|
|
||||||
|
console.log('App started');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async stop(): Promise<void> {
|
||||||
|
this.mainWindow.teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConfig(): Config {
|
||||||
|
return this.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getUpdater(): Updater {
|
||||||
|
return this.updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isDevMode(): boolean {
|
||||||
|
return this.devMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupElectronTweaks() {
|
||||||
|
// Open external links in default OS browser
|
||||||
|
app.on('web-contents-created', (e, contents) => {
|
||||||
|
if (contents.getType() === 'webview') {
|
||||||
|
console.log('Setting external links to open in default OS browser');
|
||||||
|
contents.on('new-window', (e, url) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (url.startsWith('https://')) {
|
||||||
|
shell.openExternal(url).catch(console.error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupSystemTray() {
|
||||||
|
console.log('Loading system Tray');
|
||||||
|
this.tray = new Tray(Meta.ICON_PATH);
|
||||||
|
this.tray.setToolTip('Tabs');
|
||||||
|
this.tray.setContextMenu(Menu.buildFromTemplate([
|
||||||
|
{label: 'Tabs', enabled: false},
|
||||||
|
{label: 'Open Tabs', click: () => this.mainWindow.getWindow().show()},
|
||||||
|
{type: 'separator'},
|
||||||
|
{label: 'Quit', role: 'quit'}
|
||||||
|
]));
|
||||||
|
this.tray.on('click', () => this.mainWindow.toggle());
|
||||||
|
}
|
||||||
|
}
|
23
src/Meta.ts
23
src/Meta.ts
@ -1,7 +1,18 @@
|
|||||||
import Service from "./Service";
|
import Service from "./Service";
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
export default class Meta {
|
export default class Meta {
|
||||||
public static readonly title = 'Tabs';
|
public static readonly title = 'Tabs';
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
public static readonly RESOURCES_PATH = path.resolve(__dirname, '../resources');
|
||||||
|
public static readonly ICON_PATH = path.resolve(Meta.RESOURCES_PATH, 'logo.png');
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
public static readonly BRAND_ICONS = Meta.listIcons('brands');
|
||||||
|
public static readonly SOLID_ICONS = Meta.listIcons('solid');
|
||||||
|
|
||||||
private static devMode?: boolean;
|
private static devMode?: boolean;
|
||||||
|
|
||||||
public static isDevMode() {
|
public static isDevMode() {
|
||||||
@ -20,4 +31,16 @@ export default class Meta {
|
|||||||
}
|
}
|
||||||
return this.title + ' - ' + service.name + suffix;
|
return this.title + ' - ' + service.name + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static listIcons(set: string) {
|
||||||
|
console.log('Loading icon set', set);
|
||||||
|
const directory = path.resolve(Meta.RESOURCES_PATH, 'icons/' + set);
|
||||||
|
const icons: { name: string; faIcon: string }[] = [];
|
||||||
|
const dir = set === 'brands' ? 'fab' : 'fas';
|
||||||
|
fs.readdirSync(directory).forEach(i => icons.push({
|
||||||
|
name: i.split('.svg')[0],
|
||||||
|
faIcon: dir + ' fa-' + i.split('.svg')[0],
|
||||||
|
}));
|
||||||
|
return icons;
|
||||||
|
}
|
||||||
}
|
}
|
78
src/Window.ts
Normal file
78
src/Window.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import {BrowserWindow, BrowserWindowConstructorOptions, ipcMain, IpcMainEvent} from "electron";
|
||||||
|
import Application from "./Application";
|
||||||
|
import Config from "./Config";
|
||||||
|
|
||||||
|
export default abstract class Window {
|
||||||
|
private readonly listeners: { [channel: string]: ((event: IpcMainEvent, ...args: any[]) => void)[] } = {};
|
||||||
|
private readonly onCloseListeners: (() => void)[] = [];
|
||||||
|
|
||||||
|
protected readonly application: Application;
|
||||||
|
protected readonly config: Config;
|
||||||
|
protected readonly parent?: Window;
|
||||||
|
protected window?: BrowserWindow;
|
||||||
|
|
||||||
|
protected constructor(application: Application, parent?: Window) {
|
||||||
|
this.application = application;
|
||||||
|
this.parent = parent;
|
||||||
|
this.config = this.application.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public setup(options: BrowserWindowConstructorOptions) {
|
||||||
|
console.log('Creating window', this.constructor.name);
|
||||||
|
|
||||||
|
if (this.parent) {
|
||||||
|
options.parent = this.parent.getWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.window = new BrowserWindow(options);
|
||||||
|
this.window.on('close', () => {
|
||||||
|
this.teardown();
|
||||||
|
this.window = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public teardown() {
|
||||||
|
console.log('Tearing down window', this.constructor.name);
|
||||||
|
|
||||||
|
for (const listener of this.onCloseListeners) {
|
||||||
|
listener();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const channel in this.listeners) {
|
||||||
|
for (const listener of this.listeners[channel]) {
|
||||||
|
ipcMain.removeListener(channel, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.window = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onIpc(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this {
|
||||||
|
ipcMain.on(channel, listener);
|
||||||
|
if (!this.listeners[channel]) this.listeners[channel] = [];
|
||||||
|
this.listeners[channel].push(listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onClose(listener: () => void) {
|
||||||
|
this.onCloseListeners.push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggle() {
|
||||||
|
if (this.window) {
|
||||||
|
if (!this.window.isFocused()) {
|
||||||
|
console.log('Showing window', this.constructor.name);
|
||||||
|
this.window.show();
|
||||||
|
} else {
|
||||||
|
console.log('Hiding window', this.constructor.name);
|
||||||
|
this.window.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getWindow(): BrowserWindow {
|
||||||
|
if (!this.window) throw Error('Window not initialized.');
|
||||||
|
return this.window;
|
||||||
|
}
|
||||||
|
}
|
288
src/main.ts
288
src/main.ts
@ -1,296 +1,16 @@
|
|||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import SingleInstance from "single-instance";
|
import SingleInstance from "single-instance";
|
||||||
import {app, BrowserWindow, ipcMain, Menu, shell, Tray} from "electron";
|
import {app} from "electron";
|
||||||
|
|
||||||
import Meta from "./Meta";
|
import Meta from "./Meta";
|
||||||
import Config from "./Config";
|
import Application from "./Application";
|
||||||
import Service from "./Service";
|
|
||||||
import Updater from "./Updater";
|
|
||||||
import Event = Electron.Event;
|
|
||||||
|
|
||||||
const resourcesDir = path.resolve(__dirname, '../resources');
|
|
||||||
const iconPath = path.resolve(resourcesDir, 'logo.png');
|
|
||||||
|
|
||||||
const config = new Config();
|
|
||||||
const updater = new Updater(config);
|
|
||||||
|
|
||||||
const devMode = Meta.isDevMode();
|
|
||||||
|
|
||||||
// Load icons
|
|
||||||
const brandIcons = listIcons('brands');
|
|
||||||
const solidIcons = listIcons('solid');
|
|
||||||
|
|
||||||
let selectedService = 0;
|
|
||||||
|
|
||||||
let tray: Tray;
|
|
||||||
let window: BrowserWindow | null;
|
|
||||||
let serviceSettingsWindow: BrowserWindow | null, settingsWindow: BrowserWindow | null;
|
|
||||||
|
|
||||||
function toggleMainWindow() {
|
|
||||||
if (window != null) {
|
|
||||||
if (!window.isFocused()) {
|
|
||||||
console.log('Showing main window');
|
|
||||||
window.show();
|
|
||||||
} else {
|
|
||||||
console.log('Hiding main window');
|
|
||||||
window.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createWindow() {
|
|
||||||
// Check for updates
|
|
||||||
updater.checkAndPromptForUpdates(window!).then(() => {
|
|
||||||
console.log('Update check successful.');
|
|
||||||
}).catch(console.error);
|
|
||||||
|
|
||||||
// System tray
|
|
||||||
console.log('Loading system Tray');
|
|
||||||
tray = new Tray(iconPath);
|
|
||||||
tray.setToolTip('Tabs');
|
|
||||||
tray.setContextMenu(Menu.buildFromTemplate([
|
|
||||||
{label: 'Tabs', enabled: false},
|
|
||||||
{label: 'Open Tabs', click: () => window!.show()},
|
|
||||||
{type: 'separator'},
|
|
||||||
{label: 'Quit', role: 'quit'}
|
|
||||||
]));
|
|
||||||
tray.on('click', () => toggleMainWindow());
|
|
||||||
|
|
||||||
// Create the browser window.
|
|
||||||
console.log('Creating main window');
|
|
||||||
window = new BrowserWindow({
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true,
|
|
||||||
enableRemoteModule: true,
|
|
||||||
webviewTag: true,
|
|
||||||
},
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
icon: iconPath,
|
|
||||||
title: Meta.title,
|
|
||||||
});
|
|
||||||
window.maximize();
|
|
||||||
window.on('closed', () => {
|
|
||||||
window = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (devMode) {
|
|
||||||
window.webContents.openDevTools({
|
|
||||||
mode: 'right'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open external links in default OS browser
|
|
||||||
app.on('web-contents-created', (e, contents) => {
|
|
||||||
if (contents.getType() === 'webview') {
|
|
||||||
console.log('Setting external links to open in default OS browser');
|
|
||||||
contents.on('new-window', (e, url) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (url.startsWith('https://')) {
|
|
||||||
shell.openExternal(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sync data
|
|
||||||
window.webContents.on('dom-ready', sendData);
|
|
||||||
|
|
||||||
// Load navigation view
|
|
||||||
window.loadFile(path.resolve(resourcesDir, 'index.html'))
|
|
||||||
.catch(console.error);
|
|
||||||
|
|
||||||
// Load active service
|
|
||||||
ipcMain.on('setActiveService', (event, index) => {
|
|
||||||
setActiveService(index);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set a service's favicon
|
|
||||||
ipcMain.on('setServiceFavicon', (event, index, favicon) => {
|
|
||||||
console.log('Setting service', index, 'favicon', favicon);
|
|
||||||
config.services[index].favicon = favicon;
|
|
||||||
config.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open add service window
|
|
||||||
ipcMain.on('openServiceSettings', (e, serviceId) => {
|
|
||||||
if (!serviceSettingsWindow) {
|
|
||||||
console.log('Opening service settings', serviceId);
|
|
||||||
serviceSettingsWindow = new BrowserWindow({
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true,
|
|
||||||
enableRemoteModule: true,
|
|
||||||
webviewTag: true,
|
|
||||||
},
|
|
||||||
parent: window!,
|
|
||||||
modal: true,
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
height: 850,
|
|
||||||
});
|
|
||||||
serviceSettingsWindow.on('close', () => {
|
|
||||||
serviceSettingsWindow = null;
|
|
||||||
});
|
|
||||||
if (devMode) {
|
|
||||||
serviceSettingsWindow.webContents.openDevTools({
|
|
||||||
mode: 'right'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let syncListener: () => void;
|
|
||||||
ipcMain.on('sync-settings', syncListener = () => {
|
|
||||||
serviceSettingsWindow!.webContents.send('syncIcons', brandIcons, solidIcons);
|
|
||||||
serviceSettingsWindow!.webContents.send('loadService', serviceId, config.services[serviceId]);
|
|
||||||
});
|
|
||||||
serviceSettingsWindow.on('close', () => {
|
|
||||||
ipcMain.removeListener('sync-settings', syncListener);
|
|
||||||
});
|
|
||||||
serviceSettingsWindow.loadFile(path.resolve(resourcesDir, 'service-settings.html'))
|
|
||||||
.catch(console.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('saveService', (e, id, data) => {
|
|
||||||
console.log('Saving service', id, data);
|
|
||||||
const newService = new Service(data);
|
|
||||||
if (typeof id === 'number') {
|
|
||||||
config.services[id] = newService;
|
|
||||||
} else {
|
|
||||||
config.services.push(newService);
|
|
||||||
id = config.services.indexOf(newService);
|
|
||||||
}
|
|
||||||
config.save();
|
|
||||||
|
|
||||||
window!.webContents.send('updateService', id, newService);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('deleteService', (e, id) => {
|
|
||||||
console.log('Deleting service', id);
|
|
||||||
delete config.services[id];
|
|
||||||
config.save();
|
|
||||||
|
|
||||||
window!.webContents.send('deleteService', id);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('reorderService', (e, serviceId, targetId) => {
|
|
||||||
console.log('Reordering services', serviceId, targetId);
|
|
||||||
|
|
||||||
const oldServices = config.services;
|
|
||||||
config.services = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < targetId; i++) {
|
|
||||||
if (i !== serviceId) {
|
|
||||||
config.services.push(oldServices[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.services.push(oldServices[serviceId]);
|
|
||||||
for (let i = targetId; i < oldServices.length; i++) {
|
|
||||||
if (i !== serviceId) {
|
|
||||||
config.services.push(oldServices[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.reply('reorderService', serviceId, targetId);
|
|
||||||
config.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('updateServicePermissions', (e, serviceId, permissions) => {
|
|
||||||
config.services[serviceId].permissions = permissions;
|
|
||||||
config.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on('updateWindowTitle', (event, serviceId, viewTitle) => {
|
|
||||||
if (serviceId === null) {
|
|
||||||
window!.setTitle(Meta.title);
|
|
||||||
} else {
|
|
||||||
const service = config.services[serviceId];
|
|
||||||
window!.setTitle(Meta.getTitleForService(service, viewTitle));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open add service window
|
|
||||||
ipcMain.on('openSettings', (e) => {
|
|
||||||
if (!settingsWindow) {
|
|
||||||
console.log('Opening settings');
|
|
||||||
settingsWindow = new BrowserWindow({
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true,
|
|
||||||
enableRemoteModule: true,
|
|
||||||
webviewTag: true,
|
|
||||||
},
|
|
||||||
parent: window!,
|
|
||||||
modal: true,
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
height: 850,
|
|
||||||
});
|
|
||||||
settingsWindow.on('close', () => {
|
|
||||||
settingsWindow = null;
|
|
||||||
});
|
|
||||||
if (devMode) {
|
|
||||||
settingsWindow.webContents.openDevTools({
|
|
||||||
mode: 'right'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let syncListener: () => void;
|
|
||||||
ipcMain.on('syncSettings', syncListener = () => {
|
|
||||||
settingsWindow!.webContents.send('current-version', updater.getCurrentVersion());
|
|
||||||
settingsWindow!.webContents.send('config', config);
|
|
||||||
});
|
|
||||||
|
|
||||||
let checkForUpdatesListener: () => void;
|
|
||||||
ipcMain.on('checkForUpdates', checkForUpdatesListener = () => {
|
|
||||||
updater.checkForUpdates().then(updateInfo => {
|
|
||||||
settingsWindow!.webContents.send('updateStatus', typeof updateInfo === 'object', updateInfo);
|
|
||||||
}).catch(console.error);
|
|
||||||
});
|
|
||||||
|
|
||||||
let saveConfigListener: (e: Event, data: any) => void;
|
|
||||||
ipcMain.on('save-config', saveConfigListener = (e: Event, data: any) => {
|
|
||||||
config.update(data);
|
|
||||||
config.save();
|
|
||||||
sendData();
|
|
||||||
});
|
|
||||||
|
|
||||||
settingsWindow.on('close', () => {
|
|
||||||
ipcMain.removeListener('syncSettings', syncListener);
|
|
||||||
ipcMain.removeListener('checkForUpdates', checkForUpdatesListener);
|
|
||||||
ipcMain.removeListener('save-config', saveConfigListener);
|
|
||||||
});
|
|
||||||
settingsWindow.loadFile(path.resolve(resourcesDir, 'settings.html'))
|
|
||||||
.catch(console.error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('> App started');
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendData() {
|
|
||||||
console.log('Syncing data');
|
|
||||||
window!.webContents.send('data', Meta.title, brandIcons, solidIcons, selectedService, path.resolve(resourcesDir, 'empty.html'), config);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setActiveService(index: number) {
|
|
||||||
console.log('Selected service is now', index);
|
|
||||||
selectedService = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
function listIcons(set: string) {
|
|
||||||
console.log('Loading icon set', set);
|
|
||||||
const directory = path.resolve(resourcesDir, 'icons/' + set);
|
|
||||||
const icons: { name: string; faIcon: string }[] = [];
|
|
||||||
const dir = set === 'brands' ? 'fab' : 'fas';
|
|
||||||
fs.readdirSync(directory).forEach(i => icons.push({
|
|
||||||
name: i.split('.svg')[0],
|
|
||||||
faIcon: dir + ' fa-' + i.split('.svg')[0],
|
|
||||||
}));
|
|
||||||
return icons;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const application = new Application(Meta.isDevMode());
|
||||||
|
|
||||||
// Check if application is already running
|
// Check if application is already running
|
||||||
const lock = new SingleInstance('tabs-app');
|
const lock = new SingleInstance('tabs-app');
|
||||||
lock.lock().then(() => {
|
lock.lock().then(() => {
|
||||||
console.log('Starting app');
|
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
createWindow().catch(console.error);
|
application.start().catch(console.error);
|
||||||
});
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
149
src/windows/MainWindow.ts
Normal file
149
src/windows/MainWindow.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import path from "path";
|
||||||
|
import {ipcMain} from "electron";
|
||||||
|
import ServiceSettingsWindow from "./ServiceSettingsWindow";
|
||||||
|
import SettingsWindow from "./SettingsWindow";
|
||||||
|
import Application from "../Application";
|
||||||
|
import Meta from "../Meta";
|
||||||
|
import Window from "../Window";
|
||||||
|
|
||||||
|
export default class MainWindow extends Window {
|
||||||
|
private activeService: number = 0;
|
||||||
|
private serviceSettingsWindow?: ServiceSettingsWindow;
|
||||||
|
private settingsWindow?: SettingsWindow;
|
||||||
|
|
||||||
|
constructor(application: Application) {
|
||||||
|
super(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setup() {
|
||||||
|
super.setup({
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableRemoteModule: true,
|
||||||
|
webviewTag: true,
|
||||||
|
},
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
icon: Meta.ICON_PATH,
|
||||||
|
title: Meta.title,
|
||||||
|
});
|
||||||
|
|
||||||
|
const window = this.getWindow();
|
||||||
|
|
||||||
|
window.maximize();
|
||||||
|
|
||||||
|
if (this.application.isDevMode()) {
|
||||||
|
window.webContents.openDevTools({
|
||||||
|
mode: 'right'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync data
|
||||||
|
window.webContents.on('dom-ready', () => {
|
||||||
|
this.syncData();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load active service
|
||||||
|
this.onIpc('setActiveService', (event, index) => {
|
||||||
|
this.setActiveService(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set a service's favicon
|
||||||
|
this.onIpc('setServiceFavicon', (event, index, favicon) => {
|
||||||
|
console.log('Setting service', index, 'favicon', favicon);
|
||||||
|
this.config.services[index].favicon = favicon;
|
||||||
|
this.config.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reorder services
|
||||||
|
this.onIpc('reorderService', (event, serviceId, targetId) => {
|
||||||
|
console.log('Reordering services', serviceId, targetId);
|
||||||
|
|
||||||
|
const oldServices = this.config.services;
|
||||||
|
this.config.services = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < targetId; i++) {
|
||||||
|
if (i !== serviceId) {
|
||||||
|
this.config.services.push(oldServices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.config.services.push(oldServices[serviceId]);
|
||||||
|
for (let i = targetId; i < oldServices.length; i++) {
|
||||||
|
if (i !== serviceId) {
|
||||||
|
this.config.services.push(oldServices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event.reply('reorderService', serviceId, targetId);
|
||||||
|
this.config.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete service
|
||||||
|
this.onIpc('deleteService', (e, id) => {
|
||||||
|
console.log('Deleting service', id);
|
||||||
|
delete this.config.services[id];
|
||||||
|
this.config.save();
|
||||||
|
|
||||||
|
window.webContents.send('deleteService', id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update service permissions
|
||||||
|
ipcMain.on('updateServicePermissions', (e, serviceId, permissions) => {
|
||||||
|
this.config.services[serviceId].permissions = permissions;
|
||||||
|
this.config.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update window title
|
||||||
|
ipcMain.on('updateWindowTitle', (event, serviceId, viewTitle) => {
|
||||||
|
if (serviceId === null) {
|
||||||
|
window.setTitle(Meta.title);
|
||||||
|
} else {
|
||||||
|
const service = this.config.services[serviceId];
|
||||||
|
window.setTitle(Meta.getTitleForService(service, viewTitle));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open service settings window
|
||||||
|
ipcMain.on('openServiceSettings', (e, serviceId) => {
|
||||||
|
if (!this.serviceSettingsWindow) {
|
||||||
|
console.log('Opening service settings', serviceId);
|
||||||
|
this.serviceSettingsWindow = new ServiceSettingsWindow(this.application, this, serviceId);
|
||||||
|
this.serviceSettingsWindow.setup();
|
||||||
|
this.serviceSettingsWindow.onClose(() => {
|
||||||
|
this.serviceSettingsWindow = undefined;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open settings window
|
||||||
|
ipcMain.on('openSettings', () => {
|
||||||
|
if (!this.settingsWindow) {
|
||||||
|
console.log('Opening settings');
|
||||||
|
this.settingsWindow = new SettingsWindow(this.application, this);
|
||||||
|
this.settingsWindow.setup();
|
||||||
|
this.settingsWindow.onClose(() => {
|
||||||
|
this.settingsWindow = undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load navigation view
|
||||||
|
window.loadFile(path.resolve(Meta.RESOURCES_PATH, 'index.html'))
|
||||||
|
.catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public syncData() {
|
||||||
|
this.getWindow().webContents.send('data',
|
||||||
|
Meta.title,
|
||||||
|
Meta.BRAND_ICONS,
|
||||||
|
Meta.SOLID_ICONS,
|
||||||
|
this.activeService,
|
||||||
|
path.resolve(Meta.RESOURCES_PATH, 'empty.html'),
|
||||||
|
this.config
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setActiveService(index: number) {
|
||||||
|
console.log('Set active service', index);
|
||||||
|
this.activeService = index;
|
||||||
|
}
|
||||||
|
}
|
58
src/windows/ServiceSettingsWindow.ts
Normal file
58
src/windows/ServiceSettingsWindow.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import path from "path";
|
||||||
|
import Window from "../Window";
|
||||||
|
import Application from "../Application";
|
||||||
|
import Meta from "../Meta";
|
||||||
|
import Service from "../Service";
|
||||||
|
|
||||||
|
export default class ServiceSettingsWindow extends Window {
|
||||||
|
private readonly serviceId: number;
|
||||||
|
|
||||||
|
constructor(application: Application, parent: Window, serviceId: number) {
|
||||||
|
super(application, parent);
|
||||||
|
this.serviceId = serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setup() {
|
||||||
|
super.setup({
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableRemoteModule: true,
|
||||||
|
webviewTag: true,
|
||||||
|
},
|
||||||
|
modal: true,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
height: 850,
|
||||||
|
});
|
||||||
|
|
||||||
|
const window = this.getWindow();
|
||||||
|
|
||||||
|
if (this.application.isDevMode()) {
|
||||||
|
window.webContents.openDevTools({
|
||||||
|
mode: 'right'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onIpc('sync-settings', () => {
|
||||||
|
window.webContents.send('syncIcons', Meta.BRAND_ICONS, Meta.SOLID_ICONS);
|
||||||
|
window.webContents.send('loadService', this.serviceId, this.config.services[this.serviceId]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onIpc('saveService', (e, id, data) => {
|
||||||
|
console.log('Saving service', id, data);
|
||||||
|
const newService = new Service(data);
|
||||||
|
if (typeof id === 'number') {
|
||||||
|
this.config.services[id] = newService;
|
||||||
|
} else {
|
||||||
|
this.config.services.push(newService);
|
||||||
|
id = this.config.services.indexOf(newService);
|
||||||
|
}
|
||||||
|
this.config.save();
|
||||||
|
|
||||||
|
this.parent?.getWindow().webContents.send('updateService', id, newService);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.loadFile(path.resolve(Meta.RESOURCES_PATH, 'service-settings.html'))
|
||||||
|
.catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/windows/SettingsWindow.ts
Normal file
50
src/windows/SettingsWindow.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import {Event} from "electron";
|
||||||
|
import path from "path";
|
||||||
|
import Window from "../Window";
|
||||||
|
import MainWindow from "./MainWindow";
|
||||||
|
import Meta from "../Meta";
|
||||||
|
|
||||||
|
export default class SettingsWindow extends Window {
|
||||||
|
public setup() {
|
||||||
|
super.setup({
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
enableRemoteModule: true,
|
||||||
|
webviewTag: true,
|
||||||
|
},
|
||||||
|
modal: true,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
height: 850,
|
||||||
|
});
|
||||||
|
|
||||||
|
const window = this.getWindow();
|
||||||
|
|
||||||
|
if (this.application.isDevMode()) {
|
||||||
|
window.webContents.openDevTools({
|
||||||
|
mode: 'right'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onIpc('syncSettings', () => {
|
||||||
|
window.webContents.send('current-version', this.application.getUpdater().getCurrentVersion());
|
||||||
|
window.webContents.send('config', this.config);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onIpc('checkForUpdates', () => {
|
||||||
|
this.application.getUpdater().checkForUpdates().then(updateInfo => {
|
||||||
|
window.webContents.send('updateStatus', typeof updateInfo === 'object', updateInfo);
|
||||||
|
}).catch(console.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onIpc('save-config', (e: Event, data: any) => {
|
||||||
|
this.config.update(data);
|
||||||
|
this.config.save();
|
||||||
|
if (this.parent instanceof MainWindow) {
|
||||||
|
this.parent.syncData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.loadFile(path.resolve(Meta.RESOURCES_PATH, 'settings.html'))
|
||||||
|
.catch(console.error);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user