Initial Commit ...
This commit is contained in:
@@ -0,0 +1,460 @@
|
||||
//
|
||||
//#region Required Modules ...
|
||||
const url = require("url");
|
||||
const path = require("path");
|
||||
const { Subject } = require("rxjs");
|
||||
const uuid = require("./modules/tools/x-uuid.tools");
|
||||
const XLogger = require("./modules/tools/x-logger.tools");
|
||||
const windowManager = require('./modules/tools/x-window.tools');
|
||||
const { XElectronChannel, XElectronMessage } = require('./modules/services/x-electron.service');
|
||||
const { app, shell, Tray, ipcMain, BrowserWindow, Menu } = require("electron");
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Prepare Required Config Data ...
|
||||
//
|
||||
// Set Environment ...
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
//
|
||||
const isDevelopment = process.env.NODE_ENV !== "production" ? true : false; // app.isPackaged;
|
||||
const isMac = process.platform === "darwin" ? true : false;
|
||||
|
||||
//
|
||||
// Show Logs ...
|
||||
const showLogs = false;
|
||||
|
||||
//
|
||||
// Show Debug Window ...
|
||||
const showDebug = false;
|
||||
|
||||
//
|
||||
// Force Window to show fullscreen ...
|
||||
const isFullscreen = false;
|
||||
|
||||
//
|
||||
// Show Window on Startup ...
|
||||
const showWindowOnStartup = true;
|
||||
|
||||
//
|
||||
const iconPath = path.join(__dirname, "www/assets/icon/favicon.png");
|
||||
const trayIconPath = path.join(__dirname, "www/assets/icon/icon-16x16.png");
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Handle Logging ...
|
||||
if (showLogs) {
|
||||
XLogger.enableLogging();
|
||||
} else {
|
||||
XLogger.disableLogging();
|
||||
}
|
||||
|
||||
//
|
||||
console.log('XLogger State: ', XLogger.isLoggingEnable());
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Global Objects ...
|
||||
//
|
||||
let tray;
|
||||
let mainUrl;
|
||||
let mainWindow;
|
||||
let mainWindowID;
|
||||
|
||||
//
|
||||
const appId = uuid.generateUuid('XFrameworkElectronApp');
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Subscribers ...
|
||||
//
|
||||
const otherChannelsSubject = new Subject();
|
||||
const defaultChannelSubject = new Subject();
|
||||
const handShakeChannelSubject = new Subject();
|
||||
|
||||
//
|
||||
// Register Handshake Handler ...
|
||||
handShakeChannelSubject
|
||||
.asObservable()
|
||||
.subscribe(message => {
|
||||
//
|
||||
XLogger.logWarn(
|
||||
XLogger.XLogMessage(
|
||||
XLogger.XLogTag.Warn,
|
||||
`Handshake Channel`,
|
||||
[message]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
//
|
||||
// Register Default Handler ...
|
||||
defaultChannelSubject
|
||||
.asObservable()
|
||||
.subscribe(message => {
|
||||
//
|
||||
XLogger.logWarn(
|
||||
XLogger.XLogMessage(
|
||||
XLogger.XLogTag.Warn,
|
||||
`Default Channel`,
|
||||
[message]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
//
|
||||
// Register Other Handler ...
|
||||
otherChannelsSubject
|
||||
.asObservable()
|
||||
.subscribe(async message => {
|
||||
//
|
||||
XLogger.logWarn(
|
||||
XLogger.XLogMessage(
|
||||
XLogger.XLogTag.Warn,
|
||||
`Other Channel`,
|
||||
[message]
|
||||
)
|
||||
);
|
||||
|
||||
//
|
||||
// File Service ...
|
||||
if (message && message.channel === XElectronChannel.FileService) {
|
||||
await handleFileServiceAction(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Projects Service ...
|
||||
if (message && message.channel === XElectronChannel.ProjectsService) {
|
||||
await handleProjectsServiceAction(message);
|
||||
}
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Creator Fuctions ...
|
||||
/**
|
||||
* Creat SysTray Object for using in app ...
|
||||
*/
|
||||
function createTray() {
|
||||
//
|
||||
// Create Tray Instance ...
|
||||
tray = new Tray(trayIconPath);
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'Tray Created ...'));
|
||||
|
||||
//
|
||||
// Attach Event Listener to Tray Click ...
|
||||
tray.on("click", () => {
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'Tray Clicked ...'));
|
||||
|
||||
//
|
||||
toggleMainWindow();
|
||||
});
|
||||
|
||||
//
|
||||
// Attach Event Listener to Tray RightClick ...
|
||||
tray.on("right-click", () => {
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'Tray Right Clicked ...'));
|
||||
|
||||
//
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: "quit",
|
||||
click: () => {
|
||||
//
|
||||
app.isClosing = true;
|
||||
app.quit();
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
//
|
||||
tray.popUpContextMenu(contextMenu);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Main Window Instance ...
|
||||
*/
|
||||
function createWindow() {
|
||||
//
|
||||
// Create Main Window ...
|
||||
mainWindow = new BrowserWindow({
|
||||
icon: iconPath,
|
||||
show: showWindowOnStartup,
|
||||
width: isDevelopment ? 1200 : 800,
|
||||
height: isDevelopment ? 800 : 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
// Handle FullScreen state if Window shown on startup ...
|
||||
if (isFullscreen && showWindowOnStartup) {
|
||||
mainWindow.maximize();
|
||||
mainWindow.setFullScreen(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Generate Main Windows UUID ...
|
||||
mainWindowID = uuid.generateUuid("XFrameworkElectronWindow");
|
||||
mainWindow.name = mainWindowID;
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `Window ${mainWindowID} Created ...`));
|
||||
|
||||
//
|
||||
// Fix new Window Open action ...
|
||||
mainWindow.webContents.on("new-window", function (e, url) {
|
||||
e.preventDefault();
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'New Window Requested ...'));
|
||||
|
||||
//
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
//
|
||||
// Handle load Main Url on Navigate for handling Navigation on Angular Apps ...
|
||||
mainWindow.webContents.on("will-navigate", function (e, url) {
|
||||
e.preventDefault();
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'Window Will Navigate Called ...'));
|
||||
|
||||
//
|
||||
mainWindow.loadURL(mainUrl);
|
||||
});
|
||||
|
||||
//
|
||||
// Prepare Main Url ...
|
||||
mainUrl = url.format({
|
||||
pathname: path.join(__dirname, "/www/index.html"),
|
||||
protocol: "file",
|
||||
slashes: true,
|
||||
});
|
||||
|
||||
//
|
||||
// Load Content on Main Window ...
|
||||
mainWindow.loadURL(mainUrl);
|
||||
|
||||
//
|
||||
// Remove Browser Window Default menu ...
|
||||
mainWindow.removeMenu();
|
||||
|
||||
//
|
||||
// Open Dev Tools on Development environment ...
|
||||
if (showDebug) {
|
||||
//
|
||||
mainWindow.webContents.openDevTools();
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, 'Window Dev Tools Opened ...'));
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Window Closed ...
|
||||
mainWindow.on("closed", () => {
|
||||
//
|
||||
mainWindow = null;
|
||||
windowManager.remove(mainWindowID);
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `Window ${mainWindowID} Closed ...`));
|
||||
});
|
||||
|
||||
//
|
||||
// Handle Window Close ...
|
||||
mainWindow.on("close", (e) => {
|
||||
//
|
||||
if (!app.isClosing) {
|
||||
//
|
||||
e.preventDefault();
|
||||
|
||||
//
|
||||
mainWindow.hide();
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `Window ${mainWindowID} Hided ...`));
|
||||
}
|
||||
|
||||
//
|
||||
return true;
|
||||
});
|
||||
|
||||
//
|
||||
// Send Handshake Message to Angular App for Notifing id of main window ...
|
||||
mainWindow.webContents.on("did-finish-load", () => {
|
||||
//
|
||||
// Instancing new Message for Sending ...
|
||||
const handshakeMsg = new XElectronMessage(
|
||||
appId,
|
||||
mainWindowID,
|
||||
undefined,
|
||||
undefined,
|
||||
XElectronChannel.Handshake,
|
||||
new Date().getTime()
|
||||
);
|
||||
|
||||
//
|
||||
// Sending Handshake Message to MainWindow ...
|
||||
sendMessage(handshakeMsg);
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `sending Handshake to Window ${mainWindowID} ...`));
|
||||
});
|
||||
|
||||
//
|
||||
//#region IPC Handlers ...
|
||||
//
|
||||
// Register Event Handler for HandShake ...
|
||||
ipcMain.on(XElectronChannel.Handshake, (event, message) => {
|
||||
//
|
||||
if (!message || !message.sender) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
const windowID = message.sender;
|
||||
windowManager.set(windowID, mainWindow);
|
||||
|
||||
//
|
||||
handShakeChannelSubject.next(message);
|
||||
});
|
||||
|
||||
//
|
||||
// Register Event Handler for Message ...
|
||||
ipcMain.on(XElectronChannel.Default, (event, message) => {
|
||||
defaultChannelSubject.next(message);
|
||||
});
|
||||
|
||||
//
|
||||
const channels = Object.assign({}, XElectronChannel);
|
||||
delete channels.Default;
|
||||
delete channels.Handshake;
|
||||
|
||||
//
|
||||
Object.keys(channels).forEach(channel => {
|
||||
//
|
||||
// Register Event Handler for Message on other Channel ...
|
||||
ipcMain.on(channels[channel], (event, message) => {
|
||||
otherChannelsSubject.next(message);
|
||||
});
|
||||
});
|
||||
//#endregion
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Show/Hide Main Window ...
|
||||
*/
|
||||
function toggleMainWindow() {
|
||||
//
|
||||
if (!mainWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `Toggle Window ...`));
|
||||
|
||||
//
|
||||
if (mainWindow.isVisible()) {
|
||||
mainWindow.hide();
|
||||
} else {
|
||||
//
|
||||
if (isFullscreen) {
|
||||
mainWindow.maximize();
|
||||
mainWindow.setFullScreen(true);
|
||||
}
|
||||
mainWindow.show();
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Event Emitters ...
|
||||
/**
|
||||
* attach event to call when it's ready, to app object ...
|
||||
*/
|
||||
app.whenReady().then(() => {
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `App Ready ...`));
|
||||
|
||||
//
|
||||
createTray();
|
||||
createWindow();
|
||||
});
|
||||
|
||||
/**
|
||||
* attach event to call when all application Windows closed, to app object ...
|
||||
*/
|
||||
app.on("window-all-closed", () => {
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `All Windows Closed ...`));
|
||||
|
||||
//
|
||||
if (!isMac) {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* attach event to call when application activated, to app object ...
|
||||
*/
|
||||
app.on("activate", () => {
|
||||
//
|
||||
XLogger.logDebug(XLogger.XLogMessage(XLogger.XLogTag.Debug, `App Activated ...`));
|
||||
|
||||
//
|
||||
if (!mainWindow) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//
|
||||
//#region Window Comminucations ...
|
||||
/**
|
||||
* send a message to specified window ...
|
||||
*
|
||||
* @param {XElectronMessageDto} message the message which required to send ...
|
||||
*/
|
||||
function sendMessage(message) {
|
||||
//
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
if (!message.sender) {
|
||||
message.sender = appId;
|
||||
}
|
||||
|
||||
//
|
||||
if (!message.reciever) {
|
||||
message.reciever = mainWindowID;
|
||||
}
|
||||
|
||||
//
|
||||
let destWindow = undefined;
|
||||
if (windowManager.count() === 0) {
|
||||
destWindow = mainWindow;
|
||||
} else {
|
||||
destWindow = windowManager.get(message.reciever);
|
||||
}
|
||||
|
||||
//
|
||||
if (!destWindow) {
|
||||
//
|
||||
const errorMessage = 'Dest Window not found ...';
|
||||
XLogger.logError(XLogger.XLogMessage(XLogger.XLogTag.Error, errorMessage))
|
||||
throw errorMessage;
|
||||
}
|
||||
|
||||
//
|
||||
// Sending Message to Window ...
|
||||
destWindow.webContents.send(
|
||||
message.channel,
|
||||
JSON.stringify(message)
|
||||
);
|
||||
}
|
||||
//#endregion
|
||||
Reference in New Issue
Block a user