Merge branch 'master' of https://git.loafle.net/ucap-web/next-ucap-messenger
This commit is contained in:
commit
20110f2c2a
|
@ -5,7 +5,8 @@ import {
|
|||
Tray,
|
||||
Menu,
|
||||
shell,
|
||||
dialog
|
||||
dialog,
|
||||
webFrame
|
||||
} from 'electron';
|
||||
import path from 'path';
|
||||
import fse from 'fs-extra';
|
||||
|
@ -396,6 +397,13 @@ ipcMain.on(
|
|||
}
|
||||
);
|
||||
|
||||
ipcMain.on(
|
||||
MessengerChannel.GetVersionInfo,
|
||||
(event: IpcMainEvent, ...args: any[]) => {
|
||||
event.returnValue = app.getVersion();
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.on(
|
||||
MessengerChannel.ChangeAutoLaunch,
|
||||
(event: IpcMainEvent, ...args: any[]) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ucap-webmessenger",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.3",
|
||||
"author": {
|
||||
"name": "LG CNS",
|
||||
"email": "lgucap@lgcns.com"
|
||||
|
|
|
@ -168,7 +168,7 @@
|
|||
(click)="onClickProfileContextMenu('REGISTER_FAVORITE', userInfo)"
|
||||
>
|
||||
{{
|
||||
(userInfo.isFavorit ? 'group.unfavorite' : 'group.favorite') | translate
|
||||
(userInfo.isFavorit ? 'group.unfavorite' : 'group.favorit') | translate
|
||||
}}
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickProfileContextMenu('CHAT', userInfo)">
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
'common.file.errors.expired' | translate
|
||||
}}</span>
|
||||
<button
|
||||
mat-stroked-button
|
||||
mat-flat-button
|
||||
class="mat-primary"
|
||||
(click)="downloadAttachFileAll()"
|
||||
>
|
||||
|
@ -143,7 +143,8 @@
|
|||
<div>
|
||||
<span class="mdi" [ngClass]="getFileStatusIcon(file)"></span>
|
||||
<span>{{ file.resContent }}</span>
|
||||
<span>{{ file.resSize | ucapBytes }}</span>
|
||||
</div>
|
||||
<span class="file-size">{{ file.resSize | ucapBytes }}</span>
|
||||
<a>
|
||||
<span
|
||||
class="mdi mdi-download"
|
||||
|
@ -151,7 +152,6 @@
|
|||
(click)="downloadAttachFileSingle(file)"
|
||||
></span>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -109,5 +109,42 @@
|
|||
.ps {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.attachFile {
|
||||
border-top: 1px solid #dddddd;
|
||||
li {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
line-height: 2em;
|
||||
flex: 1 1 auto;
|
||||
.file-name {
|
||||
display: inline-flex;
|
||||
flex-flow: row;
|
||||
flex: 1 1 auto;
|
||||
border: 1px solid red;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
overflow: hidden;
|
||||
margin-right: 10px;
|
||||
span:last-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
.file-size {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
align-self: flex-end;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 100%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,7 +281,7 @@
|
|||
(click)="onClickZoomOut($event)"
|
||||
>
|
||||
축소</button
|
||||
><span class="set-size">100%</span
|
||||
><span class="set-size" (click)="onClickZoomLabel($event)">{{ zoom }}%</span
|
||||
><button
|
||||
mat-menu-item
|
||||
class="zoom plus-square"
|
||||
|
@ -306,6 +306,12 @@
|
|||
</button>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="setting">
|
||||
<button mat-menu-item [matMenuTriggerFor]="informationMenu">
|
||||
{{ 'information.label' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="setting">
|
||||
<button mat-menu-item (click)="onClickLogout()">
|
||||
{{ 'accounts.logout' | translate }}
|
||||
|
@ -334,35 +340,71 @@
|
|||
<div class="setting">
|
||||
<button mat-menu-item (click)="onClickStatusBusy($event, 1)">
|
||||
<span class="presence pcOther"> </span>
|
||||
{{ loginRes?.statusMessage1 }}
|
||||
<ucap-inline-edit-input
|
||||
(apply)="
|
||||
$event.stopPropagation();
|
||||
onApplyStatusMessage(1, statusMessage1.value)
|
||||
"
|
||||
(edit)="$event.stopPropagation()"
|
||||
(cancel)="$event.stopPropagation()"
|
||||
>
|
||||
<span ucapInlineEditInput="view">{{ loginRes?.statusMessage1 }}</span>
|
||||
<span ucapInlineEditInput="edit"
|
||||
><input
|
||||
matInput
|
||||
#statusMessage1
|
||||
type="text"
|
||||
[value]="loginRes?.statusMessage1"
|
||||
(click)="$event.stopPropagation()"
|
||||
/></span>
|
||||
</ucap-inline-edit-input>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="edit"
|
||||
(click)="onClickChangeStatusBusy($event, 1)"
|
||||
></button>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<button mat-menu-item (click)="onClickStatusBusy($event, 2)">
|
||||
<span class="presence pcOther"> </span>
|
||||
{{ loginRes?.statusMessage2 }}
|
||||
<ucap-inline-edit-input
|
||||
(apply)="
|
||||
$event.stopPropagation();
|
||||
onApplyStatusMessage(2, statusMessage2.value)
|
||||
"
|
||||
(edit)="$event.stopPropagation()"
|
||||
(cancel)="$event.stopPropagation()"
|
||||
>
|
||||
<span ucapInlineEditInput="view">{{ loginRes?.statusMessage2 }}</span>
|
||||
<span ucapInlineEditInput="edit"
|
||||
><input
|
||||
matInput
|
||||
#statusMessage2
|
||||
type="text"
|
||||
[value]="loginRes?.statusMessage2"
|
||||
(click)="$event.stopPropagation()"
|
||||
/></span>
|
||||
</ucap-inline-edit-input>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="edit"
|
||||
(click)="onClickChangeStatusBusy($event, 2)"
|
||||
></button>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<button mat-menu-item (click)="onClickStatusBusy($event, 3)">
|
||||
<span class="presence pcOther"> </span>
|
||||
{{ loginRes?.statusMessage3 }}
|
||||
<ucap-inline-edit-input
|
||||
(apply)="
|
||||
$event.stopPropagation();
|
||||
onApplyStatusMessage(3, statusMessage3.value)
|
||||
"
|
||||
(edit)="$event.stopPropagation()"
|
||||
(cancel)="$event.stopPropagation()"
|
||||
>
|
||||
<span ucapInlineEditInput="view">{{ loginRes?.statusMessage3 }}</span>
|
||||
<span ucapInlineEditInput="edit"
|
||||
><input
|
||||
matInput
|
||||
#statusMessage3
|
||||
type="text"
|
||||
[value]="loginRes?.statusMessage3"
|
||||
(click)="$event.stopPropagation()"
|
||||
/></span>
|
||||
</ucap-inline-edit-input>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="edit"
|
||||
(click)="onClickChangeStatusBusy($event, 3)"
|
||||
></button>
|
||||
</div>
|
||||
</mat-menu>
|
||||
|
||||
|
@ -370,28 +412,17 @@
|
|||
<div mat-menu-item (click)="$event.stopPropagation()">
|
||||
{{ 'presence.settingOfAwayTime' | translate }}
|
||||
</div>
|
||||
<mat-radio-group aria-label="Select an option" [value]="myIdleCheckTime">
|
||||
<div mat-menu-item *ngFor="let awayTime of awayTimeList">
|
||||
<mat-radio-button [value]="awayTime" (change)="onChangeAwayTime($event)">
|
||||
{{ awayTime }}{{ 'common.units.minute' | translate }}</mat-radio-button
|
||||
>
|
||||
</div>
|
||||
</mat-radio-group>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #informationMenu="matMenu">
|
||||
<div mat-menu-item>
|
||||
<mat-radio-button
|
||||
value="10"
|
||||
[checked]="myIdleCheckTime === 10"
|
||||
(change)="onChangeAwayTime($event)"
|
||||
>10{{ 'common.units.minute' | translate }}</mat-radio-button
|
||||
>
|
||||
</div>
|
||||
<div mat-menu-item>
|
||||
<mat-radio-button
|
||||
value="20"
|
||||
[checked]="myIdleCheckTime === 20"
|
||||
(change)="onChangeAwayTime($event)"
|
||||
>20{{ 'common.units.minute' | translate }}</mat-radio-button
|
||||
>
|
||||
</div>
|
||||
<div mat-menu-item>
|
||||
<mat-radio-button
|
||||
value="30"
|
||||
[checked]="myIdleCheckTime === 30"
|
||||
(change)="onChangeAwayTime($event)"
|
||||
>30{{ 'common.units.minute' | translate }}</mat-radio-button
|
||||
>
|
||||
{{ 'information.version' | translate }}: {{ appVersion }}
|
||||
</div>
|
||||
</mat-menu>
|
||||
|
|
|
@ -20,6 +20,7 @@ import * as ChatStore from '@app/store/messenger/chat';
|
|||
import * as AuthenticationStore from '@app/store/account/authentication';
|
||||
import * as SettingsStore from '@app/store/messenger/settings';
|
||||
import * as UpdateStore from '@app/store/setting/update';
|
||||
import * as SettingNativeStore from '@app/store/setting/native';
|
||||
import * as StatusStore from '@app/store/messenger/status';
|
||||
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
|
@ -58,6 +59,9 @@ import { DOCUMENT } from '@angular/common';
|
|||
import { MatMenu, MatRadioChange } from '@angular/material';
|
||||
import { StatusCode, StatusType } from '@ucap-webmessenger/core';
|
||||
import { StatusInfo } from '@ucap-webmessenger/protocol-status';
|
||||
import { UserInfoUpdateType } from '@ucap-webmessenger/protocol-info';
|
||||
|
||||
const zoomFactors = [60, 70, 85, 100, 120, 145, 170, 200];
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-native-top-bar',
|
||||
|
@ -80,14 +84,21 @@ export class TopBarComponent implements OnInit, OnDestroy {
|
|||
myIdleCheckTime: number;
|
||||
myIdleCheckTimeSubscription: Subscription;
|
||||
|
||||
zoom: number;
|
||||
zoomSubscription: Subscription;
|
||||
|
||||
loginInfo: LoginInfo;
|
||||
weblink: WebLink[] = [];
|
||||
webLinkBadgeMail = 0;
|
||||
webLinkBadgePayment = 0;
|
||||
|
||||
appVersion: string;
|
||||
|
||||
WebLinkType = WebLinkType;
|
||||
StatusCode = StatusCode;
|
||||
|
||||
readonly awayTimeList = [10, 20, 30];
|
||||
|
||||
@ViewChild('profileMenu', { static: true })
|
||||
profileMenu: MatMenu;
|
||||
|
||||
|
@ -127,35 +138,50 @@ export class TopBarComponent implements OnInit, OnDestroy {
|
|||
.subscribe();
|
||||
|
||||
this.myStatusSubscription = this.store
|
||||
.pipe(select(AppStore.MessengerSelector.StatusSelector.selectedMyStatus))
|
||||
.pipe(select(AppStore.MessengerSelector.StatusSelector.selectMyStatus))
|
||||
.subscribe(myStatus => {
|
||||
this.myStatus = myStatus;
|
||||
});
|
||||
|
||||
this.myIdleCheckTimeSubscription = this.store
|
||||
.pipe(
|
||||
select(
|
||||
AppStore.MessengerSelector.StatusSelector.selectedMyIdleCheckTime
|
||||
)
|
||||
select(AppStore.MessengerSelector.StatusSelector.selectMyIdleCheckTime)
|
||||
)
|
||||
.subscribe(myIdleCheckTime => {
|
||||
this.myIdleCheckTime = myIdleCheckTime;
|
||||
});
|
||||
|
||||
this.zoomSubscription = this.store
|
||||
.pipe(select(AppStore.SettingSelector.NativeSelector.selectZoom))
|
||||
.subscribe(zoom => {
|
||||
this.zoom = zoom;
|
||||
});
|
||||
|
||||
this.updateInfo$ = this.store.pipe(
|
||||
select(AppStore.SettingSelector.UpdateSelector.updateInfo)
|
||||
);
|
||||
|
||||
this.nativeService.getVersionInfo().then(ver => {
|
||||
this.appVersion = ver;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.loginResSubscription) {
|
||||
this.loginResSubscription.unsubscribe();
|
||||
this.loginResSubscription = undefined;
|
||||
}
|
||||
if (!!this.myStatusSubscription) {
|
||||
this.myStatusSubscription.unsubscribe();
|
||||
this.myStatusSubscription = undefined;
|
||||
}
|
||||
if (!!this.myIdleCheckTimeSubscription) {
|
||||
this.myIdleCheckTimeSubscription.unsubscribe();
|
||||
this.myIdleCheckTimeSubscription = undefined;
|
||||
}
|
||||
if (!!this.zoomSubscription) {
|
||||
this.zoomSubscription.unsubscribe();
|
||||
this.zoomSubscription = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,15 +383,27 @@ export class TopBarComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onClickZoomOut(event: Event) {
|
||||
event.stopPropagation();
|
||||
const i = zoomFactors.indexOf(this.zoom);
|
||||
if (-1 === i || 0 === i) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.document.body.style.zoom = '80%';
|
||||
const zoom = zoomFactors[i - 1];
|
||||
this.store.dispatch(SettingNativeStore.changeZoom({ zoom }));
|
||||
}
|
||||
|
||||
onClickZoomLabel(event: Event) {
|
||||
this.store.dispatch(SettingNativeStore.changeZoom({ zoom: 100 }));
|
||||
}
|
||||
|
||||
onClickZoomIn(event: Event) {
|
||||
event.stopPropagation();
|
||||
const i = zoomFactors.indexOf(this.zoom);
|
||||
if (-1 === i || zoomFactors.length - 1 === i) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.document.body.style.zoom = '120%';
|
||||
const zoom = zoomFactors[i + 1];
|
||||
this.store.dispatch(SettingNativeStore.changeZoom({ zoom }));
|
||||
}
|
||||
|
||||
onClickRemoteSupport(event: Event) {
|
||||
|
@ -419,6 +457,32 @@ export class TopBarComponent implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
onApplyStatusMessage(index: number, statusMessage: string) {
|
||||
this.logger.debug('StatusMessage', index, statusMessage);
|
||||
|
||||
let updateType: UserInfoUpdateType;
|
||||
switch (index) {
|
||||
case 1:
|
||||
updateType = UserInfoUpdateType.StatusMessage1;
|
||||
break;
|
||||
case 2:
|
||||
updateType = UserInfoUpdateType.StatusMessage2;
|
||||
break;
|
||||
case 3:
|
||||
updateType = UserInfoUpdateType.StatusMessage3;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
AuthenticationStore.infoUser({
|
||||
req: { type: updateType, info: statusMessage }
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onClickChangeStatusBusy(event: Event, index: number) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
|
|
@ -137,9 +137,7 @@ export class MainPageComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.myIdleCheckTimeSubscription = this.store
|
||||
.pipe(
|
||||
select(
|
||||
AppStore.MessengerSelector.StatusSelector.selectedMyIdleCheckTime
|
||||
)
|
||||
select(AppStore.MessengerSelector.StatusSelector.selectMyIdleCheckTime)
|
||||
)
|
||||
.subscribe(checkTime => {
|
||||
this.nativeService.changeLimitOfIdleState(checkTime);
|
||||
|
|
|
@ -58,6 +58,7 @@ import * as OptionStore from '@app/store/messenger/option';
|
|||
import * as QueryStore from '@app/store/messenger/query';
|
||||
import * as SyncStore from '@app/store/messenger/sync';
|
||||
import * as StatusStore from '@app/store/messenger/status';
|
||||
import * as SettingInitStore from '@app/store/setting/init';
|
||||
import { KEY_LOGIN_RES_INFO, KEY_VER_INFO } from '@app/types';
|
||||
|
||||
import { environment } from '../../environments/environment';
|
||||
|
|
|
@ -66,6 +66,7 @@ export class AppAuthenticationService {
|
|||
if (!appUserInfo) {
|
||||
appUserInfo = {
|
||||
idleCheckTime: 10,
|
||||
zoom: 100,
|
||||
settings: {
|
||||
...environment.productConfig.defaultSettings,
|
||||
chat: {
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
UserPasswordSetRequest,
|
||||
UserPasswordSetResponse
|
||||
} from '@ucap-webmessenger/protocol-service';
|
||||
import { UserRequest, UserResponse } from '@ucap-webmessenger/protocol-info';
|
||||
|
||||
export const webLogin = createAction(
|
||||
'[Account::Authentication] Web Login',
|
||||
|
@ -122,3 +123,20 @@ export const updateLoginRes = createAction(
|
|||
loginRes: LoginResponse;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const infoUser = createAction(
|
||||
'[Account::Authentication] Info User',
|
||||
props<{ req: UserRequest }>()
|
||||
);
|
||||
|
||||
export const infoUserSuccess = createAction(
|
||||
'[Account::Authentication] Info User Success',
|
||||
props<{
|
||||
res: UserResponse;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const infoUserFailure = createAction(
|
||||
'[Account::Authentication] Info User Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
|
|
@ -41,7 +41,10 @@ import {
|
|||
logoutInitialize,
|
||||
userPasswordSet,
|
||||
userPasswordSetSuccess,
|
||||
userPasswordSetFailure
|
||||
userPasswordSetFailure,
|
||||
infoUser,
|
||||
infoUserSuccess,
|
||||
infoUserFailure
|
||||
} from './actions';
|
||||
import {
|
||||
LoginInfo,
|
||||
|
@ -77,6 +80,10 @@ import { DaesangUrlInfoResponse } from '@ucap-webmessenger/api-external';
|
|||
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';
|
||||
import { DaesangCipherService, WebLinkType } from '@ucap-webmessenger/daesang';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
InfoProtocolService,
|
||||
UserResponse
|
||||
} from '@ucap-webmessenger/protocol-info';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
@ -482,6 +489,23 @@ export class Effects {
|
|||
{ dispatch: false }
|
||||
);
|
||||
|
||||
infoUser$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(infoUser),
|
||||
map(action => action.req),
|
||||
exhaustMap(req =>
|
||||
this.infoProtocolService.user(req).pipe(
|
||||
map((res: UserResponse) => {
|
||||
return infoUserSuccess({
|
||||
res
|
||||
});
|
||||
}),
|
||||
catchError(error => of(infoUserFailure({ error })))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private ngZone: NgZone,
|
||||
|
@ -493,6 +517,7 @@ export class Effects {
|
|||
private appAuthenticationService: AppAuthenticationService,
|
||||
private protocolService: ProtocolService,
|
||||
private authenticationProtocolService: AuthenticationProtocolService,
|
||||
private infoProtocolService: InfoProtocolService,
|
||||
private serviceProtocolService: ServiceProtocolService,
|
||||
private translateService: TranslateService,
|
||||
private dialogService: DialogService,
|
||||
|
|
|
@ -6,8 +6,10 @@ import {
|
|||
initialLoginFailCount,
|
||||
logout,
|
||||
logoutInitialize,
|
||||
updateLoginRes
|
||||
updateLoginRes,
|
||||
infoUserSuccess
|
||||
} from './actions';
|
||||
import { UserInfoUpdateType } from '@ucap-webmessenger/protocol-info';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
@ -39,6 +41,57 @@ export const reducer = createReducer(
|
|||
};
|
||||
}),
|
||||
|
||||
on(infoUserSuccess, (state, action) => {
|
||||
let loginRes = {
|
||||
...state.loginRes
|
||||
};
|
||||
|
||||
switch (action.res.type) {
|
||||
case UserInfoUpdateType.Image:
|
||||
loginRes = {
|
||||
...loginRes
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.Intro:
|
||||
loginRes = {
|
||||
...loginRes
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.TelephoneVisible:
|
||||
loginRes = {
|
||||
...loginRes
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.StatusMessage1:
|
||||
loginRes = {
|
||||
...loginRes,
|
||||
statusMessage1: action.res.info
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.StatusMessage2:
|
||||
loginRes = {
|
||||
...loginRes,
|
||||
statusMessage2: action.res.info
|
||||
};
|
||||
break;
|
||||
case UserInfoUpdateType.StatusMessage3:
|
||||
loginRes = {
|
||||
...loginRes,
|
||||
statusMessage3: action.res.info
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
loginRes: {
|
||||
...loginRes
|
||||
}
|
||||
};
|
||||
}),
|
||||
|
||||
on(logoutInitialize, (state, action) => {
|
||||
return {
|
||||
...initialState
|
||||
|
|
|
@ -62,11 +62,8 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
ngeSelectEntitiesStatusBulkInfo,
|
||||
(_, entities) => (!!entities ? entities[userSeq] : undefined)
|
||||
),
|
||||
selectedMyStatus: createSelector(
|
||||
selector,
|
||||
(state: State) => state.myStatus
|
||||
),
|
||||
selectedMyIdleCheckTime: createSelector(
|
||||
selectMyStatus: createSelector(selector, (state: State) => state.myStatus),
|
||||
selectMyIdleCheckTime: createSelector(
|
||||
selector,
|
||||
(state: State) => state.myIdleCheckTime
|
||||
)
|
||||
|
|
|
@ -5,19 +5,22 @@ import * as CompanyStore from './company';
|
|||
import * as InitStore from './init';
|
||||
import * as VersionInfoStore from './version-info';
|
||||
import * as UpdateStore from './update';
|
||||
import * as NativeStore from './native';
|
||||
|
||||
export interface State {
|
||||
company: CompanyStore.State;
|
||||
init: InitStore.State;
|
||||
versionInfo: VersionInfoStore.State;
|
||||
update: UpdateStore.State;
|
||||
native: NativeStore.State;
|
||||
}
|
||||
|
||||
export const effects: Type<any>[] = [
|
||||
CompanyStore.Effects,
|
||||
InitStore.Effects,
|
||||
VersionInfoStore.Effects,
|
||||
UpdateStore.Effects
|
||||
UpdateStore.Effects,
|
||||
NativeStore.Effects
|
||||
];
|
||||
|
||||
export function reducers(state: State | undefined, action: Action) {
|
||||
|
@ -25,7 +28,8 @@ export function reducers(state: State | undefined, action: Action) {
|
|||
company: CompanyStore.reducer,
|
||||
init: InitStore.reducer,
|
||||
versionInfo: VersionInfoStore.reducer,
|
||||
update: UpdateStore.reducer
|
||||
update: UpdateStore.reducer,
|
||||
native: NativeStore.reducer
|
||||
})(state, action);
|
||||
}
|
||||
|
||||
|
@ -42,6 +46,9 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
),
|
||||
UpdateSelector: UpdateStore.selectors(
|
||||
createSelector(selector, (state: State) => state.update)
|
||||
),
|
||||
NativeSelector: NativeStore.selectors(
|
||||
createSelector(selector, (state: State) => state.native)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ export class Effects {
|
|||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private translateService: TranslateService,
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { createAction, props } from '@ngrx/store';
|
||||
|
||||
export const changeZoom = createAction(
|
||||
'[Setting::Native] Change Zoom',
|
||||
props<{ zoom: number }>()
|
||||
);
|
||||
|
||||
export const changeZoomSuccess = createAction(
|
||||
'[Setting::Native] changeZoom Success',
|
||||
props<{
|
||||
zoom: number;
|
||||
}>()
|
||||
);
|
||||
export const changeZoomFailure = createAction(
|
||||
'[Setting::Native] changeZoom Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
|
@ -0,0 +1,77 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui';
|
||||
import { DateService as UCapDateService } from '@ucap-webmessenger/ui';
|
||||
|
||||
import * as AuthenticationStore from '@app/store/account/authentication';
|
||||
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 { changeZoom, changeZoomSuccess, changeZoomFailure } from './actions';
|
||||
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
postLogin$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(AuthenticationStore.postLogin),
|
||||
map(action => action.loginRes),
|
||||
tap(async loginRes => {
|
||||
const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
|
||||
KEY_APP_USER_INFO,
|
||||
environment.customConfig.appKey
|
||||
);
|
||||
|
||||
this.store.dispatch(changeZoom({ zoom: appUserInfo.zoom }));
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
changeZoom$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(changeZoom),
|
||||
map(action => action.zoom),
|
||||
tap(zoom => {
|
||||
const appUserInfo = this.localStorageService.encGet<AppUserInfo>(
|
||||
KEY_APP_USER_INFO,
|
||||
environment.customConfig.appKey
|
||||
);
|
||||
|
||||
this.nativeService
|
||||
.zoomTo(zoom)
|
||||
.then(f => {
|
||||
this.localStorageService.encSet<AppUserInfo>(
|
||||
KEY_APP_USER_INFO,
|
||||
{
|
||||
...appUserInfo,
|
||||
zoom
|
||||
},
|
||||
environment.customConfig.appKey
|
||||
);
|
||||
|
||||
this.store.dispatch(changeZoomSuccess({ zoom }));
|
||||
})
|
||||
.catch(reason => {
|
||||
this.store.dispatch(changeZoomFailure({ error: reason }));
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private store: Store<any>,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private localStorageService: LocalStorageService
|
||||
) {}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export * from './actions';
|
||||
export * from './effects';
|
||||
export * from './reducers';
|
||||
export * from './state';
|
|
@ -0,0 +1,13 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
import { State, initialState } from './state';
|
||||
import { changeZoomSuccess } from './actions';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
on(changeZoomSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
zoom: action.zoom
|
||||
} as State;
|
||||
})
|
||||
);
|
|
@ -0,0 +1,16 @@
|
|||
import { Selector, createSelector } from '@ngrx/store';
|
||||
|
||||
// tslint:disable-next-line: no-empty-interface
|
||||
export interface State {
|
||||
zoom: number;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
zoom: 100
|
||||
};
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
return {
|
||||
selectZoom: createSelector(selector, (state: State) => state.zoom)
|
||||
};
|
||||
}
|
|
@ -11,6 +11,7 @@ export interface AppUserInfo {
|
|||
companyGroupType?: string;
|
||||
localeCode?: LocaleCode;
|
||||
idleCheckTime?: number;
|
||||
zoom?: number;
|
||||
|
||||
settings?: Settings;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,10 @@
|
|||
"failToChangeProfileImage": "Failed to change profile image."
|
||||
}
|
||||
},
|
||||
"information": {
|
||||
"label": "Information",
|
||||
"version": "Version"
|
||||
},
|
||||
"settings": {
|
||||
"label": "Settings",
|
||||
"typeGenernal": "Genernal",
|
||||
|
|
|
@ -67,6 +67,10 @@
|
|||
"failToChangeProfileImage": "프로필 이미지 변경에 실패 하였습니다."
|
||||
}
|
||||
},
|
||||
"information": {
|
||||
"label": "정보",
|
||||
"version": "버전"
|
||||
},
|
||||
"settings": {
|
||||
"label": "설정",
|
||||
"typeGenernal": "일반",
|
||||
|
|
|
@ -78,6 +78,12 @@ export class BrowserNativeService extends NativeService {
|
|||
});
|
||||
}
|
||||
|
||||
getVersionInfo(): Promise<string> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
resolve('');
|
||||
});
|
||||
}
|
||||
|
||||
changeAutoLaunch(autoLaunch: boolean): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
resolve(true);
|
||||
|
@ -215,6 +221,12 @@ export class BrowserNativeService extends NativeService {
|
|||
|
||||
windowMaximize(): void {}
|
||||
|
||||
zoomTo(factor: number): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
resolve(-1);
|
||||
});
|
||||
}
|
||||
|
||||
idleStateChanged(): Observable<WindowIdle> {
|
||||
return new Observable<WindowIdle>(subscriber => {
|
||||
try {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ipcRenderer, remote, shell } from 'electron';
|
||||
import { ipcRenderer, remote, shell, webFrame } from 'electron';
|
||||
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
|
@ -34,6 +34,7 @@ import { StatusCode } from '@ucap-webmessenger/core';
|
|||
})
|
||||
export class ElectronNativeService implements NativeService {
|
||||
private ipcRenderer: typeof ipcRenderer;
|
||||
private webFrame: typeof webFrame;
|
||||
private remote: typeof remote;
|
||||
private shell: typeof shell;
|
||||
|
||||
|
@ -89,6 +90,16 @@ export class ElectronNativeService implements NativeService {
|
|||
});
|
||||
}
|
||||
|
||||
getVersionInfo(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
try {
|
||||
resolve(this.ipcRenderer.sendSync(MessengerChannel.GetVersionInfo));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
changeStatus(): Observable<StatusCode> {
|
||||
if (!this.changeStatusSubject) {
|
||||
this.changeStatusSubject = new Subject<StatusCode>();
|
||||
|
@ -377,6 +388,17 @@ export class ElectronNativeService implements NativeService {
|
|||
}
|
||||
}
|
||||
|
||||
zoomTo(factor: number): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
try {
|
||||
this.webFrame.setZoomFactor(factor / 100);
|
||||
resolve(this.webFrame.getZoomFactor());
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
idleStateChanged(): Observable<WindowIdle> {
|
||||
if (!this.idleStateChangedSubject) {
|
||||
this.idleStateChangedSubject = new Subject<WindowIdle>();
|
||||
|
@ -448,6 +470,7 @@ export class ElectronNativeService implements NativeService {
|
|||
this.ipcRenderer = (window as any).require('electron').ipcRenderer;
|
||||
this.remote = (window as any).require('electron').remote;
|
||||
this.shell = (window as any).require('electron').shell;
|
||||
this.webFrame = (window as any).require('electron').webFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ export enum MessengerChannel {
|
|||
ChangeAutoLaunch = 'UCAP::messenger::changeAutoLaunch',
|
||||
ChangeStartupHideWindow = 'UCAP::messenger::changeStartupHideWindow',
|
||||
ChangeDownloadPath = 'UCAP::messenger::changeDownloadPath',
|
||||
GetNetworkInfo = 'UCAP::messenger::getNetworkInfo'
|
||||
GetNetworkInfo = 'UCAP::messenger::getNetworkInfo',
|
||||
GetVersionInfo = 'UCAP::messenger::getVersionInfo'
|
||||
}
|
||||
|
||||
export enum ChatChannel {
|
||||
|
|
|
@ -25,6 +25,7 @@ export abstract class NativeService {
|
|||
abstract showSetting(): Observable<void>;
|
||||
|
||||
abstract getNetworkInfo(): Promise<any>;
|
||||
abstract getVersionInfo(): Promise<string>;
|
||||
|
||||
abstract changeAutoLaunch(autoLaunch: boolean): Promise<boolean>;
|
||||
abstract changeStartupHideWindow(
|
||||
|
@ -66,6 +67,7 @@ export abstract class NativeService {
|
|||
abstract windowClose(): void;
|
||||
abstract windowMinimize(): void;
|
||||
abstract windowMaximize(): void;
|
||||
abstract zoomTo(factor: number): Promise<number>;
|
||||
|
||||
abstract idleStateChanged(): Observable<WindowIdle>;
|
||||
abstract changeLimitOfIdleState(limitTime: number): void;
|
||||
|
|
|
@ -4,7 +4,13 @@ export enum UserInfoUpdateType {
|
|||
// R: 인트로소개
|
||||
Intro = 'R',
|
||||
// T: 전화보이기여부
|
||||
TelephoneVisible = 'T'
|
||||
TelephoneVisible = 'T',
|
||||
/** StatusMessage1 */
|
||||
StatusMessage1 = 'S1',
|
||||
/** StatusMessage2 */
|
||||
StatusMessage2 = 'S2',
|
||||
/** StatusMessage3 */
|
||||
StatusMessage3 = 'S3'
|
||||
}
|
||||
|
||||
export enum TelephoneVisibleType {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--체크박스 보여줄때는 <div class="list-item checkbox" matRipple> 클래스에 checkbox만 추가-->
|
||||
<div class="list-item" *ngIf="message" matRipple>
|
||||
<!--<div class="list-item" *ngIf="message" matRipple>
|
||||
<dl class="item-default">
|
||||
<dt>
|
||||
<mat-icon
|
||||
|
@ -34,4 +34,39 @@
|
|||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>-->
|
||||
|
||||
<div class="list-item message-list" *ngIf="message" matRipple>
|
||||
<dl class="item-default">
|
||||
<dt>
|
||||
<span class="name">
|
||||
{{ message.userName }}
|
||||
<span *ngIf="message.userCount > 1" class="text-accent-color number">
|
||||
{{
|
||||
'message.andOthers' | translate: { count: message.userCount - 1 }
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<mat-icon
|
||||
*ngIf="!!message.resType && message.resType === ContentType.Image"
|
||||
>image</mat-icon
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="!!message.resType && message.resType === ContentType.AttachFile"
|
||||
>attach_file</mat-icon
|
||||
>
|
||||
{{ message.title }}
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="date">
|
||||
<span>{{ message.regDate | ucapDate: 'MM:DD' }}</span>
|
||||
<span
|
||||
*ngIf="message.type === MessageType.Receive && !message.readYn"
|
||||
class="badge-new bg-warn-darkest"
|
||||
>
|
||||
N
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
.message-list {
|
||||
&.list-item {
|
||||
dl {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
flex: 1 1 auto;
|
||||
width: calc(100% - 80px);
|
||||
dt {
|
||||
.name {
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
font-weight: 600;
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
color: #777777;
|
||||
margin-top: 4px;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.date {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-self: flex-start;
|
||||
.badge-new {
|
||||
border-radius: 50%;
|
||||
color: #ffffff;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
align-self: flex-end;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<!--체크박스 보여줄때는 <div class="list-item checkbox" matRipple> 클래스에 checkbox만 추가-->
|
||||
<div class="list-item" *ngIf="userInfo" matRipple>
|
||||
<div class="list-item checkbox" *ngIf="userInfo" matRipple>
|
||||
<!--pcOn , pcOut pcOff , pcOther-->
|
||||
<span class="presence" [ngClass]="getPresence(PresenceType.PC)"> </span>
|
||||
<dl class="item-default">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div>
|
||||
<mat-list>
|
||||
<h1 mat-subheader>{{ 'settings.chat.label' | translate }}</h1>
|
||||
<!-- <h1 mat-subheader>{{ 'settings.chat.label' | translate }}</h1>
|
||||
<mat-list-item>
|
||||
<span class="item-title">{{
|
||||
'settings.chat.fontFamily' | translate
|
||||
|
@ -37,7 +37,7 @@
|
|||
</span>
|
||||
</mat-list-item>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<mat-divider></mat-divider> -->
|
||||
|
||||
<h1 mat-subheader *ngIf="_isNodeWebkit">
|
||||
{{ 'settings.chat.file' | translate }}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<ng-container>
|
||||
<ng-container #view *ngIf="!editMode">
|
||||
<ng-content select="[ucapInlineEditInput='view']"></ng-content>
|
||||
<span class="view-actions">
|
||||
<button mat-icon-button aria-label="Edit" (click)="onClickEdit($event)">
|
||||
<span class="mdi mdi-square-edit-outline mdi-20px"></span>
|
||||
</button>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container #edit *ngIf="editMode">
|
||||
<ng-content select="[ucapInlineEditInput='edit']"></ng-content>
|
||||
<span class="edit-actions">
|
||||
<button mat-icon-button aria-label="Apply" (click)="onClickApply($event)">
|
||||
<span class="mdi mdi-check mdi-20px"></span>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
aria-label="Cacel"
|
||||
(click)="onClickCancel($event)"
|
||||
>
|
||||
<span class="mdi mdi-close mdi-20px"></span>
|
||||
</button>
|
||||
</span>
|
||||
</ng-container>
|
||||
</ng-container>
|
|
@ -0,0 +1,7 @@
|
|||
.view-actions {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.edit-actions {
|
||||
margin-right: 0px;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* tslint:disable:no-unused-variable */
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InlineEditInputComponent } from './inline-edit-input.component';
|
||||
|
||||
describe('InlineEditInputComponent', () => {
|
||||
let component: InlineEditInputComponent;
|
||||
let fixture: ComponentFixture<InlineEditInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [InlineEditInputComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InlineEditInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-inline-edit-input',
|
||||
templateUrl: './inline-edit-input.component.html',
|
||||
styleUrls: ['./inline-edit-input.component.scss']
|
||||
})
|
||||
export class InlineEditInputComponent implements OnInit {
|
||||
@Output()
|
||||
edit = new EventEmitter<Event>();
|
||||
@Output()
|
||||
cancel = new EventEmitter<Event>();
|
||||
@Output()
|
||||
apply = new EventEmitter<Event>();
|
||||
|
||||
get editMode() {
|
||||
return this._editMode;
|
||||
}
|
||||
set editMode(editMode: boolean) {
|
||||
this._editMode = editMode;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_editMode = false;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onClickEdit(event: Event) {
|
||||
this.editMode = true;
|
||||
this.edit.emit(event);
|
||||
}
|
||||
|
||||
onClickCancel(event: Event) {
|
||||
this.editMode = false;
|
||||
this.cancel.emit(event);
|
||||
}
|
||||
|
||||
onClickApply(event: Event) {
|
||||
this.editMode = false;
|
||||
this.apply.emit(event);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import { PickDateComponent } from './components/pick-date.component';
|
|||
import { PickTimeComponent } from './components/pick-time.component';
|
||||
import { StepInputComponent } from './components/step-input.component';
|
||||
import { StickerSelectorComponent } from './components/sticker-selector.component';
|
||||
import { InlineEditInputComponent } from './components/inline-edit-input.component';
|
||||
|
||||
import { BinaryViewerComponent } from './components/file-viewer/binary-viewer.component';
|
||||
import { DocumentViewerComponent } from './components/file-viewer/document-viewer.component';
|
||||
|
@ -88,6 +89,7 @@ const COMPONENTS = [
|
|||
PickTimeComponent,
|
||||
StepInputComponent,
|
||||
TranslationSectionComponent,
|
||||
InlineEditInputComponent,
|
||||
|
||||
BinaryViewerComponent,
|
||||
DocumentViewerComponent,
|
||||
|
|
|
@ -18,6 +18,7 @@ export * from './lib/components/pick-time.component';
|
|||
export * from './lib/components/step-input.component';
|
||||
export * from './lib/components/split-button.component';
|
||||
export * from './lib/components/sticker-selector.component';
|
||||
export * from './lib/components/inline-edit-input.component';
|
||||
|
||||
export * from './lib/data-source/virtual-scroll-tree-flat.data-source';
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user