Merge branch 'master' of http://10.81.13.221:6990/Web/next-ucap-messenger
# Conflicts: # projects/ucap-webmessenger-app/src/app/layouts/messenger/components/right-side.component.html
This commit is contained in:
commit
13a6f53919
|
@ -55,7 +55,16 @@
|
|||
mode="indeterminate"
|
||||
></mat-progress-bar>
|
||||
<!-- CHAT CONTENT -->
|
||||
<div fxFlex="1 1 auto" class="chat-content" #messageBoxContainer>
|
||||
<div
|
||||
fxFlex="1 1 auto"
|
||||
class="chat-content"
|
||||
#messageBoxContainer
|
||||
ucapUiFileUploadFor
|
||||
(fileSelected)="onFileSelected($event)"
|
||||
(fileDragEnter)="onFileDragEnter()"
|
||||
(fileDragOver)="onFileDragOver()"
|
||||
(fileDragLeave)="onFileDragLeave()"
|
||||
>
|
||||
<!-- Timer Room Info -->
|
||||
<span *ngIf="roomInfo && roomInfo.isTimeRoom">비밀 대화방입니다.</span>
|
||||
<!-- Timer Room Info -->
|
||||
|
@ -73,6 +82,17 @@
|
|||
>
|
||||
</ucap-chat-messages>
|
||||
<!-- CHAT MESSAGES -->
|
||||
|
||||
<div
|
||||
*ngIf="fileDragOver || (files && 0 < files.length)"
|
||||
class="file-drop-zone-container"
|
||||
>
|
||||
<div class="file-drop-zone">
|
||||
<ucap-ui-file-upload-queue
|
||||
[(files)]="files"
|
||||
></ucap-ui-file-upload-queue>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / CHAT CONTENT -->
|
||||
|
||||
|
|
|
@ -44,6 +44,22 @@
|
|||
background: transparent;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
.file-drop-zone-container {
|
||||
position: relative;
|
||||
|
||||
.file-drop-zone {
|
||||
position: absolute;
|
||||
border: 2px solid gray;
|
||||
background-color: white;
|
||||
width: 600px;
|
||||
height: 150px;
|
||||
bottom: 0px;
|
||||
margin: auto;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewChecked {
|
|||
isCopyableMessage = isCopyable;
|
||||
isRecallableMessage = isRecallable;
|
||||
|
||||
fileDragOver = false;
|
||||
files: File[];
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
|
@ -198,6 +201,30 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewChecked {
|
|||
this.logger.debug('fileSave', value);
|
||||
}
|
||||
|
||||
onFileDragEnter() {
|
||||
this.logger.debug('onFileDragEnter');
|
||||
this.fileDragOver = true;
|
||||
}
|
||||
|
||||
onFileDragOver() {
|
||||
this.logger.debug('onFileDragOver');
|
||||
}
|
||||
|
||||
onFileDragLeave() {
|
||||
this.logger.debug('onFileDragLeave');
|
||||
this.fileDragOver = false;
|
||||
}
|
||||
|
||||
onFileSelected(files: File[]) {
|
||||
this.logger.debug('onFileSelected', files);
|
||||
if (!this.files) {
|
||||
this.files = [];
|
||||
}
|
||||
this.files.push(...files);
|
||||
|
||||
this.fileDragOver = false;
|
||||
}
|
||||
|
||||
onContextMenuMessage(params: { event: MouseEvent; message: Info }) {
|
||||
params.event.preventDefault();
|
||||
params.event.stopPropagation();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<div fxLayout="row-reverse" class="right">
|
||||
<div class="slide-menu">
|
||||
slide dashboard
|
||||
</div>
|
||||
<div class="slide-menu"></div>
|
||||
</div>
|
||||
|
|
|
@ -17,6 +17,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
|
||||
import { UCapUiModule } from '@ucap-webmessenger/ui';
|
||||
import { UCapUiChatModule } from '@ucap-webmessenger/ui-chat';
|
||||
|
@ -35,6 +36,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
|||
FlexLayoutModule,
|
||||
DragDropModule,
|
||||
ReactiveFormsModule,
|
||||
OverlayModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatBadgeModule,
|
||||
|
|
|
@ -2,3 +2,7 @@
|
|||
|
||||
// Import app.theme.scss
|
||||
@import 'app/app.theme';
|
||||
|
||||
.file-upload-backdrop {
|
||||
background-color: aqua;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
UserInfoF,
|
||||
UserInfoDN
|
||||
} from '@ucap-webmessenger/protocol-query';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-group-expansion-panel',
|
||||
|
@ -57,7 +58,7 @@ export class ExpansionPanelComponent implements OnInit {
|
|||
|
||||
@ViewChild('groupAccordion', { static: true }) groupAccordion: MatAccordion;
|
||||
|
||||
constructor() {}
|
||||
constructor(private logger: NGXLogger) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<div
|
||||
fxLayout="row wrap"
|
||||
fxFlex="100"
|
||||
class="ucap-ui-file-upload-queue-container"
|
||||
>
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxFlex="100"
|
||||
fxFlex.gt-xs="50"
|
||||
fxFlex.gt-md="25"
|
||||
*ngFor="let file of uploadFiles"
|
||||
>
|
||||
<div>
|
||||
<mat-icon>image</mat-icon>
|
||||
</div>
|
||||
<div>{{ file.name }}</div>
|
||||
<div (click)="onClickClear(file)">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,4 @@
|
|||
.ucap-ui-file-upload-queue-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-ui-file-upload-queue',
|
||||
templateUrl: './file-upload-queue.component.html',
|
||||
styleUrls: ['./file-upload-queue.component.scss']
|
||||
})
|
||||
export class FileUploadQueueComponent implements OnInit {
|
||||
@Output()
|
||||
filesChange = new EventEmitter<File[]>();
|
||||
@Input() set files(files: File[]) {
|
||||
this.uploadFiles = files;
|
||||
}
|
||||
|
||||
uploadFiles: File[];
|
||||
|
||||
constructor(private logger: NGXLogger) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onClickClear(file: File) {
|
||||
this.uploadFiles = this.uploadFiles.filter(f => {
|
||||
return f.name !== file.name && f.path !== file.path;
|
||||
});
|
||||
this.filesChange.emit(this.uploadFiles);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
@Directive({
|
||||
selector: 'input[ucapUiFileUploadFor], div[ucapUiFileUploadFor]'
|
||||
})
|
||||
export class FileUploadForDirective {
|
||||
@Output()
|
||||
public fileDragEnter: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
public fileDragOver: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
public fileDragLeave: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
public fileSelected: EventEmitter<File[]> = new EventEmitter<File[]>();
|
||||
|
||||
dragOver = false;
|
||||
|
||||
constructor(private elementRef: ElementRef, private logger: NGXLogger) {}
|
||||
|
||||
@HostListener('window:dragenter', ['$event'])
|
||||
public onDragEnter(event: any): any {
|
||||
const files = event.dataTransfer.files;
|
||||
if (!this.dragOver) {
|
||||
this.fileDragEnter.emit(files);
|
||||
this.dragOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:dragover', ['$event'])
|
||||
public onDragOver(event: any): any {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
@HostListener('window:dragleave', ['$event'])
|
||||
public onDragLeave(event: any): any {
|
||||
if (event && event.pageX === 0 && event.pageY === 0) {
|
||||
this.fileDragLeave.emit();
|
||||
this.dragOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('change')
|
||||
public onChange(): any {
|
||||
const files = this.elementRef.nativeElement.files;
|
||||
this.fileSelected.emit(files);
|
||||
this.elementRef.nativeElement.value = '';
|
||||
}
|
||||
|
||||
@HostListener('window:drop', ['$event'])
|
||||
public onDrop(event: any): any {
|
||||
const files = event.dataTransfer.files;
|
||||
this.fileSelected.emit(files);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.elementRef.nativeElement.value = '';
|
||||
this.dragOver = false;
|
||||
}
|
||||
}
|
20
projects/ucap-webmessenger-ui/src/lib/pipes/bytes.pipe.ts
Normal file
20
projects/ucap-webmessenger-ui/src/lib/pipes/bytes.pipe.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
@Pipe({ name: 'ucapBytes' })
|
||||
export class BytesPipe implements PipeTransform {
|
||||
public transform(bytes: number): string {
|
||||
if (isNaN(parseFloat('' + bytes)) || !isFinite(bytes)) {
|
||||
return '-';
|
||||
}
|
||||
if (bytes <= 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
const num = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return (
|
||||
(bytes / Math.pow(1024, Math.floor(num))).toFixed(1) + ' ' + units[num]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
import { PipeTransform, Pipe } from '@angular/core';
|
||||
import { of, Observable } from 'rxjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { take, map, catchError, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
export interface ImagePipeParameter {
|
||||
path?: string;
|
||||
validation?: boolean;
|
||||
default?: string;
|
||||
}
|
||||
|
||||
@Pipe({ name: 'ucapUiImaage' })
|
||||
export class ImagePipe implements PipeTransform {
|
||||
constructor(private httpClient: HttpClient, private logger: NGXLogger) {}
|
||||
|
||||
transform(
|
||||
base: string,
|
||||
params?: ImagePipeParameter
|
||||
): Observable<string | ArrayBuffer> {
|
||||
params = !!params ? params : {};
|
||||
params.validation = !!params.validation ? params.validation : true;
|
||||
|
||||
if (params.validation) {
|
||||
if (
|
||||
!base ||
|
||||
'' === base.trim() ||
|
||||
!params.path ||
|
||||
'' === params.path.trim()
|
||||
) {
|
||||
return of(params.default);
|
||||
}
|
||||
}
|
||||
|
||||
const imageUrl = `${base}${params.path}`;
|
||||
|
||||
return new Observable<string | ArrayBuffer>(subscriber => {
|
||||
subscriber.next(params.default);
|
||||
|
||||
this.httpClient
|
||||
.get(imageUrl, { responseType: 'blob' })
|
||||
.pipe(
|
||||
take(1),
|
||||
tap(blob => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = ev => {
|
||||
subscriber.next(reader.result);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
}),
|
||||
catchError(err => {
|
||||
this.logger.error(err);
|
||||
return params.default;
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
});
|
||||
|
||||
return this.httpClient.get(imageUrl, { responseType: 'blob' }).pipe(
|
||||
take(1),
|
||||
switchMap(blob => {
|
||||
return new Observable<string | ArrayBuffer>(subscriber => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = ev => {
|
||||
subscriber.next(reader.result);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}),
|
||||
catchError(err => {
|
||||
this.logger.error(err);
|
||||
return params.default;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
|
||||
import { FileUploadQueueComponent } from './components/file-upload-queue.component';
|
||||
import { ImageComponent } from './components/image.component';
|
||||
const COMPONENTS = [ImageComponent];
|
||||
const COMPONENTS = [ImageComponent, FileUploadQueueComponent];
|
||||
|
||||
import { BottomSheetService } from './services/bottom-sheet.service';
|
||||
import { ClipboardService } from './services/clipboard.service';
|
||||
|
@ -22,24 +26,29 @@ const SERVICES = [
|
|||
SnackBarService
|
||||
];
|
||||
|
||||
import { FileUploadForDirective } from './directives/file-upload-for.directive';
|
||||
const DIRECTIVES = [FileUploadForDirective];
|
||||
|
||||
import { AlertDialogComponent } from './dialogs/alert.dialog.component';
|
||||
import { ConfirmDialogComponent } from './dialogs/confirm.dialog.component';
|
||||
const DIALOGS = [AlertDialogComponent, ConfirmDialogComponent];
|
||||
|
||||
import { ImagePipe } from './pipes/image.pipe';
|
||||
const PIPES = [ImagePipe];
|
||||
import { BytesPipe } from './pipes/bytes.pipe';
|
||||
const PIPES = [BytesPipe];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatDialogModule,
|
||||
MatIconModule,
|
||||
MatSnackBarModule,
|
||||
DragDropModule
|
||||
],
|
||||
exports: [...COMPONENTS, ...PIPES],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...PIPES],
|
||||
exports: [...COMPONENTS, ...DIRECTIVES, ...PIPES],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...DIRECTIVES, ...PIPES],
|
||||
entryComponents: [...DIALOGS]
|
||||
})
|
||||
export class UCapUiModule {
|
||||
|
|
|
@ -7,7 +7,7 @@ export * from './lib/animations';
|
|||
export * from './lib/dialogs/alert.dialog.component';
|
||||
export * from './lib/dialogs/confirm.dialog.component';
|
||||
|
||||
export * from './lib/pipes/image.pipe';
|
||||
export * from './lib/directives/file-upload-for.directive';
|
||||
|
||||
export * from './lib/services/bottom-sheet.service';
|
||||
export * from './lib/services/clipboard.service';
|
||||
|
|
Loading…
Reference in New Issue
Block a user