mirror of
https://github.com/anyproto/anytype-ts.git
synced 2025-06-08 05:57:02 +09:00
WindowManager
This commit is contained in:
parent
426adc96ff
commit
0c81b8c81c
7 changed files with 315 additions and 289 deletions
326
electron.js
326
electron.js
|
@ -1,5 +1,5 @@
|
|||
const electron = require('electron');
|
||||
const { app, BrowserWindow, ipcMain, shell, session, nativeImage, nativeTheme, dialog } = require('electron');
|
||||
const { app, BrowserWindow, ipcMain, shell, session, nativeTheme } = require('electron');
|
||||
const { is, fixPathForAsarUnpack } = require('electron-util');
|
||||
const { download } = require('electron-dl');
|
||||
const path = require('path');
|
||||
|
@ -8,7 +8,6 @@ const storage = require('electron-json-storage');
|
|||
const fs = require('fs');
|
||||
const readChunk = require('read-chunk');
|
||||
const fileType = require('file-type');
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
const port = process.env.SERVER_PORT;
|
||||
const keytar = require('keytar');
|
||||
const bindings = require('bindings');
|
||||
|
@ -17,17 +16,22 @@ const systemVersion = process.getSystemVersion();
|
|||
const protocol = 'anytype';
|
||||
const remote = require('@electron/remote/main');
|
||||
|
||||
const userPath = app.getPath('userData');
|
||||
const tmpPath = path.join(userPath, 'tmp');
|
||||
const binPath = fixPathForAsarUnpack(path.join(__dirname, 'dist', `anytypeHelper${is.windows ? '.exe' : ''}`));
|
||||
|
||||
const ConfigManager = require('./electron/js/config.js');
|
||||
const UpdateManager = require('./electron/js/updater.js');
|
||||
const MenuManager = require('./electron/js/menu.js');
|
||||
const WindowManager = require('./electron/js/window.js');
|
||||
const Server = require('./electron/js/server.js');
|
||||
const Util = require('./electron/js/util.js');
|
||||
|
||||
const MIN_WIDTH = 752;
|
||||
const MIN_HEIGHT = 480;
|
||||
const KEYTAR_SERVICE = 'Anytype';
|
||||
|
||||
app.removeAsDefaultProtocolClient(protocol);
|
||||
Util.setPath(path.join(__dirname));
|
||||
Util.setAppPath(path.join(__dirname));
|
||||
WindowManager.exit = exit;
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
|
@ -41,16 +45,11 @@ try { env = JSON.parse(fs.readFileSync(envPath)); } catch (e) {};
|
|||
|
||||
remote.initialize();
|
||||
|
||||
let windows = new Set();
|
||||
let env = {};
|
||||
let deeplinkingUrl = '';
|
||||
let userPath = app.getPath('userData');
|
||||
let tmpPath = path.join(userPath, 'tmp');
|
||||
let waitLibraryPromise;
|
||||
let useGRPC = !process.env.ANYTYPE_USE_ADDON && (env.USE_GRPC || process.env.ANYTYPE_USE_GRPC || is.windows || is.development);
|
||||
let server;
|
||||
let dataPath = [];
|
||||
let win = null;
|
||||
let mainWindow = null;
|
||||
let csp = [
|
||||
"default-src 'self' 'unsafe-eval'",
|
||||
"img-src 'self' http://*:* https://*:* data: blob: file://*",
|
||||
|
@ -72,10 +71,10 @@ if (app.isPackaged && !app.requestSingleInstanceLock()) {
|
|||
};
|
||||
|
||||
storage.setDataPath(userPath);
|
||||
Util.mkDir(tmpPath);
|
||||
|
||||
if (process.env.DATA_PATH) {
|
||||
try { fs.mkdirSync(process.env.DATA_PATH); } catch (e) {};
|
||||
|
||||
Util.mkDir(process.env.DATA_PATH);
|
||||
dataPath.push(process.env.DATA_PATH);
|
||||
} else {
|
||||
dataPath.push(userPath);
|
||||
|
@ -85,28 +84,17 @@ if (process.env.DATA_PATH) {
|
|||
dataPath.push('data');
|
||||
};
|
||||
|
||||
try { fs.mkdirSync(tmpPath); } catch (e) {};
|
||||
|
||||
if (useGRPC) {
|
||||
let binPath = fixPathForAsarUnpack(path.join(__dirname, 'dist', `anytypeHelper${is.windows ? '.exe' : ''}`));
|
||||
server = require('./electron/js/server.js');
|
||||
|
||||
if (process.env.ANYTYPE_USE_SIDE_SERVER) {
|
||||
// use the grpc server started from the outside
|
||||
server.setAddress(process.env.ANYTYPE_USE_SIDE_SERVER);
|
||||
waitLibraryPromise = Promise.resolve();
|
||||
} else {
|
||||
waitLibraryPromise = server.start(binPath, userPath);
|
||||
};
|
||||
} else {
|
||||
if (process.env.ANYTYPE_USE_SIDE_SERVER) {
|
||||
// use the grpc server started from the outside
|
||||
Server.setAddress(process.env.ANYTYPE_USE_SIDE_SERVER);
|
||||
waitLibraryPromise = Promise.resolve();
|
||||
} else {
|
||||
waitLibraryPromise = Server.start(binPath, userPath);
|
||||
};
|
||||
|
||||
function waitForLibraryAndCreateWindows () {
|
||||
waitLibraryPromise.then((res) => {
|
||||
if (server) {
|
||||
global.serverAddr = server.getAddress();
|
||||
};
|
||||
global.serverAddr = Server.getAddress();
|
||||
createMainWindow();
|
||||
}, (err) => {
|
||||
electron.dialog.showErrorBox('Error: failed to run server', err.toString());
|
||||
|
@ -115,170 +103,82 @@ function waitForLibraryAndCreateWindows () {
|
|||
|
||||
nativeTheme.on('updated', () => {
|
||||
MenuManager.updateTrayIcon();
|
||||
Util.send(win, 'native-theme', Util.isDarkTheme());
|
||||
Util.send(mainWindow, 'native-theme', Util.isDarkTheme());
|
||||
});
|
||||
|
||||
function createMainWindow () {
|
||||
const image = nativeImage.createFromPath(path.join(Util.imagePath(), 'icon512x512.png'));
|
||||
mainWindow = WindowManager.createMain({ withState: true });
|
||||
|
||||
let state = windowStateKeeper({
|
||||
defaultWidth: 800,
|
||||
defaultHeight: 600
|
||||
});
|
||||
|
||||
let param = {
|
||||
backgroundColor: Util.getBgColor(),
|
||||
show: false,
|
||||
x: state.x,
|
||||
y: state.y,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
minWidth: MIN_WIDTH,
|
||||
minHeight: MIN_HEIGHT,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
spellcheck: false
|
||||
},
|
||||
};
|
||||
|
||||
if (is.linux) {
|
||||
param.icon = image;
|
||||
} else {
|
||||
param.frame = false;
|
||||
param.titleBarStyle = 'hidden';
|
||||
};
|
||||
|
||||
if (is.macos) {
|
||||
app.dock.setIcon(image);
|
||||
param.icon = path.join(Util.imagePath(), 'icon.icns');
|
||||
param.trafficLightPosition = { x: 20, y: 18 };
|
||||
};
|
||||
|
||||
if (is.windows) {
|
||||
param.icon = path.join(Util.imagePath(), 'icon64x64.png');
|
||||
};
|
||||
|
||||
win = new BrowserWindow(param);
|
||||
remote.enable(win.webContents);
|
||||
|
||||
state.manage(win);
|
||||
|
||||
win.once('ready-to-show', () => {
|
||||
win.show();
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
|
||||
if (deeplinkingUrl) {
|
||||
Util.send(win, 'route', deeplinkingUrl.replace(`${protocol}://`, '/'));
|
||||
Util.send(mainWindow, 'route', Util.getRouteFromUrl(deeplinkingUrl));
|
||||
};
|
||||
});
|
||||
|
||||
win.on('close', (e) => {
|
||||
Util.log('info', 'close: ' + app.isQuiting);
|
||||
|
||||
if (app.isQuiting) {
|
||||
return;
|
||||
};
|
||||
|
||||
e.preventDefault();
|
||||
if (!is.linux) {
|
||||
if (win.isFullScreen()) {
|
||||
win.setFullScreen(false);
|
||||
win.once('leave-full-screen', () => { win.hide(); });
|
||||
} else {
|
||||
win.hide();
|
||||
};
|
||||
} else {
|
||||
exit(false);
|
||||
};
|
||||
return false;
|
||||
});
|
||||
|
||||
win.on('enter-full-screen', () => {
|
||||
Util.send(win, 'enter-full-screen');
|
||||
});
|
||||
|
||||
win.on('leave-full-screen', () => {
|
||||
Util.send(win, 'leave-full-screen');
|
||||
});
|
||||
|
||||
if (process.env.ELECTRON_DEV_EXTENSIONS) {
|
||||
BrowserWindow.addDevToolsExtension(
|
||||
path.join(os.homedir(), '/Library/Application Support/Google/Chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/4.6.0_0')
|
||||
);
|
||||
};
|
||||
|
||||
if (is.development) {
|
||||
win.loadURL('http://localhost:' + port);
|
||||
win.toggleDevTools();
|
||||
} else {
|
||||
win.loadFile('./dist/index.html');
|
||||
};
|
||||
registerIpcEvents();
|
||||
|
||||
ipcMain.on('appLoaded', () => {
|
||||
Util.send(win, 'init', dataPath.join('/'), ConfigManager.config, Util.isDarkTheme());
|
||||
UpdateManager.init(mainWindow);
|
||||
UpdateManager.exit = exit;
|
||||
|
||||
MenuManager.exit = exit;
|
||||
MenuManager.setConfig = setConfig;
|
||||
MenuManager.setChannel = (channel) => {
|
||||
if (!UpdateManager.isUpdating) {
|
||||
setConfig({ channel: channel }, (error) => {
|
||||
UpdateManager.setChannel(channel);
|
||||
});
|
||||
};
|
||||
};
|
||||
MenuManager.initMenu(mainWindow);
|
||||
MenuManager.initTray(mainWindow);
|
||||
};
|
||||
|
||||
function createChildWindow (route) {
|
||||
const win = WindowManager.createMain({ withState: false });
|
||||
|
||||
win.once('ready-to-show', () => {
|
||||
win.show();
|
||||
|
||||
if (route) {
|
||||
Util.send(win, 'route', route);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
function registerIpcEvents () {
|
||||
ipcMain.on('appLoaded', () => { Util.send(mainWindow, 'init', dataPath.join('/'), ConfigManager.config, Util.isDarkTheme()); });
|
||||
ipcMain.on('exit', (e, relaunch) => { exit(relaunch); });
|
||||
ipcMain.on('shutdown', (e, relaunch) => { shutdown(relaunch); });
|
||||
ipcMain.on('configSet', (e, config) => { setConfig(config); });
|
||||
|
||||
ipcMain.on('keytarSet', (e, key, value) => {
|
||||
if (key && value) {
|
||||
keytar.setPassword(KEYTAR_SERVICE, key, value);
|
||||
};
|
||||
});
|
||||
|
||||
ipcMain.on('keytarGet', (e, key) => {
|
||||
keytar.getPassword(KEYTAR_SERVICE, key).then((value) => {
|
||||
Util.send(win, 'keytarGet', key, value);
|
||||
});
|
||||
keytar.getPassword(KEYTAR_SERVICE, key).then((value) => { Util.send(mainWindow, 'keytarGet', key, value); });
|
||||
});
|
||||
ipcMain.on('keytarDelete', (e, key) => { keytar.deletePassword(KEYTAR_SERVICE, key); });
|
||||
|
||||
ipcMain.on('keytarDelete', (e, key) => {
|
||||
keytar.deletePassword(KEYTAR_SERVICE, key);
|
||||
});
|
||||
ipcMain.on('updateDownload', (e) => { UpdateManager.download(); });
|
||||
ipcMain.on('updateConfirm', (e) => { exit(true); });
|
||||
ipcMain.on('updateCancel', (e) => { UpdateManager.cancel(); });
|
||||
|
||||
ipcMain.on('exit', (e, relaunch) => {
|
||||
exit(relaunch);
|
||||
});
|
||||
|
||||
ipcMain.on('shutdown', (e, relaunch) => {
|
||||
shutdown(relaunch);
|
||||
});
|
||||
|
||||
ipcMain.on('updateDownload', (e) => {
|
||||
UpdateManager.download();
|
||||
});
|
||||
|
||||
ipcMain.on('updateConfirm', (e) => {
|
||||
exit(true);
|
||||
});
|
||||
|
||||
ipcMain.on('configSet', (e, config) => {
|
||||
setConfig(config);
|
||||
});
|
||||
|
||||
ipcMain.on('updateCancel', (e) => {
|
||||
UpdateManager.cancel();
|
||||
});
|
||||
|
||||
ipcMain.on('urlOpen', async (e, url) => {
|
||||
shell.openExternal(url).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('pathOpen', async (e, path) => {
|
||||
shell.openPath(path).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('windowOpen', (e, route) => {
|
||||
deeplinkingUrl = route;
|
||||
createWindow();
|
||||
});
|
||||
ipcMain.on('urlOpen', async (e, v) => { shell.openExternal(v); });
|
||||
ipcMain.on('pathOpen', async (e, v) => { shell.openPath(v); });
|
||||
ipcMain.on('windowOpen', (e, v) => { createChildWindow(v); });
|
||||
|
||||
ipcMain.on('download', async (e, url) => {
|
||||
const win = BrowserWindow.getFocusedWindow();
|
||||
await download(win, url, { saveAs: true });
|
||||
await download(BrowserWindow.getFocusedWindow(), url, { saveAs: true });
|
||||
});
|
||||
|
||||
ipcMain.on('proxyEvent', function () {
|
||||
|
@ -288,60 +188,12 @@ function createMainWindow () {
|
|||
send.apply(this, args);
|
||||
});
|
||||
|
||||
ipcMain.on('winCommand', (e, cmd, param) => {
|
||||
param = param || {};
|
||||
|
||||
switch (cmd) {
|
||||
case 'menu':
|
||||
MenuManager.menu.popup({ x: 16, y: 38 });
|
||||
break;
|
||||
|
||||
case 'minimize':
|
||||
win.minimize();
|
||||
break;
|
||||
|
||||
case 'maximize':
|
||||
win.isMaximized() ? win.unmaximize() : win.maximize();
|
||||
break;
|
||||
|
||||
case 'close':
|
||||
win.hide();
|
||||
break;
|
||||
|
||||
case 'saveAsHTML':
|
||||
dialog.showOpenDialog({
|
||||
properties: [ 'openDirectory' ],
|
||||
}).then((result) => {
|
||||
const files = result.filePaths;
|
||||
if ((files == undefined) || !files.length) {
|
||||
Util.send(win, 'command', 'saveAsHTMLSuccess');
|
||||
return;
|
||||
};
|
||||
|
||||
Util.savePage(win, files[0], param.name);
|
||||
});
|
||||
break;
|
||||
};
|
||||
});
|
||||
|
||||
UpdateManager.init(win);
|
||||
UpdateManager.exit = exit;
|
||||
|
||||
MenuManager.setConfig = setConfig;
|
||||
MenuManager.setChannel = (channel) => {
|
||||
if (!UpdateManager.isUpdating) {
|
||||
setConfig({ channel: channel }, (error) => {
|
||||
UpdateManager.setChannel(channel);
|
||||
});
|
||||
};
|
||||
};
|
||||
MenuManager.initMenu(win);
|
||||
MenuManager.initTray(win);
|
||||
ipcMain.on('winCommand', (e, cmd, param) => { WindowManager.command(mainWindow, cmd, param); });
|
||||
};
|
||||
|
||||
function setConfig (obj, callBack) {
|
||||
ConfigManager.set(obj, (err) => {
|
||||
Util.send(win, 'config', ConfigManager.config);
|
||||
Util.send(mainWindow, 'config', ConfigManager.config);
|
||||
|
||||
if (callBack) {
|
||||
callBack(err);
|
||||
|
@ -366,19 +218,18 @@ app.on('second-instance', (event, argv, cwd) => {
|
|||
Util.log('info', 'second-instance');
|
||||
|
||||
if (!is.macos) {
|
||||
const scheme = `${protocol}://`;
|
||||
deeplinkingUrl = argv.find((arg) => arg.startsWith(scheme));
|
||||
deeplinkingUrl = argv.find((arg) => arg.startsWith(`${protocol}://`));
|
||||
if (deeplinkingUrl) {
|
||||
Util.send(win, 'route', deeplinkingUrl.replace(scheme, '/'));
|
||||
Util.send(mainWindow, 'route', Util.getRouteFromUrl(deeplinkingUrl));
|
||||
};
|
||||
};
|
||||
|
||||
if (win) {
|
||||
if (win.isMinimized()) {
|
||||
win.restore();
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
};
|
||||
win.show();
|
||||
win.focus();
|
||||
mainWindow.show();
|
||||
mainWindow.focus();
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -402,14 +253,14 @@ app.on('before-quit', (e) => {
|
|||
};
|
||||
});
|
||||
|
||||
app.on('activate', () => { win ? win.show() : createMainWindow(); });
|
||||
app.on('activate', () => { mainWindow ? mainWindow.show() : createMainWindow(); });
|
||||
|
||||
app.on('open-url', (e, url) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (win) {
|
||||
Util.send(win, 'route', url.replace(`${protocol}://`, '/'));
|
||||
win.show();
|
||||
if (mainWindow) {
|
||||
Util.send(mainWindow, 'route', Util.getRouteFromUrl(url));
|
||||
mainWindow.show();
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -417,8 +268,6 @@ function shutdown (relaunch) {
|
|||
Util.log('info', 'AppShutdown, relaunch: ' + relaunch);
|
||||
|
||||
if (relaunch) {
|
||||
Util.log('info', 'Relaunch');
|
||||
app.isQuiting = true;
|
||||
UpdateManager.relaunch();
|
||||
} else {
|
||||
app.exit(0);
|
||||
|
@ -431,19 +280,10 @@ function exit (relaunch) {
|
|||
};
|
||||
|
||||
Util.log('info', 'MW shutdown is starting, relaunch: ' + relaunch);
|
||||
Util.send(win, 'shutdownStart');
|
||||
Util.send(mainWindow, 'shutdownStart');
|
||||
|
||||
if (useGRPC) {
|
||||
if (server) {
|
||||
server.stop().then(()=>{
|
||||
Util.log('info', 'MW shutdown complete');
|
||||
shutdown(relaunch);
|
||||
});
|
||||
} else {
|
||||
Util.log('warn', 'MW server not set');
|
||||
shutdown(relaunch);
|
||||
};
|
||||
} else {
|
||||
Util.send(win, 'shutdown', relaunch);
|
||||
};
|
||||
Server.stop().then(()=>{
|
||||
Util.log('info', 'MW shutdown complete');
|
||||
shutdown(relaunch);
|
||||
});
|
||||
};
|
|
@ -5,12 +5,12 @@
|
|||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
|
||||
<title>Anytype</title>
|
||||
|
||||
<script src="common.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="about.css" />
|
||||
<script src="./common.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="./about.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo">
|
||||
<img src="icon.png" />
|
||||
<img src="../img/icon.png" />
|
||||
</div>
|
||||
<h2 class="title">Anytype</h2>
|
||||
<h3 class="description">Anytype is a next generation software that breaks down barriers between applications, gives back privacy and data ownership to users.</h3>
|
||||
|
@ -21,6 +21,6 @@
|
|||
<button id="close">Close</button>
|
||||
</div>
|
||||
|
||||
<script src="about.js" type="text/javascript"></script>
|
||||
<script src="./about.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,8 @@
|
|||
const { app, shell, Menu, Tray } = require('electron');
|
||||
const { is } = require('electron-util');
|
||||
|
||||
const ConfigManager = require('./config.js');
|
||||
const WindowManager = require('./window.js');
|
||||
const Util = require('./util.js');
|
||||
|
||||
const Separator = { type: 'separator' };
|
||||
|
@ -11,6 +13,7 @@ class MenuManager {
|
|||
tray = {};
|
||||
setChannel = () => {};
|
||||
setConfig = () => {};
|
||||
exit = () => {};
|
||||
|
||||
initMenu (win) {
|
||||
const { config } = ConfigManager;
|
||||
|
@ -19,24 +22,32 @@ class MenuManager {
|
|||
{
|
||||
label: 'Anytype',
|
||||
submenu: [
|
||||
{ label: 'About Anytype', click: () => { Util.aboutWindow(); } },
|
||||
{ label: 'About Anytype', click: () => { WindowManager.createAbout(); } },
|
||||
|
||||
Separator,
|
||||
|
||||
{ role: 'services' },
|
||||
|
||||
Separator,
|
||||
|
||||
{ role: 'hide', label: 'Hide Anytype' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'unhide' },
|
||||
|
||||
Separator,
|
||||
|
||||
{ label: 'Check for updates', click: () => { Updater.checkUpdate(false); } },
|
||||
{ label: 'Settings', click: () => { Util.send(win, 'popup', 'settings', {}); } },
|
||||
|
||||
Separator,
|
||||
|
||||
{
|
||||
label: 'Quit', accelerator: 'CmdOrCtrl+Q',
|
||||
click: () => {
|
||||
if (win) {
|
||||
win.hide();
|
||||
};
|
||||
exit(false);
|
||||
this.exit(false);
|
||||
}
|
||||
},
|
||||
]
|
||||
|
@ -225,7 +236,7 @@ class MenuManager {
|
|||
},
|
||||
{
|
||||
label: 'Relaunch',
|
||||
click: () => { exit(true); }
|
||||
click: () => { this.exit(true); }
|
||||
},
|
||||
]
|
||||
};
|
||||
|
@ -278,7 +289,7 @@ class MenuManager {
|
|||
|
||||
Separator,
|
||||
|
||||
{ label: 'Quit', click: () => { hide(); exit(false); } },
|
||||
{ label: 'Quit', click: () => { hide(); this.exit(false); } },
|
||||
]));
|
||||
};
|
||||
|
||||
|
|
|
@ -132,4 +132,4 @@ class Server {
|
|||
|
||||
};
|
||||
|
||||
module.exports = new Server();
|
||||
module.exports = new Server();
|
|
@ -1,3 +1,4 @@
|
|||
const { app } = require('electron');
|
||||
const { autoUpdater } = require('electron-updater');
|
||||
const log = require('electron-log');
|
||||
|
||||
|
@ -110,6 +111,9 @@ class UpdateManager {
|
|||
};
|
||||
|
||||
relaunch () {
|
||||
Util.log('info', 'Relaunch');
|
||||
app.isQuiting = true;
|
||||
|
||||
autoUpdater.quitAndInstall();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const log = require('electron-log');
|
||||
const { app, BrowserWindow, shell, nativeTheme } = require('electron');
|
||||
const { is } = require('electron-util');
|
||||
const { app, shell, nativeTheme } = require('electron');
|
||||
const path = require('path');
|
||||
const version = app.getVersion();
|
||||
const protocol = 'anytype';
|
||||
|
||||
const ConfigManager = require('./config.js');
|
||||
|
||||
|
@ -12,10 +12,16 @@ class Util {
|
|||
|
||||
appPath = '';
|
||||
|
||||
setPath (value) {
|
||||
setAppPath (value) {
|
||||
this.appPath = value;
|
||||
};
|
||||
|
||||
mkDir (value) {
|
||||
if (value) {
|
||||
try { fs.mkdirSync(value); } catch (e) {};
|
||||
};
|
||||
};
|
||||
|
||||
log (method, text) {
|
||||
if (!log[method]) {
|
||||
method = 'info';
|
||||
|
@ -28,6 +34,10 @@ class Util {
|
|||
return nativeTheme.shouldUseDarkColors || nativeTheme.shouldUseHighContrastColors || nativeTheme.shouldUseInvertedColorScheme;
|
||||
};
|
||||
|
||||
getRouteFromUrl (url) {
|
||||
return url.replace(`${protocol}://`, '/');
|
||||
};
|
||||
|
||||
getTheme () {
|
||||
const { theme } = ConfigManager.config || {};
|
||||
|
||||
|
@ -60,8 +70,12 @@ class Util {
|
|||
return c;
|
||||
};
|
||||
|
||||
electronPath () {
|
||||
return path.join(this.appPath, 'electron');
|
||||
};
|
||||
|
||||
imagePath () {
|
||||
return path.join(this.appPath, 'electron', 'img' );
|
||||
return path.join(this.electronPath(), 'img');
|
||||
};
|
||||
|
||||
send () {
|
||||
|
@ -74,39 +88,6 @@ class Util {
|
|||
};
|
||||
};
|
||||
|
||||
aboutWindow () {
|
||||
let window = new BrowserWindow({
|
||||
backgroundColor: this.getBgColor(),
|
||||
width: 400,
|
||||
height: 400,
|
||||
useContentSize: true,
|
||||
titleBarStyle: 'hidden-inset',
|
||||
show: true,
|
||||
icon: path.join(__dirname, 'electron', 'img', 'icon.png'),
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
},
|
||||
});
|
||||
|
||||
window.loadURL('file://' + path.join(__dirname, 'electron', 'about', `index.html?version=${version}&theme=${this.getTheme()}`));
|
||||
|
||||
window.once('closed', () => { window = null; });
|
||||
window.once('ready-to-show', () => { window.show(); });
|
||||
window.setMenu(null);
|
||||
|
||||
window.webContents.on('will-navigate', (e, url) => {
|
||||
e.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
window.webContents.on('new-window', (e, url) => {
|
||||
e.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
return window;
|
||||
};
|
||||
|
||||
savePage (win, exportPath, name) {
|
||||
name = String(name || 'untitled').replace(/[^\w -\._]/gi, '-').toLowerCase();
|
||||
|
||||
|
|
190
electron/js/window.js
Normal file
190
electron/js/window.js
Normal file
|
@ -0,0 +1,190 @@
|
|||
const { app, BrowserWindow, nativeImage, dialog } = require('electron');
|
||||
const { is } = require('electron-util');
|
||||
const version = app.getVersion();
|
||||
const path = require('path');
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
const remote = require('@electron/remote/main');
|
||||
const port = process.env.SERVER_PORT;
|
||||
|
||||
const MenuManager = require('./menu.js');
|
||||
const Util = require('./util.js');
|
||||
|
||||
const MIN_WIDTH = 752;
|
||||
const MIN_HEIGHT = 480;
|
||||
|
||||
class WindowManager {
|
||||
|
||||
list = new Set();
|
||||
exit = () => {};
|
||||
|
||||
create (param) {
|
||||
param = Object.assign({
|
||||
backgroundColor: Util.getBgColor(),
|
||||
icon: path.join(Util.imagePath(), 'icon.png'),
|
||||
show: false,
|
||||
titleBarStyle: 'hidden-inset',
|
||||
webPreferences: {},
|
||||
}, param);
|
||||
|
||||
param.webPreferences = Object.assign({
|
||||
nodeIntegration: true,
|
||||
}, param.webPreferences);
|
||||
|
||||
let win = new BrowserWindow(param);
|
||||
|
||||
win.on('closed', () => {
|
||||
this.list.delete(win);
|
||||
win = null;
|
||||
});
|
||||
|
||||
this.list.add(win);
|
||||
|
||||
return win;
|
||||
};
|
||||
|
||||
createMain (options) {
|
||||
const { withState } = options;
|
||||
|
||||
const image = nativeImage.createFromPath(path.join(Util.imagePath(), 'icon512x512.png'));
|
||||
const state = windowStateKeeper({ defaultWidth: 800, defaultHeight: 600 });
|
||||
|
||||
let param = {
|
||||
minWidth: MIN_WIDTH,
|
||||
minHeight: MIN_HEIGHT,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
spellcheck: false
|
||||
},
|
||||
};
|
||||
|
||||
if (is.linux) {
|
||||
param.icon = image;
|
||||
} else {
|
||||
param.frame = false;
|
||||
param.titleBarStyle = 'hidden';
|
||||
};
|
||||
|
||||
if (is.macos) {
|
||||
app.dock.setIcon(image);
|
||||
|
||||
param.icon = path.join(Util.imagePath(), 'icon.icns');
|
||||
param.trafficLightPosition = { x: 20, y: 18 };
|
||||
};
|
||||
|
||||
if (is.windows) {
|
||||
param.icon = path.join(Util.imagePath(), 'icon64x64.png');
|
||||
};
|
||||
|
||||
if (withState) {
|
||||
param = Object.assign(param, {
|
||||
x: state.x,
|
||||
y: state.y,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
});
|
||||
};
|
||||
|
||||
const win = this.create(param);
|
||||
|
||||
remote.enable(win.webContents);
|
||||
|
||||
if (withState) {
|
||||
state.manage(win);
|
||||
};
|
||||
|
||||
if (is.development) {
|
||||
win.loadURL(`http://localhost:${port}`);
|
||||
win.toggleDevTools();
|
||||
} else {
|
||||
win.loadFile('./dist/index.html');
|
||||
};
|
||||
|
||||
win.on('enter-full-screen', () => { Util.send(win, 'enter-full-screen'); });
|
||||
win.on('leave-full-screen', () => { Util.send(win, 'leave-full-screen'); });
|
||||
|
||||
win.on('close', (e) => {
|
||||
Util.log('info', 'close: ' + app.isQuiting);
|
||||
|
||||
if (app.isQuiting) {
|
||||
return;
|
||||
};
|
||||
|
||||
e.preventDefault();
|
||||
if (!is.linux) {
|
||||
if (win.isFullScreen()) {
|
||||
win.setFullScreen(false);
|
||||
win.once('leave-full-screen', () => { win.hide(); });
|
||||
} else {
|
||||
win.hide();
|
||||
};
|
||||
} else {
|
||||
this.exit(false);
|
||||
};
|
||||
return false;
|
||||
});
|
||||
|
||||
return win;
|
||||
};
|
||||
|
||||
createAbout () {
|
||||
const win = this.create({ width: 400, height: 400, useContentSize: true });
|
||||
|
||||
win.loadURL('file://' + path.join(Util.electronPath(), 'about', `index.html?version=${version}&theme=${Util.getTheme()}`));
|
||||
|
||||
win.once('ready-to-show', () => { win.show(); });
|
||||
win.setMenu(null);
|
||||
|
||||
win.webContents.on('will-navigate', (e, url) => {
|
||||
e.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
win.webContents.on('new-window', (e, url) => {
|
||||
e.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
return win;
|
||||
};
|
||||
|
||||
command (win, cmd, param) {
|
||||
param = param || {};
|
||||
|
||||
switch (cmd) {
|
||||
case 'menu':
|
||||
MenuManager.menu.popup({ x: 16, y: 38 });
|
||||
break;
|
||||
|
||||
case 'minimize':
|
||||
win.minimize();
|
||||
break;
|
||||
|
||||
case 'maximize':
|
||||
win.isMaximized() ? win.unmaximize() : win.maximize();
|
||||
break;
|
||||
|
||||
case 'close':
|
||||
win.hide();
|
||||
break;
|
||||
|
||||
case 'saveAsHTML':
|
||||
dialog.showOpenDialog({
|
||||
properties: [ 'openDirectory' ],
|
||||
}).then((result) => {
|
||||
const files = result.filePaths;
|
||||
|
||||
if ((files == undefined) || !files.length) {
|
||||
Util.send(win, 'command', 'saveAsHTMLSuccess');
|
||||
} else {
|
||||
Util.savePage(win, files[0], param.name);
|
||||
};
|
||||
});
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
module.exports = new WindowManager();
|
Loading…
Add table
Add a link
Reference in a new issue