settings is modified

This commit is contained in:
병준 박 2019-12-24 16:16:13 +09:00
parent 8ed5c11300
commit 23cd003795
24 changed files with 209 additions and 122 deletions

View File

@ -1,4 +1,12 @@
import { app, ipcMain, IpcMainEvent, Tray, Menu, shell } from 'electron';
import {
app,
ipcMain,
IpcMainEvent,
Tray,
Menu,
shell,
dialog
} from 'electron';
import path from 'path';
import fse from 'fs-extra';
import semver from 'semver';
@ -22,7 +30,6 @@ import { ElectronNotificationService } from '@ucap-webmessenger/electron-notific
import { ElectronUpdateWindowService } from '@ucap-webmessenger/electron-update-window';
import { root } from './util/root';
import { DefaultFolder } from './lib/default-folder';
import { FileUtil } from './lib/file-util';
import { IdleChecker } from './lib/idle-checker';
@ -453,7 +460,7 @@ ipcMain.on(
const fileName: string = args[1];
const mimeType: string = args[2];
let savePath: string = path.join(
!!args[3] ? args[3] : DefaultFolder.downloads(),
!!args[3] ? args[3] : app.getPath('downloads'),
fileName
);
savePath = await FileUtil.uniqueFileName(savePath);
@ -478,7 +485,7 @@ ipcMain.on(
let folderItem: string = args[0];
const make: boolean = args[1];
if (!folderItem) {
folderItem = DefaultFolder.downloads();
folderItem = app.getPath('downloads');
}
let isSuccess = true;
@ -512,6 +519,23 @@ ipcMain.on(FileChannel.GetPath, async (event: IpcMainEvent, ...args: any[]) => {
}
});
ipcMain.on(
FileChannel.SelectDirectory,
(event: IpcMainEvent, ...args: any[]) => {
dialog
.showOpenDialog(appWindow.browserWindow, {
defaultPath: app.getPath('home'),
properties: ['openDirectory']
})
.then(value => {
event.returnValue = value.filePaths[0];
})
.catch(reason => {
event.returnValue = undefined;
});
}
);
ipcMain.on(
IdleStateChannel.StartCheck,
(event: IpcMainEvent, ...args: any[]) => {

View File

@ -1,37 +0,0 @@
import * as os from 'os';
import { execSync } from 'child_process';
import * as fse from 'fs-extra';
export class DefaultFolder {
static downloads(): string {
switch (os.platform()) {
case 'win32':
return `${process.env.USERPROFILE}/Downloads`;
case 'darwin':
return `${process.env.HOME}/Downloads`;
case 'linux': {
let dir: Buffer;
try {
dir = execSync('xdg-user-dir DOWNLOAD', { stdio: [0, 3, 3] });
} catch (_) {}
if (dir) {
return dir.toString('utf-8');
}
let stat: fse.Stats;
const homeDownloads = `${process.env.HOME}/Downloads`;
try {
stat = fse.statSync(homeDownloads);
} catch (_) {}
if (stat) {
return homeDownloads;
}
return '/tmp/';
}
default:
break;
}
}
}

View File

@ -65,7 +65,11 @@
<span class="mdi mdi-chat"></span>
대화
</ng-template>
<ucap-settings-chat class="setting-category"></ucap-settings-chat>
<ucap-settings-chat
[setting]="appUserInfo.settings.chat"
(changed)="onChangedChatSetting($event)"
class="setting-category"
></ucap-settings-chat>
</mat-tab>
</mat-tab-group>

View File

@ -17,14 +17,19 @@ import {
} from '@ucap-webmessenger/ui';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { map } from 'rxjs/operators';
import { map, take } from 'rxjs/operators';
import { DOCUMENT } from '@angular/common';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import {
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '@app/types/environment.type';
import { environment } from '../../../../../environments/environment';
import {
GeneralSetting,
Settings,
NotificationSetting
NotificationSetting,
ChatSetting
} from '@ucap-webmessenger/ui-settings';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { TranslateService } from '@ngx-translate/core';
@ -43,6 +48,7 @@ export interface MessengerSettingsDialogResult {}
export class MessengerSettingsDialogComponent implements OnInit {
loginRes: LoginResponse;
sessionVerinfo: VersionInfo2Response;
environmentsInfo: EnvironmentsInfo;
modifiedSettings: Settings;
@ -76,6 +82,9 @@ export class MessengerSettingsDialogComponent implements OnInit {
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO
);
this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO
);
this.loginRes = this.sessionStorageService.get<LoginResponse>(
KEY_LOGIN_RES_INFO
);
@ -84,32 +93,59 @@ export class MessengerSettingsDialogComponent implements OnInit {
ngOnInit() {}
onChangedGeneralSetting(setting: GeneralSetting) {
this.applySettings(this.modifiedSettings, {
this.modifiedSettings = this.applySettings(this.modifiedSettings, {
...this.appUserInfo.settings,
general: setting
});
}
onChangedNotificationSetting(setting: NotificationSetting) {
this.applySettings(this.modifiedSettings, {
this.modifiedSettings = this.applySettings(this.modifiedSettings, {
...this.appUserInfo.settings,
notification: setting
});
}
onClickChoice(choice: boolean): void {
if (choice) {
if (ObjectUtil.equals(this.appUserInfo.settings, this.modifiedSettings)) {
// There is not modified settings.
return;
onChangedChatSetting(setting: ChatSetting) {
this.modifiedSettings = this.applySettings(this.modifiedSettings, {
...this.appUserInfo.settings,
chat: setting
});
}
onClickChoice(choice: boolean): void {
if (choice) {
if (
!ObjectUtil.equals(this.appUserInfo.settings, this.modifiedSettings)
) {
this.optionProtocolService
.regUpdate({
absenceTime: this.modifiedSettings.presence.absenceTime,
deviceType: this.environmentsInfo.deviceType,
fontFamily: this.modifiedSettings.chat.fontFamily,
fontSize: this.modifiedSettings.chat.fontSize,
hrInformationLanguage: this.modifiedSettings.general.hrInfoLocale,
menuLanguage: this.modifiedSettings.general.locale,
mobileNotification: this.modifiedSettings.notification
.receiveForMobile,
notificationExposureTime: this.modifiedSettings.notification
.alertExposureTime,
notificationMethod: this.modifiedSettings.notification.method,
notificationMethod0: this.modifiedSettings.notification.method,
receiveNotification: this.modifiedSettings.notification.use,
timeZone: this.modifiedSettings.general.timezone,
timeZoneValue: '0'
})
.pipe(take(1))
.subscribe(res => {
this.appUserInfo.settings = this.modifiedSettings;
this.localStorageService.encSet<AppUserInfo>(
KEY_APP_USER_INFO,
this.appUserInfo,
environment.customConfig.appKey
);
});
}
} else {
this.applySettings(this.modifiedSettings, this.appUserInfo.settings);
}
@ -117,7 +153,10 @@ export class MessengerSettingsDialogComponent implements OnInit {
this.dialogRef.close({});
}
private applySettings(oriSettings: Settings, modSettings: Settings) {
private applySettings(
oriSettings: Settings,
modSettings: Settings
): Settings {
if (oriSettings.general.appTheme !== modSettings.general.appTheme) {
this.renderer2.setAttribute(
this.document.body,
@ -148,6 +187,6 @@ export class MessengerSettingsDialogComponent implements OnInit {
);
}
oriSettings = modSettings;
return modSettings;
}
}

View File

@ -49,12 +49,6 @@ export class AppService {
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>(
KEY_ENVIRONMENTS_INFO,
{

View File

@ -66,7 +66,7 @@ export class AppAuthenticationService {
...environment.productConfig.defaultSettings,
chat: {
...environment.productConfig.defaultSettings.chat,
downloadPath: `${this.nativeService.getPath(
downloadPath: `${await this.nativeService.getPath(
'documents'
)}/LG UCAP `
}

View File

@ -99,6 +99,7 @@ import { LocalStorageService } from '@ucap-webmessenger/web-storage';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
import { environment } from '../../environments/environment';
import { NotificationMethod } from '@ucap-webmessenger/core';
@Injectable()
export class AppNotificationService {
@ -183,10 +184,12 @@ export class AppNotificationService {
noti.message
),
image: '',
useSound:
'SOUND' === appUserInfo.settings.notification.method ||
'SOUND_ALERT' ===
appUserInfo.settings.notification.method
useSound: [
NotificationMethod.Sound,
NotificationMethod.SoundAndAlert
].some(
n => n === appUserInfo.settings.notification.method
)
? true
: false,
displayTime:
@ -535,9 +538,10 @@ export class AppNotificationService {
title: '쪽지가 도착했습니다.',
contents: noti.text,
image: noti.senderInfo.profileImageFile,
useSound:
'SOUND' === appUserInfo.settings.notification.method ||
'SOUND_ALERT' === appUserInfo.settings.notification.method
useSound: [
NotificationMethod.Sound,
NotificationMethod.SoundAndAlert
].some(n => n === appUserInfo.settings.notification.method)
? true
: false,
displayTime:

View File

@ -11,12 +11,7 @@ export const reducer = createReducer(
reg: action.res
};
}),
on(regUpdateSuccess, (state, action) => {
return {
...state,
reg: action.res
};
}),
on(AuthenticationStore.logoutInitialize, (state, action) => {
return {
...initialState

View File

@ -9,7 +9,7 @@ import {
messageApiUrls,
promptUrls
} from './environment.type';
import { DeviceType } from '@ucap-webmessenger/core';
import { DeviceType, NotificationMethod } from '@ucap-webmessenger/core';
export const environment: Environment = {
production: false,
@ -49,7 +49,7 @@ export const environment: Environment = {
},
notification: {
use: true,
method: 'SOUND_ALERT',
method: NotificationMethod.SoundAndAlert,
alertExposureTime: 5,
receiveForMobile: false,
receiveForMessage: false
@ -58,6 +58,9 @@ export const environment: Environment = {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
},
presence: {
absenceTime: 10
}
},
CommonSetting: {

View File

@ -9,7 +9,7 @@ import {
messageApiUrls,
promptUrls
} from './environment.type';
import { DeviceType } from '@ucap-webmessenger/core';
import { DeviceType, NotificationMethod } from '@ucap-webmessenger/core';
export const environment: Environment = {
production: true,
@ -49,7 +49,7 @@ export const environment: Environment = {
},
notification: {
use: true,
method: 'SOUND_ALERT',
method: NotificationMethod.SoundAndAlert,
alertExposureTime: 5,
receiveForMobile: false,
receiveForMessage: false
@ -58,6 +58,9 @@ export const environment: Environment = {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
},
presence: {
absenceTime: 10
}
},
CommonSetting: {

View File

@ -9,7 +9,7 @@ import {
messageApiUrls,
promptUrls
} from './environment.type';
import { DeviceType } from '@ucap-webmessenger/core';
import { DeviceType, NotificationMethod } from '@ucap-webmessenger/core';
export const environment: Environment = {
production: false,
@ -49,7 +49,7 @@ export const environment: Environment = {
},
notification: {
use: true,
method: 'SOUND_ALERT',
method: NotificationMethod.SoundAndAlert,
alertExposureTime: 5,
receiveForMobile: false,
receiveForMessage: false
@ -58,6 +58,9 @@ export const environment: Environment = {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
},
presence: {
absenceTime: 10
}
},
CommonSetting: {

View File

@ -9,7 +9,7 @@ import {
messageApiUrls,
promptUrls
} from './environment.type';
import { DeviceType } from '@ucap-webmessenger/core';
import { DeviceType, NotificationMethod } from '@ucap-webmessenger/core';
export const environment: Environment = {
production: true,
@ -49,7 +49,7 @@ export const environment: Environment = {
},
notification: {
use: true,
method: 'SOUND_ALERT',
method: NotificationMethod.SoundAndAlert,
alertExposureTime: 5,
receiveForMobile: false,
receiveForMessage: false
@ -58,6 +58,9 @@ export const environment: Environment = {
fontFamily: 'Malgun Gothic',
fontSize: 12,
downloadPath: undefined
},
presence: {
absenceTime: 10
}
},
CommonSetting: {

View File

@ -167,6 +167,12 @@ export class BrowserNativeService extends NativeService {
});
}
selectDirectory(): Promise<string> {
return new Promise<string>((resolve, reject) => {
resolve('');
});
}
windowStateChanged(): Observable<WindowState> {
return new Observable<WindowState>(subscriber => {
try {

View File

@ -269,6 +269,16 @@ export class ElectronNativeService implements NativeService {
});
}
selectDirectory(): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
resolve(this.ipcRenderer.sendSync(FileChannel.SelectDirectory));
} catch (error) {
reject(error);
}
});
}
windowStateChanged(): Observable<WindowState> {
if (!this.windowStateChangedSubject) {
this.windowStateChangedSubject = new Subject<WindowState>();

View File

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

View File

@ -54,6 +54,7 @@ export abstract class NativeService {
): Promise<boolean>;
abstract openTargetItem(filePath?: string): Promise<boolean>;
abstract getPath(name: NativePathName): Promise<string>;
abstract selectDirectory(): Promise<string>;
abstract windowStateChanged(): Observable<WindowState>;
abstract windowClose(): void;

View File

@ -15,27 +15,27 @@ export interface RegUpdateRequest extends ProtocolRequest {
// 0 알림방법(n)
notificationMethod: NotificationMethod;
// 1 모바일알림(n)
mobileNotification: number;
mobileNotification: boolean;
// 2 폰트종류(s)
fontFamily: string;
// 3 폰트크기(n)
fontSize: number;
// 4 알림받음/받지않음(n)
receiveNotification: number;
receiveNotification: boolean;
// 5 알림방법(n)
notificationMethod0: number;
// 6 알림창 설정(n)
notificationExposureTime: number;
// 7 타임존(s)
timeZone: string;
// 8 타임존(s)
// 8 타임존(s)
timeZoneValue: string;
// 9 부재중시간설정(n)
absenceTime: number;
// 10 메뉴 언어(n)
menuLanguage: number;
menuLanguage: string;
// 11 인사정보 언어(n)
hrInformationLanguage: number;
hrInformationLanguage: string;
deviceType: DeviceType;
}
@ -43,13 +43,13 @@ export interface RegUpdateResponse extends ProtocolResponse {
// 0 알림방법(n)
notificationMethod?: NotificationMethod;
// 1 모바일알림(n)
mobileNotification?: number;
mobileNotification?: boolean;
// 2 폰트종류(s)
fontFamily?: string;
// 3 폰트크기(n)
fontSize?: number;
// 4 알림받음/받지않음(n)
receiveNotification?: number;
receiveNotification?: boolean;
// 5 알림방법(n)
notificationMethod0?: number;
// 6 알림창 설정(n)
@ -61,9 +61,9 @@ export interface RegUpdateResponse extends ProtocolResponse {
// 9 부재중시간설정(n)
absenceTime?: number;
// 10 메뉴 언어(n)
menuLanguage?: number;
menuLanguage?: string;
// 11 인사정보 언어(n)
hrInformationLanguage?: number;
hrInformationLanguage?: string;
// 12 단말타입(s)
deviceType?: DeviceType;
// 13 번역키
@ -81,7 +81,7 @@ export const encodeRegUpdate: ProtocolEncoder<RegUpdateRequest> = (
});
bodyList.push({
type: PacketBodyValue.Integer,
value: req.mobileNotification
value: req.mobileNotification ? 1 : 0
});
bodyList.push({
type: PacketBodyValue.String,
@ -93,7 +93,7 @@ export const encodeRegUpdate: ProtocolEncoder<RegUpdateRequest> = (
});
bodyList.push({
type: PacketBodyValue.Integer,
value: req.receiveNotification
value: req.receiveNotification ? 1 : 0
});
bodyList.push({
type: PacketBodyValue.Integer,
@ -116,11 +116,11 @@ export const encodeRegUpdate: ProtocolEncoder<RegUpdateRequest> = (
value: req.absenceTime
});
bodyList.push({
type: PacketBodyValue.Integer,
type: PacketBodyValue.String,
value: req.menuLanguage
});
bodyList.push({
type: PacketBodyValue.Integer,
type: PacketBodyValue.String,
value: req.hrInformationLanguage
});
bodyList.push({
@ -136,10 +136,10 @@ export const decodeRegUpdate: ProtocolDecoder<RegUpdateResponse> = (
) => {
return decodeProtocolMessage(message, {
notificationMethod: message.bodyList[0] as NotificationMethod,
mobileNotification: message.bodyList[1],
mobileNotification: message.bodyList[1] === 1 ? true : false,
fontFamily: message.bodyList[2],
fontSize: message.bodyList[3],
receiveNotification: message.bodyList[4],
receiveNotification: message.bodyList[4] === 1 ? true : false,
notificationMethod0: message.bodyList[5],
notificationExposureTime: message.bodyList[6],
timeZone: message.bodyList[7],

View File

@ -167,6 +167,7 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
}
self.fileInput.nativeElement.value = '';
this.fileInput.nativeElement.onchange = undefined;
};
}

View File

@ -21,14 +21,14 @@
<span class="item-input">
<mat-form-field>
<mat-select
[value]="setting.fontSize"
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
{{ fontSize }}
</mat-option>
</mat-select>
</mat-form-field>
@ -37,11 +37,16 @@
<mat-divider></mat-divider>
<h1 mat-subheader>파일 전송</h1>
<mat-list-item>
<h1 mat-subheader *ngIf="_isNodeWebkit">파일 전송</h1>
<mat-list-item *ngIf="_isNodeWebkit">
<mat-form-field fxFlexFill>
<input matInput placeholder="다운로드 폴더" value="" readonly />
<input type="file" #downloadPathInput style="display: none" />
<input
matInput
placeholder="다운로드 폴더"
[value]="setting.downloadPath"
readonly
(click)="onClickDownloadPath()"
/>
</mat-form-field>
</mat-list-item>
</mat-list>

View File

@ -4,7 +4,10 @@ import {
ChangeDetectorRef,
Input,
Output,
EventEmitter
EventEmitter,
ViewChild,
ElementRef,
Inject
} from '@angular/core';
import { NGXLogger } from 'ngx-logger';
import { MatSelectChange } from '@angular/material';
@ -12,6 +15,7 @@ import { MatSelectChange } from '@angular/material';
import { EnviromentsService } from '@ucap-webmessenger/enviroments';
import { ChatSetting } from '../models/settings';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
@Component({
selector: 'ucap-settings-chat',
@ -25,14 +29,17 @@ export class ChatComponent implements OnInit {
@Output()
changed = new EventEmitter<ChatSetting>();
private readonly isDesktop = false;
private readonly isBrowser = false;
// tslint:disable-next-line: variable-name
readonly _isNodeWebkit: boolean;
constructor(
private enviromentsService: EnviromentsService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger
) {}
) {
this._isNodeWebkit = this.enviromentsService.nodeWebkit();
}
ngOnInit() {}
@ -44,6 +51,16 @@ export class ChatComponent implements OnInit {
this.emit({ ...this.setting, fontSize: Number(event.value) });
}
onClickDownloadPath() {
this.logger.debug('onClickDownloadPath');
this.nativeService
.selectDirectory()
.then(path => {
this.emit({ ...this.setting, downloadPath: path });
})
.catch(reason => {});
}
private emit(setting: ChatSetting) {
this.setting = setting;
this.changed.emit(this.setting);

View File

@ -1,3 +1,5 @@
import { NotificationMethod } from '@ucap-webmessenger/core';
export interface GeneralSetting {
appTheme: string;
autoLaunch: boolean;
@ -11,7 +13,7 @@ export interface GeneralSetting {
export interface NotificationSetting {
use: boolean;
method: 'SOUND' | 'ALERT' | 'SOUND_ALERT';
method: NotificationMethod;
alertExposureTime: number;
receiveForMobile: boolean;
receiveForMessage: boolean;
@ -23,8 +25,13 @@ export interface ChatSetting {
downloadPath: string;
}
export interface PresenceSetting {
absenceTime: number;
}
export interface Settings {
general: GeneralSetting;
notification: NotificationSetting;
chat: ChatSetting;
presence: PresenceSetting;
}

View File

@ -1,11 +1,12 @@
import { Injectable } from '@angular/core';
import { StorageService } from './storage.service';
import { NGXLogger } from 'ngx-logger';
@Injectable({
providedIn: 'root'
})
export class LocalStorageService extends StorageService {
constructor() {
super(localStorage);
constructor(logger: NGXLogger) {
super(localStorage, logger);
}
}

View File

@ -1,11 +1,12 @@
import { Injectable } from '@angular/core';
import { StorageService } from './storage.service';
import { NGXLogger } from 'ngx-logger';
@Injectable({
providedIn: 'root'
})
export class SessionStorageService extends StorageService {
constructor() {
super(sessionStorage);
constructor(logger: NGXLogger) {
super(sessionStorage, logger);
}
}

View File

@ -3,9 +3,10 @@ import { fromEvent, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import CryptoJS from 'crypto-js';
import { NGXLogger } from 'ngx-logger';
export class StorageService {
constructor(private storage: Storage) {}
constructor(private storage: Storage, private logger: NGXLogger) {}
get<T>(key: string): T | null {
return StorageUtil.get(this.storage, key);
@ -38,6 +39,7 @@ export class StorageService {
expiredAt: number = 0,
expiredUnit: ExpiredUnit = 'd'
) {
this.logger.debug('encSet key:', key, ' value:', value);
const json = JSON.stringify(value);
const encrypted = CryptoJS.AES.encrypt(json, secretPassphrase);
return StorageUtil.set(