This commit is contained in:
leejinho 2019-12-24 14:59:08 +09:00
commit ffce78720b
40 changed files with 781 additions and 71 deletions

View File

@ -366,6 +366,40 @@
} }
} }
}, },
"ucap-webmessenger-enviroments": {
"projectType": "library",
"root": "projects/ucap-webmessenger-enviroments",
"sourceRoot": "projects/ucap-webmessenger-enviroments/src",
"prefix": "ucap-enviroments",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/ucap-webmessenger-enviroments/tsconfig.lib.json",
"project": "projects/ucap-webmessenger-enviroments/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ucap-webmessenger-enviroments/src/test.ts",
"tsConfig": "projects/ucap-webmessenger-enviroments/tsconfig.spec.json",
"karmaConfig": "projects/ucap-webmessenger-enviroments/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/ucap-webmessenger-enviroments/tsconfig.lib.json",
"projects/ucap-webmessenger-enviroments/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
}
},
"ucap-webmessenger-api-common": { "ucap-webmessenger-api-common": {
"projectType": "library", "projectType": "library",
"root": "projects/ucap-webmessenger-api-common", "root": "projects/ucap-webmessenger-api-common",

View File

@ -29,7 +29,8 @@ import { FileUtil } from './lib/file-util';
import { IdleChecker } from './lib/idle-checker'; import { IdleChecker } from './lib/idle-checker';
import { import {
NotificationRequest, NotificationRequest,
NotificationType NotificationType,
NativePathName
} from '@ucap-webmessenger/native'; } from '@ucap-webmessenger/native';
import { ElectronAppChannel } from '@ucap-webmessenger/electron-core'; import { ElectronAppChannel } from '@ucap-webmessenger/electron-core';
@ -524,6 +525,15 @@ ipcMain.on(
} }
); );
ipcMain.on(FileChannel.GetPath, async (event: IpcMainEvent, ...args: any[]) => {
try {
const name: NativePathName = args[0];
event.returnValue = app.getPath(name);
} catch (error) {
event.returnValue = undefined;
}
});
ipcMain.on( ipcMain.on(
IdleStateChannel.StartCheck, IdleStateChannel.StartCheck,
(event: IpcMainEvent, ...args: any[]) => { (event: IpcMainEvent, ...args: any[]) => {

6
package-lock.json generated
View File

@ -2285,6 +2285,12 @@
"axios": "*" "axios": "*"
} }
}, },
"@types/clone": {
"version": "0.1.30",
"resolved": "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz",
"integrity": "sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=",
"dev": true
},
"@types/copy-webpack-plugin": { "@types/copy-webpack-plugin": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-5.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-5.0.0.tgz",

View File

@ -72,6 +72,7 @@
"@ngx-translate/core": "^11.0.1", "@ngx-translate/core": "^11.0.1",
"@types/auto-launch": "^5.0.1", "@types/auto-launch": "^5.0.1",
"@types/axios": "^0.14.0", "@types/axios": "^0.14.0",
"@types/clone": "^0.1.30",
"@types/copy-webpack-plugin": "^5.0.0", "@types/copy-webpack-plugin": "^5.0.0",
"@types/crypto-js": "^3.1.43", "@types/crypto-js": "^3.1.43",
"@types/detect-browser": "^4.0.0", "@types/detect-browser": "^4.0.0",
@ -96,6 +97,7 @@
"awesome-typescript-loader": "^5.2.1", "awesome-typescript-loader": "^5.2.1",
"classlist.js": "^1.1.20150312", "classlist.js": "^1.1.20150312",
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"clone": "^2.1.2",
"copy-webpack-plugin": "^5.0.4", "copy-webpack-plugin": "^5.0.4",
"codelyzer": "^5.0.0", "codelyzer": "^5.0.0",
"concurrently": "^4.1.2", "concurrently": "^4.1.2",

View File

@ -2,20 +2,33 @@ import { NgModule } from '@angular/core';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native'; import {
UCAP_NATIVE_SERVICE,
NativeService,
NativeType
} from '@ucap-webmessenger/native';
import { environment } from '../environments/environment'; import { environment } from '../environments/environment';
export function createTranslateLoader(nativeService: NativeService) { export function createTranslateLoader(nativeService: NativeService) {
const translateLoader = nativeService.getTranslateLoader( let prefix: string;
environment.production
? '/dist/ucap-webmessenger-app/assets/i18n/'
: '/projects/ucap-webmessenger-app/src/assets/i18n/',
'.json'
);
// return new TranslateBrowserLoader(nativeService, './assets/i18n/', '.json'); switch (nativeService.type()) {
return translateLoader; case NativeType.Browser:
prefix = '/assets/i18n/';
break;
case NativeType.Electron:
prefix = environment.production
? '/dist/ucap-webmessenger-app/assets/i18n/'
: '/projects/ucap-webmessenger-app/src/assets/i18n/';
break;
default:
break;
}
return nativeService.getTranslateLoader(prefix, '.json');
} }
@NgModule({ @NgModule({

View File

@ -7,19 +7,15 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar'; import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { UCapUiModule } from '@ucap-webmessenger/ui'; import { UCapEnviromentsModule } from '@ucap-webmessenger/enviroments';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
import { UCapWebStorageModule } from '@ucap-webmessenger/web-storage'; import { UCapWebStorageModule } from '@ucap-webmessenger/web-storage';
import { UCapUtilModule } from '@ucap-webmessenger/util';
import { UCapCommonApiModule } from '@ucap-webmessenger/api-common'; import { UCapCommonApiModule } from '@ucap-webmessenger/api-common';
import { UCapExternalApiModule } from '@ucap-webmessenger/api-external'; import { UCapExternalApiModule } from '@ucap-webmessenger/api-external';
import { UCapMessageApiModule } from '@ucap-webmessenger/api-message'; import { UCapMessageApiModule } from '@ucap-webmessenger/api-message';
import { UCapPublicApiModule } from '@ucap-webmessenger/api-public'; import { UCapPublicApiModule } from '@ucap-webmessenger/api-public';
import { UCapPromptApiModule } from '@ucap-webmessenger/api-prompt'; import { UCapPromptApiModule } from '@ucap-webmessenger/api-prompt';
import { UCapPiModule } from '@ucap-webmessenger/pi'; import { UCapPiModule } from '@ucap-webmessenger/pi';
import { UCapProtocolModule } from '@ucap-webmessenger/protocol'; import { UCapProtocolModule } from '@ucap-webmessenger/protocol';
@ -34,6 +30,9 @@ import { UCapServiceProtocolModule } from '@ucap-webmessenger/protocol-service';
import { UCapStatusProtocolModule } from '@ucap-webmessenger/protocol-status'; import { UCapStatusProtocolModule } from '@ucap-webmessenger/protocol-status';
import { UCapSyncProtocolModule } from '@ucap-webmessenger/protocol-sync'; import { UCapSyncProtocolModule } from '@ucap-webmessenger/protocol-sync';
import { UCapUiModule } from '@ucap-webmessenger/ui';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
import { UCapDaesangModule } from '@ucap-webmessenger/daesang'; import { UCapDaesangModule } from '@ucap-webmessenger/daesang';
import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; import { LoggerModule, NgxLoggerLevel } from 'ngx-logger';
@ -90,7 +89,7 @@ import { environment } from '../environments/environment';
UCapWebStorageModule.forRoot(), UCapWebStorageModule.forRoot(),
UCapUtilModule.forRoot(), UCapEnviromentsModule.forRoot(),
AppProviderModule, AppProviderModule,
AppRoutingModule, AppRoutingModule,

View File

@ -60,6 +60,13 @@
</ng-template> </ng-template>
<ucap-settings-call class="setting-category"></ucap-settings-call> <ucap-settings-call class="setting-category"></ucap-settings-call>
</mat-tab> --> </mat-tab> -->
<mat-tab>
<ng-template mat-tab-label>
<span class="mdi mdi-chat"></span>
대화
</ng-template>
<ucap-settings-chat class="setting-category"></ucap-settings-chat>
</mat-tab>
</mat-tab-group> </mat-tab-group>
<!-- <div class="left-side-tabs-body"> <!-- <div class="left-side-tabs-body">

View File

@ -8,6 +8,8 @@ import {
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import clone from 'clone';
import { import {
DialogService, DialogService,
TranslateService as UCapTranslateService, TranslateService as UCapTranslateService,
@ -26,6 +28,8 @@ import {
} from '@ucap-webmessenger/ui-settings'; } from '@ucap-webmessenger/ui-settings';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native'; import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { ObjectUtil } from '@ucap-webmessenger/core';
import { OptionProtocolService } from '@ucap-webmessenger/protocol-option';
export interface MessengerSettingsDialogData {} export interface MessengerSettingsDialogData {}
@ -39,6 +43,9 @@ export interface MessengerSettingsDialogResult {}
export class MessengerSettingsDialogComponent implements OnInit { export class MessengerSettingsDialogComponent implements OnInit {
loginRes: LoginResponse; loginRes: LoginResponse;
sessionVerinfo: VersionInfo2Response; sessionVerinfo: VersionInfo2Response;
modifiedSettings: Settings;
appUserInfo: AppUserInfo; appUserInfo: AppUserInfo;
constructor( constructor(
@ -52,6 +59,7 @@ export class MessengerSettingsDialogComponent implements OnInit {
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService,
private ucapTranslateService: UCapTranslateService, private ucapTranslateService: UCapTranslateService,
private ucapDateService: UCapDateService, private ucapDateService: UCapDateService,
private optionProtocolService: OptionProtocolService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService, @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private translateService: TranslateService, private translateService: TranslateService,
private store: Store<any>, private store: Store<any>,
@ -63,6 +71,8 @@ export class MessengerSettingsDialogComponent implements OnInit {
environment.customConfig.appKey environment.customConfig.appKey
); );
this.modifiedSettings = clone(this.appUserInfo.settings);
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>( this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO KEY_VER_INFO
); );
@ -74,54 +84,70 @@ export class MessengerSettingsDialogComponent implements OnInit {
ngOnInit() {} ngOnInit() {}
onChangedGeneralSetting(setting: GeneralSetting) { onChangedGeneralSetting(setting: GeneralSetting) {
if (this.appUserInfo.settings.general.appTheme !== setting.appTheme) { this.applySettings(this.modifiedSettings, {
this.renderer2.setAttribute( ...this.appUserInfo.settings,
this.document.body, general: setting
'class', });
setting.appTheme
);
}
if (this.appUserInfo.settings.general.locale !== setting.locale) {
this.translateService.use(setting.locale);
}
if (
this.appUserInfo.settings.general.hrInfoLocale !== setting.hrInfoLocale
) {
this.ucapTranslateService.use(setting.hrInfoLocale);
}
if (this.appUserInfo.settings.general.timezone !== setting.timezone) {
this.ucapDateService.use(setting.timezone);
}
if (this.appUserInfo.settings.general.autoLaunch !== setting.autoLaunch) {
this.nativeService.changeAutoLaunch(setting.autoLaunch);
}
if (
this.appUserInfo.settings.general.startupHideWindow !==
setting.startupHideWindow
) {
this.nativeService.changeStartupHideWindow(setting.startupHideWindow);
}
this.applySettings({ ...this.appUserInfo.settings, general: setting });
} }
onChangedNotificationSetting(setting: NotificationSetting) { onChangedNotificationSetting(setting: NotificationSetting) {
this.applySettings({ ...this.appUserInfo.settings, notification: setting }); this.applySettings(this.modifiedSettings, {
...this.appUserInfo.settings,
notification: setting
});
} }
onClickChoice(choice: boolean): void { onClickChoice(choice: boolean): void {
this.dialogRef.close({}); if (choice) {
if (ObjectUtil.equals(this.appUserInfo.settings, this.modifiedSettings)) {
// There is not modified settings.
return;
} }
private applySettings(settings: Settings) { this.appUserInfo.settings = this.modifiedSettings;
this.appUserInfo.settings = settings;
this.localStorageService.encSet<AppUserInfo>( this.localStorageService.encSet<AppUserInfo>(
KEY_APP_USER_INFO, KEY_APP_USER_INFO,
this.appUserInfo, this.appUserInfo,
environment.customConfig.appKey environment.customConfig.appKey
); );
} else {
this.applySettings(this.modifiedSettings, this.appUserInfo.settings);
}
this.dialogRef.close({});
}
private applySettings(oriSettings: Settings, modSettings: Settings) {
if (oriSettings.general.appTheme !== modSettings.general.appTheme) {
this.renderer2.setAttribute(
this.document.body,
'class',
modSettings.general.appTheme
);
}
if (oriSettings.general.locale !== modSettings.general.locale) {
this.translateService.use(modSettings.general.locale);
}
if (oriSettings.general.hrInfoLocale !== modSettings.general.hrInfoLocale) {
this.ucapTranslateService.use(modSettings.general.hrInfoLocale);
}
if (oriSettings.general.timezone !== modSettings.general.timezone) {
this.ucapDateService.use(modSettings.general.timezone);
}
if (oriSettings.general.autoLaunch !== modSettings.general.autoLaunch) {
this.nativeService.changeAutoLaunch(modSettings.general.autoLaunch);
}
if (
oriSettings.general.startupHideWindow !==
modSettings.general.startupHideWindow
) {
this.nativeService.changeStartupHideWindow(
modSettings.general.startupHideWindow
);
}
oriSettings = modSettings;
} }
} }

View File

@ -1,6 +1,5 @@
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { EnviromentUtilService } from '@ucap-webmessenger/util';
import { DeviceType } from '@ucap-webmessenger/core'; import { DeviceType } from '@ucap-webmessenger/core';
import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types'; import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types';
import { AppNotificationService } from './notification.service'; import { AppNotificationService } from './notification.service';
@ -9,18 +8,21 @@ import { AppNativeService } from './native.service';
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui'; import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
import { DateService as UCapDateService } from '@ucap-webmessenger/ui'; import { DateService as UCapDateService } from '@ucap-webmessenger/ui';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { EnviromentsService } from '@ucap-webmessenger/enviroments';
import { NGXLogger } from 'ngx-logger';
@Injectable() @Injectable()
export class AppService { export class AppService {
constructor( constructor(
private enviromentUtilService: EnviromentUtilService, private enviromentsService: EnviromentsService,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private appNotificationService: AppNotificationService, private appNotificationService: AppNotificationService,
private appNativeService: AppNativeService, private appNativeService: AppNativeService,
private translateService: TranslateService, private translateService: TranslateService,
private ucapTranslateService: UCapTranslateService, private ucapTranslateService: UCapTranslateService,
private ucapDateService: UCapDateService, private ucapDateService: UCapDateService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private logger: NGXLogger
) { ) {
this.translateService.setDefaultLang('ko'); this.translateService.setDefaultLang('ko');
this.translateService.use('ko'); this.translateService.use('ko');
@ -37,16 +39,22 @@ export class AppService {
const initPromise = new Promise<void>((resolve, reject) => { const initPromise = new Promise<void>((resolve, reject) => {
try { try {
let deviceType: DeviceType; let deviceType: DeviceType;
if (this.enviromentUtilService.nodeWebkit()) { if (this.enviromentsService.nodeWebkit()) {
deviceType = DeviceType.PC; deviceType = DeviceType.PC;
} else if (this.enviromentUtilService.android()) { } else if (this.enviromentsService.android()) {
deviceType = DeviceType.Android; deviceType = DeviceType.Android;
} else if (this.enviromentUtilService.ios()) { } else if (this.enviromentsService.ios()) {
deviceType = DeviceType.iOS; deviceType = DeviceType.iOS;
} else { } else {
deviceType = DeviceType.Web; deviceType = DeviceType.Web;
} }
this.logger.info(
'platform is desktop ',
this.enviromentsService.desktop()
);
this.logger.info('native type is ', this.nativeService.type());
this.sessionStorageService.set<EnvironmentsInfo>( this.sessionStorageService.set<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO, KEY_ENVIRONMENTS_INFO,
{ {

View File

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { import {
SessionStorageService, SessionStorageService,
@ -18,6 +18,8 @@ import { DaesangCipherService } from '@ucap-webmessenger/daesang';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type'; import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { Settings } from '@ucap-webmessenger/ui-settings';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -28,6 +30,7 @@ export class AppAuthenticationService {
constructor( constructor(
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private daesangCipherService: DaesangCipherService private daesangCipherService: DaesangCipherService
) {} ) {}
@ -36,7 +39,7 @@ export class AppAuthenticationService {
return null !== loginInfo && !!loginInfo.loginId; return null !== loginInfo && !!loginInfo.loginId;
} }
login(loginInfo: LoginInfo, rememberMe: boolean, autoLogin: boolean) { async login(loginInfo: LoginInfo, rememberMe: boolean, autoLogin: boolean) {
loginInfo = { ...loginInfo, localeCode: LocaleCode.Korean }; loginInfo = { ...loginInfo, localeCode: LocaleCode.Korean };
const encLoginPw = this.daesangCipherService.encrypt( const encLoginPw = this.daesangCipherService.encrypt(
@ -59,7 +62,15 @@ export class AppAuthenticationService {
if (!appUserInfo) { if (!appUserInfo) {
appUserInfo = { appUserInfo = {
settings: environment.productConfig.defaultSettings settings: {
...environment.productConfig.defaultSettings,
chat: {
...environment.productConfig.defaultSettings.chat,
downloadPath: `${this.nativeService.getPath(
'documents'
)}/LG UCAP `
}
}
}; };
} }

View File

@ -53,6 +53,11 @@ export const environment: Environment = {
alertExposureTime: 5, alertExposureTime: 5,
receiveForMobile: false, receiveForMobile: false,
receiveForMessage: false receiveForMessage: false
},
chat: {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
} }
}, },
CommonSetting: { CommonSetting: {

View File

@ -53,6 +53,11 @@ export const environment: Environment = {
alertExposureTime: 5, alertExposureTime: 5,
receiveForMobile: false, receiveForMobile: false,
receiveForMessage: false receiveForMessage: false
},
chat: {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
} }
}, },
CommonSetting: { CommonSetting: {

View File

@ -53,6 +53,11 @@ export const environment: Environment = {
alertExposureTime: 5, alertExposureTime: 5,
receiveForMobile: false, receiveForMobile: false,
receiveForMessage: false receiveForMessage: false
},
chat: {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
} }
}, },
CommonSetting: { CommonSetting: {

View File

@ -53,6 +53,11 @@ export const environment: Environment = {
alertExposureTime: 5, alertExposureTime: 5,
receiveForMobile: false, receiveForMobile: false,
receiveForMessage: false receiveForMessage: false
},
chat: {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
} }
}, },
CommonSetting: { CommonSetting: {

View File

@ -0,0 +1,24 @@
# UcapWebmessengerEnviroments
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-enviroments` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ucap-webmessenger-enviroments`.
> Note: Don't forget to add `--project ucap-webmessenger-enviroments` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build ucap-webmessenger-enviroments` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build ucap-webmessenger-enviroments`, go to the dist folder `cd dist/ucap-webmessenger-enviroments` and run `npm publish`.
## Running unit tests
Run `ng test ucap-webmessenger-enviroments` 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).

View File

@ -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-enviroments'),
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
});
};

View File

@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ucap-webmessenger-enviroments",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@ -0,0 +1,8 @@
{
"name": "@ucap-webmessenger/enviroments",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^8.2.11",
"@angular/core": "^8.2.11"
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { EnviromentsService } from './enviroments.service';
describe('EnviromentsService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: EnviromentsService = TestBed.get(EnviromentsService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,185 @@
import { Injectable } from '@angular/core';
import { detect, BrowserInfo, BotInfo, NodeInfo } from 'detect-browser';
const deviceTypeList = ['mobile', 'tablet', 'desktop'];
const osTypeList = [
'ios',
'iphone',
'ipad',
'ipod',
'android',
'blackberry',
'macos',
'windows',
'fxos',
'meego',
'television'
];
@Injectable({
providedIn: 'root'
})
export class EnviromentsService {
private readonly userAgent: string;
constructor() {
this.userAgent = window.navigator.userAgent.toLowerCase();
}
public macos(): boolean {
return this.find('mac');
}
public ios(): boolean {
return this.iphone() || this.ipod() || this.ipad();
}
public iphone(): boolean {
return !this.windows() && this.find('iphone');
}
public ipod(): boolean {
return this.find('ipod');
}
public ipad(): boolean {
return this.find('ipad');
}
public android(): boolean {
return !this.windows() && this.find('android');
}
public androidPhone(): boolean {
return this.android() && this.find('mobile');
}
public androidTablet(): boolean {
return this.android() && !this.find('mobile');
}
public blackberry(): boolean {
return this.find('blackberry') || this.find('bb10') || this.find('rim');
}
public blackberryPhone(): boolean {
return this.blackberry() && !this.find('tablet');
}
public blackberryTablet(): boolean {
return this.blackberry() && this.find('tablet');
}
public windows(): boolean {
return this.find('windows');
}
public windowsPhone(): boolean {
return this.windows() && this.find('phone');
}
public windowsTablet(): boolean {
return this.windows() && this.find('touch') && !this.windowsPhone();
}
public fxos(): boolean {
return (this.find('(mobile') || this.find('(tablet')) && this.find(' rv:');
}
public fxosPhone(): boolean {
return this.fxos() && this.find('mobile');
}
public fxosTablet(): boolean {
return this.fxos() && this.find('tablet');
}
public meego(): boolean {
return this.find('meego');
}
public cordova(): boolean {
return (window as any).cordova && location.protocol === 'file:';
}
public nodeWebkit(): boolean {
return typeof (window as any).process === 'object';
}
public mobile(): boolean {
return (
this.androidPhone() ||
this.iphone() ||
this.ipod() ||
this.windowsPhone() ||
this.blackberryPhone() ||
this.fxosPhone() ||
this.meego()
);
}
public tablet(): boolean {
return (
this.ipad() ||
this.androidTablet() ||
this.blackberryTablet() ||
this.windowsTablet() ||
this.fxosTablet()
);
}
public desktop(): boolean {
return !this.tablet() && !this.mobile();
}
public portrait(): boolean {
if (
screen.orientation &&
Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
) {
return this.includes(screen.orientation.type, 'portrait');
}
return window.innerHeight / window.innerWidth > 1;
}
public landscape(): boolean {
if (
screen.orientation &&
Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
) {
return this.includes(screen.orientation.type, 'landscape');
}
return window.innerHeight / window.innerWidth < 1;
}
public type(): string {
return this.findMatch(deviceTypeList);
}
public os(): string {
return this.findMatch(osTypeList);
}
public browser(): BrowserInfo | BotInfo | NodeInfo {
return detect();
}
private includes(haystack: string, needle: string): boolean {
return haystack.indexOf(needle) !== -1;
}
private find(needle: string): boolean {
return this.includes(this.userAgent, needle);
}
private findMatch(arr: string[]): string {
for (const item of arr) {
if (this[item]()) {
return item;
}
}
return 'unknown';
}
}

View File

@ -0,0 +1,23 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
const COMPONENTS = [];
const DIALOGS = [];
const DIRECTIVES = [];
const PIPES = [];
const SERVICES = [];
@NgModule({
imports: [CommonModule],
exports: [...COMPONENTS, ...DIRECTIVES, ...PIPES],
declarations: [...COMPONENTS, ...DIALOGS, ...DIRECTIVES, ...PIPES],
entryComponents: [...DIALOGS]
})
export class UCapEnviromentsModule {
public static forRoot(): ModuleWithProviders<UCapEnviromentsModule> {
return {
ngModule: UCapEnviromentsModule,
providers: [...SERVICES]
};
}
}

View File

@ -0,0 +1,7 @@
/*
* Public API Surface of ucap-webmessenger-enviroments
*/
export * from './lib/services/enviroments.service';
export * from './lib/ucap-enviroments.module';

View File

@ -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);

View File

@ -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"
]
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,17 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"ucapEnviroments",
"camelCase"
],
"component-selector": [
true,
"element",
"ucap-enviroments",
"kebab-case"
]
}
}

View File

@ -7,10 +7,12 @@ import {
WindowIdle, WindowIdle,
UpdateInfo, UpdateInfo,
UpdateCheckConfig, UpdateCheckConfig,
NotificationType NotificationType,
NativePathName,
NativeType
} from '@ucap-webmessenger/native'; } from '@ucap-webmessenger/native';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { map, share } from 'rxjs/operators'; import { map, share, take } from 'rxjs/operators';
import { TranslateLoader } from '@ngx-translate/core'; import { TranslateLoader } from '@ngx-translate/core';
import { TranslateLoaderService } from '../translate/browser-loader'; import { TranslateLoaderService } from '../translate/browser-loader';
import { NotificationService } from '../notification/notification.service'; import { NotificationService } from '../notification/notification.service';
@ -29,6 +31,10 @@ export class BrowserNativeService extends NativeService {
private msgOpenMessageSubject: Subject<string> | null = null; private msgOpenMessageSubject: Subject<string> | null = null;
private msgOpenMessage$: Observable<string> | null = null; private msgOpenMessage$: Observable<string> | null = null;
type(): NativeType {
return NativeType.Browser;
}
postAppInit(): void { postAppInit(): void {
this.notificationService.requestPermission(); this.notificationService.requestPermission();
} }
@ -119,7 +125,12 @@ export class BrowserNativeService extends NativeService {
readFile(path: string): Promise<Buffer> { readFile(path: string): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => { return new Promise<Buffer>((resolve, reject) => {
resolve(null); this.httpClient
.get(path, { responseType: 'arraybuffer' })
.pipe(take(1))
.subscribe(arraybuffer => {
resolve(Buffer.from(arraybuffer));
});
}); });
} }
@ -156,6 +167,12 @@ export class BrowserNativeService extends NativeService {
}); });
} }
getPath(name: NativePathName): Promise<string> {
return new Promise<string>((resolve, reject) => {
resolve('');
});
}
windowStateChanged(): Observable<WindowState> { windowStateChanged(): Observable<WindowState> {
return new Observable<WindowState>(subscriber => { return new Observable<WindowState>(subscriber => {
try { try {

View File

@ -15,7 +15,7 @@ export class TranslateLoaderService implements TranslateLoader {
public getTranslation(lang: string): Observable<any> { public getTranslation(lang: string): Observable<any> {
return new Observable<any>(subscriber => { return new Observable<any>(subscriber => {
this.nativeService this.nativeService
.readFile(`${this.prefix}${lang}.${this.suffix}`) .readFile(`${this.prefix}${lang}${this.suffix}`)
.then(buffer => { .then(buffer => {
subscriber.next(JSON.parse(buffer.toString('utf-8'))); subscriber.next(JSON.parse(buffer.toString('utf-8')));
}) })

View File

@ -8,7 +8,9 @@ import {
NotificationRequest, NotificationRequest,
WindowIdle, WindowIdle,
UpdateInfo, UpdateInfo,
UpdateCheckConfig UpdateCheckConfig,
NativePathName,
NativeType
} from '@ucap-webmessenger/native'; } from '@ucap-webmessenger/native';
import { share } from 'rxjs/operators'; import { share } from 'rxjs/operators';
import { import {
@ -58,6 +60,10 @@ export class ElectronNativeService implements NativeService {
private backgroundCheckForUpdatesSubject: Subject<UpdateInfo> | null = null; private backgroundCheckForUpdatesSubject: Subject<UpdateInfo> | null = null;
private backgroundCheckForUpdates$: Observable<UpdateInfo> | null = null; private backgroundCheckForUpdates$: Observable<UpdateInfo> | null = null;
type(): NativeType {
return NativeType.Electron;
}
postAppInit(): void {} postAppInit(): void {}
logout(): Observable<void> { logout(): Observable<void> {
@ -263,6 +269,15 @@ export class ElectronNativeService implements NativeService {
} }
}); });
} }
getPath(name: NativePathName): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
resolve(this.ipcRenderer.sendSync(FileChannel.GetPath, name));
} catch (error) {
reject(error);
}
});
}
windowStateChanged(): Observable<WindowState> { windowStateChanged(): Observable<WindowState> {
if (!this.windowStateChangedSubject) { if (!this.windowStateChangedSubject) {

View File

@ -32,7 +32,8 @@ export enum FileChannel {
OpenFolderItem = 'UCAP::file::openFolderItem', OpenFolderItem = 'UCAP::file::openFolderItem',
ShowImageViewer = 'UCAP::file::showImageViewer', ShowImageViewer = 'UCAP::file::showImageViewer',
SaveFile = 'UCAP::file::saveFile', SaveFile = 'UCAP::file::saveFile',
ReadFile = 'UCAP::file::readFile' ReadFile = 'UCAP::file::readFile',
GetPath = 'UCAP::file::getPath'
} }
export enum WindowStateChannel { export enum WindowStateChannel {

View File

@ -6,8 +6,18 @@ import { NotificationRequest } from '../models/notification';
import { TranslateLoader } from '@ngx-translate/core'; import { TranslateLoader } from '@ngx-translate/core';
import { StatusCode } from '@ucap-webmessenger/core'; import { StatusCode } from '@ucap-webmessenger/core';
import { UpdateInfo, UpdateCheckConfig } from '../models/update-info'; import { UpdateInfo, UpdateCheckConfig } from '../models/update-info';
import { NativeType } from '../types/native.type';
export type NativePathName =
| 'home'
| 'documents'
| 'downloads'
| 'music'
| 'pictures'
| 'videos';
export abstract class NativeService { export abstract class NativeService {
abstract type(): NativeType;
abstract postAppInit(): void; abstract postAppInit(): void;
abstract logout(): Observable<void>; abstract logout(): Observable<void>;
@ -45,6 +55,7 @@ export abstract class NativeService {
make?: boolean make?: boolean
): Promise<boolean>; ): Promise<boolean>;
abstract openTargetItem(filePath?: string): Promise<boolean>; abstract openTargetItem(filePath?: string): Promise<boolean>;
abstract getPath(name: NativePathName): Promise<string>;
abstract windowStateChanged(): Observable<WindowState>; abstract windowStateChanged(): Observable<WindowState>;
abstract windowClose(): void; abstract windowClose(): void;

View File

@ -0,0 +1,6 @@
export enum NativeType {
/** 브라우저 */
Browser = 'Browser',
/** Electron */
Electron = 'Electron'
}

View File

@ -6,6 +6,7 @@ export * from './lib/types/notification.type';
export * from './lib/types/token'; export * from './lib/types/token';
export * from './lib/types/window-state.type'; export * from './lib/types/window-state.type';
export * from './lib/types/window-idle.type'; export * from './lib/types/window-idle.type';
export * from './lib/types/native.type';
export * from './lib/models/notification'; export * from './lib/models/notification';
export * from './lib/models/update-info'; export * from './lib/models/update-info';

View File

@ -0,0 +1,48 @@
<div>
<mat-list>
<h1 mat-subheader>대화</h1>
<mat-list-item>
<span class="item-title">글꼴</span>
<span class="item-input">
<mat-form-field>
<mat-select
[value]="setting.fontFamily"
(selectionChange)="onSelectionChangeFontFamily($event)"
>
<mat-option value="Malgun Gothic">
맑은 고딕
</mat-option>
</mat-select>
</mat-form-field>
</span>
</mat-list-item>
<mat-list-item>
<span class="item-title">크기</span>
<span class="item-input">
<mat-form-field>
<mat-select
[value]="setting.fontSize"
(selectionChange)="onSelectionChangeFontSize($event)"
>
<mat-option
*ngFor="let fontSize of [8, 9, 10, 11, 12, 13, 14, 15, 16, 18]"
value="{{ fontSize }}"
>
fontSize
</mat-option>
</mat-select>
</mat-form-field>
</span>
</mat-list-item>
<mat-divider></mat-divider>
<h1 mat-subheader>파일 전송</h1>
<mat-list-item>
<mat-form-field fxFlexFill>
<input matInput placeholder="다운로드 폴더" value="" readonly />
<input type="file" #downloadPathInput style="display: none" />
</mat-form-field>
</mat-list-item>
</mat-list>
</div>

View File

@ -0,0 +1,7 @@
.item-title {
width: 25rem;
}
.item-input {
width: 20rem;
}

View File

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChatComponent } from './chat.component';
describe('Settings::ChatComponent', () => {
let component: ChatComponent;
let fixture: ComponentFixture<ChatComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ChatComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChatComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,51 @@
import {
Component,
OnInit,
ChangeDetectorRef,
Input,
Output,
EventEmitter
} from '@angular/core';
import { NGXLogger } from 'ngx-logger';
import { MatSelectChange } from '@angular/material';
import { EnviromentsService } from '@ucap-webmessenger/enviroments';
import { ChatSetting } from '../models/settings';
@Component({
selector: 'ucap-settings-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss']
})
export class ChatComponent implements OnInit {
@Input()
setting: ChatSetting;
@Output()
changed = new EventEmitter<ChatSetting>();
private readonly isDesktop = false;
private readonly isBrowser = false;
constructor(
private enviromentsService: EnviromentsService,
private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger
) {}
ngOnInit() {}
onSelectionChangeFontFamily(event: MatSelectChange) {
this.emit({ ...this.setting, fontFamily: event.value });
}
onSelectionChangeFontSize(event: MatSelectChange) {
this.emit({ ...this.setting, fontSize: Number(event.value) });
}
private emit(setting: ChatSetting) {
this.setting = setting;
this.changed.emit(this.setting);
}
}

View File

@ -17,7 +17,14 @@ export interface NotificationSetting {
receiveForMessage: boolean; receiveForMessage: boolean;
} }
export interface ChatSetting {
fontFamily: string;
fontSize: number;
downloadPath: string;
}
export interface Settings { export interface Settings {
general: GeneralSetting; general: GeneralSetting;
notification: NotificationSetting; notification: NotificationSetting;
chat: ChatSetting;
} }

View File

@ -6,6 +6,7 @@ import { FlexLayoutModule } from '@angular/flex-layout';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list'; import { MatListModule } from '@angular/material/list';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatSlideToggleModule } from '@angular/material/slide-toggle';
@ -18,6 +19,7 @@ import { GeneralComponent } from './components/general.component';
import { NotificationComponent } from './components/notification.component'; import { NotificationComponent } from './components/notification.component';
import { PermissionComponent } from './components/permission.component'; import { PermissionComponent } from './components/permission.component';
import { PrivacyComponent } from './components/privacy.component'; import { PrivacyComponent } from './components/privacy.component';
import { ChatComponent } from './components/chat.component';
const COMPONENTS = [ const COMPONENTS = [
CallComponent, CallComponent,
@ -25,7 +27,8 @@ const COMPONENTS = [
GeneralComponent, GeneralComponent,
NotificationComponent, NotificationComponent,
PermissionComponent, PermissionComponent,
PrivacyComponent PrivacyComponent,
ChatComponent
]; ];
const SERVICES = []; const SERVICES = [];
@ -36,6 +39,7 @@ const SERVICES = [];
FlexLayoutModule, FlexLayoutModule,
MatCheckboxModule, MatCheckboxModule,
MatFormFieldModule, MatFormFieldModule,
MatInputModule,
MatListModule, MatListModule,
MatSelectModule, MatSelectModule,
MatSlideToggleModule, MatSlideToggleModule,

View File

@ -18,6 +18,9 @@
"@ucap-webmessenger/core": [ "@ucap-webmessenger/core": [
"projects/ucap-webmessenger-core/src/public-api" "projects/ucap-webmessenger-core/src/public-api"
], ],
"@ucap-webmessenger/enviroments": [
"projects/ucap-webmessenger-enviroments/src/public-api"
],
"@ucap-webmessenger/api": [ "@ucap-webmessenger/api": [
"projects/ucap-webmessenger-api/src/public-api" "projects/ucap-webmessenger-api/src/public-api"
], ],