This commit is contained in:
leejinho 2019-11-13 15:42:56 +09:00
commit 2c41c49cdb
25 changed files with 422 additions and 148 deletions

View File

@ -241,8 +241,9 @@ ipcMain.on(
try {
const buffer: Buffer = args[0];
const fileName: string = args[1];
const mimeType: string = args[2];
let savePath: string = path.join(
!!args[2] ? args[2] : DefaultFolder.downloads(),
!!args[3] ? args[3] : DefaultFolder.downloads(),
fileName
);
savePath = await FileUtil.uniqueFileName(savePath);

9
package-lock.json generated
View File

@ -2789,6 +2789,15 @@
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"angular-split": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/angular-split/-/angular-split-3.0.2.tgz",
"integrity": "sha512-km59k1kEgVlplo2t4t5Ob43Vx16qVXWXsl5gbsdQtqrOW7341So4CFUmCjcZgfk1swu9RBaCdSQEqzNWOe/89w==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"ansi-align": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",

View File

@ -1,11 +1,6 @@
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
<ucap-file-viewer
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-file-viewer>

View File

@ -3,7 +3,7 @@ import {
OnInit,
OnDestroy,
Inject,
EventEmitter
EventEmitter,
} from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
@ -15,7 +15,7 @@ import { take, map, finalize, tap } from 'rxjs/operators';
import { SnackBarService } from '@ucap-webmessenger/ui';
import {
FileDownloadItem,
CommonApiService
CommonApiService,
} from '@ucap-webmessenger/api-common';
export interface FileViewerDialogData {
@ -31,7 +31,7 @@ export interface FileViewerDialogResult {}
@Component({
selector: 'app-layout-common-file-viewer',
templateUrl: './file-viewer.dialog.component.html',
styleUrls: ['./file-viewer.dialog.component.scss']
styleUrls: ['./file-viewer.dialog.component.scss'],
})
export class FileViewerDialogComponent implements OnInit, OnDestroy {
fileInfo: FileEventJson;
@ -40,8 +40,6 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
deviceType: DeviceType;
token: string;
fileDownloadItem: FileDownloadItem;
fileDownloadUrl: string;
constructor(
@ -66,7 +64,7 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
userSeq: this.userSeq,
deviceType: this.deviceType,
token: this.token,
attachmentsSeq: this.fileInfo.attachmentSeq
attachmentsSeq: this.fileInfo.attachmentSeq,
},
this.downloadUrl
);
@ -76,8 +74,7 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
ngOnDestroy(): void {}
onDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
onDownload(fileDownloadItem: FileDownloadItem): void {
this.commonApiService
.fileTalkDownload(
{
@ -85,37 +82,36 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
deviceType: this.deviceType,
token: this.token,
attachmentsSeq: this.fileInfo.attachmentSeq,
fileDownloadItem: this.fileDownloadItem
fileDownloadItem,
},
this.downloadUrl
)
.pipe(
take(1),
map(async rawBlob => {
const blob = rawBlob.slice(
0,
rawBlob.size,
MimeUtil.getMimeFromExtension(this.fileInfo.fileExt)
);
const mimeType = MimeUtil.getMimeFromExtension(this.fileInfo.fileExt);
const blob = rawBlob.slice(0, rawBlob.size, mimeType);
FileUtil.fromBlobToBuffer(blob)
.then(buffer => {
this.nativeService
.saveFile(buffer, this.fileInfo.fileName)
.pipe(take(1))
.subscribe(result => {
.saveFile(buffer, this.fileInfo.fileName, mimeType)
.then(result => {
if (!!result) {
this.snackBarService.open(
`파일이 경로[${result}]에 저장되었습니다.`,
'',
{
duration: 3000,
verticalPosition: 'bottom'
verticalPosition: 'bottom',
}
);
} else {
this.snackBarService.open('파일 저장에 실패하였습니다.');
}
})
.catch(reason => {
this.snackBarService.open('파일 저장에 실패하였습니다.');
});
})
.catch(reason => {
@ -123,7 +119,9 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
});
}),
finalize(() => {
this.fileDownloadItem = undefined;
setTimeout(() => {
fileDownloadItem.downloadingProgress$ = undefined;
}, 1000);
})
)
.subscribe();

View File

@ -485,7 +485,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
}
async onFileViewer(fileInfo: FileEventJson) {
this.logger.debug('onFileViewer', fileInfo);
const result = await this.dialogService.open<
FileViewerDialogComponent,
FileViewerDialogData,

View File

@ -1,7 +1,7 @@
import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router';
import { of } from 'rxjs';
import { of, Observable } from 'rxjs';
import { catchError, exhaustMap, map, tap, switchMap } from 'rxjs/operators';
import { Actions, ofType, createEffect } from '@ngrx/effects';
@ -86,19 +86,28 @@ export class Effects {
() =>
this.actions$.pipe(
ofType(webLoginSuccess),
switchMap(params =>
this.nativeService.checkForUpdates().pipe(
map((update: boolean) => {
if (!update) {
this.appAuthenticationService.login(
params.loginInfo,
params.rememberMe
);
this.router.navigate(['/messenger']);
}
}),
catchError(error => of(error))
)
switchMap(
params =>
new Observable<void>(subscriber => {
this.nativeService
.checkForUpdates()
.then((update: boolean) => {
if (!update) {
this.appAuthenticationService.login(
params.loginInfo,
params.rememberMe
);
this.router.navigate(['/messenger']);
}
subscriber.next();
})
.catch(reason => {
subscriber.error(reason);
})
.finally(() => {
subscriber.complete();
});
})
)
),
{ dispatch: false }

View File

@ -69,6 +69,113 @@ export class FileUtil {
a.remove();
}
static save(
buffer: Buffer,
fileName: string,
mimeType: string
): Promise<string> {
return new Promise<string>((resolve, reject) => {
const defaultMime = 'application/octet-stream';
const mime = !!mimeType ? mimeType : defaultMime;
const blob = new Blob([buffer], { type: mime });
if (navigator.msSaveBlob) {
// IE10+ : (has Blob, but not a[download] or URL)
navigator.msSaveBlob(blob, fileName);
resolve(fileName);
return;
}
const download = (url: string, mode: boolean = false) => {
const anchor = document.createElement('a');
if ('download' in anchor) {
// html5 A[download]
anchor.href = url;
anchor.setAttribute('download', fileName);
anchor.className = 'download-js-link';
anchor.innerHTML = 'downloading...';
anchor.style.display = 'none';
document.body.appendChild(anchor);
setTimeout(() => {
anchor.click();
document.body.removeChild(anchor);
resolve(fileName);
if (mode) {
setTimeout(() => {
window.URL.revokeObjectURL(anchor.href);
}, 250);
}
}, 66);
return;
}
// handle non-a[download] safari as best we can:
if (
/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(
navigator.userAgent
)
) {
url = url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
if (!window.open(url)) {
// popup blocked, offer direct download:
if (
confirm(
'Displaying New Document\n\nUse Save As... to download, then click back to return to this page.'
)
) {
location.href = url;
}
}
resolve(fileName);
return;
}
// do iframe dataURL download (old ch+FF):
const f = document.createElement('iframe');
document.body.appendChild(f);
if (!mode) {
// force a mime that will download:
url = 'data:' + url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
}
f.src = url;
setTimeout(() => {
document.body.removeChild(f);
}, 333);
};
if (window.URL) {
download(window.URL.createObjectURL(blob), true);
} else {
if (
typeof blob === 'string' ||
(blob as any).constructor === this.toString
) {
try {
download(
'data:' + mime + ';base64,' + window.btoa((blob as any) as string)
);
} catch (e) {
download(
'data:' +
mime +
';base64,' +
encodeURIComponent((blob as any) as string)
);
}
} else {
const fileReader = new FileReader();
fileReader.onload = () => {
download(fileReader.result as string);
};
fileReader.readAsDataURL(blob);
}
}
});
}
static thumbnail(file: File): Promise<File> {
return new Promise<File>((resolve, reject) => {
const fileReader = new FileReader();

View File

@ -12,6 +12,7 @@ import { TranslateLoader } from '@ngx-translate/core';
import { TranslateLoaderService } from '../translate/browser-loader';
import { NotificationService } from '../notification/notification.service';
import { Injectable } from '@angular/core';
import { FileUtil } from '@ucap-webmessenger/core';
@Injectable({
providedIn: 'root',
@ -34,34 +35,35 @@ export class BrowserNativeService extends NativeService {
}
closeAllNotify(): void {}
checkForUpdates(): Observable<boolean> {
return new Observable<boolean>(subscriber => {
try {
subscriber.next(false);
} catch (error) {
subscriber.error(error);
} finally {
subscriber.complete();
}
checkForUpdates(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
resolve(false);
});
}
showImageViewer(): void {}
readFile(path: string): Observable<Buffer> {
return this.httpClient.get(path, { responseType: 'arraybuffer' }).pipe(
map(arrayBuffer => {
return Buffer.from(arrayBuffer);
})
);
readFile(path: string): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
resolve(null);
});
}
saveFile(
buffer: Buffer,
fileName: string,
mimeType: string,
path?: string
): Observable<string> {
return this.httpClient.post<string>(path, buffer, {});
): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
FileUtil.save(buffer, fileName, mimeType).then(fn => {
resolve(fn);
});
} catch (error) {
reject(error);
}
});
}
windowStateChanged(): Observable<WindowState> {
@ -85,7 +87,6 @@ export class BrowserNativeService extends NativeService {
idleStateChanged(): Observable<WindowIdle> {
return new Observable<WindowIdle>(subscriber => {
try {
subscriber.next(WindowIdle.Active);
} catch (error) {
subscriber.error(error);
} finally {

View File

@ -1,7 +1,6 @@
import { TranslateLoader } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { NativeService } from '@ucap-webmessenger/native';
import { take, map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
@Injectable({
@ -18,13 +17,18 @@ export class TranslateLoaderService implements TranslateLoader {
* Gets the translations from the server
*/
public getTranslation(lang: string): Observable<any> {
return this.nativeService
.readFile(`${this.prefix}${lang}.${this.suffix}`)
.pipe(
take(1),
map(buffer => {
return JSON.parse(buffer.toString('utf-8'));
return new Observable<any>(subscriber => {
this.nativeService
.readFile(`${this.prefix}${lang}.${this.suffix}`)
.then(buffer => {
subscriber.next(JSON.parse(buffer.toString('utf-8')));
})
);
.catch(reason => {
subscriber.error(reason);
})
.finally(() => {
subscriber.complete();
});
});
}
}

View File

@ -47,14 +47,12 @@ export class ElectronNativeService implements NativeService {
this.ipcRenderer.send(NotificationChannel.CloseAllNotify);
}
checkForUpdates(): Observable<boolean> {
return new Observable<boolean>(subscriber => {
checkForUpdates(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
try {
subscriber.next(this.ipcRenderer.sendSync(UpdaterChannel.Check));
resolve(this.ipcRenderer.sendSync(UpdaterChannel.Check));
} catch (error) {
subscriber.error(error);
} finally {
subscriber.complete();
reject(error);
}
});
}
@ -63,14 +61,12 @@ export class ElectronNativeService implements NativeService {
this.ipcRenderer.send(FileChannel.ShowImageViewer);
}
readFile(path: string): Observable<Buffer> {
return new Observable<Buffer>(subscriber => {
readFile(path: string): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
try {
subscriber.next(this.ipcRenderer.sendSync(FileChannel.ReadFile, path));
resolve(this.ipcRenderer.sendSync(FileChannel.ReadFile, path));
} catch (error) {
subscriber.error(error);
} finally {
subscriber.complete();
reject(error);
}
});
}
@ -78,22 +74,22 @@ export class ElectronNativeService implements NativeService {
saveFile(
buffer: Buffer,
fileName: string,
mimeType: string,
path?: string
): Observable<string> {
return new Observable<string>(subscriber => {
): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
subscriber.next(
resolve(
this.ipcRenderer.sendSync(
FileChannel.SaveFile,
buffer,
fileName,
mimeType,
path
)
);
} catch (error) {
subscriber.error(error);
} finally {
subscriber.complete();
reject(error);
}
});
}

View File

@ -1,7 +1,6 @@
import { TranslateLoader } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { NativeService } from '@ucap-webmessenger/native';
import { take, map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
@Injectable({
@ -18,13 +17,18 @@ export class TranslateLoaderService implements TranslateLoader {
* Gets the translations from the server
*/
public getTranslation(lang: string): Observable<any> {
return this.nativeService
.readFile(`${this.prefix}${lang}.${this.suffix}`)
.pipe(
take(1),
map(buf => {
return JSON.parse(buf.toString());
return new Observable<any>(subscriber => {
this.nativeService
.readFile(`${this.prefix}${lang}.${this.suffix}`)
.then(buffer => {
subscriber.next(JSON.parse(buffer.toString('utf-8')));
})
);
.catch(reason => {
subscriber.error(reason);
})
.finally(() => {
subscriber.complete();
});
});
}
}

View File

@ -11,16 +11,17 @@ export abstract class NativeService {
abstract notify(noti: NotificationRequest): void;
abstract closeAllNotify(): void;
abstract checkForUpdates(): Observable<boolean>;
abstract checkForUpdates(): Promise<boolean>;
abstract showImageViewer(): void;
abstract saveFile(
buffer: Buffer,
fileName: string,
mimeType: string,
path?: string
): Observable<string>;
abstract readFile(path: string): Observable<Buffer>;
): Promise<string>;
abstract readFile(path: string): Promise<Buffer>;
abstract windowStateChanged(): Observable<WindowState>;
abstract windowClose(): void;

View File

@ -191,12 +191,18 @@ export class ProtocolService {
responseSubject = new Subject<ProtocolMessage>().pipe(
finalize(() => {
this.logger.debug(
'ProtocolService::pendingRequests.finalize',
requestId
);
if (this.pendingRequests.has(requestId)) {
this.pendingRequests.delete(requestId);
}
this.logger.debug(
'ProtocolService::pendingRequests.size',
this.pendingRequests.size
this.pendingRequests.size,
this.pendingRequests
);
})
) as Subject<ProtocolMessage>;

View File

@ -6,35 +6,35 @@
*ngSwitchCase="FileViewerType.Document"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-document-viewer>
<ucap-image-viewer
*ngSwitchCase="FileViewerType.Image"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-image-viewer>
<ucap-sound-viewer
*ngSwitchCase="FileViewerType.Sound"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-sound-viewer>
<ucap-video-viewer
*ngSwitchCase="FileViewerType.Video"
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-video-viewer>
<ucap-binary-viewer
*ngSwitchDefault
[fileInfo]="fileInfo"
[fileDownloadUrl]="fileDownloadUrl"
(download)="onDownload()"
(download)="onDownload($event)"
(closed)="onClosedViewer()"
></ucap-binary-viewer>
</div>

View File

@ -3,12 +3,13 @@ import { ucapAnimations } from '../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { FileViewerType } from '../types/file-viewer.type';
import { FileType } from '@ucap-webmessenger/protocol-file';
import { FileDownloadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-file-viewer',
templateUrl: './file-viewer.component.html',
styleUrls: ['./file-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class FileViewerComponent implements OnInit {
@Input()
@ -18,7 +19,7 @@ export class FileViewerComponent implements OnInit {
fileDownloadUrl: string;
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
@ -44,8 +45,8 @@ export class FileViewerComponent implements OnInit {
return FileViewerType.Binary;
}
}
onDownload(): void {
this.download.emit();
onDownload(fileDownloadItem: FileDownloadItem): void {
this.download.emit(fileDownloadItem);
}
onClosedViewer(): void {

View File

@ -24,6 +24,11 @@
Close
</button>
</mat-toolbar>
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
<div class="ucap-binary-viewer-body">
<div
class="ucap-binary-viewer-content-wrapper"

View File

@ -2,12 +2,13 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { DeviceType } from '@ucap-webmessenger/core';
import { FileDownloadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-binary-viewer',
templateUrl: './binary-viewer.component.html',
styleUrls: ['./binary-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class BinaryViewerComponent implements OnInit {
@Input()
@ -17,17 +18,20 @@ export class BinaryViewerComponent implements OnInit {
fileDownloadUrl: string;
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickDownload(): void {
this.download.emit();
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {

View File

@ -15,4 +15,9 @@
>delete</mat-icon
>
</mat-toolbar>
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
</div>

View File

@ -2,12 +2,13 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { DeviceType } from '@ucap-webmessenger/core';
import { FileDownloadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-document-viewer',
templateUrl: './document-viewer.component.html',
styleUrls: ['./document-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class DocumentViewerComponent implements OnInit {
@Input()
@ -17,16 +18,21 @@ export class DocumentViewerComponent implements OnInit {
fileDownloadUrl: string;
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickDownload(): void {}
onClickDownload(): void {
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {
this.closed.emit();

View File

@ -1,11 +1,22 @@
<div class="ucap-image-viewer-container">
<mat-toolbar class="ucap-image-viewer-header bg-primary-dark">
<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">
<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>
<path d="M20.4 14.5L16 10 4 20" />
</svg>
<span class="ucap-image-viewer-title">{{ fileInfo.fileName }}</span>
<span class="ucap-image-viewer-spacer"></span>
@ -18,9 +29,20 @@
>
<!--<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
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
@ -31,7 +53,21 @@
aria-label=""
>
<!--<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>
<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
@ -41,8 +77,17 @@
aria-label=""
>
<!--<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">
<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>
@ -58,25 +103,51 @@
(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>
<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="뷰어닫기"
matTooltip="뷰어닫기"
(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">
<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>
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
<div class="ucap-image-viewer-body">
<div
class="ucap-image-viewer-image-wrapper"

View File

@ -2,13 +2,16 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { DeviceType } from '@ucap-webmessenger/core';
import { CommonApiService } from '@ucap-webmessenger/api-common';
import {
CommonApiService,
FileDownloadItem,
} from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-image-viewer',
templateUrl: './image-viewer.component.html',
styleUrls: ['./image-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class ImageViewerComponent implements OnInit {
@Input()
@ -21,14 +24,17 @@ export class ImageViewerComponent implements OnInit {
closed = new EventEmitter<void>();
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
fileDownloadItem: FileDownloadItem;
constructor() {}
ngOnInit() {}
onClickDownload(): void {
this.download.emit();
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {

View File

@ -22,6 +22,11 @@
Close
</button>
</mat-toolbar>
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
<div class="ucap-sound-viewer-body">
<div
class="ucap-sound-viewer-sound-icon"

View File

@ -5,17 +5,18 @@ import {
Output,
EventEmitter,
ViewChild,
ElementRef
ElementRef,
} from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { MatSlider, MatSliderChange } from '@angular/material';
import { FileDownloadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-sound-viewer',
templateUrl: './sound-viewer.component.html',
styleUrls: ['./sound-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class SoundViewerComponent implements OnInit {
@Input()
@ -25,7 +26,7 @@ export class SoundViewerComponent implements OnInit {
fileDownloadUrl: string;
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
@ -41,6 +42,7 @@ export class SoundViewerComponent implements OnInit {
currentTime = 0;
volume = 0.1;
loading = false;
fileDownloadItem: FileDownloadItem;
constructor() {}
@ -90,7 +92,8 @@ export class SoundViewerComponent implements OnInit {
}
onClickDownload(): void {
this.download.emit();
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {

View File

@ -1,8 +1,18 @@
<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">
<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>
@ -23,9 +33,20 @@
(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
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>
@ -33,16 +54,30 @@
mat-icon-button
color="warn"
class="ucap-image-viewer-action btn-close"
matTooltip="뷰어닫기"
matTooltip="뷰어닫기"
(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">
<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>
<mat-progress-bar
*ngIf="fileDownloadItem && fileDownloadItem.downloadingProgress$"
mode="determinate"
[value]="fileDownloadItem.downloadingProgress$ | async"
></mat-progress-bar>
<div class="ucap-video-viewer-body">
<div
class="ucap-video-viewer-video-icon"

View File

@ -5,17 +5,18 @@ import {
Output,
EventEmitter,
ViewChild,
ElementRef
ElementRef,
} from '@angular/core';
import { ucapAnimations } from '../../animations';
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
import { MatSlider, MatSliderChange } from '@angular/material';
import { FileDownloadItem } from '@ucap-webmessenger/api-common';
@Component({
selector: 'ucap-video-viewer',
templateUrl: './video-viewer.component.html',
styleUrls: ['./video-viewer.component.scss'],
animations: ucapAnimations
animations: ucapAnimations,
})
export class VideoViewerComponent implements OnInit {
@Input()
@ -25,7 +26,7 @@ export class VideoViewerComponent implements OnInit {
fileDownloadUrl: string;
@Output()
download = new EventEmitter<void>();
download = new EventEmitter<FileDownloadItem>();
@Output()
closed = new EventEmitter<void>();
@ -41,6 +42,7 @@ export class VideoViewerComponent implements OnInit {
currentTime = 0;
volume = 0.1;
loading = false;
fileDownloadItem: FileDownloadItem;
constructor() {}
@ -90,7 +92,8 @@ export class VideoViewerComponent implements OnInit {
}
onClickDownload(): void {
this.download.emit();
this.fileDownloadItem = new FileDownloadItem();
this.download.emit(this.fileDownloadItem);
}
onClickClose(): void {