project initialized
This commit is contained in:
commit
c17f98928c
13
.editorconfig
Normal file
13
.editorconfig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"Angular.ng-template",
|
||||||
|
"msjsdiag.debugger-for-chrome",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||||
|
"VisualStudioExptTeam.vscodeintellicode",
|
||||||
|
"nkokhelox.svg-font-previewer"
|
||||||
|
]
|
||||||
|
}
|
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": []
|
||||||
|
}
|
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.autoClosingBrackets": "languageDefined",
|
||||||
|
"editor.trimAutoWhitespace": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.trimFinalNewlines": true,
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/dist": true
|
||||||
|
},
|
||||||
|
"go.testFlags": ["-v"],
|
||||||
|
"go.testTimeout": "100s",
|
||||||
|
"debug.node.autoAttach": "on"
|
||||||
|
}
|
15
.vscode/tasks.json
vendored
Normal file
15
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "build:main:dev",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# MMessengerLg
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.0.6.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## 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).
|
37
config/webpack.config.js
Normal file
37
config/webpack.config.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const path = require('path');
|
||||||
|
const webpackNodeExternals = require('webpack-node-externals');
|
||||||
|
|
||||||
|
const rootPath = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
mode: process.env.ENV || 'development',
|
||||||
|
entry: path.join(rootPath, 'src', 'main'),
|
||||||
|
target: 'electron-main',
|
||||||
|
devtool: 'source-map',
|
||||||
|
externals: [webpackNodeExternals()],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
configFile: path.join(rootPath, 'tsconfig.app.json')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
exclude: /node_modules/
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.join(rootPath, 'dist'),
|
||||||
|
filename: 'electron-main.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
9256
package-lock.json
generated
Normal file
9256
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
55
package.json
Normal file
55
package.json
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"name": "ucap-lg-desktop",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "npm run build && electron --nolazy --inspect-brk=9229 ./dist/electron-main.js",
|
||||||
|
"build": "webpack --config ./config/webpack.config.js"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@tsed/core": "^5.44.11",
|
||||||
|
"@tsed/di": "^5.44.11",
|
||||||
|
"@ucap/electron-core": "~0.0.1",
|
||||||
|
"auto-launch": "^5.0.5",
|
||||||
|
"electron-log": "^4.1.0",
|
||||||
|
"electron-store": "^5.1.1",
|
||||||
|
"electron-updater": "^4.2.5",
|
||||||
|
"electron-window-state": "^5.0.3",
|
||||||
|
"fs-extra": "^9.0.0",
|
||||||
|
"rxjs": "^6.5.4",
|
||||||
|
"semver": "^7.1.3",
|
||||||
|
"tmp": "^0.1.0",
|
||||||
|
"tslib": "^1.10.0",
|
||||||
|
"v8-compile-cache": "^2.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^12.11.1",
|
||||||
|
"@types/jasmine": "~3.5.0",
|
||||||
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"devtron": "^1.4.0",
|
||||||
|
"electron": "^8.1.1",
|
||||||
|
"electron-builder": "^22.4.1",
|
||||||
|
"electron-debug": "^3.0.1",
|
||||||
|
"electron-devtools-installer": "^2.2.4",
|
||||||
|
"electron-reload": "^1.5.0",
|
||||||
|
"i18next": "^19.3.3",
|
||||||
|
"jasmine-core": "~3.5.0",
|
||||||
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
"karma": "~4.3.0",
|
||||||
|
"karma-chrome-launcher": "~3.1.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "~2.1.0",
|
||||||
|
"karma-jasmine": "~2.0.1",
|
||||||
|
"karma-jasmine-html-reporter": "^1.4.2",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"protractor": "~5.4.3",
|
||||||
|
"ts-loader": "^6.2.1",
|
||||||
|
"ts-node": "~8.3.0",
|
||||||
|
"tslint": "~5.18.0",
|
||||||
|
"typescript": "~3.7.5",
|
||||||
|
"webpack": "^4.42.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-merge": "^4.2.2",
|
||||||
|
"webpack-node-externals": "^1.7.2"
|
||||||
|
}
|
||||||
|
}
|
51
src/app/app.ts
Normal file
51
src/app/app.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
|
||||||
|
import log from 'electron-log';
|
||||||
|
|
||||||
|
import { AppChannel } from '@ucap/electron-core';
|
||||||
|
import { AppLoader } from '../common/app/app-loader';
|
||||||
|
import { AppSettings } from '../common/app/decorators/app-settings';
|
||||||
|
import { On } from '../common/app/decorators/on';
|
||||||
|
|
||||||
|
import { AppWindow } from './app.window';
|
||||||
|
import { BrowserWindowRegistry } from '../common/browser-window/registries/browser-window.registry';
|
||||||
|
|
||||||
|
@AppSettings({
|
||||||
|
bootstrap: AppWindow
|
||||||
|
})
|
||||||
|
export class App extends AppLoader {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(AppChannel.SecondInstance)
|
||||||
|
onSecondInstance(event: Event, argv: string[], workingDirectory: string) {
|
||||||
|
log.info('AppChannel.SecondInstance');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(AppChannel.Ready)
|
||||||
|
onReady(launchInfo: any) {
|
||||||
|
log.info('AppChannel.Ready');
|
||||||
|
|
||||||
|
this.createMainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(AppChannel.Activate)
|
||||||
|
onActivate(event: Event, hasVisibleWindows: boolean) {
|
||||||
|
log.info('AppChannel.Activate');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(AppChannel.WindowAllClosed)
|
||||||
|
onWindowAllClosed() {
|
||||||
|
log.info('AppChannel.WindowAllClosed');
|
||||||
|
}
|
||||||
|
|
||||||
|
private createMainWindow() {
|
||||||
|
const bootstrap = this.settings.get('bootstrap');
|
||||||
|
|
||||||
|
const provider = BrowserWindowRegistry.get(bootstrap);
|
||||||
|
const i = provider.useFactory(this.electronApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createTrayIcon() {}
|
||||||
|
}
|
106
src/app/app.window.ts
Normal file
106
src/app/app.window.ts
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
import log from 'electron-log';
|
||||||
|
import * as windowStateKeeper from 'electron-window-state';
|
||||||
|
|
||||||
|
import { BrowserWindow } from '../common/browser-window/decorators/browser-window';
|
||||||
|
import { On } from '../common/browser-window/decorators/on';
|
||||||
|
import { BrowserWindowChannel, AppChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
const MIN_WIDTH = 700;
|
||||||
|
const MIN_HEIGHT = 600;
|
||||||
|
const DEFAULT_WIDTH = 1160;
|
||||||
|
const DEFAULT_HEIGHT = 800;
|
||||||
|
|
||||||
|
let savedWindowState: windowStateKeeper.State;
|
||||||
|
|
||||||
|
@BrowserWindow({
|
||||||
|
constructorOptions: {
|
||||||
|
minWidth: MIN_WIDTH,
|
||||||
|
minHeight: MIN_HEIGHT,
|
||||||
|
center: true,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
webPreferences: {
|
||||||
|
// Disable auxclick event
|
||||||
|
// See https://developers.google.com/web/updates/2016/10/auxclick
|
||||||
|
disableBlinkFeatures: 'Auxclick',
|
||||||
|
// Enable, among other things, the ResizeObserver
|
||||||
|
experimentalFeatures: true,
|
||||||
|
nodeIntegration: true
|
||||||
|
},
|
||||||
|
acceptFirstMouse: true
|
||||||
|
},
|
||||||
|
beforeConstructor: constructorOptions => {
|
||||||
|
savedWindowState = windowStateKeeper({
|
||||||
|
defaultWidth: DEFAULT_WIDTH,
|
||||||
|
defaultHeight: DEFAULT_HEIGHT
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...constructorOptions,
|
||||||
|
x: savedWindowState.x,
|
||||||
|
y: savedWindowState.y,
|
||||||
|
width: savedWindowState.width,
|
||||||
|
height: savedWindowState.height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class AppWindow {
|
||||||
|
constructor(
|
||||||
|
private app: Electron.App,
|
||||||
|
private window: Electron.BrowserWindow
|
||||||
|
) {
|
||||||
|
savedWindowState.manage(this.window);
|
||||||
|
|
||||||
|
this.attachHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.ReadyToShow)
|
||||||
|
onReadyToShow() {
|
||||||
|
log.info('BrowserWindowChannel.ReadyToShow');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Close)
|
||||||
|
onClose(event: Event) {
|
||||||
|
log.info('BrowserWindowChannel.Close');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Focus)
|
||||||
|
onFocus() {
|
||||||
|
log.info('BrowserWindowChannel.Focus');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Blur)
|
||||||
|
onBlur() {
|
||||||
|
log.info('BrowserWindowChannel.Blur');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Minimize)
|
||||||
|
onMinimize() {
|
||||||
|
log.info('BrowserWindowChannel.Minimize');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Maximize)
|
||||||
|
onMaximize() {
|
||||||
|
log.info('BrowserWindowChannel.Maximize');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Unmaximize)
|
||||||
|
onUnmaximize() {
|
||||||
|
log.info('BrowserWindowChannel.Unmaximize');
|
||||||
|
}
|
||||||
|
|
||||||
|
@On(BrowserWindowChannel.Closed)
|
||||||
|
onClosed() {
|
||||||
|
log.info('BrowserWindowChannel.Closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachHandlers() {
|
||||||
|
this.attachAppHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachAppHandlers() {
|
||||||
|
this.app.on(AppChannel.BeforeQuit, (event: Electron.Event) => {
|
||||||
|
log.info('AppChannel.BeforeQuit');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
114
src/common/app/app-loader.ts
Normal file
114
src/common/app/app-loader.ts
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import { Type, constructorOf, Store } from '@tsed/core';
|
||||||
|
import { GlobalProviders, InjectorService, registerProvider } from '@tsed/di';
|
||||||
|
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
|
||||||
|
import { AppOptions } from './decorators/app-settings';
|
||||||
|
import { AppSettingsService } from './services/app-settings.service';
|
||||||
|
import { ELECTRON_APP } from './types/electron-app';
|
||||||
|
import {
|
||||||
|
AppProviderMetadata,
|
||||||
|
AppEventHandlerMetadata
|
||||||
|
} from './models/app-provider.metadata';
|
||||||
|
import { createElectronApp } from './utils/electron';
|
||||||
|
import { ElectronApp } from './decorators/electron-app';
|
||||||
|
|
||||||
|
export abstract class AppLoader {
|
||||||
|
readonly injector: InjectorService;
|
||||||
|
private startedAt = new Date();
|
||||||
|
|
||||||
|
constructor(settings: Partial<AppOptions> = {}) {
|
||||||
|
// create injector with initial configuration
|
||||||
|
this.injector = this.createInjector(this.getConfiguration(this, settings));
|
||||||
|
|
||||||
|
createElectronApp(this.injector);
|
||||||
|
this.attachEventHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
get settings(): AppSettingsService {
|
||||||
|
return this.injector.settings as AppSettingsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
get electronApp(): Electron.App {
|
||||||
|
return this.injector.get<ElectronApp>(ElectronApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async bootstrap<App extends AppLoader>(
|
||||||
|
module: Type<App>,
|
||||||
|
settings: Partial<AppOptions> = {}
|
||||||
|
): Promise<App> {
|
||||||
|
const app = new module(settings);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(): Promise<any> {
|
||||||
|
try {
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createInjector(settings: Partial<AppOptions> = {}) {
|
||||||
|
const injector = new InjectorService();
|
||||||
|
injector.settings = this.createSettingsService(injector);
|
||||||
|
// injector.logger = $log;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
injector.settings.set(settings);
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (injector.settings.env === 'test') {
|
||||||
|
injector.logger.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSettingsService(injector: InjectorService): AppSettingsService {
|
||||||
|
const provider = GlobalProviders.get(AppSettingsService)!.clone();
|
||||||
|
|
||||||
|
provider.instance = injector.invoke<AppSettingsService>(provider.useClass);
|
||||||
|
injector.addProvider(AppSettingsService, provider);
|
||||||
|
|
||||||
|
return provider.instance as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getConfiguration(module: any, configuration: any = {}) {
|
||||||
|
const provider = GlobalProviders.get(constructorOf(module))!;
|
||||||
|
|
||||||
|
return { ...provider.configuration, ...configuration };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async invoke(
|
||||||
|
instance: any,
|
||||||
|
handlerMetadata: AppEventHandlerMetadata,
|
||||||
|
args: any[]
|
||||||
|
): Promise<any> {
|
||||||
|
const { methodClassName } = handlerMetadata;
|
||||||
|
|
||||||
|
return await instance[methodClassName](...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachEventHandler() {
|
||||||
|
const handlerMetadata: AppProviderMetadata = Store.from(this).get(
|
||||||
|
ELECTRON_APP
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!handlerMetadata || !handlerMetadata.handlers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const __this = this;
|
||||||
|
|
||||||
|
for (const handler in handlerMetadata.handlers) {
|
||||||
|
if (handlerMetadata.handlers.hasOwnProperty(handler)) {
|
||||||
|
const metadata = handlerMetadata.handlers[handler];
|
||||||
|
|
||||||
|
Electron.app.on(metadata.channel as any, (...args: any[]) => {
|
||||||
|
__this.invoke(__this, metadata, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/common/app/decorators/app-settings.ts
Normal file
12
src/common/app/decorators/app-settings.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Type, Store } from '@tsed/core';
|
||||||
|
import { IModuleOptions, registerProvider, Module } from '@tsed/di';
|
||||||
|
|
||||||
|
export const APP_OPTIONS = Symbol.for('APP_OPTIONS');
|
||||||
|
|
||||||
|
export interface AppOptions extends IModuleOptions {
|
||||||
|
bootstrap?: Type<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AppSettings(options?: AppOptions): Function {
|
||||||
|
return Module({ ...options, root: true });
|
||||||
|
}
|
19
src/common/app/decorators/electron-app.ts
Normal file
19
src/common/app/decorators/electron-app.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
import { Type } from '@tsed/core';
|
||||||
|
import { Inject } from '@tsed/di';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace Electron {
|
||||||
|
interface App {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ElectronApp = Electron.App;
|
||||||
|
|
||||||
|
export function ElectronApp(
|
||||||
|
target: Type<any>,
|
||||||
|
targetKey: string,
|
||||||
|
descriptor: TypedPropertyDescriptor<Function> | number
|
||||||
|
) {
|
||||||
|
return Inject(ElectronApp)(target, targetKey, descriptor);
|
||||||
|
}
|
18
src/common/app/decorators/on.ts
Normal file
18
src/common/app/decorators/on.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { Store } from '@tsed/core';
|
||||||
|
|
||||||
|
import { AppChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
import { ELECTRON_APP } from '../types/electron-app';
|
||||||
|
|
||||||
|
export function On(channel: AppChannel) {
|
||||||
|
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
||||||
|
Store.from(target).merge(ELECTRON_APP, {
|
||||||
|
handlers: {
|
||||||
|
[propertyKey]: {
|
||||||
|
channel,
|
||||||
|
methodClassName: propertyKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
12
src/common/app/models/app-provider.metadata.ts
Normal file
12
src/common/app/models/app-provider.metadata.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { AppChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
export interface AppEventHandlerMetadata {
|
||||||
|
channel: AppChannel;
|
||||||
|
methodClassName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppProviderMetadata {
|
||||||
|
handlers: {
|
||||||
|
[propertyKey: string]: AppEventHandlerMetadata;
|
||||||
|
};
|
||||||
|
}
|
16
src/common/app/services/app-settings.service.ts
Normal file
16
src/common/app/services/app-settings.service.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import {
|
||||||
|
DIConfiguration,
|
||||||
|
Injectable,
|
||||||
|
ProviderScope,
|
||||||
|
ProviderType
|
||||||
|
} from '@tsed/di';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
scope: ProviderScope.SINGLETON,
|
||||||
|
global: true
|
||||||
|
})
|
||||||
|
export class AppSettingsService extends DIConfiguration {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
1
src/common/app/types/electron-app.ts
Normal file
1
src/common/app/types/electron-app.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const ELECTRON_APP = Symbol.for('ELECTRON_APP');
|
20
src/common/app/utils/electron.ts
Normal file
20
src/common/app/utils/electron.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { InjectorService, ProviderScope, registerProvider } from '@tsed/di';
|
||||||
|
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
|
||||||
|
import { ElectronApp } from '../decorators/electron-app';
|
||||||
|
|
||||||
|
export function createElectronApp(injector: InjectorService): void {
|
||||||
|
injector.forkProvider(ElectronApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProvider({
|
||||||
|
provide: ElectronApp,
|
||||||
|
scope: ProviderScope.SINGLETON,
|
||||||
|
global: true,
|
||||||
|
useFactory() {
|
||||||
|
const app = Electron.app;
|
||||||
|
app.allowRendererProcessReuse = true;
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
});
|
64
src/common/browser-window/decorators/browser-window.ts
Normal file
64
src/common/browser-window/decorators/browser-window.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
import { registerBrowserWindow } from '../registries/browser-window.registry';
|
||||||
|
import { Store } from '@tsed/core';
|
||||||
|
import { ELECTRON_BROWSER_WINDOW } from '../types/electron-browser-window';
|
||||||
|
import {
|
||||||
|
BrowserWindowEventHandlerMetadata,
|
||||||
|
BrowserWindowProviderMetadata
|
||||||
|
} from '../models/browser-window-provider.metadata';
|
||||||
|
|
||||||
|
export interface BrowserWindowOptions {
|
||||||
|
constructorOptions?: Electron.BrowserWindowConstructorOptions;
|
||||||
|
beforeConstructor?: (
|
||||||
|
constructorOptions: Electron.BrowserWindowConstructorOptions
|
||||||
|
) => Electron.BrowserWindowConstructorOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BrowserWindow(options?: BrowserWindowOptions): Function {
|
||||||
|
return (target: any): void => {
|
||||||
|
registerBrowserWindow({
|
||||||
|
provide: target,
|
||||||
|
useFactory(app: Electron.App) {
|
||||||
|
options = options || {};
|
||||||
|
let constructorOptions = options.constructorOptions || {};
|
||||||
|
|
||||||
|
if (!!options.beforeConstructor) {
|
||||||
|
constructorOptions = options.beforeConstructor(constructorOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
const window = new Electron.BrowserWindow(constructorOptions);
|
||||||
|
|
||||||
|
const w = new target(app, window);
|
||||||
|
|
||||||
|
const providerMetadata: BrowserWindowProviderMetadata = Store.from(
|
||||||
|
w
|
||||||
|
).get(ELECTRON_BROWSER_WINDOW);
|
||||||
|
|
||||||
|
if (!!providerMetadata && !!providerMetadata.handlers) {
|
||||||
|
const __this = w;
|
||||||
|
const invoke = async (
|
||||||
|
instance: any,
|
||||||
|
handlerMetadata: BrowserWindowEventHandlerMetadata,
|
||||||
|
args: any[]
|
||||||
|
) => {
|
||||||
|
const { methodClassName } = handlerMetadata;
|
||||||
|
|
||||||
|
return await instance[methodClassName](...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const handler in providerMetadata.handlers) {
|
||||||
|
if (providerMetadata.handlers.hasOwnProperty(handler)) {
|
||||||
|
const metadata = providerMetadata.handlers[handler];
|
||||||
|
|
||||||
|
window.on(metadata.channel as any, (...args: any[]) => {
|
||||||
|
invoke(__this, metadata, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
18
src/common/browser-window/decorators/on.ts
Normal file
18
src/common/browser-window/decorators/on.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { Store } from '@tsed/core';
|
||||||
|
|
||||||
|
import { BrowserWindowChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
import { ELECTRON_BROWSER_WINDOW } from '../types/electron-browser-window';
|
||||||
|
|
||||||
|
export function On(channel: BrowserWindowChannel) {
|
||||||
|
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
||||||
|
Store.from(target).merge(ELECTRON_BROWSER_WINDOW, {
|
||||||
|
handlers: {
|
||||||
|
[propertyKey]: {
|
||||||
|
channel,
|
||||||
|
methodClassName: propertyKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { BrowserWindowChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
export interface BrowserWindowEventHandlerMetadata {
|
||||||
|
channel: BrowserWindowChannel;
|
||||||
|
methodClassName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrowserWindowProviderMetadata {
|
||||||
|
handlers: {
|
||||||
|
[propertyKey: string]: BrowserWindowEventHandlerMetadata;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Provider, GlobalProviders, TypedProvidersRegistry } from '@tsed/di';
|
||||||
|
|
||||||
|
export const PROVIDER_TYPE_BROWSER_WINDOW = 'BrowserWindow';
|
||||||
|
|
||||||
|
export const BrowserWindowRegistry: TypedProvidersRegistry = GlobalProviders.createRegistry(
|
||||||
|
PROVIDER_TYPE_BROWSER_WINDOW,
|
||||||
|
Provider
|
||||||
|
);
|
||||||
|
|
||||||
|
export const registerBrowserWindow = GlobalProviders.createRegisterFn(
|
||||||
|
PROVIDER_TYPE_BROWSER_WINDOW
|
||||||
|
);
|
|
@ -0,0 +1 @@
|
||||||
|
export const ELECTRON_BROWSER_WINDOW = Symbol.for('ELECTRON_BROWSER_WINDOW');
|
17
src/main.ts
Normal file
17
src/main.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import log from 'electron-log';
|
||||||
|
import { AppLoader } from './common/app/app-loader';
|
||||||
|
import { App } from './app/app';
|
||||||
|
|
||||||
|
async function bootstrap() {
|
||||||
|
try {
|
||||||
|
log.debug('Start app...');
|
||||||
|
const app = await AppLoader.bootstrap(App);
|
||||||
|
|
||||||
|
await app.start();
|
||||||
|
log.debug('App initialized');
|
||||||
|
} catch (er) {
|
||||||
|
log.error(er);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap();
|
9
tsconfig.app.json
Normal file
9
tsconfig.app.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": ["src/main.ts"],
|
||||||
|
"include": ["src/**/*.d.ts"]
|
||||||
|
}
|
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "es2015",
|
||||||
|
"lib": ["es2018", "dom"],
|
||||||
|
"types": ["node"],
|
||||||
|
"paths": {
|
||||||
|
"@app/*": ["src/app/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"fullTemplateTypeCheck": true,
|
||||||
|
"strictInjectionParameters": true
|
||||||
|
}
|
||||||
|
}
|
18
tsconfig.spec.json
Normal file
18
tsconfig.spec.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
91
tslint.json
Normal file
91
tslint.json
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
"extends": "tslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"array-type": false,
|
||||||
|
"arrow-parens": false,
|
||||||
|
"deprecation": {
|
||||||
|
"severity": "warning"
|
||||||
|
},
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"contextual-lifecycle": true,
|
||||||
|
"directive-class-suffix": true,
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"app",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"app",
|
||||||
|
"kebab-case"
|
||||||
|
],
|
||||||
|
"import-blacklist": [
|
||||||
|
true,
|
||||||
|
"rxjs/Rx"
|
||||||
|
],
|
||||||
|
"interface-name": false,
|
||||||
|
"max-classes-per-file": false,
|
||||||
|
"max-line-length": [
|
||||||
|
true,
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"static-method",
|
||||||
|
"instance-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-consecutive-blank-lines": false,
|
||||||
|
"no-console": [
|
||||||
|
true,
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"time",
|
||||||
|
"timeEnd",
|
||||||
|
"trace"
|
||||||
|
],
|
||||||
|
"no-empty": false,
|
||||||
|
"no-inferrable-types": [
|
||||||
|
true,
|
||||||
|
"ignore-params"
|
||||||
|
],
|
||||||
|
"no-non-null-assertion": true,
|
||||||
|
"no-redundant-jsdoc": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-var-requires": false,
|
||||||
|
"object-literal-key-quotes": [
|
||||||
|
true,
|
||||||
|
"as-needed"
|
||||||
|
],
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"trailing-comma": false,
|
||||||
|
"no-conflicting-lifecycle": true,
|
||||||
|
"no-host-metadata-property": true,
|
||||||
|
"no-input-rename": true,
|
||||||
|
"no-inputs-metadata-property": true,
|
||||||
|
"no-output-native": true,
|
||||||
|
"no-output-on-prefix": true,
|
||||||
|
"no-output-rename": true,
|
||||||
|
"no-outputs-metadata-property": true,
|
||||||
|
"template-banana-in-box": true,
|
||||||
|
"template-no-negated-async": true,
|
||||||
|
"use-lifecycle-interface": true,
|
||||||
|
"use-pipe-transform-interface": true
|
||||||
|
},
|
||||||
|
"rulesDirectory": [
|
||||||
|
"codelyzer"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user