Merge branch 'master' of http://10.81.13.221:6990/Web/next-ucap-messenger
This commit is contained in:
commit
fe1ebca2b5
|
@ -2,14 +2,18 @@ import { IntroComponent } from './intro.component';
|
|||
import { LeftSideComponent } from './left-side.component';
|
||||
import { MessagesComponent } from './messages.component';
|
||||
import { RightSideComponent } from './right-side.component';
|
||||
import { RightDrawerComponent } from './right-drawer.component';
|
||||
|
||||
import { LEFT_SIDENAV_COMPONENTS } from './left-sidenav';
|
||||
import { RIGHT_DRAWER_COMPONENTS } from './right-drawer';
|
||||
|
||||
export const COMPONENTS = [
|
||||
IntroComponent,
|
||||
LeftSideComponent,
|
||||
MessagesComponent,
|
||||
RightSideComponent,
|
||||
RightDrawerComponent,
|
||||
|
||||
...LEFT_SIDENAV_COMPONENTS
|
||||
...LEFT_SIDENAV_COMPONENTS,
|
||||
...RIGHT_DRAWER_COMPONENTS
|
||||
];
|
||||
|
|
|
@ -27,7 +27,14 @@
|
|||
[hasBackdrop]="false"
|
||||
>
|
||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_NEW')">
|
||||
<mat-icon>group_add</mat-icon>
|
||||
<!--<mat-icon>group_add</mat-icon>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1.5" stroke-linecap="butt" stroke-linejoin="round">
|
||||
<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="8.5" cy="7" r="4"></circle>
|
||||
<line x1="20" y1="8" x2="20" y2="14"></line>
|
||||
<line x1="23" y1="11" x2="17" y2="11"></line>
|
||||
</svg>
|
||||
<span>새 그룹 추가</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_EXPAND_MORE')">
|
||||
|
|
|
@ -37,3 +37,10 @@
|
|||
height: 100%;
|
||||
overflow: unset;
|
||||
}
|
||||
.mat-menu-item{
|
||||
display:flex;
|
||||
align-items: center;
|
||||
svg{
|
||||
margin-right:10px;
|
||||
}
|
||||
}
|
|
@ -11,15 +11,24 @@
|
|||
class="responsive-chats-button"
|
||||
>
|
||||
<!--<mat-icon>chat</mat-icon>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="currentColor"
|
||||
stroke-width="1.5" stroke-linecap="butt" stroke-linejoin="round">
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="30"
|
||||
height="30"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="butt"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<g>
|
||||
<path d="M3,21.8c-0.2,0-0.4-0.1-0.5-0.2c-0.2-0.2-0.3-0.5-0.2-0.8l1.8-5.4c-0.6-1.2-0.8-2.5-0.8-3.9c0-3.5,2-6.7,5.1-8.3
|
||||
<path
|
||||
d="M3,21.8c-0.2,0-0.4-0.1-0.5-0.2c-0.2-0.2-0.3-0.5-0.2-0.8l1.8-5.4c-0.6-1.2-0.8-2.5-0.8-3.9c0-3.5,2-6.7,5.1-8.3
|
||||
c1.3-0.6,2.7-0.9,4.1-1H13c4.7,0.3,8.5,4,8.7,8.7l0,0.5c0,1.4-0.3,2.9-1,4.1c-1.6,3.2-4.7,5.1-8.3,5.1c0,0,0,0,0,0
|
||||
c-1.3,0-2.6-0.3-3.8-0.8l-5.4,1.8C3.2,21.7,3.1,21.8,3,21.8z M12.5,3.8C11.3,3.8,10.1,4,9,4.6c-2.6,1.3-4.3,4-4.3,6.9
|
||||
c0,1.2,0.3,2.4,0.8,3.5c0.1,0.2,0.1,0.4,0,0.6l-1.4,4.3l4.3-1.4c0.2-0.1,0.4,0,0.6,0c1.1,0.5,2.3,0.8,3.5,0.8c3,0,5.6-1.6,6.9-4.3
|
||||
c0.5-1.1,0.8-2.3,0.8-3.5c0,0,0,0,0,0V11C20,7.1,16.9,4,13,3.7L12.5,3.8C12.5,3.8,12.5,3.8,12.5,3.8z" />
|
||||
c0.5-1.1,0.8-2.3,0.8-3.5c0,0,0,0,0,0V11C20,7.1,16.9,4,13,3.7L12.5,3.8C12.5,3.8,12.5,3.8,12.5,3.8z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<circle cx="9" cy="12" r="1" />
|
||||
|
@ -27,7 +36,6 @@
|
|||
<circle cx="16" cy="12" r="1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<!-- / RESPONSIVE CHATS BUTTON-->
|
||||
<button
|
||||
|
@ -48,7 +56,7 @@
|
|||
*ngIf="roomInfo && roomInfo.isTimeRoom"
|
||||
class="room-type text-accent-color "
|
||||
>
|
||||
<span class="bg-accent-light"
|
||||
<span class="bg-accent-dark"
|
||||
>{{ getConvertTimer(roomInfo.timeRoomInterval) }} </span
|
||||
>비밀 대화방입니다.
|
||||
</div>
|
||||
|
@ -78,9 +86,18 @@
|
|||
</button>
|
||||
|
||||
<mat-menu #contactMenu="matMenu" [hasBackdrop]="false">
|
||||
<button mat-menu-item (click)="onClickContextMenu('OPEN_ALBUM_LIST')">
|
||||
앨범함
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickContextMenu('OPEN_FILE_LIST')">
|
||||
파일함
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickContextMenu('ADD_MEMBER')">
|
||||
대화상대추가
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickContextMenu('ADD_GROUP')">
|
||||
그룹멤버로추가
|
||||
</button>
|
||||
<button mat-menu-item (click)="onClickContextMenu('EDIT_ROOM')">
|
||||
대화방설정
|
||||
</button>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
.chat-toolbar {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
min-height: 70px;
|
||||
min-height: 80px;
|
||||
align-items: center;
|
||||
background-color: #ffffff !important;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
|
@ -68,7 +68,7 @@
|
|||
height: 20px;
|
||||
span {
|
||||
border-radius: 10px;
|
||||
padding: 1px 10px;
|
||||
padding: 2px 10px;
|
||||
margin-right: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
|
@ -40,12 +40,14 @@ import * as AppStore from '@app/store';
|
|||
import * as EventStore from '@app/store/messenger/event';
|
||||
import * as ChatStore from '@app/store/messenger/chat';
|
||||
import * as RoomStore from '@app/store/messenger/room';
|
||||
import * as SyncStore from '@app/store/messenger/sync';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import {
|
||||
EnvironmentsInfo,
|
||||
KEY_ENVIRONMENTS_INFO,
|
||||
UserSelectDialogType
|
||||
UserSelectDialogType,
|
||||
RightDrawer
|
||||
} from '@app/types';
|
||||
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
|
||||
import { tap, take, map, catchError } from 'rxjs/operators';
|
||||
|
@ -84,6 +86,12 @@ import {
|
|||
EditChatRoomDialogResult,
|
||||
EditChatRoomDialogData
|
||||
} from '../dialogs/chat/edit-chat-room.dialog.component';
|
||||
import {
|
||||
SelectGroupDialogComponent,
|
||||
SelectGroupDialogResult,
|
||||
SelectGroupDialogData
|
||||
} from '../dialogs/group/select-group.dialog.component';
|
||||
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-messages',
|
||||
|
@ -794,6 +802,24 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
|
||||
async onClickContextMenu(menuType: string) {
|
||||
switch (menuType) {
|
||||
case 'OPEN_ALBUM_LIST':
|
||||
{
|
||||
this.store.dispatch(
|
||||
ChatStore.selectedRightDrawer({
|
||||
req: RightDrawer.AlbumBox
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'OPEN_FILE_LIST':
|
||||
{
|
||||
this.store.dispatch(
|
||||
ChatStore.selectedRightDrawer({
|
||||
req: RightDrawer.FileBox
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'ADD_MEMBER':
|
||||
{
|
||||
const result = await this.dialogService.open<
|
||||
|
@ -838,6 +864,40 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'ADD_GROUP':
|
||||
{
|
||||
const result = await this.dialogService.open<
|
||||
SelectGroupDialogComponent,
|
||||
SelectGroupDialogData,
|
||||
SelectGroupDialogResult
|
||||
>(SelectGroupDialogComponent, {
|
||||
width: '600px',
|
||||
data: {
|
||||
title: 'Group Select'
|
||||
}
|
||||
});
|
||||
|
||||
if (!!result && !!result.choice && result.choice) {
|
||||
if (!!result.group) {
|
||||
const oldGroup: GroupDetailData = result.group;
|
||||
const trgtUserSeq: number[] = [];
|
||||
result.group.userSeqs.map(seq => trgtUserSeq.push(seq));
|
||||
this.userInfoList
|
||||
.filter(v => result.group.userSeqs.indexOf(v.seq) < 0)
|
||||
.forEach(user => {
|
||||
trgtUserSeq.push(user.seq);
|
||||
});
|
||||
|
||||
this.store.dispatch(
|
||||
SyncStore.updateGroupMember({
|
||||
oldGroup,
|
||||
trgtUserSeq
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'EDIT_ROOM':
|
||||
{
|
||||
const result = await this.dialogService.open<
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<ng-container *ngIf="selectedRightDrawer" [ngSwitch]="selectedRightDrawer">
|
||||
<app-layout-chat-right-drawer-file-box *ngSwitchCase="RightDrawer.FileBox">
|
||||
</app-layout-chat-right-drawer-file-box>
|
||||
|
||||
<app-layout-chat-right-drawer-album-box *ngSwitchCase="RightDrawer.AlbumBox">
|
||||
</app-layout-chat-right-drawer-album-box>
|
||||
</ng-container>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RightDrawerComponent } from './right-drawer.component';
|
||||
|
||||
describe('RightDrawerComponent', () => {
|
||||
let component: RightDrawerComponent;
|
||||
let fixture: ComponentFixture<RightDrawerComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RightDrawerComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RightDrawerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { RightDrawer } from '@app/types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-right-drawer',
|
||||
templateUrl: './right-drawer.component.html',
|
||||
styleUrls: ['./right-drawer.component.scss']
|
||||
})
|
||||
export class RightDrawerComponent implements OnInit {
|
||||
@Input()
|
||||
selectedRightDrawer: RightDrawer;
|
||||
|
||||
RightDrawer = RightDrawer;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<p>album-box works!</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AlbumBoxComponent } from './album-box.component';
|
||||
|
||||
describe('AlbumBoxComponent', () => {
|
||||
let component: AlbumBoxComponent;
|
||||
let fixture: ComponentFixture<AlbumBoxComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AlbumBoxComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AlbumBoxComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-chat-right-drawer-album-box',
|
||||
templateUrl: './album-box.component.html',
|
||||
styleUrls: ['./album-box.component.scss']
|
||||
})
|
||||
export class AlbumBoxComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<p>file-box works!</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FileBoxComponent } from './file-box.component';
|
||||
|
||||
describe('FileBoxComponent', () => {
|
||||
let component: FileBoxComponent;
|
||||
let fixture: ComponentFixture<FileBoxComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ FileBoxComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileBoxComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-chat-right-drawer-file-box',
|
||||
templateUrl: './file-box.component.html',
|
||||
styleUrls: ['./file-box.component.scss']
|
||||
})
|
||||
export class FileBoxComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import { FileBoxComponent } from './file-box.component';
|
||||
import { AlbumBoxComponent } from './album-box.component';
|
||||
|
||||
export const RIGHT_DRAWER_COMPONENTS = [FileBoxComponent, AlbumBoxComponent];
|
|
@ -76,3 +76,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.mat-tab-group>.mat-tab-header .mat-tab-label{
|
||||
border-bottom:2px solid #dddddd;
|
||||
}
|
|
@ -5,12 +5,11 @@
|
|||
></app-layout-messenger-left-side>
|
||||
</div>
|
||||
<mat-drawer-container class="contents" autosize>
|
||||
<mat-drawer #drawer mode="over">
|
||||
<!-- <mat-drawer #drawer mode="over">
|
||||
<p>Auto-resizing sidenav</p>
|
||||
</mat-drawer>
|
||||
</mat-drawer> -->
|
||||
<div class="messages">
|
||||
<app-layout-messenger-intro
|
||||
(click)="drawer.toggle()"
|
||||
*ngIf="!(this.selectedChat$ | async)"
|
||||
></app-layout-messenger-intro>
|
||||
<!-- <app-layout-messenger-intro
|
||||
|
@ -21,9 +20,17 @@
|
|||
(openProfile)="onClickOpenProfile($event)"
|
||||
></app-layout-messenger-messages>
|
||||
</div>
|
||||
<!-- <mat-drawer #drawer mode="side" position="end">
|
||||
<p>Auto-resizing sidenav</p>
|
||||
</mat-drawer> -->
|
||||
<mat-drawer
|
||||
#rightDrawer
|
||||
mode="side"
|
||||
position="end"
|
||||
(openedChange)="onOpenedChange($event)"
|
||||
>
|
||||
<app-layout-messenger-right-drawer
|
||||
[selectedRightDrawer]="selectedRightDrawer$ | async"
|
||||
>
|
||||
</app-layout-messenger-right-drawer>
|
||||
</mat-drawer>
|
||||
</mat-drawer-container>
|
||||
|
||||
<!-- <div class="right-side">
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { map, tap } from 'rxjs/operators';
|
||||
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
|
||||
import { Component, OnInit, Inject, OnDestroy, ViewChild } from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import * as AppSotre from '@app/store';
|
||||
import * as ChatStore from '@app/store/messenger/chat';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import {
|
||||
WindowIdle,
|
||||
|
@ -25,6 +26,7 @@ import {
|
|||
ProfileDialogData,
|
||||
ProfileDialogResult
|
||||
} from '@app/layouts/messenger/dialogs/profile/profile.dialog.component';
|
||||
import { MatSidenav, MatDrawer } from '@angular/material';
|
||||
|
||||
@Component({
|
||||
selector: 'app-page-messenger-main',
|
||||
|
@ -33,8 +35,11 @@ import {
|
|||
})
|
||||
export class MainPageComponent implements OnInit {
|
||||
selectedChat$: Observable<string | null>;
|
||||
selectedRightDrawer$: Observable<string | null>;
|
||||
idleStateChangedSubscription: Subscription;
|
||||
|
||||
@ViewChild('rightDrawer', { static: true }) rightDrawer: MatDrawer;
|
||||
|
||||
constructor(
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private store: Store<any>,
|
||||
|
@ -44,7 +49,23 @@ export class MainPageComponent implements OnInit {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.selectedChat$ = this.store.pipe(
|
||||
select(AppSotre.MessengerSelector.ChatSelector.selectedRoom)
|
||||
select(AppSotre.MessengerSelector.ChatSelector.selectedRoom),
|
||||
tap(selectedRoom => {
|
||||
if (!selectedRoom) {
|
||||
this.rightDrawer.close();
|
||||
}
|
||||
return selectedRoom;
|
||||
})
|
||||
);
|
||||
this.selectedRightDrawer$ = this.store.pipe(
|
||||
select(AppSotre.MessengerSelector.ChatSelector.selectedRightDrawer),
|
||||
tap(selectedRightDrawer => {
|
||||
if (!!selectedRightDrawer) {
|
||||
this.rightDrawer.open();
|
||||
} else {
|
||||
this.rightDrawer.close();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.idleStateChangedSubscription = this.nativeService
|
||||
|
@ -75,6 +96,16 @@ export class MainPageComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
onOpenedChange(event: boolean) {
|
||||
if (!event) {
|
||||
this.store.dispatch(
|
||||
ChatStore.selectedRightDrawer({
|
||||
req: null
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onClickOpenProfile(userInfo: UserInfo | UserInfoSS | UserInfoF | UserInfoDN) {
|
||||
this.dialogService.open<
|
||||
ProfileDialogComponent,
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
MassTalkDownloadRequest,
|
||||
MassTalkDownloadResponse
|
||||
} from '@ucap-webmessenger/api-common';
|
||||
import { RightDrawer } from '@app/types';
|
||||
|
||||
export const selectedRoom = createAction(
|
||||
'[Messenger::Chat] selectedRoom',
|
||||
|
@ -43,3 +44,12 @@ export const openRoom = createAction(
|
|||
'[Messenger::Chat] Open Room',
|
||||
props<{ userSeqList: number[]; isTimeRoom?: boolean }>()
|
||||
);
|
||||
|
||||
export const selectedRightDrawer = createAction(
|
||||
'[Messenger::Chat] Selected Right Drawer',
|
||||
props<{ req: RightDrawer }>()
|
||||
);
|
||||
export const clearRightDrawer = createAction(
|
||||
'[Messenger::Chat] Clear Right Drawer',
|
||||
props()
|
||||
);
|
||||
|
|
|
@ -10,7 +10,8 @@ import {
|
|||
selectedMassDetail,
|
||||
massTalkDownload,
|
||||
massTalkDownloadFailure,
|
||||
massTalkDownloadSuccess
|
||||
massTalkDownloadSuccess,
|
||||
clearSelectedRoom
|
||||
} from './actions';
|
||||
import { of } from 'rxjs';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
|
@ -24,6 +25,7 @@ import {
|
|||
AlertDialogComponent,
|
||||
AlertDialogData
|
||||
} from '@ucap-webmessenger/ui';
|
||||
import { initialState } from '../event';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
|
|
@ -6,7 +6,9 @@ import {
|
|||
massTalkDownloadFailure,
|
||||
massTalkDownload,
|
||||
massTalkDownloadSuccess,
|
||||
clearSelectedRoom
|
||||
clearSelectedRoom,
|
||||
selectedRightDrawer,
|
||||
clearRightDrawer
|
||||
} from './actions';
|
||||
|
||||
export const reducer = createReducer(
|
||||
|
@ -49,5 +51,18 @@ export const reducer = createReducer(
|
|||
...state,
|
||||
massDetailProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(selectedRightDrawer, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
selectedRightDrawer: action.req
|
||||
};
|
||||
}),
|
||||
on(clearRightDrawer, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
selectedRightDrawer: null
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -5,12 +5,15 @@ export interface State {
|
|||
|
||||
selectedMassDetail: number | null;
|
||||
massDetailProcessing: boolean;
|
||||
|
||||
selectedRightDrawer: string | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
selectedRoom: null,
|
||||
selectedMassDetail: null,
|
||||
massDetailProcessing: false
|
||||
massDetailProcessing: false,
|
||||
selectedRightDrawer: ''
|
||||
};
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
|
@ -22,6 +25,10 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
selectedMassDetail: createSelector(
|
||||
selector,
|
||||
(state: State) => state.selectedMassDetail
|
||||
),
|
||||
selectedRightDrawer: createSelector(
|
||||
selector,
|
||||
(state: State) => state.selectedRightDrawer
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,12 +16,17 @@ import {
|
|||
CancelResponse,
|
||||
EventJson
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
import {
|
||||
InfoRequest as FileInfoRequest,
|
||||
InfoResponse as FileInfoResponse,
|
||||
FileDownloadInfo,
|
||||
FileInfo
|
||||
} from '@ucap-webmessenger/protocol-file';
|
||||
|
||||
export const info = createAction(
|
||||
'[Messenger::Event] Info',
|
||||
props<InfoRequest>()
|
||||
);
|
||||
|
||||
export const infoSuccess = createAction(
|
||||
'[Messenger::Event] Info Success',
|
||||
props<{
|
||||
|
@ -29,6 +34,27 @@ export const infoSuccess = createAction(
|
|||
res: InfoResponse;
|
||||
}>()
|
||||
);
|
||||
export const infoFailure = createAction(
|
||||
'[Messenger::Event] Info Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
export const fileInfo = createAction(
|
||||
'[Messenger::Event] File Info',
|
||||
props<{ req: FileInfoRequest }>()
|
||||
);
|
||||
export const fileInfoSuccess = createAction(
|
||||
'[Messenger::Event] File Info Success',
|
||||
props<{
|
||||
fileInfoList: FileInfo[];
|
||||
fileInfoCheckList: FileDownloadInfo[];
|
||||
res: FileInfoResponse;
|
||||
}>()
|
||||
);
|
||||
export const fileInfoFailure = createAction(
|
||||
'[Messenger::Event] File Info Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
export const infoMoreSuccess = createAction(
|
||||
'[Messenger::Event] Info More Success',
|
||||
|
@ -43,11 +69,6 @@ export const infoIntervalClear = createAction(
|
|||
props()
|
||||
);
|
||||
|
||||
export const infoFailure = createAction(
|
||||
'[Messenger::Event] Info Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
export const newInfo = createAction(
|
||||
'[Messenger::Event] New Info',
|
||||
props<{
|
||||
|
|
|
@ -70,7 +70,10 @@ import {
|
|||
sendMass,
|
||||
sendMassFailure,
|
||||
infoMoreSuccess,
|
||||
infoIntervalClear
|
||||
infoIntervalClear,
|
||||
fileInfo,
|
||||
fileInfoSuccess,
|
||||
fileInfoFailure
|
||||
} from './actions';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import {
|
||||
|
@ -85,6 +88,18 @@ import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
|||
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
|
||||
import { StatusCode } from '@ucap-webmessenger/api';
|
||||
import { CONST } from '@ucap-webmessenger/core';
|
||||
import {
|
||||
FileProtocolService,
|
||||
SSVC_TYPE_FILE_INFO_DATA,
|
||||
SSVC_TYPE_FILE_INFO_CHECK_DATA,
|
||||
SSVC_TYPE_FILE_INFO_RES,
|
||||
FileInfo,
|
||||
FileDownloadInfo,
|
||||
InfoData as FileInfoData,
|
||||
InfoCheckData as FileInfoCheckData,
|
||||
InfoResponse as FileInfoResponse,
|
||||
FileType
|
||||
} from '@ucap-webmessenger/protocol-file';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
@ -136,7 +151,8 @@ export class Effects {
|
|||
}
|
||||
|
||||
if (req.baseSeq === 0) {
|
||||
// 최초 이벤트 목록 조회시 SSVC_TYPE_EVENT_READ_REQ 수행.
|
||||
// 최초 이벤트 목록 조회
|
||||
// SSVC_TYPE_EVENT_READ_REQ 수행.
|
||||
const maxSeq = Math.max.apply(
|
||||
Math,
|
||||
infoList.map(v => v.seq)
|
||||
|
@ -147,6 +163,17 @@ export class Effects {
|
|||
lastReadSeq: Number(maxSeq)
|
||||
})
|
||||
);
|
||||
|
||||
// File 정보 수집.
|
||||
this.store.dispatch(
|
||||
fileInfo({
|
||||
req: {
|
||||
roomSeq: req.roomSeq,
|
||||
// { 파일타입 } cf) I : 이미지 V: 동영상 F: 파일 "" 빈값이면 모든 타입을 내려줌
|
||||
type: FileType.All
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -160,6 +187,50 @@ export class Effects {
|
|||
{ dispatch: false }
|
||||
);
|
||||
|
||||
fileInfo$ = createEffect(
|
||||
() => {
|
||||
let fileInfoList: FileInfo[];
|
||||
let fileInfoCheckList: FileDownloadInfo[];
|
||||
|
||||
return this.actions$.pipe(
|
||||
ofType(fileInfo),
|
||||
tap(() => {
|
||||
fileInfoList = [];
|
||||
fileInfoCheckList = [];
|
||||
}),
|
||||
switchMap(action => {
|
||||
return this.fileProtocolService.info(action.req).pipe(
|
||||
map(res => {
|
||||
switch (res.SSVC_TYPE) {
|
||||
case SSVC_TYPE_FILE_INFO_DATA:
|
||||
fileInfoList.push(...(res as FileInfoData).fileInfos);
|
||||
break;
|
||||
case SSVC_TYPE_FILE_INFO_CHECK_DATA:
|
||||
fileInfoCheckList.push(
|
||||
...(res as FileInfoCheckData).fileDownloadInfos
|
||||
);
|
||||
break;
|
||||
case SSVC_TYPE_FILE_INFO_RES:
|
||||
{
|
||||
this.store.dispatch(
|
||||
fileInfoSuccess({
|
||||
fileInfoList,
|
||||
fileInfoCheckList,
|
||||
res: res as FileInfoResponse
|
||||
})
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}),
|
||||
catchError(error => of(fileInfoFailure({ error })))
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
infoIntervalClear$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
|
@ -584,6 +655,7 @@ export class Effects {
|
|||
private store: Store<any>,
|
||||
private commonApiService: CommonApiService,
|
||||
private eventProtocolService: EventProtocolService,
|
||||
private fileProtocolService: FileProtocolService,
|
||||
private roomProtocolService: RoomProtocolService,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private logger: NGXLogger
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
import { initialState, adapterInfoList } from './state';
|
||||
import {
|
||||
initialState,
|
||||
adapterInfoList,
|
||||
adapterFileInfoList,
|
||||
adapterFileInfoCheckList
|
||||
} from './state';
|
||||
import {
|
||||
infoSuccess,
|
||||
appendInfoList,
|
||||
|
@ -7,9 +12,11 @@ import {
|
|||
infoFailure,
|
||||
recallInfoList,
|
||||
delInfoList,
|
||||
infoMoreSuccess
|
||||
infoMoreSuccess,
|
||||
fileInfoSuccess
|
||||
} from './actions';
|
||||
import * as AuthenticationStore from '@app/store/account/authentication';
|
||||
import * as ChatStore from '@app/store/messenger/chat';
|
||||
import { Info, EventType, EventJson } from '@ucap-webmessenger/protocol-event';
|
||||
import { CONST } from '@ucap-webmessenger/core';
|
||||
|
||||
|
@ -52,7 +59,6 @@ export const reducer = createReducer(
|
|||
: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(infoFailure, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
|
@ -60,6 +66,23 @@ export const reducer = createReducer(
|
|||
};
|
||||
}),
|
||||
|
||||
on(fileInfoSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
fileInfoList: adapterFileInfoList.addAll(action.fileInfoList, {
|
||||
...state.fileInfoList
|
||||
}),
|
||||
fileInfoCheckList: adapterFileInfoCheckList.addAll(
|
||||
action.fileInfoCheckList,
|
||||
{
|
||||
...state.fileInfoCheckList
|
||||
}
|
||||
),
|
||||
fileInfoListProcessing: false,
|
||||
fileInfoSyncDate: new Date().toString()
|
||||
};
|
||||
}),
|
||||
|
||||
on(appendInfoList, (state, action) => {
|
||||
const eventinfo = action.info;
|
||||
|
||||
|
@ -109,5 +132,10 @@ export const reducer = createReducer(
|
|||
return {
|
||||
...initialState
|
||||
};
|
||||
}),
|
||||
on(ChatStore.clearSelectedRoom, (state, action) => {
|
||||
return {
|
||||
...initialState
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -5,14 +5,22 @@ import {
|
|||
EventJson
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
import { EntityState, createEntityAdapter } from '@ngrx/entity';
|
||||
import { FileInfo, FileDownloadInfo } from '@ucap-webmessenger/protocol-file';
|
||||
|
||||
export interface InfoListState extends EntityState<Info<EventJson>> {}
|
||||
export interface FileInfoListState extends EntityState<FileInfo> {}
|
||||
export interface FileInfoCheckListState extends EntityState<FileDownloadInfo> {}
|
||||
|
||||
export interface State {
|
||||
infoListProcessing: boolean;
|
||||
infoList: InfoListState;
|
||||
infoStatus: InfoResponse | null;
|
||||
remainInfo: boolean;
|
||||
|
||||
fileInfoListProcessing: boolean;
|
||||
fileInfoList: FileInfoListState;
|
||||
fileInfoCheckList: FileInfoCheckListState;
|
||||
fileInfoSyncDate: string;
|
||||
}
|
||||
|
||||
export const adapterInfoList = createEntityAdapter<Info<EventJson>>({
|
||||
|
@ -21,14 +29,37 @@ export const adapterInfoList = createEntityAdapter<Info<EventJson>>({
|
|||
return a.seq - b.seq;
|
||||
}
|
||||
});
|
||||
export const adapterFileInfoList = createEntityAdapter<FileInfo>({
|
||||
selectId: info => info.seq,
|
||||
sortComparer: (a, b) => {
|
||||
return b.seq - a.seq;
|
||||
}
|
||||
});
|
||||
export const adapterFileInfoCheckList = createEntityAdapter<FileDownloadInfo>({
|
||||
selectId: info => info.seq,
|
||||
sortComparer: (a, b) => {
|
||||
return b.seq - a.seq;
|
||||
}
|
||||
});
|
||||
|
||||
const infoListInitialState: InfoListState = adapterInfoList.getInitialState({});
|
||||
const fileInfoListInitialState: FileInfoListState = adapterFileInfoList.getInitialState(
|
||||
{}
|
||||
);
|
||||
const fileInfoCheckListInitialState: FileInfoCheckListState = adapterFileInfoCheckList.getInitialState(
|
||||
{}
|
||||
);
|
||||
|
||||
export const initialState: State = {
|
||||
infoListProcessing: false,
|
||||
infoList: infoListInitialState,
|
||||
infoStatus: null,
|
||||
remainInfo: false
|
||||
remainInfo: false,
|
||||
|
||||
fileInfoListProcessing: false,
|
||||
fileInfoList: fileInfoListInitialState,
|
||||
fileInfoCheckList: fileInfoCheckListInitialState,
|
||||
fileInfoSyncDate: ''
|
||||
};
|
||||
|
||||
const {
|
||||
|
@ -37,12 +68,32 @@ const {
|
|||
selectIds: ngeSelectIdsInfoList,
|
||||
selectTotal: ngeSelectTotalInfoList
|
||||
} = adapterInfoList.getSelectors();
|
||||
const {
|
||||
selectAll: ngeSelectAllFileInfoList,
|
||||
selectEntities: ngeSelectEntitiesFileInfoList,
|
||||
selectIds: ngeSelectIdsFileInfoList,
|
||||
selectTotal: ngeSelectTotalFileInfoList
|
||||
} = adapterFileInfoList.getSelectors();
|
||||
const {
|
||||
selectAll: ngeSelectAllFileInfoCheckList,
|
||||
selectEntities: ngeSelectEntitiesFileInfoCheckList,
|
||||
selectIds: ngeSelectIdsFileInfoCheckList,
|
||||
selectTotal: ngeSelectTotalFileInfoCheckList
|
||||
} = adapterFileInfoCheckList.getSelectors();
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
const selectInfoList = createSelector(
|
||||
selector,
|
||||
(state: State) => state.infoList
|
||||
);
|
||||
const selectFileInfoList = createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoList
|
||||
);
|
||||
const selectFileInfoCheckList = createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoCheckList
|
||||
);
|
||||
|
||||
return {
|
||||
infoListProcessing: createSelector(
|
||||
|
@ -75,6 +126,51 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
selectInfoList,
|
||||
ngeSelectEntitiesInfoList,
|
||||
(_, entities) => (!!entities ? entities[seq] : undefined)
|
||||
),
|
||||
|
||||
fileInfoListProcessing: createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoListProcessing
|
||||
),
|
||||
fileInfoSyncDate: createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoSyncDate
|
||||
),
|
||||
fileInfoList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoList
|
||||
),
|
||||
fileInfoCheckList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.fileInfoCheckList
|
||||
),
|
||||
selectAllFileInfoList: createSelector(
|
||||
selectFileInfoList,
|
||||
ngeSelectAllFileInfoList
|
||||
),
|
||||
selectEntitiesFileInfoList: createSelector(
|
||||
selectFileInfoList,
|
||||
ngeSelectEntitiesFileInfoList
|
||||
),
|
||||
selectFileInfoList: (seq: number) =>
|
||||
createSelector(
|
||||
selectFileInfoList,
|
||||
ngeSelectEntitiesFileInfoList,
|
||||
(_, entities) => (!!entities ? entities[seq] : undefined)
|
||||
),
|
||||
selectAllFileInfoCheckList: createSelector(
|
||||
selectFileInfoCheckList,
|
||||
ngeSelectAllFileInfoCheckList
|
||||
),
|
||||
selectEntitiesFileInfoCheckList: createSelector(
|
||||
selectFileInfoCheckList,
|
||||
ngeSelectEntitiesFileInfoCheckList
|
||||
),
|
||||
selectFileInfoCheckList: (seq: number) =>
|
||||
createSelector(
|
||||
selectFileInfoCheckList,
|
||||
ngeSelectEntitiesFileInfoCheckList,
|
||||
(_, entities) => (!!entities ? entities[seq] : undefined)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export * from './environment.type';
|
||||
export * from './login-info.type';
|
||||
export * from './userselect.dialog.type';
|
||||
export * from './right-drawer.type';
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export enum RightDrawer {
|
||||
FileBox = 'FILE_BOX',
|
||||
AlbumBox = 'ALBUM_BOX'
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
export enum FileType {
|
||||
// I : 이미지
|
||||
/** I : 이미지 */
|
||||
Image = 'I',
|
||||
// V : 동영상
|
||||
/** V : 동영상 */
|
||||
Video = 'V',
|
||||
// F : 파일
|
||||
/** F : 파일 */
|
||||
File = 'F',
|
||||
// S : 사운드파일
|
||||
/** S : 사운드파일 */
|
||||
Sound = 'S',
|
||||
// "" 빈값이면 모든 타입을 내려줌
|
||||
All = ''
|
||||
/** "" 빈값이면 모든 타입을 내려줌 */
|
||||
All = ' '
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
flex-direction: column;
|
||||
text-align: left;
|
||||
line-height: 1.6em;
|
||||
width:100%;
|
||||
margin-top:10px;
|
||||
.file-name {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
@ -59,5 +61,14 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
&.expired{
|
||||
li{
|
||||
width:100%;
|
||||
white-space: nowrap;
|
||||
color:#999999;
|
||||
align-items: center;
|
||||
line-height:40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,16 +51,17 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box-more-spacer {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
::ng-deep .mat-content{
|
||||
overflow: unset;
|
||||
overflow: unset !important;
|
||||
}
|
||||
|
||||
.number{
|
||||
margin-left:6px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
margin-left:6px;
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<div class="ucap-image-viewer-container">
|
||||
<mat-toolbar color="primary">
|
||||
<mat-toolbar class="bg-primary-dark">
|
||||
<span>Third Line</span>
|
||||
<span class="ucap-image-viewer-spacer"></span>
|
||||
<mat-icon
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
<div class="ucap-video-viewer-container">
|
||||
<mat-toolbar color="accent" class="ucap-video-viewer-header">
|
||||
<mat-icon class="ucap-video-viewer-icon">video_label</mat-icon>
|
||||
<!--<mat-icon class="ucap-video-viewer-icon">video_label</mat-icon>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="butt" stroke-linejoin="round" class="ucap-video-viewer-icon">
|
||||
<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect>
|
||||
<line x1="7" y1="2" x2="7" y2="22"></line>
|
||||
<line x1="17" y1="2" x2="17" y2="22"></line>
|
||||
<line x1="2" y1="12" x2="22" y2="12"></line>
|
||||
<line x1="2" y1="7" x2="7" y2="7"></line>
|
||||
<line x1="2" y1="17" x2="7" y2="17"></line>
|
||||
<line x1="17" y1="17" x2="22" y2="17"></line>
|
||||
<line x1="17" y1="7" x2="22" y2="7"></line>
|
||||
</svg>
|
||||
<span class="ucap-video-viewer-title">{{ fileInfo.fileName }}</span>
|
||||
<span class="ucap-video-viewer-spacer"></span>
|
||||
<button
|
||||
|
@ -11,16 +22,25 @@
|
|||
aria-label=""
|
||||
(click)="onClickDownload()"
|
||||
>
|
||||
<mat-icon>get_app</mat-icon>
|
||||
<!--<mat-icon>get_app</mat-icon>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="butt" stroke-linejoin="round">
|
||||
<path d="M3 15v4c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2v-4M17 9l-5 5-5-5M12 12.8V2.5" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<span class="stroke-bar"></span>
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
class="ucap-video-viewer-action"
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
class="ucap-image-viewer-action btn-close"
|
||||
matTooltip="뷰어닫기"
|
||||
(click)="onClickClose()"
|
||||
>
|
||||
Close
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="butt" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
<div class="ucap-video-viewer-body">
|
||||
|
@ -41,43 +61,52 @@
|
|||
(loadeddata)="onLoadedDataVideo()"
|
||||
></video>
|
||||
</div>
|
||||
<div
|
||||
class="ucap-video-viewer-video-time"
|
||||
fxLayout="row"
|
||||
fxLayout.xs="column"
|
||||
fxLayoutAlign="center center"
|
||||
>
|
||||
<mat-slider
|
||||
#timeSlider
|
||||
min="0"
|
||||
[max]="duration"
|
||||
[value]="currentTime"
|
||||
(change)="onChangeTimeSlider($event)"
|
||||
<div class="viewer-bottom">
|
||||
<div
|
||||
class="ucap-video-viewer-video-time"
|
||||
fxLayout="row"
|
||||
fxLayout.xs="column"
|
||||
fxLayoutAlign="center center"
|
||||
>
|
||||
</mat-slider>
|
||||
</div>
|
||||
<div
|
||||
class="ucap-video-viewer-video-controls"
|
||||
fxLayout="row"
|
||||
fxLayout.xs="column"
|
||||
fxLayoutAlign="center center"
|
||||
>
|
||||
<div class="ucap-video-viewer-video-time-current">
|
||||
{{ currentTime | ucapSecondsToMinutes }}
|
||||
<mat-slider
|
||||
#timeSlider
|
||||
min="0"
|
||||
[max]="duration"
|
||||
[value]="currentTime"
|
||||
(change)="onChangeTimeSlider($event)"
|
||||
>
|
||||
</mat-slider>
|
||||
</div>
|
||||
<span class="ucap-video-viewer-spacer"></span>
|
||||
<button
|
||||
mat-icon-button
|
||||
class="ucap-video-viewer-action"
|
||||
[matTooltip]="playing ? '멈춤' : '재생'"
|
||||
aria-label=""
|
||||
(click)="onClickPlayOrPause()"
|
||||
<div
|
||||
class="ucap-video-viewer-video-controls"
|
||||
fxLayout="row"
|
||||
fxLayout.xs="column"
|
||||
>
|
||||
<mat-icon>{{ playing ? 'pause' : 'play_arrow' }}</mat-icon>
|
||||
</button>
|
||||
<span class="ucap-video-viewer-spacer"></span>
|
||||
<div class="ucap-video-viewer-video-time-total">
|
||||
{{ duration | ucapSecondsToMinutes }}
|
||||
<div class="ucap-video-viewer-video-time-current">
|
||||
{{ currentTime | ucapSecondsToMinutes }}
|
||||
</div>
|
||||
<span class="ucap-video-viewer-spacer"></span>
|
||||
<button
|
||||
mat-icon-button
|
||||
class="ucap-video-viewer-action"
|
||||
[matTooltip]="playing ? '멈춤' : '재생'"
|
||||
aria-label=""
|
||||
(click)="onClickPlayOrPause()"
|
||||
>
|
||||
<mat-icon>{{ playing ? 'pause' : 'play_arrow' }}</mat-icon>
|
||||
<!--{{ playing ? '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="butt" stroke-linejoin="round">
|
||||
<rect x="6" y="4" width="4" height="16"></rect>
|
||||
<rect x="14" y="4" width="4" height="16"></rect>
|
||||
</svg>' : '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="butt" stroke-linejoin="round">
|
||||
<polygon points="5 3 19 12 5 21 5 3"></polygon>
|
||||
</svg>'}}-->
|
||||
</button>
|
||||
<span class="ucap-video-viewer-spacer"></span>
|
||||
<div class="ucap-video-viewer-video-time-total">
|
||||
{{ duration | ucapSecondsToMinutes }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,40 +4,57 @@
|
|||
|
||||
.ucap-video-viewer-header {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
height: 60px;
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
|
||||
background-color: #333333;
|
||||
|
||||
.ucap-video-viewer-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ucap-video-viewer-title {
|
||||
font-size:16px;
|
||||
}
|
||||
.stroke-bar {
|
||||
width: 1px;
|
||||
height: 30px;
|
||||
background-color: rgba(256, 256, 256, 0.3);
|
||||
margin: 0 10px;
|
||||
}
|
||||
.ucap-image-viewer-action {
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ucap-video-viewer-body {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 70px;
|
||||
height: calc(100% - 60px);
|
||||
|
||||
.ucap-video-viewer-video-icon {
|
||||
width: 100%;
|
||||
height: calc(100% - 60px);
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
.ucap-video-viewer-video-time {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
}
|
||||
.ucap-video-viewer-video-controls {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
|
||||
.ucap-video-viewer-video-time-current {
|
||||
padding-left: 30px;
|
||||
.viewer-bottom{
|
||||
background-color: #212121;
|
||||
color:#ffffff;
|
||||
.ucap-video-viewer-video-time {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
}
|
||||
.ucap-video-viewer-video-controls {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
|
||||
.ucap-video-viewer-video-time-total {
|
||||
padding-right: 30px;
|
||||
.ucap-video-viewer-video-time-current {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.ucap-video-viewer-video-time-total {
|
||||
padding-right: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +62,22 @@
|
|||
flex: 1 1 auto;
|
||||
}
|
||||
.ucap-video-viewer-action {
|
||||
.mat-icon{
|
||||
font-size: 40px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height:40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-slider {
|
||||
width: 95%;
|
||||
width: 94%;
|
||||
}
|
||||
|
||||
::ng-deep .mat-slider-horizontal .mat-slider-track-background{
|
||||
background-color: #999999 !important;
|
||||
}
|
||||
::ng-deep .mat-slider-min-value:not(.mat-slider-thumb-label-showing) .mat-slider-thumb{
|
||||
border-color: #999999 !important;
|
||||
}
|
Loading…
Reference in New Issue
Block a user