diff --git a/angular.json b/angular.json
index 2ca10f49..2210dd0b 100644
--- a/angular.json
+++ b/angular.json
@@ -1445,6 +1445,76 @@
}
}
}
+ },
+ "ucap-webmessenger-electron-notification": {
+ "projectType": "library",
+ "root": "projects/ucap-webmessenger-electron-notification",
+ "sourceRoot": "projects/ucap-webmessenger-electron-notification/src",
+ "prefix": "ucap-electron-notification",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-ng-packagr:build",
+ "options": {
+ "tsConfig": "projects/ucap-webmessenger-electron-notification/tsconfig.lib.json",
+ "project": "projects/ucap-webmessenger-electron-notification/ng-package.json"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "projects/ucap-webmessenger-electron-notification/src/test.ts",
+ "tsConfig": "projects/ucap-webmessenger-electron-notification/tsconfig.spec.json",
+ "karmaConfig": "projects/ucap-webmessenger-electron-notification/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "projects/ucap-webmessenger-electron-notification/tsconfig.lib.json",
+ "projects/ucap-webmessenger-electron-notification/tsconfig.spec.json"
+ ],
+ "exclude": [
+ "**/node_modules/**"
+ ]
+ }
+ }
+ }
+ },
+ "ucap-webmessenger-electron-core": {
+ "projectType": "library",
+ "root": "projects/ucap-webmessenger-electron-core",
+ "sourceRoot": "projects/ucap-webmessenger-electron-core/src",
+ "prefix": "ucap-electron-core",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-ng-packagr:build",
+ "options": {
+ "tsConfig": "projects/ucap-webmessenger-electron-core/tsconfig.lib.json",
+ "project": "projects/ucap-webmessenger-electron-core/ng-package.json"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "projects/ucap-webmessenger-electron-core/src/test.ts",
+ "tsConfig": "projects/ucap-webmessenger-electron-core/tsconfig.spec.json",
+ "karmaConfig": "projects/ucap-webmessenger-electron-core/karma.conf.js"
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "projects/ucap-webmessenger-electron-core/tsconfig.lib.json",
+ "projects/ucap-webmessenger-electron-core/tsconfig.spec.json"
+ ],
+ "exclude": [
+ "**/node_modules/**"
+ ]
+ }
+ }
+ }
}
},
"defaultProject": "ucap-webmessenger-app"
diff --git a/config/main.webpack.config.ts b/config/main.webpack.config.ts
index 523d6814..d42998ac 100644
--- a/config/main.webpack.config.ts
+++ b/config/main.webpack.config.ts
@@ -79,6 +79,16 @@ const mainConfig: webpack.Configuration = {
resolve: {
extensions: ['.js', '.ts'],
alias: {
+ '@ucap-webmessenger/electron-core': path.resolve(
+ __dirname,
+ '..',
+ 'projects/ucap-webmessenger-electron-core/src/public-api'
+ ),
+ '@ucap-webmessenger/electron-notification': path.resolve(
+ __dirname,
+ '..',
+ 'projects/ucap-webmessenger-electron-notification/src/public-api'
+ ),
'@ucap-webmessenger/native': path.resolve(
__dirname,
'..',
diff --git a/main/resources/notification/image/btn_call_message.png b/main/resources/notification/image/btn_call_message.png
new file mode 100644
index 00000000..0e2c7949
Binary files /dev/null and b/main/resources/notification/image/btn_call_message.png differ
diff --git a/main/resources/notification/image/btn_call_receive.png b/main/resources/notification/image/btn_call_receive.png
new file mode 100644
index 00000000..7f60010e
Binary files /dev/null and b/main/resources/notification/image/btn_call_receive.png differ
diff --git a/main/resources/notification/image/btn_call_refuse.png b/main/resources/notification/image/btn_call_refuse.png
new file mode 100644
index 00000000..674a5843
Binary files /dev/null and b/main/resources/notification/image/btn_call_refuse.png differ
diff --git a/main/resources/notification/image/btn_call_transfer.png b/main/resources/notification/image/btn_call_transfer.png
new file mode 100644
index 00000000..fdd11523
Binary files /dev/null and b/main/resources/notification/image/btn_call_transfer.png differ
diff --git a/main/resources/notification/image/btn_close.png b/main/resources/notification/image/btn_close.png
new file mode 100644
index 00000000..2cdaee37
Binary files /dev/null and b/main/resources/notification/image/btn_close.png differ
diff --git a/main/resources/notification/image/btn_close_gray.png b/main/resources/notification/image/btn_close_gray.png
new file mode 100644
index 00000000..0ce0aba0
Binary files /dev/null and b/main/resources/notification/image/btn_close_gray.png differ
diff --git a/main/resources/notification/image/btn_noti_call.png b/main/resources/notification/image/btn_noti_call.png
new file mode 100644
index 00000000..9e695905
Binary files /dev/null and b/main/resources/notification/image/btn_noti_call.png differ
diff --git a/main/resources/notification/image/img_nophoto_50.png b/main/resources/notification/image/img_nophoto_50.png
new file mode 100644
index 00000000..029f81bd
Binary files /dev/null and b/main/resources/notification/image/img_nophoto_50.png differ
diff --git a/main/resources/notification/preload.js b/main/resources/notification/preload.js
new file mode 100644
index 00000000..86975a25
--- /dev/null
+++ b/main/resources/notification/preload.js
@@ -0,0 +1,143 @@
+'use strict';
+
+const electron = require('electron');
+const ipc = electron.ipcRenderer;
+const winId = electron.remote.getCurrentWindow().id;
+
+function setStyle(config) {
+ // Style it
+ let notiDoc = global.window.document;
+ let container = notiDoc.getElementById('container');
+ let appIcon = notiDoc.getElementById('appIcon');
+ let image = notiDoc.getElementById('image');
+ let close = notiDoc.getElementById('close');
+ let message = notiDoc.getElementById('message');
+ // Default style
+ setStyleOnDomElement(config.defaultStyleContainer, container);
+ // Size and radius
+ let style = {
+ height:
+ config.height -
+ 2 * config.borderRadius -
+ 2 * config.defaultStyleContainer.padding,
+ width:
+ config.width -
+ 2 * config.borderRadius -
+ 2 * config.defaultStyleContainer.padding,
+ borderRadius: config.borderRadius + 'px'
+ };
+ setStyleOnDomElement(style, container);
+ // Style appIcon or hide
+ if (config.appIcon) {
+ setStyleOnDomElement(config.defaultStyleAppIcon, appIcon);
+ appIcon.src = config.appIcon;
+ } else {
+ setStyleOnDomElement(
+ {
+ display: 'none'
+ },
+ appIcon
+ );
+ }
+ // Style image
+ setStyleOnDomElement(config.defaultStyleImage, image);
+ // Style close button
+ setStyleOnDomElement(config.defaultStyleClose, close);
+ // Remove margin from text p
+ setStyleOnDomElement(config.defaultStyleText, message);
+}
+
+function setContents(event, notificationObj) {
+ // sound
+ if (notificationObj.sound) {
+ // Check if file is accessible
+ try {
+ // If it's a local file, check it's existence
+ // Won't check remote files e.g. http://
+ if (
+ notificationObj.sound.match(/^file\:/) !== null ||
+ notificationObj.sound.match(/^\//) !== null
+ ) {
+ let audio = new global.window.Audio(notificationObj.sound);
+ audio.play();
+ }
+ } catch (e) {
+ log(
+ 'electron-notify: ERROR could not find sound file: ' +
+ notificationObj.sound.replace('file://', ''),
+ e,
+ e.stack
+ );
+ }
+ }
+
+ let notiDoc = global.window.document;
+ // Title
+ let titleDoc = notiDoc.getElementById('title');
+ titleDoc.innerHTML = notificationObj.title || '';
+ // message
+ let messageDoc = notiDoc.getElementById('message');
+ messageDoc.innerHTML = notificationObj.text || '';
+ // Image
+ let imageDoc = notiDoc.getElementById('image');
+ if (notificationObj.image) {
+ imageDoc.src = notificationObj.image;
+ } else {
+ setStyleOnDomElement({ display: 'none' }, imageDoc);
+ }
+
+ // Close button
+ let closeButton = notiDoc.getElementById('close');
+ closeButton.addEventListener('click', function(event) {
+ event.stopPropagation();
+ ipc.send('UCAP::ElectronNotification::close', winId, notificationObj);
+ });
+
+ // URL
+ let container = notiDoc.getElementById('container');
+ container.addEventListener('click', function() {
+ ipc.send('UCAP::ElectronNotification::click', winId, notificationObj);
+ });
+}
+
+function setStyleOnDomElement(styleObj, domElement) {
+ try {
+ for (let styleAttr in styleObj) {
+ domElement.style[styleAttr] = styleObj[styleAttr];
+ }
+ } catch (e) {
+ throw new Error(
+ 'electron-notify: Could not set style on domElement',
+ styleObj,
+ domElement
+ );
+ }
+}
+
+function loadConfig(event, conf) {
+ setStyle(conf || {});
+}
+
+function reset() {
+ let notiDoc = global.window.document;
+ let container = notiDoc.getElementById('container');
+ let closeButton = notiDoc.getElementById('close');
+
+ // Remove event listener
+ let newContainer = container.cloneNode(true);
+ container.parentNode.replaceChild(newContainer, container);
+ let newCloseButton = closeButton.cloneNode(true);
+ closeButton.parentNode.replaceChild(newCloseButton, closeButton);
+}
+
+ipc.on('UCAP::ElectronNotification::BrowserWindowSetContents', setContents);
+ipc.on('UCAP::ElectronNotification::loadConfig', loadConfig);
+ipc.on('UCAP::ElectronNotification::reset', reset);
+
+function log() {
+ console.log.apply(console, arguments);
+}
+
+delete global.require;
+delete global.exports;
+delete global.module;
diff --git a/main/resources/notification/sound/messageAlarm.mp3 b/main/resources/notification/sound/messageAlarm.mp3
new file mode 100644
index 00000000..abaa3831
Binary files /dev/null and b/main/resources/notification/sound/messageAlarm.mp3 differ
diff --git a/main/resources/notification/styles/noti_messege.css b/main/resources/notification/styles/noti_messege.css
new file mode 100644
index 00000000..02cbf609
--- /dev/null
+++ b/main/resources/notification/styles/noti_messege.css
@@ -0,0 +1,130 @@
+html {
+ height: 100%;
+ overflow-y: scroll;
+}
+body {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ color: #333;
+ font-family: '나눔고딕', Malgun Gothic, '맑은고딕', Arial, Dotum, '돋움',
+ Gulim, '굴림';
+ font-size: 12px;
+ line-height: 18px !important;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+body * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+ul,
+ol {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+img {
+ border: none;
+}
+a:link,
+a:visited,
+a:hover,
+a:active {
+ text-decoration: none;
+}
+
+.noti_messege {
+ width: 340px;
+ height: 100px;
+ border: 1px solid #666;
+ background-color: #fff;
+ box-shadow: 0px 0px 3px 0px #e7e7e7;
+}
+.info {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ padding: 16px 14px;
+ color: #fff;
+}
+.btn_close {
+ position: absolute;
+ z-index: 1;
+ right: 6px;
+ top: 6px;
+ width: 20px;
+ height: 20px;
+ background: url(../image/btn_close_gray.png) no-repeat 50% 50%;
+}
+.btn_close:hover {
+ opacity: 0.7;
+}
+.photo {
+ position: relative;
+ top: 0px;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: 4px 0;
+ width: 54px;
+ height: 54px;
+ border-radius: 50%;
+ background: #5bc1ff url(../image/img_nophoto_50.png) no-repeat 50% 50%;
+ border: 2px solid #ddd;
+}
+.info .profile {
+ position: absolute;
+ width: 60px;
+ text-align: center;
+}
+.photo img {
+ overflow: hidden;
+ width: 50px;
+ height: 50px;
+ border-radius: 50px;
+}
+.noti_messege .info .profile + div {
+ padding-left: 70px;
+ position: relative;
+ line-height: 180%;
+ height: 100%;
+}
+.sender {
+ font-size: 14px;
+ font-weight: bold;
+ margin-bottom: 4px;
+ color: #333;
+ width: 94%;
+}
+.sender .name {
+ color: #2e7fb5;
+}
+.message {
+ color: #666;
+}
+.ellipsis {
+ display: block;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ word-wrap: normal;
+ overflow: hidden;
+}
+.ellipsis_row2 {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ word-wrap: break-word;
+ line-height: 1.6em;
+ height: 3.2em;
+}
diff --git a/main/resources/notification/template.html b/main/resources/notification/template.html
new file mode 100644
index 00000000..5bec4a80
--- /dev/null
+++ b/main/resources/notification/template.html
@@ -0,0 +1,50 @@
+
+
+
+ [개발]M Messenger - 메시지 알림
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
![]()
+
+
+
+
+ -
+ 김 수안무 거북이와 두루미님이 메시지를
+ 보냈습니다.
+
+ -
+ 홍길동 대리(솔루션사업팀)홍길동 대리(솔루션사업팀)홍길동
+ 대리(솔루션사업팀)홍길동 대리(솔루션사업팀)
+
+
+
+
+
+
+
diff --git a/main/src/app/AppWindow.ts b/main/src/app/AppWindow.ts
index 4e4e1f11..32d06ded 100644
--- a/main/src/app/AppWindow.ts
+++ b/main/src/app/AppWindow.ts
@@ -7,6 +7,11 @@ import { EventEmitter } from 'events';
import { now } from '../util/now';
import { registerWindowStateChangedEvents } from '../lib/window-state';
+import {
+ ElectronAppChannel,
+ ElectronBrowserWindowChannel,
+ ElectronWebContentsChannel
+} from '@ucap-webmessenger/electron-core';
export class AppWindow {
private window: BrowserWindow | null = null;
@@ -62,11 +67,11 @@ export class AppWindow {
savedWindowState.manage(this.window);
let quitting = false;
- app.on('before-quit', () => {
+ app.on(ElectronAppChannel.BeforeQuit, () => {
quitting = true;
});
- ipcMain.on('will-quit', (event: IpcMainEvent) => {
+ ipcMain.on(ElectronAppChannel.WillQuit, (event: IpcMainEvent) => {
quitting = true;
event.returnValue = true;
});
@@ -75,7 +80,7 @@ export class AppWindow {
// lets us activate quickly and keep all our interesting logic in the
// renderer.
if (__DARWIN__) {
- this.window.on('close', e => {
+ this.window.on(ElectronBrowserWindowChannel.Close, e => {
if (!quitting) {
e.preventDefault();
}
@@ -92,8 +97,8 @@ export class AppWindow {
//
// can be tidied up once https://github.com/electron/electron/issues/12971
// has been confirmed as resolved
- this.window.once('ready-to-show', () => {
- this.window.on('unmaximize', () => {
+ this.window.once(ElectronBrowserWindowChannel.ReadyToShow, () => {
+ this.window.on(ElectronBrowserWindowChannel.Unmaximize, () => {
setTimeout(() => {
const bounds = this.window.getBounds();
bounds.width += 1;
@@ -109,26 +114,30 @@ export class AppWindow {
public load(): void {
let startLoad = 0;
- this.window.webContents.once('did-start-loading', () => {
- this._rendererReadyTime = null;
- this._loadTime = null;
+ this.window.webContents.once(
+ ElectronWebContentsChannel.DidStartLoading,
+ () => {
+ this._rendererReadyTime = null;
+ this._loadTime = null;
- startLoad = now();
- });
-
- this.window.webContents.once('did-finish-load', () => {
- if (process.env.NODE_ENV === 'development') {
- this.window.webContents.openDevTools();
+ startLoad = now();
}
+ );
- this._loadTime = now() - startLoad;
- });
+ this.window.webContents.once(
+ ElectronWebContentsChannel.DidFinishLoad,
+ () => {
+ this.window.webContents.setVisualZoomLevelLimits(1, 1);
- this.window.webContents.on('did-finish-load', () => {
- this.window.webContents.setVisualZoomLevelLimits(1, 1);
- });
+ if (process.env.NODE_ENV === 'development') {
+ this.window.webContents.openDevTools();
+ }
- this.window.webContents.on('did-fail-load', () => {
+ this._loadTime = now() - startLoad;
+ }
+ );
+
+ this.window.webContents.on(ElectronWebContentsChannel.DidFailLoad, () => {
this.window.webContents.openDevTools();
this.window.show();
});
@@ -158,7 +167,7 @@ export class AppWindow {
}
public onClose(fn: () => void) {
- this.window.on('closed', fn);
+ this.window.on(ElectronBrowserWindowChannel.Closed, fn);
}
/**
diff --git a/main/src/index.ts b/main/src/index.ts
index 2a0a55fd..743ad281 100644
--- a/main/src/index.ts
+++ b/main/src/index.ts
@@ -7,12 +7,22 @@ import * as fs from 'fs';
import { AppWindow } from './app/AppWindow';
import { now } from './util/now';
import { showUncaughtException } from './crash/show-uncaught-exception';
-import { Channel } from '@ucap-webmessenger/native-electron';
+
+import {
+ UpdaterChannel,
+ FileChannel,
+ IdleStateChannel,
+ NotificationChannel
+} from '@ucap-webmessenger/native-electron';
+import { ElectronNotificationService } from '@ucap-webmessenger/electron-notification';
+
import { root } from './util/root';
import { DefaultFolder } from './lib/default-folder';
import { FileUtil } from './lib/file-util';
import { IdleChecker } from './lib/idle-checker';
+import { NotificationRequest } from '@ucap-webmessenger/native';
+import { ElectronAppChannel } from '@ucap-webmessenger/electron-core';
let appWindow: AppWindow | null = null;
@@ -23,6 +33,9 @@ type OnDidLoadFn = (window: AppWindow) => void;
let onDidLoadFns: Array | null = [];
let preventQuit = false;
+
+let notificationService: ElectronNotificationService | null;
+
function handleUncaughtException(error: Error) {
preventQuit = true;
@@ -57,7 +70,7 @@ const gotSingleInstanceLock = app.requestSingleInstanceLock();
isDuplicateInstance = !gotSingleInstanceLock;
let idle: IdleChecker | null;
-app.on('second-instance', (event, args, workingDirectory) => {
+app.on(ElectronAppChannel.SecondInstance, (event, args, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (appWindow) {
if (appWindow.isMinimized()) {
@@ -132,7 +145,7 @@ function createWindow() {
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
-app.on('ready', () => {
+app.on(ElectronAppChannel.Ready, () => {
if (isDuplicateInstance) {
return;
}
@@ -141,6 +154,30 @@ app.on('ready', () => {
createWindow();
+ notificationService = new ElectronNotificationService({
+ width: 340,
+ height: 100,
+ padding: 0,
+ borderRadius: 0,
+ // appIcon: iconPath,
+ displayTime: 5000,
+ defaultStyleContainer: {},
+ defaultStyleAppIcon: { display: 'none' },
+ defaultStyleImage: {},
+ defaultStyleClose: {},
+ defaultStyleText: {}
+ });
+
+ notificationService.options.defaultWindow.webPreferences.preload = path.join(
+ __dirname,
+ 'resources/notification/preload.js'
+ );
+
+ notificationService.templatePath = path.join(
+ __dirname,
+ 'resources/notification/template.html'
+ );
+
ipcMain.on('uncaught-exception', (event: IpcMainEvent, error: Error) => {
handleUncaughtException(error);
});
@@ -155,7 +192,7 @@ app.on('ready', () => {
});
// Quit when all windows are closed.
-app.on('window-all-closed', () => {
+app.on(ElectronAppChannel.WindowAllClosed, () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
@@ -163,7 +200,7 @@ app.on('window-all-closed', () => {
}
});
-app.on('activate', () => {
+app.on(ElectronAppChannel.Activate, () => {
onDidLoad(window => {
window.show();
});
@@ -179,11 +216,11 @@ function onDidLoad(fn: OnDidLoadFn) {
}
}
-ipcMain.on(Channel.checkForUpdates, (event: IpcMainEvent, ...args: any[]) => {
+ipcMain.on(UpdaterChannel.Check, (event: IpcMainEvent, ...args: any[]) => {
event.returnValue = false;
});
-ipcMain.on(Channel.readFile, (event: IpcMainEvent, ...args: any[]) => {
+ipcMain.on(FileChannel.ReadFile, (event: IpcMainEvent, ...args: any[]) => {
try {
fse.readFile(root(args[0]), (err, data) => {
if (!!err) {
@@ -197,37 +234,73 @@ ipcMain.on(Channel.readFile, (event: IpcMainEvent, ...args: any[]) => {
}
});
-ipcMain.on(Channel.saveFile, async (event: IpcMainEvent, ...args: any[]) => {
- try {
- const buffer: Buffer = args[0];
- const fileName: string = args[1];
- let savePath: string = path.join(
- !!args[2] ? args[2] : DefaultFolder.downloads(),
- fileName
- );
- savePath = await FileUtil.uniqueFileName(savePath);
+ipcMain.on(
+ FileChannel.SaveFile,
+ async (event: IpcMainEvent, ...args: any[]) => {
+ try {
+ const buffer: Buffer = args[0];
+ const fileName: string = args[1];
+ let savePath: string = path.join(
+ !!args[2] ? args[2] : DefaultFolder.downloads(),
+ fileName
+ );
+ savePath = await FileUtil.uniqueFileName(savePath);
- fse.writeFile(savePath, buffer, err => {
- if (!err) {
- event.returnValue = savePath;
- } else {
- event.returnValue = undefined;
+ fse.writeFile(savePath, buffer, err => {
+ if (!err) {
+ event.returnValue = savePath;
+ } else {
+ event.returnValue = undefined;
+ }
+ });
+ } catch (error) {
+ event.returnValue = undefined;
+ }
+ }
+);
+
+ipcMain.on(
+ IdleStateChannel.StartCheck,
+ (event: IpcMainEvent, ...args: any[]) => {
+ if (!!idle) {
+ idle.destoryChecker();
+ idle = null;
+ }
+ idle = new IdleChecker(appWindow.browserWindow); // default 10min
+ idle.startChecker();
+ }
+);
+
+ipcMain.on(
+ NotificationChannel.Notify,
+ (event: IpcMainEvent, ...args: any[]) => {
+ const noti: NotificationRequest = args[0];
+
+ notificationService.notify({
+ title: noti.title,
+ text: noti.contents,
+ image:
+ noti.image ||
+ path.join(__dirname, 'resources/notification/image/img_nophoto_50.png'),
+ sound: noti.useSound
+ ? path.join(
+ 'file://',
+ __dirname,
+ 'resources/notification/sound/messageAlarm.mp3'
+ )
+ : '',
+ onClick: () => {
+ console.log('onClick');
}
});
- } catch (error) {
- event.returnValue = undefined;
- }
-});
-ipcMain.on(Channel.idleStateStart, (event: IpcMainEvent, ...args: any[]) => {
- if (!!idle) {
- idle.destoryChecker();
- idle = null;
+ console.log('Channel.notify', noti);
}
- idle = new IdleChecker(appWindow.browserWindow); // default 10min
- idle.startChecker();
-});
+);
-ipcMain.on(Channel.showNotify, (event: IpcMainEvent, ...args: any[]) => {
- console.log('Channel.showNotify', args);
-});
+ipcMain.on(
+ NotificationChannel.CloseAllNotify,
+ (event: IpcMainEvent, ...args: any[]) => {
+ console.log('Channel.closeAllNotify', args);
+ }
+);
diff --git a/main/src/lib/idle-checker.ts b/main/src/lib/idle-checker.ts
index f66c3da6..4d222bf5 100644
--- a/main/src/lib/idle-checker.ts
+++ b/main/src/lib/idle-checker.ts
@@ -1,5 +1,5 @@
import { powerMonitor, BrowserWindow } from 'electron';
-import { Channel } from '@ucap-webmessenger/native-electron';
+import { IdleStateChannel } from '@ucap-webmessenger/native-electron';
import { setInterval } from 'timers';
export enum IdleType {
@@ -28,13 +28,13 @@ export class IdleChecker {
if (this.status === IdleType.ACTIVE) {
this.status = IdleType.IDLE;
// TODO :: USER_STATUS change away
- this.window.webContents.send(Channel.idleStateChanged, this.status);
+ this.window.webContents.send(IdleStateChannel.Changed, this.status);
}
} else {
if (this.status === IdleType.IDLE) {
this.status = IdleType.ACTIVE;
// TODO :: USER_STATUS chage online
- this.window.webContents.send(Channel.idleStateChanged, this.status);
+ this.window.webContents.send(IdleStateChannel.Changed, this.status);
}
}
}
diff --git a/main/src/lib/window-state.ts b/main/src/lib/window-state.ts
index 1c5af590..93eb1c1a 100644
--- a/main/src/lib/window-state.ts
+++ b/main/src/lib/window-state.ts
@@ -1,6 +1,7 @@
import { BrowserWindow } from 'electron';
import { WindowState } from '@ucap-webmessenger/native';
-import { Channel } from '@ucap-webmessenger/native-electron';
+import { WindowStateChannel } from '@ucap-webmessenger/native-electron';
+import { ElectronBrowserWindowChannel } from '@ucap-webmessenger/electron-core';
export function getWindowState(window: Electron.BrowserWindow): WindowState {
if (window.isFullScreen()) {
@@ -17,26 +18,30 @@ export function getWindowState(window: Electron.BrowserWindow): WindowState {
}
export function registerWindowStateChangedEvents(window: BrowserWindow) {
- window.on('enter-full-screen', () =>
+ window.on(ElectronBrowserWindowChannel.EnterFullScreen, () =>
sendWindowStateEvent(window, WindowState.FullScreen)
);
- window.on('leave-full-screen', () =>
+ window.on(ElectronBrowserWindowChannel.LeaveFullScreen, () =>
sendWindowStateEvent(window, WindowState.Normal)
);
- window.on('maximize', () =>
+ window.on(ElectronBrowserWindowChannel.Maximize, () =>
sendWindowStateEvent(window, WindowState.Maximized)
);
- window.on('minimize', () =>
+ window.on(ElectronBrowserWindowChannel.Minimize, () =>
sendWindowStateEvent(window, WindowState.Minimized)
);
- window.on('unmaximize', () =>
+ window.on(ElectronBrowserWindowChannel.Unmaximize, () =>
sendWindowStateEvent(window, WindowState.Normal)
);
- window.on('restore', () => sendWindowStateEvent(window, WindowState.Normal));
- window.on('hide', () => sendWindowStateEvent(window, WindowState.Hidden));
- window.on('show', () => {
+ window.on(ElectronBrowserWindowChannel.Restore, () =>
+ sendWindowStateEvent(window, WindowState.Normal)
+ );
+ window.on(ElectronBrowserWindowChannel.Hide, () =>
+ sendWindowStateEvent(window, WindowState.Hidden)
+ );
+ window.on(ElectronBrowserWindowChannel.Show, () => {
// because the app can be maximized before being closed - which will restore it
// maximized on the next launch - this function should inspect the current state
// rather than always assume it is a 'normal' launch
@@ -45,5 +50,5 @@ export function registerWindowStateChangedEvents(window: BrowserWindow) {
}
function sendWindowStateEvent(window: BrowserWindow, windowState: WindowState) {
- window.webContents.send(Channel.windowStateChanged, windowState);
+ window.webContents.send(WindowStateChannel.Changed, windowState);
}
diff --git a/main/tsconfig.main.json b/main/tsconfig.main.json
index f2a2e501..39a77301 100644
--- a/main/tsconfig.main.json
+++ b/main/tsconfig.main.json
@@ -13,6 +13,12 @@
"types": ["node"],
"lib": ["es2017", "es2016", "es2015", "dom"],
"paths": {
+ "@ucap-webmessenger/electron-core": [
+ "../projects/ucap-webmessenger-electron-core/src/public-api"
+ ],
+ "@ucap-webmessenger/electron-notification": [
+ "../projects/ucap-webmessenger-electron-notification/src/public-api"
+ ],
"@ucap-webmessenger/native": [
"../projects/ucap-webmessenger-native/src/public-api"
],
diff --git a/package-lock.json b/package-lock.json
index bade9cfb..53a09073 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3101,15 +3101,6 @@
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
"dev": true
},
- "async": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
- "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.14"
- }
- },
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
@@ -8061,6 +8052,15 @@
"once": "^1.4.0"
},
"dependencies": {
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"istanbul-lib-coverage": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
@@ -11239,6 +11239,15 @@
"mkdirp": "^0.5.1"
},
"dependencies": {
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -13255,6 +13264,17 @@
"requires": {
"async": "^2.5.0",
"loader-utils": "^1.1.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ }
}
},
"source-map-resolve": {
@@ -13519,6 +13539,15 @@
"lodash": "^4.17.14"
},
"dependencies": {
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -14116,8 +14145,7 @@
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
- "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
- "dev": true
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
},
"tslint": {
"version": "5.15.0",
diff --git a/package.json b/package.json
index 61d69f6a..bb242173 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"start": "npm-run-all -p start:renderer start:main",
"start:main": "wait-on http-get://localhost:4200/ && npm run build:main:dev && electron --nolazy --inspect-brk=9229 .",
"start:renderer": "ng serve",
+ "start:web": "cross-env UCAP_ENV=WEB ng serve",
"start:production": "npm run build:renderer && npm run build:main:prod && electron --nolazy --inspect-brk=9229 .",
"build:renderer": "cross-env NODE_ENV=production ng build --base-href ./",
"build:main:dev": "cross-env NODE_ENV=development TS_NODE_PROJECT='./config/tsconfig.webpack.json' parallel-webpack --config=config/main.webpack.config.ts",
@@ -15,7 +16,9 @@
"e2e": "ng e2e"
},
"private": true,
- "dependencies": {},
+ "dependencies": {
+ "tslib": "^1.10.0"
+ },
"devDependencies": {
"@angular-builders/custom-webpack": "^8.2.0",
"@angular-devkit/build-angular": "~0.803.14",
diff --git a/projects/ucap-webmessenger-electron-core/README.md b/projects/ucap-webmessenger-electron-core/README.md
new file mode 100644
index 00000000..80da145b
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/README.md
@@ -0,0 +1,24 @@
+# UcapWebmessengerElectronCore
+
+This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.11.
+
+## Code scaffolding
+
+Run `ng generate component component-name --project ucap-webmessenger-electron-core` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-electron-core`.
+> Note: Don't forget to add `--project ucap-webmessenger-electron-core` or else it will be added to the default project in your `angular.json` file.
+
+## Build
+
+Run `ng build ucap-webmessenger-electron-core` to build the project. The build artifacts will be stored in the `dist/` directory.
+
+## Publishing
+
+After building your library with `ng build ucap-webmessenger-electron-core`, go to the dist folder `cd dist/ucap-webmessenger-electron-core` and run `npm publish`.
+
+## Running unit tests
+
+Run `ng test ucap-webmessenger-electron-core` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
diff --git a/projects/ucap-webmessenger-electron-core/karma.conf.js b/projects/ucap-webmessenger-electron-core/karma.conf.js
new file mode 100644
index 00000000..5eed1538
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/karma.conf.js
@@ -0,0 +1,32 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, '../../coverage/ucap-webmessenger-electron-core'),
+ reports: ['html', 'lcovonly', 'text-summary'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false,
+ restartOnFileChange: true
+ });
+};
diff --git a/projects/ucap-webmessenger-electron-core/ng-package.json b/projects/ucap-webmessenger-electron-core/ng-package.json
new file mode 100644
index 00000000..e9e6f76e
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/ng-package.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
+ "dest": "../../dist/ucap-webmessenger-electron-core",
+ "lib": {
+ "entryFile": "src/public-api.ts"
+ }
+}
\ No newline at end of file
diff --git a/projects/ucap-webmessenger-electron-core/package.json b/projects/ucap-webmessenger-electron-core/package.json
new file mode 100644
index 00000000..a7ad1a34
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@ucap-webmessenger/electron-core",
+ "version": "0.0.1",
+ "peerDependencies": {
+ "@angular/common": "^8.2.11",
+ "@angular/core": "^8.2.11"
+ }
+}
diff --git a/projects/ucap-webmessenger-electron-core/src/lib/types/channel.type.ts b/projects/ucap-webmessenger-electron-core/src/lib/types/channel.type.ts
new file mode 100644
index 00000000..aab87d73
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/src/lib/types/channel.type.ts
@@ -0,0 +1,37 @@
+export enum ElectronAppChannel {
+ WillFinishLaunching = 'will-finish-launching',
+ Ready = 'ready',
+ WindowAllClosed = 'window-all-closed',
+ BeforeQuit = 'before-quit',
+ WillQuit = 'will-quit',
+ Quit = 'quit',
+ OpenFile = 'open-file',
+ OpenUrl = 'open-url',
+ Activate = 'activate',
+ ContinueActivity = 'continue-activity',
+ WillContinueActivity = 'will-continue-activity',
+ ContinueActivityError = 'continue-activity-error',
+ ActivityWasContinued = 'activity-was-continued',
+ SecondInstance = 'second-instance'
+}
+
+export enum ElectronBrowserWindowChannel {
+ EnterFullScreen = 'enter-full-screen',
+ LeaveFullScreen = 'leave-full-screen',
+ Maximize = 'maximize',
+ Minimize = 'minimize',
+ Unmaximize = 'unmaximize',
+ Restore = 'restore',
+ Hide = 'hide',
+ Show = 'show',
+ Close = 'close',
+ Closed = 'closed',
+ ReadyToShow = 'ready-to-show'
+}
+
+export enum ElectronWebContentsChannel {
+ DevtoolsOpened = 'devtools-opened',
+ DidStartLoading = 'did-start-loading',
+ DidFinishLoad = 'did-finish-load',
+ DidFailLoad = 'did-fail-load'
+}
diff --git a/projects/ucap-webmessenger-electron-core/src/public-api.ts b/projects/ucap-webmessenger-electron-core/src/public-api.ts
new file mode 100644
index 00000000..31f5a3de
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/src/public-api.ts
@@ -0,0 +1,5 @@
+/*
+ * Public API Surface of ucap-webmessenger-electron-core
+ */
+
+export * from './lib/types/channel.type';
diff --git a/projects/ucap-webmessenger-electron-core/src/test.ts b/projects/ucap-webmessenger-electron-core/src/test.ts
new file mode 100644
index 00000000..978c64fb
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/src/test.ts
@@ -0,0 +1,21 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone';
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/projects/ucap-webmessenger-electron-core/tsconfig.lib.json b/projects/ucap-webmessenger-electron-core/tsconfig.lib.json
new file mode 100644
index 00000000..bd23948e
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/tsconfig.lib.json
@@ -0,0 +1,26 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/lib",
+ "target": "es2015",
+ "declaration": true,
+ "inlineSources": true,
+ "types": [],
+ "lib": [
+ "dom",
+ "es2018"
+ ]
+ },
+ "angularCompilerOptions": {
+ "annotateForClosureCompiler": true,
+ "skipTemplateCodegen": true,
+ "strictMetadataEmit": true,
+ "fullTemplateTypeCheck": true,
+ "strictInjectionParameters": true,
+ "enableResourceInlining": true
+ },
+ "exclude": [
+ "src/test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/projects/ucap-webmessenger-electron-core/tsconfig.spec.json b/projects/ucap-webmessenger-electron-core/tsconfig.spec.json
new file mode 100644
index 00000000..16da33db
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/tsconfig.spec.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/spec",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "src/test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/projects/ucap-webmessenger-electron-core/tslint.json b/projects/ucap-webmessenger-electron-core/tslint.json
new file mode 100644
index 00000000..97d86d7a
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-core/tslint.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tslint.json",
+ "rules": {
+ "directive-selector": [
+ true,
+ "attribute",
+ "ucapElectronCore",
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element",
+ "ucap-electron-core",
+ "kebab-case"
+ ]
+ }
+}
diff --git a/projects/ucap-webmessenger-electron-notification/README.md b/projects/ucap-webmessenger-electron-notification/README.md
new file mode 100644
index 00000000..3da195b7
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/README.md
@@ -0,0 +1,24 @@
+# UcapWebmessengerElectronNotification
+
+This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.11.
+
+## Code scaffolding
+
+Run `ng generate component component-name --project ucap-webmessenger-electron-notification` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-electron-notification`.
+> Note: Don't forget to add `--project ucap-webmessenger-electron-notification` or else it will be added to the default project in your `angular.json` file.
+
+## Build
+
+Run `ng build ucap-webmessenger-electron-notification` to build the project. The build artifacts will be stored in the `dist/` directory.
+
+## Publishing
+
+After building your library with `ng build ucap-webmessenger-electron-notification`, go to the dist folder `cd dist/ucap-webmessenger-electron-notification` and run `npm publish`.
+
+## Running unit tests
+
+Run `ng test ucap-webmessenger-electron-notification` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
diff --git a/projects/ucap-webmessenger-electron-notification/karma.conf.js b/projects/ucap-webmessenger-electron-notification/karma.conf.js
new file mode 100644
index 00000000..2b6d790e
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/karma.conf.js
@@ -0,0 +1,32 @@
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, '../../coverage/ucap-webmessenger-electron-notification'),
+ reports: ['html', 'lcovonly', 'text-summary'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false,
+ restartOnFileChange: true
+ });
+};
diff --git a/projects/ucap-webmessenger-electron-notification/ng-package.json b/projects/ucap-webmessenger-electron-notification/ng-package.json
new file mode 100644
index 00000000..fc7aaf11
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/ng-package.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
+ "dest": "../../dist/ucap-webmessenger-electron-notification",
+ "lib": {
+ "entryFile": "src/public-api.ts"
+ }
+}
\ No newline at end of file
diff --git a/projects/ucap-webmessenger-electron-notification/package.json b/projects/ucap-webmessenger-electron-notification/package.json
new file mode 100644
index 00000000..b9dbe1af
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "@ucap-webmessenger/electron-notification",
+ "version": "0.0.1",
+ "peerDependencies": {}
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification-options.ts b/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification-options.ts
new file mode 100644
index 00000000..d25ec28d
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification-options.ts
@@ -0,0 +1,113 @@
+import * as path from 'path';
+import { BrowserWindowConstructorOptions } from 'electron';
+
+export interface ElectronNotificationOptions {
+ width?: number;
+ height?: number;
+ padding?: number;
+ borderRadius?: number;
+ displayTime?: number;
+ animationSteps?: number;
+ animationStepMs?: number;
+ animateInParallel?: boolean;
+ appIcon?: string;
+ pathToModule?: string;
+ logging?: boolean;
+ defaultStyleContainer?: {
+ [attribute: string]: any;
+ };
+ defaultStyleAppIcon?: {
+ [attribute: string]: any;
+ };
+ defaultStyleImage?: {
+ [attribute: string]: any;
+ };
+ defaultStyleClose?: {
+ [attribute: string]: any;
+ };
+ defaultStyleText?: {
+ [attribute: string]: any;
+ };
+ defaultWindow?: BrowserWindowConstructorOptions;
+ templatePath?: string;
+ htmlTemplate?: string;
+}
+
+export const DefaultElectronNotificationOptions: ElectronNotificationOptions = {
+ width: 300,
+ height: 65,
+ padding: 10,
+ borderRadius: 5,
+ displayTime: 5000,
+ animationSteps: 5,
+ animationStepMs: 20,
+ appIcon: null,
+ pathToModule: '',
+ logging: true,
+
+ defaultStyleContainer: {
+ backgroundColor: '#f0f0f0',
+ overflow: 'hidden',
+ padding: 8,
+ border: '1px solid #CCC',
+ fontFamily: 'Arial',
+ fontSize: 12,
+ position: 'relative',
+ lineHeight: '15px'
+ },
+ defaultStyleAppIcon: {
+ overflow: 'hidden',
+ float: 'left',
+ height: 40,
+ width: 40,
+ marginRight: 10
+ },
+ defaultStyleImage: {
+ overflow: 'hidden',
+ float: 'right',
+ height: 40,
+ width: 40,
+ marginLeft: 10
+ },
+ defaultStyleClose: {
+ position: 'absolute',
+ top: 1,
+ right: 3,
+ fontSize: 11,
+ color: '#CCC'
+ },
+ defaultStyleText: {
+ margin: 0,
+ overflow: 'hidden',
+ cursor: 'default'
+ },
+ defaultWindow: {
+ alwaysOnTop: true,
+ skipTaskbar: true,
+ resizable: false,
+ show: false,
+ frame: false,
+ transparent: true,
+ acceptFirstMouse: true,
+ webPreferences: {
+ preload: path.join(__dirname, 'preload.js'),
+ webSecurity: false,
+ allowRunningInsecureContent: true
+ }
+ },
+ htmlTemplate:
+ '\n' +
+ '\n' +
+ '\n' +
+ '\n' +
+ '
![]()
\n' +
+ '
![]()
\n' +
+ '
\n' +
+ '
\n' +
+ '
\n' +
+ '
\n' +
+ '
X
\n' +
+ '
\n' +
+ '\n' +
+ ''
+};
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification.ts b/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification.ts
new file mode 100644
index 00000000..c7416e57
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/models/electron-notification.ts
@@ -0,0 +1,20 @@
+import { ElectronNotificationEventType } from '../types/event.type';
+
+export interface ElectronNotificationEvent {
+ type: ElectronNotificationEventType;
+ id: number;
+ close?: (reason: any) => void;
+}
+
+export interface ElectronNotification {
+ id?: number;
+ displayTime?: number;
+ title?: string;
+ text?: string;
+ image?: string;
+ url?: string;
+ sound?: string;
+ onClick?: (e: ElectronNotificationEvent) => void;
+ onShow?: (e: ElectronNotificationEvent) => void;
+ onClose?: (e: ElectronNotificationEvent) => void;
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/services/electron-notification.service.ts b/projects/ucap-webmessenger-electron-notification/src/lib/services/electron-notification.service.ts
new file mode 100644
index 00000000..1800f793
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/services/electron-notification.service.ts
@@ -0,0 +1,461 @@
+import * as path from 'path';
+import * as url from 'url';
+
+import { AnimationQueue } from '../utils/animation-queue';
+import {
+ ElectronNotificationOptions,
+ DefaultElectronNotificationOptions
+} from '../models/electron-notification-options';
+import { screen, BrowserWindow, ipcMain, IpcMainEvent, shell } from 'electron';
+import { ElectronNotification } from '../models/electron-notification';
+import { ElectronNotificationEventType } from '../types/event.type';
+import { Channel } from '../types/channel.type';
+import { ElectronWebContentsChannel } from '@ucap-webmessenger/electron-core';
+
+const onClickElectronNotification = 'onClickElectronNotification';
+const onCloseElectronNotification = 'onCloseElectronNotification';
+
+interface ENPoint {
+ x: number;
+ y: number;
+}
+
+interface ENDimension {
+ width: number;
+ height: number;
+}
+
+export class ElectronNotificationService {
+ private animationQueue: AnimationQueue;
+ private customOptions: ElectronNotificationOptions;
+ private nextInsertPosition: ENPoint;
+ private totalDimension: ENDimension;
+ private firstPosition: ENPoint;
+ private lowerRightCornerPosition: ENPoint;
+ private maxVisibleNotifications: number;
+ private activeNotifications: BrowserWindow[];
+ private inactiveWindows: BrowserWindow[];
+ private notificationQueue: ElectronNotification[];
+ private closedNotifications: Map;
+ private latestId: number;
+ private templateUrl: string;
+
+ constructor(options?: ElectronNotificationOptions) {
+ this.customOptions = {
+ ...DefaultElectronNotificationOptions
+ };
+ if (!!options) {
+ this.customOptions = {
+ ...this.customOptions,
+ ...options
+ };
+ }
+
+ this.setup();
+ this.setupEvents();
+ }
+
+ set options(options: ElectronNotificationOptions) {
+ if (!!options) {
+ this.customOptions = {
+ ...this.customOptions,
+ ...options
+ };
+ }
+ this.calcDimensions();
+ }
+
+ get options(): ElectronNotificationOptions {
+ return this.customOptions;
+ }
+
+ set templatePath(templatePath: string) {
+ if (!!templatePath) {
+ this.customOptions.templatePath = templatePath;
+ this.updateTemplatePath();
+ }
+ }
+
+ get templatePath(): string {
+ if (!this.templateUrl) {
+ this.updateTemplatePath();
+ }
+ return this.templateUrl;
+ }
+
+ notify(notification: ElectronNotification): number {
+ notification.id = this.latestId++;
+ this.animationQueue.push({
+ context: this,
+ func: this.showNotification,
+ args: [notification]
+ });
+ return notification.id;
+ }
+
+ dispose(): void {
+ this.animationQueue.clear();
+ this.activeNotifications.forEach(window => window.close());
+ this.inactiveWindows.forEach(window => window.close());
+ }
+
+ closeAll(): void {
+ this.animationQueue.clear();
+ this.activeNotifications.forEach(window => window.close());
+ this.inactiveWindows.forEach(window => window.close());
+
+ this.setup();
+ }
+
+ private setup(): void {
+ this.nextInsertPosition = { x: 0, y: 0 };
+ this.totalDimension = { width: 0, height: 0 };
+ this.firstPosition = { x: 0, y: 0 };
+ this.activeNotifications = [];
+ this.inactiveWindows = [];
+ this.notificationQueue = [];
+ this.closedNotifications = new Map();
+ this.latestId = 0;
+
+ this.animationQueue = new AnimationQueue();
+
+ const display = screen.getPrimaryDisplay();
+
+ this.lowerRightCornerPosition = {
+ x: display.bounds.x + display.workArea.x + display.workAreaSize.width,
+ y: display.bounds.y + display.workArea.y + display.workAreaSize.height
+ };
+
+ this.calcDimensions();
+
+ this.maxVisibleNotifications = Math.floor(
+ display.workAreaSize.height / this.totalDimension.height
+ );
+
+ this.maxVisibleNotifications =
+ 7 < this.maxVisibleNotifications ? 7 : this.maxVisibleNotifications;
+ }
+
+ private setupEvents(): void {
+ const self = this;
+ ipcMain.on(
+ Channel.close,
+ (
+ event: IpcMainEvent,
+ windowId: number,
+ notification: ElectronNotification
+ ) => {
+ const onClose = self.buildCloseNotification(
+ BrowserWindow.fromId(windowId),
+ notification
+ );
+ self.buildCloseNotificationSafely(onClose)('close');
+ }
+ );
+
+ ipcMain.on(
+ Channel.click,
+ (
+ event: IpcMainEvent,
+ windowId: number,
+ notification: ElectronNotification
+ ) => {
+ if (!!notification.url) {
+ shell.openExternal(notification.url);
+ }
+ const notificationWindow = BrowserWindow.fromId(windowId);
+
+ if (
+ notificationWindow &&
+ notificationWindow[onClickElectronNotification]
+ ) {
+ const onClose = self.buildCloseNotification(
+ BrowserWindow.fromId(windowId),
+ notification
+ );
+ notificationWindow[onClickElectronNotification]({
+ type: ElectronNotificationEventType.Click,
+ id: notification.id,
+ close: self.buildCloseNotificationSafely(onClose)
+ });
+ delete notificationWindow[onClickElectronNotification];
+ }
+ }
+ );
+ }
+
+ private calcDimensions() {
+ this.totalDimension = {
+ width: this.customOptions.width + this.customOptions.padding,
+ height: this.customOptions.height + this.customOptions.padding
+ };
+
+ this.firstPosition = {
+ x: this.lowerRightCornerPosition.x - this.totalDimension.width,
+ y: this.lowerRightCornerPosition.y - this.totalDimension.height
+ };
+
+ this.nextInsertPosition = {
+ x: this.firstPosition.x,
+ y: this.firstPosition.y
+ };
+ }
+
+ private calcInsertPosition() {
+ if (this.activeNotifications.length < this.maxVisibleNotifications) {
+ this.nextInsertPosition.y =
+ this.lowerRightCornerPosition.y -
+ this.totalDimension.height * (this.activeNotifications.length + 1);
+ }
+ }
+
+ private updateTemplatePath() {
+ try {
+ import('fs')
+ .then(fs => {
+ fs.statSync(this.customOptions.templatePath).isFile();
+
+ this.templateUrl = url.format({
+ pathname: this.customOptions.templatePath,
+ protocol: 'file:',
+ slashes: true
+ });
+ })
+ .catch(reason => {
+ throw reason;
+ });
+ } catch (e) {
+ console.log(
+ 'electron-notify: Could not find template ("' +
+ this.customOptions.templatePath +
+ '").'
+ );
+ console.log(
+ 'electron-notify: To use a different template you need to correct the config.templatePath or simply adapt config.htmlTemplate'
+ );
+ }
+ }
+
+ private showNotification(notification: ElectronNotification): Promise {
+ const self = this;
+ return new Promise((resolve, reject) => {
+ if (this.activeNotifications.length < this.maxVisibleNotifications) {
+ self.getWindow().then(notificationWindow => {
+ self.calcInsertPosition();
+ notificationWindow.setPosition(
+ self.nextInsertPosition.x,
+ self.nextInsertPosition.y
+ );
+ self.activeNotifications.push(notificationWindow);
+
+ const displayTime = !!notification.displayTime
+ ? notification.displayTime
+ : self.customOptions.displayTime;
+ let timeoutId: any;
+ const onClose = self.buildCloseNotification(
+ notificationWindow,
+ notification,
+ () => timeoutId
+ );
+ const onCloseNotificationSafely = self.buildCloseNotificationSafely(
+ onClose
+ );
+ timeoutId = setTimeout(() => {
+ if (notificationWindow.isDestroyed()) {
+ return;
+ }
+ onCloseNotificationSafely('timeout');
+ }, displayTime);
+
+ if (!!notification.onShow) {
+ notification.onShow({
+ type: ElectronNotificationEventType.Show,
+ id: notification.id,
+ close: onCloseNotificationSafely
+ });
+ }
+
+ if (!!notification.onClose) {
+ notificationWindow[onClickElectronNotification] =
+ notification.onClick;
+ } else {
+ delete notificationWindow[onClickElectronNotification];
+ }
+
+ if (!!notification.onClose) {
+ notificationWindow[onCloseElectronNotification] =
+ notification.onClose;
+ } else {
+ delete notificationWindow[onCloseElectronNotification];
+ }
+
+ notificationWindow.webContents.send(
+ Channel.browserWindowSetContents,
+ notification
+ );
+ notificationWindow.showInactive();
+ resolve(notificationWindow);
+ });
+ } else {
+ self.notificationQueue.push(notification);
+ resolve();
+ }
+ });
+ }
+
+ private buildCloseNotification(
+ notificationWindow: BrowserWindow,
+ notification: ElectronNotification,
+ timeoutIdFunc?: () => number
+ ) {
+ const self = this;
+ return (e: ElectronNotificationEventType): Promise => {
+ if (notificationWindow.isDestroyed()) {
+ return;
+ }
+
+ if (self.closedNotifications.has(notification.id)) {
+ self.closedNotifications.delete(notification.id);
+ return new Promise(resolve => {
+ resolve();
+ });
+ } else {
+ self.closedNotifications.set(notification.id, true);
+ }
+
+ if (!!notificationWindow[onCloseElectronNotification]) {
+ notificationWindow[onCloseElectronNotification]({
+ type: e,
+ id: notification.id
+ });
+ delete notificationWindow[onCloseElectronNotification];
+ }
+
+ notificationWindow.webContents.send(Channel.reset);
+
+ if (!!timeoutIdFunc) {
+ clearTimeout(timeoutIdFunc());
+ }
+ const i = self.activeNotifications.indexOf(notificationWindow);
+ self.activeNotifications.splice(i, 1);
+ self.inactiveWindows.push(notificationWindow);
+
+ notificationWindow.hide();
+ self.checkForQueuedNotifications();
+
+ return self.moveOneDown(i);
+ };
+ }
+
+ private buildCloseNotificationSafely(
+ onClose: (e: ElectronNotificationEventType) => any
+ ) {
+ const self = this;
+ return (reason: any) => {
+ if (!reason) {
+ reason = 'closedByAPI';
+ }
+ self.animationQueue.push({
+ context: self,
+ func: onClose,
+ args: [reason]
+ });
+ };
+ }
+
+ private checkForQueuedNotifications(): void {
+ if (
+ 0 < this.notificationQueue.length &&
+ this.activeNotifications.length < this.maxVisibleNotifications
+ ) {
+ this.animationQueue.push({
+ context: this,
+ func: this.showNotification,
+ args: [this.notificationQueue.shift()]
+ });
+ }
+ }
+
+ private getWindow(): Promise {
+ const slef = this;
+ return new Promise((resolve, reject) => {
+ if (0 < slef.inactiveWindows.length) {
+ resolve(slef.inactiveWindows.pop());
+ } else {
+ const windowProperties = slef.customOptions.defaultWindow;
+ windowProperties.width = slef.customOptions.width;
+ windowProperties.height = slef.customOptions.height;
+
+ const notificationWindow = new BrowserWindow(windowProperties);
+ notificationWindow.setVisibleOnAllWorkspaces(true);
+ notificationWindow.loadURL(slef.templatePath);
+ notificationWindow.webContents.on(
+ ElectronWebContentsChannel.DidFinishLoad,
+ () => {
+ // Done
+ notificationWindow.webContents.send(
+ Channel.loadConfig,
+ slef.customOptions
+ );
+ resolve(notificationWindow);
+ }
+ );
+ notificationWindow.webContents.on(
+ ElectronWebContentsChannel.DevtoolsOpened,
+ () => {
+ notificationWindow.webContents.closeDevTools();
+ }
+ );
+ }
+ });
+ }
+
+ private moveOneDown(startPos: number): Promise {
+ const self = this;
+ return new Promise(async (resolve, reject) => {
+ if (startPos >= self.activeNotifications.length || -1 === startPos) {
+ resolve();
+ return;
+ }
+
+ const aryNotificationPos: number[] = [];
+ for (let i = startPos; i < self.activeNotifications.length; i++) {
+ aryNotificationPos.push(i);
+ }
+
+ await Promise.all(
+ aryNotificationPos.map(async index => {
+ await self.moveNotificationAnimation(index);
+ })
+ );
+ resolve();
+ });
+ }
+
+ private moveNotificationAnimation(index: number): Promise {
+ const self = this;
+ return new Promise((resolve, reject) => {
+ const notificationWindow = self.activeNotifications[index];
+ const newY =
+ self.lowerRightCornerPosition.y -
+ self.totalDimension.height * (index + 1);
+ const startY = notificationWindow.getPosition()[1];
+ const step = (newY - startY) / self.customOptions.animationSteps;
+ let curStep = 1;
+ const animationInterval = setInterval(() => {
+ // Abort condition
+ if (curStep === self.customOptions.animationSteps) {
+ notificationWindow.setPosition(self.firstPosition.x, newY);
+ clearInterval(animationInterval);
+ return resolve();
+ }
+ // Move one step down
+ notificationWindow.setPosition(
+ self.firstPosition.x,
+ Math.trunc(startY + curStep * step)
+ );
+ curStep++;
+ }, self.customOptions.animationStepMs);
+ });
+ }
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/types/channel.type.ts b/projects/ucap-webmessenger-electron-notification/src/lib/types/channel.type.ts
new file mode 100644
index 00000000..088e0e91
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/types/channel.type.ts
@@ -0,0 +1,7 @@
+export enum Channel {
+ close = 'UCAP::ElectronNotification::close',
+ click = 'UCAP::ElectronNotification::click',
+ loadConfig = 'UCAP::ElectronNotification::loadConfig',
+ reset = 'UCAP::ElectronNotification::reset',
+ browserWindowSetContents = 'UCAP::ElectronNotification::BrowserWindowSetContents'
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/types/event.type.ts b/projects/ucap-webmessenger-electron-notification/src/lib/types/event.type.ts
new file mode 100644
index 00000000..2953e3ce
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/types/event.type.ts
@@ -0,0 +1,5 @@
+export enum ElectronNotificationEventType {
+ Show = 'Show',
+ Click = 'Click',
+ Close = 'Close'
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/lib/utils/animation-queue.ts b/projects/ucap-webmessenger-electron-notification/src/lib/utils/animation-queue.ts
new file mode 100644
index 00000000..c421f726
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/lib/utils/animation-queue.ts
@@ -0,0 +1,42 @@
+export interface AnimationQueueObject {
+ context: any;
+ func: (...args: any[]) => Promise;
+ args: any[];
+}
+
+export class AnimationQueue {
+ private running = false;
+ private queue: AnimationQueueObject[] = [];
+
+ push(o: AnimationQueueObject): void {
+ if (this.running) {
+ this.queue.push(o);
+ } else {
+ this.running = true;
+ this.animate(o);
+ }
+ }
+
+ animate(o: AnimationQueueObject): void {
+ const self = this;
+ try {
+ (o.func.apply(o.context, o.args) as Promise)
+ .then(() => {
+ if (self.queue.length > 0) {
+ self.animate.call(self, self.queue.shift());
+ } else {
+ self.running = false;
+ }
+ })
+ .catch(reason => {
+ console.log(reason);
+ });
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ clear(): void {
+ this.queue = [];
+ }
+}
diff --git a/projects/ucap-webmessenger-electron-notification/src/public-api.ts b/projects/ucap-webmessenger-electron-notification/src/public-api.ts
new file mode 100644
index 00000000..d09fea3e
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/public-api.ts
@@ -0,0 +1,13 @@
+/*
+ * Public API Surface of ucap-webmessenger-electron-notification
+ */
+
+export * from './lib/models/electron-notification-options';
+export * from './lib/models/electron-notification';
+
+export * from './lib/services/electron-notification.service';
+
+export * from './lib/types/channel.type';
+export * from './lib/types/event.type';
+
+export * from './lib/utils/animation-queue';
diff --git a/projects/ucap-webmessenger-electron-notification/src/test.ts b/projects/ucap-webmessenger-electron-notification/src/test.ts
new file mode 100644
index 00000000..978c64fb
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/src/test.ts
@@ -0,0 +1,21 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone';
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/projects/ucap-webmessenger-electron-notification/tsconfig.lib.json b/projects/ucap-webmessenger-electron-notification/tsconfig.lib.json
new file mode 100644
index 00000000..bd23948e
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/tsconfig.lib.json
@@ -0,0 +1,26 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/lib",
+ "target": "es2015",
+ "declaration": true,
+ "inlineSources": true,
+ "types": [],
+ "lib": [
+ "dom",
+ "es2018"
+ ]
+ },
+ "angularCompilerOptions": {
+ "annotateForClosureCompiler": true,
+ "skipTemplateCodegen": true,
+ "strictMetadataEmit": true,
+ "fullTemplateTypeCheck": true,
+ "strictInjectionParameters": true,
+ "enableResourceInlining": true
+ },
+ "exclude": [
+ "src/test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/projects/ucap-webmessenger-electron-notification/tsconfig.spec.json b/projects/ucap-webmessenger-electron-notification/tsconfig.spec.json
new file mode 100644
index 00000000..16da33db
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/tsconfig.spec.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../out-tsc/spec",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "src/test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/projects/ucap-webmessenger-electron-notification/tslint.json b/projects/ucap-webmessenger-electron-notification/tslint.json
new file mode 100644
index 00000000..e37a3555
--- /dev/null
+++ b/projects/ucap-webmessenger-electron-notification/tslint.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tslint.json",
+ "rules": {
+ "directive-selector": [
+ true,
+ "attribute",
+ "ucapElectronNotification",
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element",
+ "ucap-electron-notification",
+ "kebab-case"
+ ]
+ }
+}
diff --git a/projects/ucap-webmessenger-native-browser/src/lib/services/browser-native.service.ts b/projects/ucap-webmessenger-native-browser/src/lib/services/browser-native.service.ts
index a00afa78..17a18a6d 100644
--- a/projects/ucap-webmessenger-native-browser/src/lib/services/browser-native.service.ts
+++ b/projects/ucap-webmessenger-native-browser/src/lib/services/browser-native.service.ts
@@ -3,14 +3,15 @@ import { Observable } from 'rxjs';
import {
NativeService,
WindowState,
- NotiRequest,
+ NotificationRequest,
WindowIdle
} from '@ucap-webmessenger/native';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
export class BrowserNativeService implements NativeService {
- showNotify(noti: NotiRequest): void {}
+ notify(noti: NotificationRequest): void {}
+ closeAllNotify(): void {}
checkForUpdates(): Observable {
return new Observable(subscriber => {
diff --git a/projects/ucap-webmessenger-native-electron/src/lib/services/electron-native.service.ts b/projects/ucap-webmessenger-native-electron/src/lib/services/electron-native.service.ts
index a051e22d..1d3b967c 100644
--- a/projects/ucap-webmessenger-native-electron/src/lib/services/electron-native.service.ts
+++ b/projects/ucap-webmessenger-native-electron/src/lib/services/electron-native.service.ts
@@ -5,11 +5,17 @@ import { Observable, Subject } from 'rxjs';
import {
NativeService,
WindowState,
- NotiRequest,
+ NotificationRequest,
WindowIdle
} from '@ucap-webmessenger/native';
-import { Channel } from '../types/channel.type';
import { share } from 'rxjs/operators';
+import {
+ NotificationChannel,
+ UpdaterChannel,
+ FileChannel,
+ WindowStateChannel,
+ IdleStateChannel
+} from '../types/channel.type';
export class ElectronNativeService implements NativeService {
private windowStateChangedSubject: Subject | null = null;
@@ -18,22 +24,18 @@ export class ElectronNativeService implements NativeService {
private idleStateChangedSubject: Subject | null = null;
private idleStateChanged$: Observable | null = null;
- showNotify(noti: NotiRequest): void {
- ipcRenderer.send(
- Channel.showNotify,
- noti.roomSeq,
- noti.title,
- noti.contents,
- noti.image,
- noti.useSound,
- noti.interval
- );
+ notify(noti: NotificationRequest): void {
+ ipcRenderer.send(NotificationChannel.Notify, noti);
+ }
+
+ closeAllNotify(): void {
+ ipcRenderer.send(NotificationChannel.CloseAllNotify);
}
checkForUpdates(): Observable {
return new Observable(subscriber => {
try {
- subscriber.next(ipcRenderer.sendSync(Channel.checkForUpdates));
+ subscriber.next(ipcRenderer.sendSync(UpdaterChannel.Check));
} catch (error) {
subscriber.error(error);
} finally {
@@ -43,13 +45,13 @@ export class ElectronNativeService implements NativeService {
}
showImageViewer(): void {
- ipcRenderer.send(Channel.showImageViewer);
+ ipcRenderer.send(FileChannel.ShowImageViewer);
}
readFile(path: string): Observable {
return new Observable(subscriber => {
try {
- subscriber.next(ipcRenderer.sendSync(Channel.readFile, path));
+ subscriber.next(ipcRenderer.sendSync(FileChannel.ReadFile, path));
} catch (error) {
subscriber.error(error);
} finally {
@@ -66,7 +68,7 @@ export class ElectronNativeService implements NativeService {
return new Observable(subscriber => {
try {
subscriber.next(
- ipcRenderer.sendSync(Channel.saveFile, buffer, fileName, path)
+ ipcRenderer.sendSync(FileChannel.SaveFile, buffer, fileName, path)
);
} catch (error) {
subscriber.error(error);
@@ -85,9 +87,8 @@ export class ElectronNativeService implements NativeService {
}
ipcRenderer.on(
- Channel.windowStateChanged,
+ WindowStateChannel.Changed,
(event: IpcRendererEvent, windowState: WindowState) => {
- console.log('windowStateChanged', windowState);
this.windowStateChangedSubject.next(windowState);
}
);
@@ -133,10 +134,10 @@ export class ElectronNativeService implements NativeService {
.pipe(share());
}
- ipcRenderer.send(Channel.idleStateStart, 'start');
+ ipcRenderer.send(IdleStateChannel.StartCheck);
ipcRenderer.on(
- Channel.idleStateChanged,
+ IdleStateChannel.Changed,
(event: IpcRendererEvent, idleState: WindowIdle) => {
this.idleStateChangedSubject.next(idleState);
}
diff --git a/projects/ucap-webmessenger-native-electron/src/lib/types/channel.type.ts b/projects/ucap-webmessenger-native-electron/src/lib/types/channel.type.ts
index 89e518ad..c698832c 100644
--- a/projects/ucap-webmessenger-native-electron/src/lib/types/channel.type.ts
+++ b/projects/ucap-webmessenger-native-electron/src/lib/types/channel.type.ts
@@ -1,11 +1,23 @@
-export enum Channel {
- windowStateChanged = 'window-state-changed',
- idleStateChanged = 'window-idle-state-changed',
- idleStateStart = 'window-idle-state-check-start',
-
- showNotify = 'UCAP::showNotify',
- checkForUpdates = 'UCAP::checkForUpdates',
- showImageViewer = 'UCAP::showImageViewer',
- saveFile = 'UCAP::saveFile',
- readFile = 'UCAP::readFile'
+export enum NotificationChannel {
+ Notify = 'UCAP::notification::notify',
+ CloseAllNotify = 'UCAP::notification::closeAllNotify'
+}
+
+export enum UpdaterChannel {
+ Check = 'UCAP::updater::check'
+}
+
+export enum FileChannel {
+ ShowImageViewer = 'UCAP::file::showImageViewer',
+ SaveFile = 'UCAP::file::saveFile',
+ ReadFile = 'UCAP::file::readFile'
+}
+
+export enum WindowStateChannel {
+ Changed = 'UCAP::windowState::windowStateChanged'
+}
+
+export enum IdleStateChannel {
+ Changed = 'UCAP::idleState::changed',
+ StartCheck = 'UCAP::idleState::startCheck'
}
diff --git a/projects/ucap-webmessenger-native/src/lib/models/notification.ts b/projects/ucap-webmessenger-native/src/lib/models/notification.ts
new file mode 100644
index 00000000..3eb08394
--- /dev/null
+++ b/projects/ucap-webmessenger-native/src/lib/models/notification.ts
@@ -0,0 +1,8 @@
+export interface NotificationRequest {
+ roomSeq: string;
+ title: string;
+ contents: string;
+ image: string;
+ useSound: boolean;
+ interval?: number;
+}
diff --git a/projects/ucap-webmessenger-native/src/lib/services/native.service.ts b/projects/ucap-webmessenger-native/src/lib/services/native.service.ts
index bd9c01a0..94ed535f 100644
--- a/projects/ucap-webmessenger-native/src/lib/services/native.service.ts
+++ b/projects/ucap-webmessenger-native/src/lib/services/native.service.ts
@@ -2,9 +2,11 @@ import { Observable } from 'rxjs';
import { WindowState } from '../types/window-state.type';
import { WindowIdle } from '../types/window-idle.type';
+import { NotificationRequest } from '../models/notification';
export interface NativeService {
- showNotify(noti: NotiRequest): void;
+ notify(noti: NotificationRequest): void;
+ closeAllNotify(): void;
checkForUpdates(): Observable;
@@ -20,12 +22,3 @@ export interface NativeService {
idleStateChanged(): Observable;
}
-
-export interface NotiRequest {
- roomSeq: string;
- title: string;
- contents: string;
- image: string;
- useSound: boolean;
- interval?: number;
-}
diff --git a/projects/ucap-webmessenger-native/src/public-api.ts b/projects/ucap-webmessenger-native/src/public-api.ts
index bcd36c4f..54f16191 100644
--- a/projects/ucap-webmessenger-native/src/public-api.ts
+++ b/projects/ucap-webmessenger-native/src/public-api.ts
@@ -2,6 +2,8 @@
* Public API Surface of ucap-webmessenger-native
*/
+export * from './lib/models/notification';
+
export * from './lib/services/native.service';
export * from './lib/types/token';
diff --git a/tsconfig.json b/tsconfig.json
index f79668c2..18fcd298 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -125,6 +125,12 @@
],
"@ucap-webmessenger/util": [
"projects/ucap-webmessenger-util/src/public-api"
+ ],
+ "@ucap-webmessenger/electron-core": [
+ "projects/ucap-webmessenger-electron-core/src/public-api"
+ ],
+ "@ucap-webmessenger/electron-notification": [
+ "projects/ucap-webmessenger-electron-notification/src/public-api"
]
}
},