This commit is contained in:
Park Byung Eun 2020-06-10 14:38:49 +09:00
parent 7dcec1aaad
commit 0c696c3a03
31 changed files with 115 additions and 1998 deletions

View File

@ -6,3 +6,67 @@
파일 컴포넌트
문서 컴포넌트
대화 복사
일반 텍스트
장문 텍스트
combineLatest([
this.store.pipe(select(LoginSelector.loginRes)),
this.store.pipe(select(DepartmentSelector.departmentInfoList))
])
.pipe(takeUntil(this.ngOnDestroySubject))
.subscribe(([loginRes, deptInfoList]) => {
this.loginRes = loginRes;
this.treeData = {
deptInfoList,
displayRoot: environment.productConfig.organization.displayRoot,
expanded: !!this._initialExpanded
? [this._initialExpanded]
: undefined
};
this.changeDetectorRef.markForCheck();
if (!!loginRes && !!deptInfoList) {
this._initialExpanded = undefined;
}
});
http://lftalk2.lfcorp.com:8011/Common/FileTalkDownload.aspx
?
p_user_seq=102&
p_device_type=P&
p_token=MTg1MDM5NTc5Nzk1MTQ1MTk0ODU0MTY2MTI0NDE2ODY3NjY5ODY5Ng&
p_att_seq=68450
attachmentsSeq: "15186849"
deviceType: "W"
token: "NDcyNDEwMjg2NjcyMjg3MTkxNzAyNDk2ODEwMzg2MDI4NjY5NzcyNA"
userSeq: 770074
http://13.124.88.127:8011/Common/FileTalkDownload.aspx?p_user_seq=770074&p_device_type=W&p_token=NDcyNDEwMjg2NjcyMjg3MTkxNzAyNDk2ODEwMzg2MDI4NjY5NzcyNA&p_att_seq=15186849
public urlForFileTalkDownload(
req: FileTalkDownloadRequest,
fileTalkDownloadUrl?: string
): string {
const fileTalkDownloadEncodeMap = {
userSeq: 'p_user_seq',
deviceType: 'p_device_type',
token: 'p_token',
attachmentsSeq: 'p_att_seq'
};
const extraParams: any = {};
const url = ParameterUtil.encode(
fileTalkDownloadEncodeMap,
req,
extraParams
);
const params = encodeFileTalkDownload(req);
const tttt = `${fileTalkDownloadUrl}?${url.toString()}`;
const temp = `${fileTalkDownloadUrl}${
!!params ? `?${params.toString()}` : ''
}`;
return tttt;
}

View File

@ -0,0 +1,50 @@
클립보드 다이얼로그
"Failed to execute 'query' on 'Permissions': The provided value 'clipboard' is not a valid enum value of type PermissionName."
"TypeError: Failed to execute 'query' on 'Permissions': The provided value 'clipboard' is not a valid enum value of type PermissionName.
at FormSectionComponent.onPasteReply (http://localhost:4200/pages-chat-chat-page-module.27fafdb1d452d17534ca.hot-update.js:251:14)
at FormSectionComponent_Template_textarea_paste_8_listener (http://localhost:4200/pages-chat-chat-page-module.27fafdb1d452d17534ca.hot-update.js:351:282)
at executeListenerWithErrorHandling (http://localhost:4200/vendor.js:54608:16)
at wrapListenerIn_markDirtyAndPreventDefault (http://localhost:4200/vendor.js:54650:22)
at HTMLTextAreaElement.<anonymous> (http://localhost:4200/vendor.js:125315:38)
at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:443:35)
at Object.onInvokeTask (http://localhost:4200/vendor.js:71697:33)
at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:442:40)
at Zone.runTask (http://localhost:4200/polyfills.js:211:51)
at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:524:38)"
navigator.permissions
.query({
name: 'clipboard-read' as PermissionName
})
.then((permissionStatus) => {
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);
// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
});
navigator.permissions
.query({ name: 'clipboard-read' as PermissionName })
.then((result: PermissionStatus) => {
console.log('1: ', result);
if ('granted' === result.state || 'prompt' === result.state) {
console.log(event.clipboardData.items);
navigator.clipboard
.readText()
.then((value) => {
console.log(value);
})
.catch((reason) => {
console.log(reason);
});
}
})
.catch((reason) => {
console.log(reason);
});

View File

@ -1,117 +0,0 @@
<div class="ucap-binary-viewer-container">
<mat-toolbar class="ucap-binary-viewer-header">
<!--<mat-icon class="ucap-binary-viewer-icon">attachment</mat-icon>-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="butt"
stroke-linejoin="round"
class="ucap-binary-viewer-icon"
>
<path
d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"
></path>
</svg>
<span class="ucap-binary-viewer-title">{{
fileInfo.sentMessageJson.fileName
}}</span>
<span class="ucap-binary-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-binary-viewer-action"
matTooltip="{{ 'common.file.download' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickDownload()"
>
<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-icon-button
color="warn"
class="ucap-binary-viewer-action"
(click)="onClickClose()"
>
<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 style="position: relative;">
<div
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
style="position: absolute; width: 100%;"
>
<mat-progress-bar
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>
</div>
<div class="ucap-binary-viewer-body">
<div
class="ucap-binary-viewer-content-wrapper"
fxLayout="column"
fxLayout.xs="row"
fxFlexFill
fxLayoutAlign="center center"
>
<div class="circle-box">
<div
[ngClass]="[
'mime-icon',
'light',
'ico-' + fileInfo.sentMessageJson.fileExt
]"
>
<div class="ico"></div>
</div>
</div>
<div class="guide-msg">
{{ 'common.file.errors.noPreview' | translate }}
</div>
<div>
<button
colori
mat-raised-button
aria-label=""
(click)="onClickDownload()"
>
{{ 'common.file.download' | translate }}
</button>
</div>
</div>
</div>
</div>

View File

@ -1,67 +0,0 @@
.ucap-binary-viewer-container {
width: 100%;
height: 100%;
.ucap-binary-viewer-header {
width: 100%;
height: 60px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
background-color: #333333;
color: #ffffff;
.ucap-binary-viewer-icon {
margin-right: 10px;
}
.ucap-binary-viewer-title {
font-size: 16px;
}
.ucap-binary-viewer-spacer {
flex: 1 1 auto;
}
.stroke-bar {
width: 1px;
height: 30px;
background-color: rgba(256, 256, 256, 0.3);
margin: 0 10px;
}
.ucap-binary-viewer-action {
margin-left: auto;
width: 24px;
height: 24px;
margin-left: 10px;
&:hover {
opacity: 0.7;
}
}
}
.ucap-binary-viewer-body {
position: relative;
width: 100%;
height: calc(100% - 60px);
.ucap-image-viewer-image-wrapper {
height: 100%;
padding: 20px;
background-color: rgba(0, 0, 0, 0.9);
}
.circle-box {
display: flex;
width: 140px;
height: 140px;
border-radius: 50%;
justify-content: center;
align-items: center;
border: 2px solid #ffffff;
background-color: rgba(256, 256, 256, 0.7);
}
.guide-msg {
font-size: 16px;
margin: 30px;
color: #ffffff;
}
}
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { BinaryViewerComponent } from './binary-viewer.component';
describe('BinaryViewerComponent', () => {
let component: BinaryViewerComponent;
let fixture: ComponentFixture<BinaryViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [BinaryViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BinaryViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,41 +0,0 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileDownloadItem } from '@ucap-webmessenger/api';
import { FileInfo } from '@ucap-webmessenger/protocol-file';
import { NGXLogger } from 'ngx-logger';
@Component({
selector: 'ucap-binary-viewer',
templateUrl: './binary-viewer.component.html',
styleUrls: ['./binary-viewer.component.scss'],
animations: ucapAnimations
})
export class BinaryViewerComponent implements OnInit {
@Input()
fileInfo: FileInfo;
@Input()
fileDownloadUrl: string;
@Output()
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();
}
}

View File

@ -1,29 +0,0 @@
<div class="ucap-image-viewer-container">
<mat-toolbar class="bg-primary-dark">
<span>Third Line</span>
<span class="ucap-image-viewer-spacer"></span>
<mat-icon
class="example-icon"
aria-hidden="false"
aria-label="Example heart icon"
>favorite</mat-icon
>
<mat-icon
class="example-icon"
aria-hidden="false"
aria-label="Example delete icon"
>delete</mat-icon
>
</mat-toolbar>
<div style="position: relative;">
<div
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
style="position: absolute; width: 100%;"
>
<mat-progress-bar
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>
</div>
</div>

View File

@ -1,13 +0,0 @@
.ucap-document-viewer-container {
width: 100%;
height: 100%;
.ucap-document-viewer-header {
width: 100%;
height: 50px;
.ucap-document-viewer-spacer {
flex: 1 1 auto;
}
}
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { DocumentViewerComponent } from './document-viewer.component';
describe('DocumentViewerComponent', () => {
let component: DocumentViewerComponent;
let fixture: ComponentFixture<DocumentViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DocumentViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DocumentViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,39 +0,0 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileInfo } from '@ucap-webmessenger/protocol-file';
import { FileDownloadItem } from '@ucap-webmessenger/api';
@Component({
selector: 'ucap-document-viewer',
templateUrl: './document-viewer.component.html',
styleUrls: ['./document-viewer.component.scss'],
animations: ucapAnimations
})
export class DocumentViewerComponent implements OnInit {
@Input()
fileInfo: FileInfo;
@Input()
fileDownloadUrl: string;
@Output()
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();
}
}

View File

@ -1,20 +0,0 @@
<div
class="ucap-file-viewer-container"
[ngSwitch]="detectFileViewerType(currentFileInfo)"
>
<ucap-document-viewer
*ngSwitchCase="FileViewerType.Document"
[fileInfo]="currentFileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
>
</ucap-document-viewer>
<ucap-binary-viewer
*ngSwitchDefault
[fileInfo]="currentFileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-binary-viewer>
</div>

View File

@ -1,4 +0,0 @@
.ucap-file-viewer-container {
width: 100%;
height: 100%;
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { FileViewerComponent } from './file-viewer.component';
describe('FileViewerComponent', () => {
let component: FileViewerComponent;
let fixture: ComponentFixture<FileViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FileViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FileViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,77 +0,0 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../animations';
import { FileViewerType } from '../types/file-viewer.type';
import { FileType, FileInfo, isSound } from '@ucap-webmessenger/protocol-file';
import { FileDownloadItem } from '@ucap-webmessenger/api';
import { SelectFileInfo } from '../models/select-file-info';
@Component({
selector: 'ucap-file-viewer',
templateUrl: './file-viewer.component.html',
styleUrls: ['./file-viewer.component.scss'],
animations: ucapAnimations
})
export class FileViewerComponent implements OnInit {
@Input()
set fileInfo(v: { fileInfos: FileInfo[]; selectFileInfo: SelectFileInfo }) {
this._fileInfo = v;
this.currentFileInfo = v.fileInfos.find(
f => f.sentMessageJson.attachmentSeq === v.selectFileInfo.attachmentSeq
);
}
// tslint:disable-next-line: variable-name
_fileInfo: {
fileInfos: FileInfo[];
selectFileInfo: SelectFileInfo;
};
@Input()
fileDownloadUrl: (attachmentSeq: number) => string;
@Output()
download = new EventEmitter<{
attachmentSeq?: number;
downloadUrl?: string;
fileName: string;
fileDownloadItem: FileDownloadItem;
}>();
@Output()
closed = new EventEmitter<void>();
currentFileInfo: FileInfo;
FileViewerType = FileViewerType;
constructor() {}
ngOnInit() {}
detectFileViewerType(fileInfo: FileInfo): FileViewerType {
switch (fileInfo.type) {
case FileType.Image:
return FileViewerType.Image;
case FileType.Sound:
return FileViewerType.Sound;
case FileType.Video:
return FileViewerType.Video;
default:
if (isSound(fileInfo)) {
return FileViewerType.Sound;
}
return FileViewerType.Binary;
}
}
onDownload(fileDownloadItem: FileDownloadItem): void {
this.download.emit({
attachmentSeq: this.currentFileInfo.sentMessageJson.attachmentSeq,
fileName: this.currentFileInfo.sentMessageJson.fileName,
fileDownloadItem
});
}
onClosedViewer(): void {
this.closed.emit();
}
}

View File

@ -1,17 +0,0 @@
<ng-container *ngIf="!!currentFileInfo">
<ucap-file-viewer
*ngIf="!isMediaType"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-file-viewer>
<ucap-media-viewer
*ngIf="isMediaType"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-media-viewer>
</ng-container>

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { FileViewerDialogComponent } from './file-viewer.dialog.component';
describe('FileViewerDialogComponent', () => {
let component: FileViewerDialogComponent;
let fixture: ComponentFixture<FileViewerDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FileViewerDialogComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FileViewerDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,178 +0,0 @@
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { NGXLogger } from 'ngx-logger';
import { DeviceType } from '@ucap-webmessenger/core';
import { FileDownloadItem } from '@ucap-webmessenger/api';
import { CommonApiService } from '@ucap-webmessenger/api-common';
import { AppFileService } from '@app/services/file.service';
import { FileInfo, isMedia } from '@ucap-webmessenger/protocol-file';
import { SelectFileInfo, SnackBarService } from '@ucap-webmessenger/ui';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { TranslateService } from '@ngx-translate/core';
export interface FileViewerDialogData {
fileInfos: FileInfo[];
selectFileInfo: SelectFileInfo;
downloadUrl: string;
userSeq: number;
deviceType: DeviceType;
token: string;
}
export interface FileViewerDialogResult {}
@Component({
selector: 'app-layout-common-file-viewer',
templateUrl: './file-viewer.dialog.component.html',
styleUrls: ['./file-viewer.dialog.component.scss']
})
export class FileViewerDialogComponent implements OnInit, OnDestroy {
isMediaType: boolean;
fileInfo: {
fileInfos: FileInfo[];
selectFileInfo: SelectFileInfo;
};
currentFileInfo: FileInfo;
constructor(
public dialogRef: MatDialogRef<
FileViewerDialogData,
FileViewerDialogResult
>,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
@Inject(MAT_DIALOG_DATA) public data: FileViewerDialogData,
private snackBarService: SnackBarService,
private commonApiService: CommonApiService,
private appFileService: AppFileService,
private translateService: TranslateService,
private logger: NGXLogger
) {
this.currentFileInfo = this.data.fileInfos.find(
(f) => f.seq === this.data.selectFileInfo.attachmentSeq
);
if (!this.currentFileInfo) {
this.logger.warn(
'file info is exist',
this.data.fileInfos,
this.data.selectFileInfo
);
this.dialogRef.close();
return;
}
this.isMediaType = isMedia(this.currentFileInfo);
this.fileInfo = {
fileInfos: this.data.fileInfos.filter((f) => {
const i = isMedia(f);
return this.isMediaType ? i : !i;
}),
selectFileInfo: this.data.selectFileInfo
};
}
ngOnInit() {}
ngOnDestroy(): void {}
onDownload(info: {
attachmentSeq?: number;
fileName: string;
fileDownloadItem: FileDownloadItem;
roomSeq?: number;
eventSeq?: number;
}): void {
let fileName;
const startIdx = info.fileName.indexOf('.thumb');
if (startIdx < 0) {
fileName = info.fileName;
} else {
const endIdx = info.fileName.lastIndexOf('.');
const startFileName = info.fileName.substring(0, startIdx - 4);
const endFileName = info.fileName.substring(endIdx, info.fileName.length);
fileName = startFileName.concat(endFileName);
}
this.nativeService
.selectSaveFilePath(fileName)
.then((result) => {
if (!result) {
return;
}
if (result.canceled) {
} else {
this.saveFile(info, result.filePath);
}
})
.catch((reason) => {
this.snackBarService.open(
this.translateService.instant('common.file.errors.failToSpecifyPath'),
this.translateService.instant('common.file.errors.label')
);
});
}
saveFile(
info: {
attachmentSeq?: number;
downloadUrl?: string;
fileName: string;
fileDownloadItem: FileDownloadItem;
roomSeq?: number;
eventSeq?: number;
},
savePath: string
) {
if (!!info.roomSeq && !!info.eventSeq) {
this.appFileService.fileTalkDownloadMulti({
req: {
userSeq: this.data.userSeq,
deviceType: this.data.deviceType,
token: this.data.token,
roomSeq: info.roomSeq,
eventSeq: info.eventSeq,
thumbUrl: info.fileName,
fileDownloadItem: info.fileDownloadItem
},
fileName: info.fileName,
savePath
});
} else {
this.appFileService.fileTalkDownlod({
req: {
userSeq: this.data.userSeq,
deviceType: this.data.deviceType,
token: this.data.token,
attachmentsSeq: info.attachmentSeq,
fileDownloadItem: info.fileDownloadItem
},
fileName: info.fileName,
fileDownloadUrl: this.data.downloadUrl,
savePath
});
}
}
onClosedViewer(): void {
this.dialogRef.close();
}
fileDownloadUrl = (attachmentSeq: number) => {
return this.commonApiService.urlForFileTalkDownload(
{
userSeq: this.data.userSeq,
deviceType: this.data.deviceType,
token: this.data.token,
attachmentsSeq: attachmentSeq
},
this.data.downloadUrl
);
};
}

View File

@ -1,179 +0,0 @@
<div class="ucap-image-viewer-container">
<mat-toolbar class="ucap-image-viewer-header bg-primary-dark">
<!--<mat-icon class="ucap-image-viewer-icon">image</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"
class="ucap-image-viewer-icon"
>
<rect x="3" y="3" width="18" height="18" rx="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<path d="M20.4 14.5L16 10 4 20" />
</svg>
<span class="ucap-image-viewer-title">{{ fileName }}</span>
<span class="ucap-image-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-image-viewer-action"
matTooltip="{{ 'common.messages.zoomReset' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickZoomReset()"
>
<!--<mat-icon>settings_overscan</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.8 3.8l16.4 16.4M20.2 3.8L3.8 20.2M15 3h6v6M9 3H3v6M15 21h6v-6M9 21H3v-6"
/>
</svg>
</button>
<button
mat-icon-button
class="ucap-image-viewer-action"
matTooltip="{{ 'common.messages.zoomOut' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickZoomOut()"
>
<!--<mat-icon>zoom_out</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"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
</button>
<button
mat-icon-button
class="ucap-image-viewer-action"
matTooltip="{{ 'common.messages.zoomIn' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickZoomIn()"
>
<!--<mat-icon>zoom_in</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"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="11" y1="8" x2="11" y2="14"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
</button>
<button
mat-icon-button
class="ucap-image-viewer-action"
matTooltip="{{ 'common.file.download' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickDownload()"
>
<!--<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-icon-button
color="warn"
class="ucap-image-viewer-action btn-close"
matTooltip="{{ 'common.messages.close' | translate }}"
(click)="onClickClose()"
>
<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 style="position: relative;">
<div
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
style="position: absolute; width: 100%;"
>
<mat-progress-bar
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>
</div>
<div class="ucap-image-viewer-body">
<div
#imageContainer
class="ucap-image-viewer-image-wrapper"
fxLayout="row"
fxLayout.xs="column"
fxFlexFill
fxLayoutAlign="center center"
>
<img
#downloadImage
*ngIf="fileDownloadUrl"
[src]="fileDownloadUrl"
[style.width]="'auto'"
[style.height]="imageHeight + 'px'"
(load)="onLoadFileDownloadUrl(downloadImage)"
/>
</div>
</div>
</div>

View File

@ -1,73 +0,0 @@
.ucap-image-viewer-container {
width: 100%;
height: 100%;
.ucap-image-viewer-header {
width: 100%;
height: 60px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
background-color: #333333;
.ucap-image-viewer-icon {
margin-right: 10px;
}
.ucap-image-viewer-title {
font-size: 16px;
}
.ucap-image-viewer-spacer {
flex: 1 1 auto;
}
.stroke-bar {
width: 1px;
height: 30px;
background-color: rgba(256, 256, 256, 0.3);
margin: 0 10px;
}
.ucap-image-viewer-action {
width: 24px;
height: 24px;
margin-left: 10px;
&:hover {
opacity: 0.7;
}
}
}
.ucap-image-viewer-body {
position: relative;
width: 100%;
height: calc(100% - 60px);
.ucap-image-viewer-image-wrapper {
position: relative;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
overflow: auto;
img {
position: absolute;
max-width: none !important;
}
&::-webkit-scrollbar {
background-color: rgba(0, 0, 0, 0.7);
}
&::-webkit-scrollbar-corner {
background-color: rgba(0, 0, 0, 0.7);
}
&::-webkit-scrollbar:hover {
background-color: rgba(255, 255, 255, 0.12);
}
&::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 0 12px rgba(255, 255, 255, 0.37);
}
&::-webkit-scrollbar-thumb:active {
box-shadow: inset 0 0 0 12px rgba(255, 255, 255, 0.54);
}
}
}
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { ImageViewerComponent } from './image-viewer.component';
describe('ImageViewerComponent', () => {
let component: ImageViewerComponent;
let fixture: ComponentFixture<ImageViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ImageViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ImageViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,149 +0,0 @@
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ChangeDetectorRef,
ChangeDetectionStrategy,
ViewChild,
ElementRef,
HostListener
} from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileDownloadItem } from '@ucap-webmessenger/api';
import { FileInfo } from '@ucap-webmessenger/protocol-file';
@Component({
selector: 'ucap-image-viewer',
templateUrl: './image-viewer.component.html',
styleUrls: ['./image-viewer.component.scss'],
animations: ucapAnimations,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageViewerComponent implements OnInit {
@Input()
fileInfo: FileInfo;
@Input()
fileName: string;
@Input()
fileDownloadUrl: string;
@Output()
closed = new EventEmitter<void>();
@Output()
download = new EventEmitter<FileDownloadItem>();
@ViewChild('imageContainer', { static: false })
imageContainer: ElementRef<HTMLElement>;
@ViewChild('downloadImage', { static: false })
downloadImage: ElementRef<HTMLElement>;
fileDownloadItem: FileDownloadItem;
naturalWidth = 0;
naturalHeight = 0;
imageHeight = 0;
zoomRatio = 100;
constructor(private changeDetectorRef: ChangeDetectorRef) {}
ngOnInit() {
this.naturalWidth = this.fileInfo.sentMessageJson.imageWidth;
this.naturalHeight = this.fileInfo.sentMessageJson.imageHeight;
}
@HostListener('window:resize', ['$event'])
onResize(event: Event) {
this.setImageHeight();
this.changeDetectorRef.detectChanges();
}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();
}
onLoadFileDownloadUrl(img: HTMLImageElement) {
this.naturalWidth = img.naturalWidth;
this.naturalHeight = img.naturalHeight;
this.setImageHeight();
this.changeDetectorRef.detectChanges();
}
onClickZoomOut() {
if (60 >= this.zoomRatio) {
return;
}
this.zoomRatio -= 10;
this.setImageHeight();
this.changeDetectorRef.detectChanges();
}
onClickZoomIn() {
if (180 <= this.zoomRatio) {
return;
}
this.zoomRatio += 10;
this.setImageHeight();
this.changeDetectorRef.detectChanges();
}
onClickZoomReset() {
this.zoomRatio = 100;
this.setImageHeight();
this.changeDetectorRef.detectChanges();
}
setImageHeight() {
const realContainerHeight =
this.imageContainer.nativeElement.clientHeight - 20;
const oriHeight =
this.naturalHeight > realContainerHeight
? realContainerHeight
: this.naturalHeight;
const oriWidth = (oriHeight * this.naturalWidth) / this.naturalHeight;
const imageHeight = oriHeight * (this.zoomRatio / 100);
const imageWidth = oriWidth * (this.zoomRatio / 100);
let imageTop =
(this.imageContainer.nativeElement.clientHeight - imageHeight) / 2;
let imageLeft =
(this.imageContainer.nativeElement.clientWidth - imageWidth) / 2;
let scrollTop = 0;
if (0 > imageTop) {
scrollTop = Math.abs(imageTop);
imageTop = 0;
}
let scrollLeft = 0;
if (0 > imageLeft) {
scrollLeft = Math.abs(imageLeft);
imageLeft = 0;
}
this.downloadImage.nativeElement.style.top = `${imageTop}px`;
this.downloadImage.nativeElement.style.left = `${imageLeft}px`;
this.imageContainer.nativeElement.scrollTop = scrollTop;
this.imageContainer.nativeElement.scrollLeft = scrollLeft;
this.imageHeight = imageHeight;
}
}

View File

@ -1,144 +0,0 @@
<div class="ucap-sound-viewer-container">
<mat-toolbar color="accent" class="ucap-sound-viewer-header">
<mat-icon class="ucap-sound-viewer-icon">music_note</mat-icon>
<span class="ucap-sound-viewer-title">{{ fileName }}</span>
<span class="ucap-sound-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-image-viewer-action"
matTooltip="{{ 'common.file.download' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickDownload()"
>
<!--<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-icon-button
color="warn"
class="ucap-image-viewer-action btn-close"
matTooltip="{{ 'common.messages.close' | translate }}"
(click)="onClickClose()"
>
<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 style="position: relative;">
<div
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
style="position: absolute; width: 100%;"
>
<mat-progress-bar
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>
</div>
<div class="ucap-sound-viewer-body">
<div
class="ucap-sound-viewer-sound-icon"
fxLayout="row"
fxLayout.xs="column"
fxLayoutAlign="center center"
>
<audio
[src]="fileDownloadUrl"
#audioPlayer
(playing)="onPlayingAudio()"
(pause)="onPauseAudio()"
(timeupdate)="onTimeUpdateAudio()"
(volumechange)="onVolumeChangeAudio()"
(loadstart)="onLoadStartAudio()"
(loadeddata)="onLoadedDataAudio()"
></audio>
<div class="circle-box">
<mat-icon class="ucap-sound-viewer-icon" *ngIf="!playing">
music_note
</mat-icon>
<div class="sound-wave" *ngIf="playing">
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
<div class="sound-bar bg-accent-dark"></div>
</div>
</div>
</div>
<div class="viewer-bottom">
<div
class="ucap-sound-viewer-sound-time"
fxLayout="row"
fxLayout.xs="column"
fxLayoutAlign="center center"
>
<mat-slider
#timeSlider
min="0"
[max]="duration"
[value]="currentTime"
(change)="onChangeTimeSlider($event)"
>
</mat-slider>
</div>
<div
class="ucap-sound-viewer-sound-controls"
fxLayout="row"
fxLayout.xs="column"
>
<div class="ucap-sound-viewer-sound-time-current">
{{ currentTime | ucapSecondsToMinutes }}
</div>
<span class="ucap-sound-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-sound-viewer-action"
matTooltip="{{
(playing ? 'common.player.stop' : 'common.player.play') | translate
}}"
aria-label=""
(click)="onClickPlayOrPause()"
>
<mat-icon>{{ playing ? 'pause' : 'play_arrow' }}</mat-icon>
</button>
<span class="ucap-sound-viewer-spacer"></span>
<div class="ucap-sound-viewer-sound-time-total">
{{ duration | ucapSecondsToMinutes }}
</div>
</div>
</div>
</div>
</div>

View File

@ -1,163 +0,0 @@
.ucap-sound-viewer-container {
width: 100%;
height: 100%;
.ucap-sound-viewer-header {
width: 100%;
height: 60px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
background-color: #333333;
.ucap-sound-viewer-icon {
margin-right: 10px;
}
.ucap-sound-viewer-title {
font-size: 16px;
}
.stroke-bar {
width: 1px;
height: 30px;
background-color: rgba(256, 256, 256, 0.3);
margin: 0 10px;
}
.ucap-sound-viewer-action {
width: 24px;
height: 24px;
margin-left: 10px;
&:hover {
opacity: 0.7;
}
}
}
.ucap-sound-viewer-body {
position: relative;
width: 100%;
height: calc(100% - 60px);
.circle-box {
position: relative;
display: flex;
width: 140px;
height: 140px;
border-radius: 50%;
justify-content: center;
align-items: center;
border: 2px solid #ffffff;
background-color: rgba(256, 256, 256, 0.7);
.mat-icon {
font-size: 100px;
height: 100px;
width: 100px;
}
.sound-wave {
height: 80px;
left: 50%;
margin: -35px 0 0 -35px;
position: absolute;
bottom: 30px;
width: 70px;
}
}
.ucap-sound-viewer-sound-icon {
width: 100%;
height: calc(100% - 80px);
}
.viewer-bottom {
background-color: #212121;
color: #ffffff;
.ucap-sound-viewer-sound-time {
width: 100%;
height: 30px;
}
.ucap-sound-viewer-sound-controls {
width: 100%;
height: 50px;
.ucap-sound-viewer-sound-time-current {
padding-left: 30px;
}
.ucap-sound-viewer-sound-time-total {
padding-right: 30px;
}
}
}
}
.ucap-sound-viewer-spacer {
flex: 1 1 auto;
}
.ucap-sound-viewer-action {
.mat-icon {
font-size: 40px;
width: 100%;
height: 100%;
line-height: 50px;
}
}
}
.sound-bar {
bottom: 1px;
height: 10px;
position: absolute;
width: 5px;
animation: sound-play 0ms -800ms linear infinite alternate;
}
.sound-bar:nth-child(1) {
left: 0px;
animation-duration: 474ms;
}
.sound-bar:nth-child(2) {
left: 7px;
animation-duration: 433ms;
}
.sound-bar {
left: 14px;
animation-duration: 407ms;
}
.sound-bar:nth-child(4) {
left: 21px;
animation-duration: 458ms;
}
.sound-bar:nth-child(5) {
left: 28px;
animation-duration: 400ms;
}
.sound-bar:nth-child(6) {
left: 35px;
animation-duration: 427ms;
}
.sound-bar:nth-child(7) {
left: 42px;
animation-duration: 441ms;
}
.sound-bar:nth-child(8) {
left: 49px;
animation-duration: 419ms;
}
.sound-bar:nth-child(9) {
left: 56px;
animation-duration: 487ms;
}
.sound-bar:nth-child(10) {
left: 63px;
animation-duration: 442ms;
}
@keyframes sound-play {
0% {
opacity: 0.35;
height: 10px;
}
100% {
opacity: 1;
height: 60px;
}
}
mat-slider {
width: 94%;
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { SoundViewerComponent } from './sound-viewer.component';
describe('SoundViewerComponent', () => {
let component: SoundViewerComponent;
let fixture: ComponentFixture<SoundViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SoundViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SoundViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,104 +0,0 @@
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef
} from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileInfo } from '@ucap-webmessenger/protocol-file';
import { MatSlider, MatSliderChange } from '@angular/material/slider';
import { FileDownloadItem } from '@ucap-webmessenger/api';
@Component({
selector: 'ucap-sound-viewer',
templateUrl: './sound-viewer.component.html',
styleUrls: ['./sound-viewer.component.scss'],
animations: ucapAnimations
})
export class SoundViewerComponent implements OnInit {
@Input()
fileInfo: FileInfo;
@Input()
fileName: string;
@Input()
fileDownloadUrl: string;
@Output()
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
@ViewChild('audioPlayer', { static: true })
audioPlayer: ElementRef<HTMLAudioElement>;
@ViewChild('timeSlider', { static: true })
timeSlider: MatSlider;
playing = false;
duration = 0.01;
currentTime = 0;
volume = 0.1;
loading = false;
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickPlayOrPause(): void {
if (this.loading) {
return;
}
if (this.audioPlayer.nativeElement.paused) {
this.audioPlayer.nativeElement.play();
} else {
this.currentTime = this.audioPlayer.nativeElement.currentTime;
this.audioPlayer.nativeElement.pause();
}
}
onChangeTimeSlider(e: MatSliderChange): void {
this.audioPlayer.nativeElement.currentTime = e.value;
}
onPlayingAudio(): void {
this.playing = true;
// this.duration = Math.floor(this.audioPlayer.nativeElement.duration);
}
onPauseAudio(): void {
this.playing = false;
}
onTimeUpdateAudio(): void {
this.currentTime = Math.floor(this.audioPlayer.nativeElement.currentTime);
}
onVolumeChangeAudio(): void {
this.volume = Math.floor(this.audioPlayer.nativeElement.volume);
}
onLoadStartAudio(): void {
this.loading = true;
}
onLoadedDataAudio(): void {
this.loading = false;
this.duration = Math.floor(this.audioPlayer.nativeElement.duration);
}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();
}
}

View File

@ -1,169 +0,0 @@
<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>-->
<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">{{ fileName }}</span>
<span class="ucap-video-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-video-viewer-action"
matTooltip="{{ 'common.file.download' | translate }}"
matTooltipPosition="below"
aria-label=""
(click)="onClickDownload()"
>
<!--<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-icon-button
color="warn"
class="ucap-image-viewer-action btn-close"
matTooltip="{{ 'common.messages.close' | translate }}"
(click)="onClickClose()"
>
<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 style="position: relative;">
<div
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
style="position: absolute; width: 100%;"
>
<mat-progress-bar
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>
</div>
<div class="ucap-video-viewer-body">
<div
#videoContainer
class="ucap-video-viewer-video-icon"
fxLayout="row"
fxLayout.xs="column"
fxLayoutAlign="center center"
>
<video
*ngIf="playable"
#audioPlayer
[src]="fileDownloadUrl"
[style.width]="'auto'"
[style.height]="
videoHeight > videoContainer.clientHeight
? ((videoContainer.clientHeight - 20) / videoHeight) * videoHeight +
'px'
: videoHeight + 'px'
"
(playing)="onPlayingVideo()"
(pause)="onPauseVideo()"
(timeupdate)="onTimeUpdateVideo()"
(volumechange)="onVolumeChangeVideo()"
(loadstart)="onLoadStartVideo()"
(loadeddata)="onLoadedDataVideo()"
></video>
<div *ngIf="!playable" class="guide-msg">
{{ 'common.file.errors.cantPlay' | translate }}
</div>
</div>
<div class="viewer-bottom">
<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)"
>
</mat-slider>
</div>
<div
class="ucap-video-viewer-video-controls"
fxLayout="row"
fxLayout.xs="column"
>
<div class="ucap-video-viewer-video-time-current">
{{ Math.floor(currentTime) | ucapSecondsToMinutes }}
</div>
<span class="ucap-video-viewer-spacer"></span>
<button
mat-icon-button
class="ucap-video-viewer-action"
matTooltip="{{
(playing ? 'common.player.stop' : 'common.player.play') | translate
}}"
aria-label=""
[disabled]="!playable"
(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">
{{ Math.floor(duration) | ucapSecondsToMinutes }}
</div>
</div>
</div>
</div>
</div>

View File

@ -1,100 +0,0 @@
.ucap-video-viewer-container {
width: 100%;
height: 100%;
.ucap-video-viewer-header {
width: 100%;
height: 60px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
background-color: #333333;
color: #ffffff;
.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 {
width: 24px;
height: 24px;
margin-left: 10px;
&:hover {
opacity: 0.7;
}
}
}
.ucap-video-viewer-body {
position: relative;
width: 100%;
height: calc(100% - 60px);
.ucap-video-viewer-video-icon {
width: 100%;
height: calc(100% - 80px);
.guide-msg {
font-size: 16px;
margin: 30px;
color: #ffffff;
}
}
.viewer-bottom {
background-color: #212121;
color: #ffffff;
.ucap-video-viewer-video-time {
width: 100%;
height: 30px;
.mat-slider {
width: 94%;
}
}
.ucap-video-viewer-video-controls {
width: 100%;
height: 50px;
.ucap-video-viewer-video-time-current {
padding-left: 30px;
}
.ucap-video-viewer-video-time-total {
padding-right: 30px;
}
}
}
}
.ucap-video-viewer-spacer {
flex: 1 1 auto;
}
.ucap-video-viewer-action {
.mat-icon {
font-size: 40px;
width: 100%;
height: 100%;
line-height: 40px;
}
}
}
//viewr 플레이어 공통
::ng-deep .viewer-bottom {
.mat-slider-horizontal {
.mat-slider-track-background {
background-color: #999999 !important;
}
&.mat-slider-min-value {
&:not(.mat-slider-thumb-label-showing) {
.mat-slider-thumb {
border-color: #999999 !important;
}
}
}
}
}

View File

@ -1,27 +0,0 @@
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { ImageViewerComponent } from './image-viewer.component';
describe('ImageViewerComponent', () => {
let component: ImageViewerComponent;
let fixture: ComponentFixture<ImageViewerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ImageViewerComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ImageViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,125 +0,0 @@
import {
Component,
OnInit,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef,
ChangeDetectorRef
} from '@angular/core';
import { MatSlider, MatSliderChange } from '@angular/material/slider';
import { NGXLogger } from 'ngx-logger';
import { FileInfo } from '@ucap-webmessenger/protocol-file';
import { FileDownloadItem } from '@ucap-webmessenger/api';
import { ucapAnimations } from '../../animations';
@Component({
selector: 'ucap-video-viewer',
templateUrl: './video-viewer.component.html',
styleUrls: ['./video-viewer.component.scss'],
animations: ucapAnimations
})
export class VideoViewerComponent implements OnInit {
@Input()
fileInfo: FileInfo;
@Input()
fileName: string;
@Input()
fileDownloadUrl: string;
@Output()
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
@ViewChild('audioPlayer', { static: false })
audioPlayer: ElementRef<HTMLVideoElement>;
@ViewChild('timeSlider', { static: true })
timeSlider: MatSlider;
playing = false;
duration = 0.0;
currentTime = 0.0;
volume = 0.1;
loading = false;
fileDownloadItem: FileDownloadItem;
videoWidth = 0;
videoHeight = 0;
playable = true;
Math = Math;
constructor(
private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger
) {}
ngOnInit() {}
onClickPlayOrPause(): void {
if (this.loading) {
return;
}
if (this.audioPlayer.nativeElement.paused) {
this.audioPlayer.nativeElement.play();
} else {
this.currentTime = this.audioPlayer.nativeElement.currentTime;
this.audioPlayer.nativeElement.pause();
}
}
onChangeTimeSlider(e: MatSliderChange): void {
this.audioPlayer.nativeElement.currentTime = e.value;
}
onPlayingVideo(): void {
this.playing = true;
// this.duration = Math.floor(this.audioPlayer.nativeElement.duration);
}
onPauseVideo(): void {
this.playing = false;
}
onTimeUpdateVideo(): void {
this.currentTime = this.audioPlayer.nativeElement.currentTime;
}
onVolumeChangeVideo(): void {
this.volume = this.audioPlayer.nativeElement.volume;
}
onLoadStartVideo(): void {
this.loading = true;
}
onLoadedDataVideo(): void {
this.loading = false;
this.duration = this.audioPlayer.nativeElement.duration;
this.videoWidth = this.audioPlayer.nativeElement.videoWidth;
this.videoHeight = this.audioPlayer.nativeElement.videoHeight;
if (0 === this.videoHeight || 0 === this.videoWidth) {
this.playable = false;
this.duration = 0;
}
}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();
}
}