mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 10:41:02 -08:00
feat: Window And Preferences wired
This commit is contained in:
parent
33b38f6314
commit
3c10dc0f6f
32 changed files with 413 additions and 467 deletions
5
package-lock.json
generated
5
package-lock.json
generated
|
|
@ -14413,6 +14413,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.5.tgz",
|
||||||
"integrity": "sha512-60QsfPz8NAU/GZqXu8hJ+BhNf/C/c+Hp0eDc6XMIJTxBiP36AQyyQKpBkOVTLWBFDQWYVHpbbEuIsHu9dLuJDA=="
|
"integrity": "sha512-60QsfPz8NAU/GZqXu8hJ+BhNf/C/c+Hp0eDc6XMIJTxBiP36AQyyQKpBkOVTLWBFDQWYVHpbbEuIsHu9dLuJDA=="
|
||||||
},
|
},
|
||||||
|
"inversify-inject-decorators": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/inversify-inject-decorators/-/inversify-inject-decorators-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-/seBlVp5bXrLQS3DpKEmlgeZL6C7Tf/QITd+IMQrbBBGuCbxb7k3hRAWu9XSreNpFzLgSboz3sClLSEmGwHphw=="
|
||||||
|
},
|
||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||||
|
|
|
||||||
15
package.json
15
package.json
|
|
@ -53,20 +53,12 @@
|
||||||
"config": "./webpack.renderer.config.js",
|
"config": "./webpack.renderer.config.js",
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
{
|
{
|
||||||
"html": "./src/index.html",
|
"html": "./src/renderer.html",
|
||||||
"js": "./src/index.tsx",
|
"js": "./src/renderer.tsx",
|
||||||
"preload": {
|
"preload": {
|
||||||
"js": "./src/services/preload/main.ts"
|
"js": "./src/services/preload/index.ts"
|
||||||
},
|
},
|
||||||
"name": "main_window"
|
"name": "main_window"
|
||||||
},
|
|
||||||
{
|
|
||||||
"html": "./src/index.html",
|
|
||||||
"js": "./src/constants/hunspell-languages.ts",
|
|
||||||
"preload": {
|
|
||||||
"js": "./src/services/preload/view.ts"
|
|
||||||
},
|
|
||||||
"name": "web_view"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -92,6 +84,7 @@
|
||||||
"i18next-electron-fs-backend": "^1.3.5",
|
"i18next-electron-fs-backend": "^1.3.5",
|
||||||
"i18next-fs-backend": "^1.0.7",
|
"i18next-fs-backend": "^1.0.7",
|
||||||
"inversify": "^5.0.5",
|
"inversify": "^5.0.5",
|
||||||
|
"inversify-inject-decorators": "^3.1.0",
|
||||||
"is-url": "1.2.4",
|
"is-url": "1.2.4",
|
||||||
"jimp": "0.16.1",
|
"jimp": "0.16.1",
|
||||||
"lodash": "4.17.20",
|
"lodash": "4.17.20",
|
||||||
|
|
|
||||||
352
src/main.ts
Executable file
352
src/main.ts
Executable file
|
|
@ -0,0 +1,352 @@
|
||||||
|
import 'reflect-metadata';
|
||||||
|
import { ipcMain, nativeTheme, protocol, session, powerMonitor, app } from 'electron';
|
||||||
|
import isDev from 'electron-is-dev';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { delay } from 'bluebird';
|
||||||
|
import settings from 'electron-settings';
|
||||||
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
|
||||||
|
import loadListeners from './services/listeners';
|
||||||
|
import { container } from './services/container';
|
||||||
|
import * as openUrlWithWindow from './services/windows/open-url-with';
|
||||||
|
|
||||||
|
import createMenu from './services/libs/create-menu';
|
||||||
|
import extractHostname from './services/libs/extract-hostname';
|
||||||
|
import sendToAllWindows from './services/libs/send-to-all-windows';
|
||||||
|
import { stopWatchAllWiki } from './services/libs/wiki/watch-wiki';
|
||||||
|
import { stopAllWiki } from './services/libs/wiki/wiki-worker-mamager';
|
||||||
|
import { addView, reloadViewsDarkReader } from './services/libs/views';
|
||||||
|
import { getWorkspaces, setWorkspace } from './services/libs/workspaces';
|
||||||
|
import { logger } from './services/libs/log';
|
||||||
|
import { commitAndSync } from './services/libs/git';
|
||||||
|
import { clearMainBindings } from './services/libs/i18next-electron-fs-backend';
|
||||||
|
|
||||||
|
import MAILTO_URLS from './services/constants/mailto-urls';
|
||||||
|
|
||||||
|
import './services/libs/updater';
|
||||||
|
|
||||||
|
import serviceIdentifier from '@/services/serviceIdentifier';
|
||||||
|
import { Window } from '@/services/windows';
|
||||||
|
import { WindowNames } from '@/services/windows/WindowProperties';
|
||||||
|
import { Preference } from '@/services/preferences';
|
||||||
|
|
||||||
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
namespace NodeJS {
|
||||||
|
interface Global {
|
||||||
|
attachToMenubar: any;
|
||||||
|
sidebar: any;
|
||||||
|
titleBar: any;
|
||||||
|
navigationBar: any;
|
||||||
|
updaterObj: any;
|
||||||
|
MAILTO_URLS: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container.bind<Window>(serviceIdentifier.Window).to(Window);
|
||||||
|
container.bind<Preference>(serviceIdentifier.Preference).to(Preference);
|
||||||
|
|
||||||
|
const windows = container.resolve(Window);
|
||||||
|
const preferences = container.resolve(Preference);
|
||||||
|
app.on('second-instance', () => {
|
||||||
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
if (mainWindow !== undefined) {
|
||||||
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!gotTheLock) {
|
||||||
|
logger.info('Quitting dut to we only allow one instance to run.');
|
||||||
|
console.info('Quitting dut to we only allow one instance to run.');
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
// make sure "Settings" file exists
|
||||||
|
// if not, ignore this chunk of code
|
||||||
|
// as using electron-settings before app.on('ready') and "Settings" is created
|
||||||
|
// would return error
|
||||||
|
// https://github.com/nathanbuchar/electron-settings/issues/111
|
||||||
|
if (fs.existsSync(settings.file())) {
|
||||||
|
const useHardwareAcceleration = preferences.get('useHardwareAcceleration');
|
||||||
|
if (!useHardwareAcceleration) {
|
||||||
|
app.disableHardwareAcceleration();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ignoreCertificateErrors = preferences.get('ignoreCertificateErrors');
|
||||||
|
if (ignoreCertificateErrors) {
|
||||||
|
// https://www.electronjs.org/docs/api/command-line-switches
|
||||||
|
app.commandLine.appendSwitch('ignore-certificate-errors');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let commonInitFinished = false;
|
||||||
|
/** mock app.whenReady */
|
||||||
|
const customCommonInitFinishedEvent = 'common-init-finished';
|
||||||
|
ipcMain.once(customCommonInitFinishedEvent, () => {
|
||||||
|
commonInitFinished = true;
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Make sure some logic only run after window and services are truly ready
|
||||||
|
*/
|
||||||
|
const whenCommonInitFinished = async (): Promise<void> => {
|
||||||
|
if (commonInitFinished) return await Promise.resolve();
|
||||||
|
return await new Promise((resolve) => {
|
||||||
|
ipcMain.once(customCommonInitFinishedEvent, () => {
|
||||||
|
commonInitFinished = true;
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol.registerSchemesAsPrivileged([
|
||||||
|
{ scheme: 'http', privileges: { standard: true } },
|
||||||
|
{ scheme: 'https', privileges: { standard: true } },
|
||||||
|
{ scheme: 'mailto', privileges: { standard: true } },
|
||||||
|
]);
|
||||||
|
|
||||||
|
loadListeners();
|
||||||
|
|
||||||
|
const commonInit = async (): Promise<void> => {
|
||||||
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
|
return await app
|
||||||
|
.whenReady()
|
||||||
|
.then(
|
||||||
|
() =>
|
||||||
|
isDev &&
|
||||||
|
protocol.registerFileProtocol('file', (request, callback) => {
|
||||||
|
// TODO: this might be useless after use electron-forge, this is for loading html file after bundle, forge handle this now
|
||||||
|
const pathname = decodeURIComponent(request.url.replace('file:///', ''));
|
||||||
|
callback(pathname);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.then(async () => await windows.open(WindowNames.main))
|
||||||
|
.then(async () => {
|
||||||
|
const { hibernateUnusedWorkspacesAtLaunch, proxyBypassRules, proxyPacScript, proxyRules, proxyType, themeSource } = preferences.getPreferences();
|
||||||
|
|
||||||
|
// configure proxy for default session
|
||||||
|
if (proxyType === 'rules') {
|
||||||
|
await session.defaultSession.setProxy({
|
||||||
|
proxyRules,
|
||||||
|
proxyBypassRules,
|
||||||
|
});
|
||||||
|
} else if (proxyType === 'pacScript') {
|
||||||
|
await session.defaultSession.setProxy({
|
||||||
|
// FIXME: 'proxyPacScript' does not exist in type 'Config'
|
||||||
|
// proxyPacScript,
|
||||||
|
proxyBypassRules,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeTheme.themeSource = themeSource;
|
||||||
|
|
||||||
|
createMenu();
|
||||||
|
|
||||||
|
nativeTheme.addListener('updated', () => {
|
||||||
|
sendToAllWindows('native-theme-updated');
|
||||||
|
reloadViewsDarkReader();
|
||||||
|
});
|
||||||
|
|
||||||
|
const workspaceObjects = getWorkspaces();
|
||||||
|
|
||||||
|
Object.keys(workspaceObjects).forEach(
|
||||||
|
async (id: string): Promise<void> => {
|
||||||
|
const workspace = workspaceObjects[id];
|
||||||
|
if ((hibernateUnusedWorkspacesAtLaunch || workspace.hibernateWhenUnused) && !workspace.active) {
|
||||||
|
if (!workspace.hibernated) {
|
||||||
|
setWorkspace(workspace.id, { hibernated: true });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
await addView(mainWindow, workspace);
|
||||||
|
try {
|
||||||
|
const userInfo = preferences.get('github-user-info');
|
||||||
|
const { name: wikiPath, gitUrl: githubRepoUrl, isSubWiki } = workspace;
|
||||||
|
// wait for main wiki's watch-fs plugin to be fully initialized
|
||||||
|
// and also wait for wiki BrowserView to be able to receive command
|
||||||
|
// eslint-disable-next-line global-require
|
||||||
|
const { getWorkspaceMeta } = require('./libs/workspace-metas');
|
||||||
|
let meta = getWorkspaceMeta(id);
|
||||||
|
if (!isSubWiki) {
|
||||||
|
while (!meta.didFailLoad && !meta.isLoading) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await delay(500);
|
||||||
|
meta = getWorkspaceMeta(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isSubWiki && !meta.didFailLoad) {
|
||||||
|
await commitAndSync(wikiPath, githubRepoUrl, userInfo);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
logger.warning(`Can't sync at wikiStartup()`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.emit('request-update-pause-notifications-info');
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Fix webview is not resized automatically
|
||||||
|
// when window is maximized on Linux
|
||||||
|
// https://github.com/atomery/webcatalog/issues/561
|
||||||
|
|
||||||
|
// run it here not in mainWindow.createAsync()
|
||||||
|
// because if the `mainWindow` is maximized or minimized
|
||||||
|
// before the workspaces's BrowserView fully loaded
|
||||||
|
// error will occur
|
||||||
|
// see https://github.com/atomery/webcatalog/issues/637
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
if (mainWindow !== undefined) {
|
||||||
|
const handleMaximize = (): void => {
|
||||||
|
// getContentSize is not updated immediately
|
||||||
|
// try once after 0.2s (for fast computer), another one after 1s (to be sure)
|
||||||
|
setTimeout(() => {
|
||||||
|
ipcMain.emit('request-realign-active-workspace');
|
||||||
|
}, 200);
|
||||||
|
setTimeout(() => {
|
||||||
|
ipcMain.emit('request-realign-active-workspace');
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
mainWindow.on('maximize', handleMaximize);
|
||||||
|
mainWindow.on('unmaximize', handleMaximize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
|
.then(() => {
|
||||||
|
// trigger whenTrulyReady
|
||||||
|
ipcMain.emit(customCommonInitFinishedEvent);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
app.on('ready', () => {
|
||||||
|
const { allowPrerelease, attachToMenubar, sidebar, titleBar, navigationBar } = preferences.getPreferences();
|
||||||
|
// TODO: use IPC to get these config
|
||||||
|
global.attachToMenubar = attachToMenubar;
|
||||||
|
global.sidebar = sidebar;
|
||||||
|
global.titleBar = titleBar;
|
||||||
|
global.navigationBar = navigationBar;
|
||||||
|
|
||||||
|
global.MAILTO_URLS = MAILTO_URLS;
|
||||||
|
|
||||||
|
autoUpdater.allowPrerelease = allowPrerelease;
|
||||||
|
autoUpdater.logger = logger;
|
||||||
|
whenCommonInitFinished()
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
|
.then(() => {
|
||||||
|
ipcMain.emit('request-check-for-updates', undefined, true);
|
||||||
|
})
|
||||||
|
.catch((error) => console.error(error));
|
||||||
|
|
||||||
|
powerMonitor.on('shutdown', () => {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
void commonInit();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
if (mainWindow === undefined) {
|
||||||
|
void commonInit();
|
||||||
|
} else {
|
||||||
|
mainWindow.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on(
|
||||||
|
'open-url',
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
async (event, url): Promise<void> => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
await whenCommonInitFinished();
|
||||||
|
// focus on window
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
if (mainWindow === undefined) {
|
||||||
|
await commonInit();
|
||||||
|
} else {
|
||||||
|
mainWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaces: any[] = Object.values(getWorkspaces());
|
||||||
|
|
||||||
|
if (workspaces.length === 0) return;
|
||||||
|
|
||||||
|
// handle mailto:
|
||||||
|
if (url.startsWith('mailto:')) {
|
||||||
|
const mailtoWorkspaces: any[] = workspaces.filter((workspace: any) => {
|
||||||
|
const hostName = extractHostname(workspace.homeUrl);
|
||||||
|
return hostName !== undefined && hostName in MAILTO_URLS;
|
||||||
|
});
|
||||||
|
|
||||||
|
// pick automatically if there's only one choice
|
||||||
|
if (mailtoWorkspaces.length === 0) {
|
||||||
|
ipcMain.emit('request-show-message-box', undefined, 'None of your workspaces supports composing email messages.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mailtoWorkspaces.length === 1) {
|
||||||
|
const hostName = extractHostname(mailtoWorkspaces[0].homeUrl);
|
||||||
|
if (hostName !== undefined) {
|
||||||
|
const mailtoUrl = MAILTO_URLS[hostName];
|
||||||
|
const u = mailtoUrl.replace('%s', url);
|
||||||
|
ipcMain.emit('request-load-url', undefined, u, mailtoWorkspaces[0].id);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return openUrlWithWindow.show(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle https/http
|
||||||
|
// pick automically if there's only one choice
|
||||||
|
if (workspaces.length === 1) {
|
||||||
|
ipcMain.emit('request-load-url', undefined, url, workspaces[0].id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return openUrlWithWindow.show(url);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
app.on(
|
||||||
|
'before-quit',
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
async (): Promise<void> => {
|
||||||
|
logger.info('Quitting worker threads and watcher.');
|
||||||
|
await Promise.all([stopAllWiki(), stopWatchAllWiki()]);
|
||||||
|
logger.info('Worker threads and watchers all terminated.');
|
||||||
|
logger.info('Quitting I18N server.');
|
||||||
|
clearMainBindings(ipcMain);
|
||||||
|
logger.info('Quitted I18N server.');
|
||||||
|
// https://github.com/atom/electron/issues/444#issuecomment-76492576
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
const mainWindow = windows.get(WindowNames.main);
|
||||||
|
if (mainWindow !== undefined) {
|
||||||
|
logger.info('App force quit on MacOS');
|
||||||
|
// FIXME: set custom property
|
||||||
|
// @ts-expect-error don't set custom property to window
|
||||||
|
mainWindow.forceClose = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.exit(0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
app.on('quit', () => {
|
||||||
|
logger.info('App quit');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -28,10 +28,9 @@ const rawMailtoUrls = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const MAILTO_URLS = {};
|
const MAILTO_URLS: Record<string, string> = {};
|
||||||
rawMailtoUrls.forEach((item) => {
|
rawMailtoUrls.forEach((item) => {
|
||||||
item.hostnames.forEach((hostname) => {
|
item.hostnames.forEach((hostname) => {
|
||||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
||||||
MAILTO_URLS[hostname] = item.mailtoUrl;
|
MAILTO_URLS[hostname] = item.mailtoUrl;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
2
src/services/container.ts
Normal file
2
src/services/container.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
import { Container } from 'inversify';
|
||||||
|
export const container = new Container();
|
||||||
|
|
@ -1,316 +0,0 @@
|
||||||
import { ipcMain, nativeTheme, protocol, session, powerMonitor, app } from 'electron';
|
|
||||||
import isDev from 'electron-is-dev';
|
|
||||||
import fs from 'fs';
|
|
||||||
// @ts-expect-error ts-migrate(2529) FIXME: Duplicate identifier 'Promise'. Compiler reserves ... Remove this comment to see the full error message
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
import settings from 'electron-settings';
|
|
||||||
import { autoUpdater } from 'electron-updater';
|
|
||||||
|
|
||||||
import loadListeners from './listeners';
|
|
||||||
|
|
||||||
import * as mainWindow from './windows/main';
|
|
||||||
import * as openUrlWithWindow from './windows/open-url-with';
|
|
||||||
|
|
||||||
import createMenu from './libs/create-menu';
|
|
||||||
import extractHostname from './libs/extract-hostname';
|
|
||||||
import sendToAllWindows from './libs/send-to-all-windows';
|
|
||||||
import { stopWatchAllWiki } from './libs/wiki/watch-wiki';
|
|
||||||
import { stopAllWiki } from './libs/wiki/wiki-worker-mamager';
|
|
||||||
import { addView, reloadViewsDarkReader } from './libs/views';
|
|
||||||
import { getPreference, getPreferences } from './libs/preferences';
|
|
||||||
import { getWorkspaces, setWorkspace } from './libs/workspaces';
|
|
||||||
import { logger } from './libs/log';
|
|
||||||
import { commitAndSync } from './libs/git';
|
|
||||||
import { clearMainBindings } from './libs/i18next-electron-fs-backend';
|
|
||||||
|
|
||||||
import MAILTO_URLS from './constants/mailto-urls';
|
|
||||||
|
|
||||||
import './libs/updater';
|
|
||||||
|
|
||||||
const gotTheLock = app.requestSingleInstanceLock();
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
||||||
namespace NodeJS {
|
|
||||||
interface Global {
|
|
||||||
attachToMenubar: any;
|
|
||||||
sidebar: any;
|
|
||||||
titleBar: any;
|
|
||||||
navigationBar: any;
|
|
||||||
updaterObj: any;
|
|
||||||
MAILTO_URLS: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.on('second-instance', () => {
|
|
||||||
// Someone tried to run a second instance, we should focus our window.
|
|
||||||
const win = mainWindow.get();
|
|
||||||
if (win !== undefined) {
|
|
||||||
if (win.isMinimized()) win.restore();
|
|
||||||
win.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!gotTheLock) {
|
|
||||||
logger.info('Quitting dut to we only allow one instance to run.');
|
|
||||||
console.info('Quitting dut to we only allow one instance to run.');
|
|
||||||
app.quit();
|
|
||||||
} else {
|
|
||||||
// make sure "Settings" file exists
|
|
||||||
// if not, ignore this chunk of code
|
|
||||||
// as using electron-settings before app.on('ready') and "Settings" is created
|
|
||||||
// would return error
|
|
||||||
// https://github.com/nathanbuchar/electron-settings/issues/111
|
|
||||||
if (fs.existsSync(settings.file())) {
|
|
||||||
const useHardwareAcceleration = getPreference('useHardwareAcceleration');
|
|
||||||
if (!useHardwareAcceleration) {
|
|
||||||
app.disableHardwareAcceleration();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignoreCertificateErrors = getPreference('ignoreCertificateErrors');
|
|
||||||
if (ignoreCertificateErrors) {
|
|
||||||
// https://www.electronjs.org/docs/api/command-line-switches
|
|
||||||
app.commandLine.appendSwitch('ignore-certificate-errors');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mock app.whenReady
|
|
||||||
let trulyReady = false;
|
|
||||||
ipcMain.once('truly-ready', () => {
|
|
||||||
trulyReady = true;
|
|
||||||
});
|
|
||||||
const whenTrulyReady = () => {
|
|
||||||
if (trulyReady) return Promise.resolve();
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
ipcMain.once('truly-ready', () => {
|
|
||||||
trulyReady = true;
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
protocol.registerSchemesAsPrivileged([
|
|
||||||
{ scheme: 'http', privileges: { standard: true } },
|
|
||||||
{ scheme: 'https', privileges: { standard: true } },
|
|
||||||
{ scheme: 'mailto', privileges: { standard: true } },
|
|
||||||
]);
|
|
||||||
|
|
||||||
loadListeners();
|
|
||||||
|
|
||||||
const commonInit = async (): Promise<void> => {
|
|
||||||
// eslint-disable-next-line promise/catch-or-return
|
|
||||||
return await app
|
|
||||||
.whenReady()
|
|
||||||
.then(
|
|
||||||
() =>
|
|
||||||
isDev &&
|
|
||||||
protocol.registerFileProtocol('file', (request, callback) => {
|
|
||||||
const pathname = decodeURIComponent(request.url.replace('file:///', ''));
|
|
||||||
callback(pathname);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.then(async () => await mainWindow.createAsync())
|
|
||||||
.then(() => {
|
|
||||||
const { hibernateUnusedWorkspacesAtLaunch, proxyBypassRules, proxyPacScript, proxyRules, proxyType, themeSource } = getPreferences();
|
|
||||||
|
|
||||||
// configure proxy for default session
|
|
||||||
if (proxyType === 'rules') {
|
|
||||||
session.defaultSession.setProxy({
|
|
||||||
proxyRules,
|
|
||||||
proxyBypassRules,
|
|
||||||
});
|
|
||||||
} else if (proxyType === 'pacScript') {
|
|
||||||
session.defaultSession.setProxy(({
|
|
||||||
proxyPacScript,
|
|
||||||
proxyBypassRules,
|
|
||||||
} as any) as Electron.Config);
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeTheme.themeSource = themeSource;
|
|
||||||
|
|
||||||
createMenu();
|
|
||||||
|
|
||||||
nativeTheme.addListener('updated', () => {
|
|
||||||
sendToAllWindows('native-theme-updated');
|
|
||||||
reloadViewsDarkReader();
|
|
||||||
});
|
|
||||||
|
|
||||||
const workspaceObjects = getWorkspaces();
|
|
||||||
|
|
||||||
Object.keys(workspaceObjects).forEach(async (id) => {
|
|
||||||
const workspace = workspaceObjects[id];
|
|
||||||
if ((hibernateUnusedWorkspacesAtLaunch || workspace.hibernateWhenUnused) && !workspace.active) {
|
|
||||||
if (!workspace.hibernated) {
|
|
||||||
setWorkspace(workspace.id, { hibernated: true });
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await addView(mainWindow.get(), workspace);
|
|
||||||
try {
|
|
||||||
const userInfo = getPreference('github-user-info');
|
|
||||||
const { name: wikiPath, gitUrl: githubRepoUrl, isSubWiki } = workspace;
|
|
||||||
// wait for main wiki's watch-fs plugin to be fully initialized
|
|
||||||
// and also wait for wiki BrowserView to be able to receive command
|
|
||||||
// eslint-disable-next-line global-require
|
|
||||||
const { getWorkspaceMeta } = require('./libs/workspace-metas');
|
|
||||||
let meta = getWorkspaceMeta(id);
|
|
||||||
if (!isSubWiki) {
|
|
||||||
while (!meta.didFailLoad && !meta.isLoading) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await Promise.delay(500);
|
|
||||||
meta = getWorkspaceMeta(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isSubWiki && !meta.didFailLoad) {
|
|
||||||
await commitAndSync(wikiPath, githubRepoUrl, userInfo);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
logger.warning(`Can't sync at wikiStartup()`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.emit('request-update-pause-notifications-info');
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// Fix webview is not resized automatically
|
|
||||||
// when window is maximized on Linux
|
|
||||||
// https://github.com/atomery/webcatalog/issues/561
|
|
||||||
|
|
||||||
// run it here not in mainWindow.createAsync()
|
|
||||||
// because if the `mainWindow` is maximized or minimized
|
|
||||||
// before the workspaces's BrowserView fully loaded
|
|
||||||
// error will occur
|
|
||||||
// see https://github.com/atomery/webcatalog/issues/637
|
|
||||||
// eslint-disable-next-line promise/always-return
|
|
||||||
if (process.platform === 'linux') {
|
|
||||||
const win = mainWindow.get();
|
|
||||||
if (win) {
|
|
||||||
const handleMaximize = () => {
|
|
||||||
// getContentSize is not updated immediately
|
|
||||||
// try once after 0.2s (for fast computer), another one after 1s (to be sure)
|
|
||||||
setTimeout(() => {
|
|
||||||
ipcMain.emit('request-realign-active-workspace');
|
|
||||||
}, 200);
|
|
||||||
setTimeout(() => {
|
|
||||||
ipcMain.emit('request-realign-active-workspace');
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
win.on('maximize', handleMaximize);
|
|
||||||
win.on('unmaximize', handleMaximize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// eslint-disable-next-line promise/always-return
|
|
||||||
.then(() => {
|
|
||||||
// trigger whenTrulyReady
|
|
||||||
ipcMain.emit('truly-ready');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
app.on('ready', () => {
|
|
||||||
const { allowPrerelease, attachToMenubar, sidebar, titleBar, navigationBar } = getPreferences();
|
|
||||||
// TODO: use IPC to get these config
|
|
||||||
global.attachToMenubar = attachToMenubar;
|
|
||||||
global.sidebar = sidebar;
|
|
||||||
global.titleBar = titleBar;
|
|
||||||
global.navigationBar = navigationBar;
|
|
||||||
|
|
||||||
global.MAILTO_URLS = MAILTO_URLS;
|
|
||||||
|
|
||||||
autoUpdater.allowPrerelease = allowPrerelease;
|
|
||||||
autoUpdater.logger = logger;
|
|
||||||
whenTrulyReady()
|
|
||||||
// eslint-disable-next-line promise/always-return
|
|
||||||
.then(() => {
|
|
||||||
ipcMain.emit('request-check-for-updates', null, true);
|
|
||||||
})
|
|
||||||
.catch((error) => console.error(error));
|
|
||||||
|
|
||||||
powerMonitor.on('shutdown', () => {
|
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
commonInit();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
|
||||||
const win = mainWindow.get();
|
|
||||||
if (win == undefined) {
|
|
||||||
commonInit();
|
|
||||||
} else {
|
|
||||||
mainWindow.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('open-url', (e, url) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
whenTrulyReady().then(() => {
|
|
||||||
// focus on window
|
|
||||||
mainWindow.show();
|
|
||||||
|
|
||||||
const workspaces: any[] = Object.values(getWorkspaces());
|
|
||||||
|
|
||||||
if (workspaces.length === 0) return null;
|
|
||||||
|
|
||||||
// handle mailto:
|
|
||||||
if (url.startsWith('mailto:')) {
|
|
||||||
const mailtoWorkspaces: any[] = workspaces.filter((workspace: any) => extractHostname(workspace.homeUrl) in MAILTO_URLS);
|
|
||||||
|
|
||||||
// pick automically if there's only one choice
|
|
||||||
if (mailtoWorkspaces.length === 0) {
|
|
||||||
ipcMain.emit('request-show-message-box', null, 'None of your workspaces supports composing email messages.', 'error');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mailtoWorkspaces.length === 1) {
|
|
||||||
const mailtoUrl = (MAILTO_URLS as any)[extractHostname(mailtoWorkspaces[0].homeUrl)];
|
|
||||||
const u = mailtoUrl.replace('%s', url);
|
|
||||||
ipcMain.emit('request-load-url', null, u, mailtoWorkspaces[0].id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return openUrlWithWindow.show(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle https/http
|
|
||||||
// pick automically if there's only one choice
|
|
||||||
if (workspaces.length === 1) {
|
|
||||||
ipcMain.emit('request-load-url', null, url, workspaces[0].id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return openUrlWithWindow.show(url);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('before-quit', async (event) => {
|
|
||||||
logger.info('Quitting worker threads and watcher.');
|
|
||||||
await Promise.all([stopAllWiki(), stopWatchAllWiki()]);
|
|
||||||
logger.info('Worker threads and watchers all terminated.');
|
|
||||||
logger.info('Quitting I18N server.');
|
|
||||||
clearMainBindings(ipcMain);
|
|
||||||
logger.info('Quitted I18N server.');
|
|
||||||
// https://github.com/atom/electron/issues/444#issuecomment-76492576
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
const win = mainWindow.get();
|
|
||||||
if (win) {
|
|
||||||
logger.info('App force quit on MacOS');
|
|
||||||
// FIXME: set custom property
|
|
||||||
(win as any).forceClose = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.exit(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('quit', async () => {
|
|
||||||
logger.info('App quit');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
/* eslint-disable prefer-destructuring */
|
const extractHostname = (url: string): string | undefined => {
|
||||||
const extractHostname = (url: any) => {
|
|
||||||
try {
|
try {
|
||||||
let hostname = url.trim();
|
let hostname = url.trim();
|
||||||
|
|
||||||
|
|
@ -17,7 +16,7 @@ const extractHostname = (url: any) => {
|
||||||
|
|
||||||
return hostname;
|
return hostname;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
// return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ import { setWorkspaceMeta, getWorkspaceMetas, getWorkspaceMeta } from './workspa
|
||||||
import sendToAllWindows from './send-to-all-windows';
|
import sendToAllWindows from './send-to-all-windows';
|
||||||
import getViewBounds from './get-view-bounds';
|
import getViewBounds from './get-view-bounds';
|
||||||
|
|
||||||
declare const WEB_VIEW_WEBPACK_ENTRY: string;
|
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
|
||||||
declare const WEB_VIEW_PRELOAD_WEBPACK_ENTRY: string;
|
|
||||||
|
|
||||||
const views = {};
|
const views = {};
|
||||||
let shouldMuteAudio: any;
|
let shouldMuteAudio: any;
|
||||||
|
|
@ -134,7 +133,7 @@ export const addView = async (browserWindow: any, workspace: any) => {
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
enableRemoteModule: true,
|
enableRemoteModule: true,
|
||||||
session: ses,
|
session: ses,
|
||||||
preload: WEB_VIEW_PRELOAD_WEBPACK_ENTRY,
|
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
|
||||||
};
|
};
|
||||||
const view = new BrowserView({
|
const view = new BrowserView({
|
||||||
webPreferences: sharedWebPreferences,
|
webPreferences: sharedWebPreferences,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
import { injectable, inject } from 'inversify';
|
import { injectable, inject } from 'inversify';
|
||||||
import { app, App, nativeTheme, ipcMain, remote } from 'electron';
|
import getDecorators from 'inversify-inject-decorators';
|
||||||
|
import { app, App, remote } from 'electron';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import settings from 'electron-settings';
|
import settings from 'electron-settings';
|
||||||
|
|
||||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||||
import { Window } from '@/services/window';
|
import { Window } from '@/services/windows';
|
||||||
import { PreferenceChannel } from '@/services/channels';
|
import { PreferenceChannel } from '@/services/channels';
|
||||||
|
import { container } from '@/services/container';
|
||||||
|
|
||||||
|
const { lazyInject } = getDecorators(container);
|
||||||
|
|
||||||
/** get path, note that if use this from the preload script, app will be undefined, so have to use remote.app here */
|
/** get path, note that if use this from the preload script, app will be undefined, so have to use remote.app here */
|
||||||
const getDefaultDownloadsPath = (): string => {
|
const getDefaultDownloadsPath = (): string => {
|
||||||
|
|
@ -67,7 +71,7 @@ const defaultPreferences = {
|
||||||
spellcheckLanguages: ['en-US'],
|
spellcheckLanguages: ['en-US'],
|
||||||
swipeToNavigate: true,
|
swipeToNavigate: true,
|
||||||
syncDebounceInterval: 1000 * 60 * 30,
|
syncDebounceInterval: 1000 * 60 * 30,
|
||||||
themeSource: 'system',
|
themeSource: 'system' as 'system' | 'light' | 'dark',
|
||||||
titleBar: true,
|
titleBar: true,
|
||||||
unreadCountBadge: true,
|
unreadCountBadge: true,
|
||||||
useHardwareAcceleration: true,
|
useHardwareAcceleration: true,
|
||||||
|
|
@ -76,13 +80,12 @@ export type IPreferences = typeof defaultPreferences;
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class Preference {
|
export class Preference {
|
||||||
windowService: Window;
|
@lazyInject(serviceIdentifiers.Window) private readonly windowService!: Window;
|
||||||
|
|
||||||
cachedPreferences: IPreferences;
|
cachedPreferences: IPreferences;
|
||||||
readonly version = '2018.2';
|
readonly version = '2018.2';
|
||||||
|
|
||||||
constructor(@inject(serviceIdentifiers.Window) windowService: Window) {
|
constructor() {
|
||||||
this.windowService = windowService;
|
|
||||||
this.cachedPreferences = this.getInitPreferencesForCache();
|
this.cachedPreferences = this.getInitPreferencesForCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'about', iconPath: path.join(__dirname, '..', 'icon@5x.png') });
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
import './common/i18n';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/authing-postmessage';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'add-workspace' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'auth' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'code-injection' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'custom-user-agent' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'display-media' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'edit-workspace' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'go-to-url' });
|
|
||||||
|
|
@ -4,10 +4,15 @@ import './common/i18n';
|
||||||
import './common/require-nodejs';
|
import './common/require-nodejs';
|
||||||
import './common/simple-context-menu';
|
import './common/simple-context-menu';
|
||||||
import './common/authing-postmessage';
|
import './common/authing-postmessage';
|
||||||
|
import { WindowNames } from '@/services/windows/WindowProperties';
|
||||||
|
|
||||||
const windowName = process.argv[0];
|
const windowName = process.argv[0] as WindowNames;
|
||||||
|
|
||||||
// DEBUG: console
|
// DEBUG: console
|
||||||
console.log(`windowName`, windowName);
|
console.log(`windowName`, windowName);
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { windowName });
|
contextBridge.exposeInMainWorld('meta', { windowName });
|
||||||
|
|
||||||
|
if (windowName === WindowNames.view) {
|
||||||
|
void import('./view');
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'main' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'menubar' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'notifications' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'open-url-with' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
import './common/authing-postmessage';
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'preferences' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'proxy' });
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import './common/simple-context-menu';
|
|
||||||
import './common/require-nodejs';
|
|
||||||
import './common/i18n';
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('meta', { mode: 'spellcheck-languages' });
|
|
||||||
23
src/services/windows/WindowProperties.ts
Normal file
23
src/services/windows/WindowProperties.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
export enum WindowNames {
|
||||||
|
main = 'main',
|
||||||
|
view = 'view',
|
||||||
|
addWorkspace = 'addWorkspace',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width height of windows
|
||||||
|
*/
|
||||||
|
export const windowDimension: Record<WindowNames, { width?: number; height?: number }> = {
|
||||||
|
[WindowNames.main]: {
|
||||||
|
width: 1200,
|
||||||
|
height: 768,
|
||||||
|
},
|
||||||
|
[WindowNames.view]: {
|
||||||
|
width: undefined,
|
||||||
|
height: undefined,
|
||||||
|
},
|
||||||
|
[WindowNames.addWorkspace]: {
|
||||||
|
width: 600,
|
||||||
|
height: 800,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -5,28 +5,18 @@ import { injectable, inject } from 'inversify';
|
||||||
import serviceIdentifiers from '@services/serviceIdentifier';
|
import serviceIdentifiers from '@services/serviceIdentifier';
|
||||||
import { Preference } from '@services/preferences';
|
import { Preference } from '@services/preferences';
|
||||||
import { Channels } from '@/services/channels';
|
import { Channels } from '@/services/channels';
|
||||||
|
import { WindowNames, windowDimension } from '@/services/windows/WindowProperties';
|
||||||
export enum WindowNames {
|
|
||||||
main = 'main',
|
|
||||||
view = 'view',
|
|
||||||
addWorkspace = 'addWorkspace',
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
||||||
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
|
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class Window {
|
export class Window {
|
||||||
preferenceService: Preference;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
private windows = {} as Record<WindowNames, BrowserWindow | undefined>;
|
private windows = {} as Record<WindowNames, BrowserWindow | undefined>;
|
||||||
|
|
||||||
constructor(@inject(serviceIdentifiers.Preference) preferenceService: Preference) {
|
constructor(@inject(serviceIdentifiers.Preference) private readonly preferenceService: Preference) {}
|
||||||
this.preferenceService = preferenceService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get(name: WindowNames): BrowserWindow | undefined {
|
public get(name: WindowNames): BrowserWindow | undefined {
|
||||||
return this.windows[name];
|
return this.windows[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,8 +24,7 @@ export class Window {
|
||||||
const attachToMenubar: boolean = this.preferenceService.get('attachToMenubar');
|
const attachToMenubar: boolean = this.preferenceService.get('attachToMenubar');
|
||||||
|
|
||||||
const newWindow = new BrowserWindow({
|
const newWindow = new BrowserWindow({
|
||||||
width: 600,
|
...windowDimension[name],
|
||||||
height: 800,
|
|
||||||
resizable: false,
|
resizable: false,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
minimizable: false,
|
minimizable: false,
|
||||||
|
|
@ -7,8 +7,6 @@ import { REACT_PATH, isDev as isDevelopment } from '../constants/paths';
|
||||||
import { getPreference } from '../libs/preferences';
|
import { getPreference } from '../libs/preferences';
|
||||||
import formatBytes from '../libs/format-bytes';
|
import formatBytes from '../libs/format-bytes';
|
||||||
|
|
||||||
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
|
||||||
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
|
|
||||||
|
|
||||||
let win: BrowserWindow | undefined;
|
let win: BrowserWindow | undefined;
|
||||||
let menuBar: Menubar;
|
let menuBar: Menubar;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const { webpackAlias } = require('./webpack.alias');
|
const { webpackAlias } = require('./webpack.alias');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -5,7 +6,7 @@ module.exports = {
|
||||||
* This is the main entry point for your application, it's the first file
|
* This is the main entry point for your application, it's the first file
|
||||||
* that runs in the main process.
|
* that runs in the main process.
|
||||||
*/
|
*/
|
||||||
entry: './src/services/electron.ts',
|
entry: './src/main.ts',
|
||||||
// Put your normal webpack config below here
|
// Put your normal webpack config below here
|
||||||
module: {
|
module: {
|
||||||
rules: require('./webpack.rules'),
|
rules: require('./webpack.rules'),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue