This commit is contained in:
Richard Park 2020-01-09 18:52:16 +09:00
commit ed3f7e8ab5
19 changed files with 345 additions and 72 deletions

View File

@ -141,25 +141,27 @@
} }
} }
} }
.translation-section { .translation-container {
display: flex; .translation-section {
flex-flow: column; display: flex;
flex-flow: column;
.translation-container { border-top: 1px solid #dddddd;
position: absolute; .translation-container {
bottom: 0;
left: 0;
width: 100%;
background-color: transparent;
background-color: rgba(250, 255, 255, 0.8);
border-top: 1px solid;
.translation-zone {
position: absolute; position: absolute;
padding: 10px 10px 0 10px;
background-color: rgba(250, 255, 255, 0.8);
bottom: 0; bottom: 0;
left: 0;
width: 100%; width: 100%;
background-color: transparent;
background-color: rgba(250, 255, 255, 0.8);
border-top: 1px solid;
.translation-zone {
position: absolute;
padding: 10px 10px 0 10px;
background-color: rgba(250, 255, 255, 0.8);
bottom: 0;
width: 100%;
}
} }
} }
} }

View File

@ -584,12 +584,16 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
info.sentMessageJson || info.sentMessage info.sentMessageJson || info.sentMessage
); );
this.snackBarPreviewEvent = this.snackBarService.open(message, this.translateService.instant('common.messages.confirm'), { this.snackBarPreviewEvent = this.snackBarService.open(
// duration: 3000, message,
verticalPosition: 'bottom', this.translateService.instant('common.messages.confirm'),
horizontalPosition: 'center', {
panelClass: ['chat-snackbar-class'] // duration: 3000,
}); verticalPosition: 'bottom',
horizontalPosition: 'center',
panelClass: ['chat-snackbar-class']
}
);
this.snackBarPreviewEvent.onAction().subscribe(() => { this.snackBarPreviewEvent.onAction().subscribe(() => {
this.setEventMoreInit(); this.setEventMoreInit();
this.scrollToBottom(); this.scrollToBottom();
@ -1052,6 +1056,68 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
const allObservables: Observable<FileTalkSaveResponse>[] = []; const allObservables: Observable<FileTalkSaveResponse>[] = [];
const fileAllowSize =
!!this.sessionVerInfo && this.sessionVerInfo.fileAllowSize
? this.sessionVerInfo.fileAllowSize
: environment.productConfig.CommonSetting.defaultFileAllowSize;
if (fileAllowSize > 0) {
if (
fileUploadItems.filter(
fui => fui.file.size > fileAllowSize * 1024 * 1024
).length
) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
width: '360px',
data: {
title: '',
message: this.translateService.instant(
'common.file.errors.oversize',
{
maxSize: fileAllowSize
}
)
}
});
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onUploadComplete();
}
return;
}
}
const checkExt = this.commonApiService.acceptableExtensionForFileTalk(
fileUploadItems.map(fui => FileUtil.getExtension(fui.file.name))
);
if (!checkExt.accept) {
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onUploadComplete();
}
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: 'Alert',
html: `${this.translateService.instant(
'common.file.errors.notSupporedType'
)} ${
checkExt.reject.length > 0
? '<br/>(' + checkExt.reject.join(',') + ')'
: ''
}`
}
});
return;
}
for (const fileUploadItem of fileUploadItems) { for (const fileUploadItem of fileUploadItems) {
let thumbnail: File; let thumbnail: File;
if ( if (
@ -1127,6 +1193,10 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
this.translateService.instant('common.file.errors.failToUpload'), this.translateService.instant('common.file.errors.failToUpload'),
this.translateService.instant('common.file.errors.label') this.translateService.instant('common.file.errors.label')
); );
if (!!this.fileUploadQueue) {
this.fileUploadQueue.onUploadComplete();
}
}, },
() => { () => {
this.fileUploadQueue.onUploadComplete(); this.fileUploadQueue.onUploadComplete();

View File

@ -11,6 +11,7 @@
[detail]="data.detail" [detail]="data.detail"
[detailContents]="data.detailContents" [detailContents]="data.detailContents"
[curReceiverList]="data.receiverList" [curReceiverList]="data.receiverList"
[fileAllowSize]="fileAllowSize"
(send)="onSend($event)" (send)="onSend($event)"
(selectReceiver)="onSelectReceiver($event)" (selectReceiver)="onSelectReceiver($event)"
(cancel)="onCancel()" (cancel)="onCancel()"

View File

@ -7,13 +7,11 @@ import {
DetailResponse, DetailResponse,
DetailContent, DetailContent,
MessageApiService, MessageApiService,
DetailReceiver,
MessageType MessageType
} from '@ucap-webmessenger/api-message'; } from '@ucap-webmessenger/api-message';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { MessageStatusCode } from '@ucap-webmessenger/api';
import { import {
WriteComponent as UCapMessageWriteComponent, WriteComponent as UCapMessageWriteComponent,
Message, Message,
@ -25,10 +23,17 @@ import {
CreateChatDialogData, CreateChatDialogData,
CreateChatDialogResult CreateChatDialogResult
} from '../chat/create-chat.dialog.component'; } from '../chat/create-chat.dialog.component';
import { UserSelectDialogType, EnvironmentsInfo } from '@app/types'; import {
UserSelectDialogType,
EnvironmentsInfo,
KEY_VER_INFO
} from '@app/types';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { UserInfoSS } from '@ucap-webmessenger/protocol-query'; import { UserInfoSS } from '@ucap-webmessenger/protocol-query';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { environment } from '../../../../../environments/environment';
export interface MessageWriteDialogData { export interface MessageWriteDialogData {
loginRes: LoginResponse; loginRes: LoginResponse;
@ -57,6 +62,10 @@ export class MessageWriteDialogComponent implements OnInit {
@ViewChild('messageWrite', { static: true }) @ViewChild('messageWrite', { static: true })
messageWrite: UCapMessageWriteComponent; messageWrite: UCapMessageWriteComponent;
sessionVerInfo: VersionInfo2Response;
fileAllowSize: number;
isModify = false; isModify = false;
constructor( constructor(
@ -68,11 +77,21 @@ export class MessageWriteDialogComponent implements OnInit {
private messageApiService: MessageApiService, private messageApiService: MessageApiService,
private snackBarService: SnackBarService, private snackBarService: SnackBarService,
private translateService: TranslateService, private translateService: TranslateService,
private sessionStorageService: SessionStorageService,
private logger: NGXLogger, private logger: NGXLogger,
private dialogService: DialogService private dialogService: DialogService
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.sessionVerInfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO
);
this.fileAllowSize =
!!this.sessionVerInfo && this.sessionVerInfo.fileAllowSize
? this.sessionVerInfo.fileAllowSize
: environment.productConfig.CommonSetting.defaultFileAllowSize;
if (!!this.data.detail && !!this.data.detail.msgInfo) { if (!!this.data.detail && !!this.data.detail.msgInfo) {
this.isModify = true; this.isModify = true;
} }

View File

@ -350,12 +350,13 @@
"errors": { "errors": {
"label": "File errors", "label": "File errors",
"failToUpload": "File upload failed.", "failToUpload": "File upload failed.",
"failToSave": "File save failed.", "failToSave": "File save failed. Please 'Save As'.",
"failToSaveSomeOfAll": "Some of file(s) save failed", "failToSaveSomeOfAll": "Some of file(s) save failed. Please 'Save As'.",
"failToSpecifyPath": "Specifing of save path failed.", "failToSpecifyPath": "Specifing of save path failed.",
"expired": "This file has expired", "expired": "This file has expired",
"noPreview": "This file does not support preview.", "noPreview": "This file does not support preview.",
"notSupporedType": "File format is not supported." "notSupporedType": "File format is not supported.",
"oversize": "You cannot upload files larger than {{size}} megabytes."
} }
}, },
"clipboard": { "clipboard": {

View File

@ -329,8 +329,8 @@
"size": "파일 크기", "size": "파일 크기",
"download": "파일 다운로드", "download": "파일 다운로드",
"delete": "파일 삭제", "delete": "파일 삭제",
"save": "파일 저장", "save": "저장",
"saveAs": "파일을 다른 이름으로 저장", "saveAs": "다른 이름으로 저장",
"saveAll": "파일 모두 저장", "saveAll": "파일 모두 저장",
"downloadSelected": "선택된 파일 다운로드", "downloadSelected": "선택된 파일 다운로드",
"openDownloadFolder": "다운로드 폴더 열기", "openDownloadFolder": "다운로드 폴더 열기",
@ -350,12 +350,13 @@
"errors": { "errors": {
"label": "파일 에러", "label": "파일 에러",
"failToUpload": "파일 업로드에 실패하였습니다.", "failToUpload": "파일 업로드에 실패하였습니다.",
"failToSave": "파일 저장에 실패하였습니다.", "failToSave": "파일 저장에 실패하였습니다. '다른 이름으로 저장' 하십시요.",
"failToSaveSomeOfAll": "파일 저장 중 일부 파일이 실패하였습니다.", "failToSaveSomeOfAll": "파일 저장 중 일부 파일이 실패하였습니다. '다른 이름으로 저장' 하십시요.",
"failToSpecifyPath": "저장경로 지정에 실패하였습니다.", "failToSpecifyPath": "저장경로 지정에 실패하였습니다.",
"expired": "기간이 만료된 파일입니다", "expired": "기간이 만료된 파일입니다",
"noPreview": "미리보기를 지원하지 않는 파일입니다.", "noPreview": "미리보기를 지원하지 않는 파일입니다.",
"notSupporedType": "지원하지 않는 파일형식입니다." "notSupporedType": "지원하지 않는 파일형식입니다.",
"oversize": "{{maxSize}}MB 이상 파일을 업로드 할 수 없습니다."
} }
}, },
"clipboard": { "clipboard": {

View File

@ -237,13 +237,13 @@ $daesang-grey: (
color: mat-color($warn, 800); color: mat-color($warn, 800);
} }
.border-primary-color { .border-primary-color {
border: 1px solid mat-color($primary); border-color: 1px solid mat-color($primary);
} }
.border-accent-bright { .border-accent-bright {
border-color: mat-color($accent, 300); border-color: mat-color($accent, 300);
} }
.border-accent-color { .border-accent-color {
border: 1px solid mat-color($accent); border-color: 1px solid mat-color($accent);
} }
.stroke-accent-darkest { .stroke-accent-darkest {
stroke: mat-color($accent, 800); stroke: mat-color($accent, 800);
@ -420,9 +420,9 @@ $daesang-grey: (
} }
} }
.translationForm { .translationForm {
background-color: mat-color($accent, 200, 0.5); background-color: mat-color($accent, 200, 0.4);
} }
.translation-preview { .translation-preview {
background-color: mat-color($accent, 800, 0.8); background-color: mat-color($accent, 900, 0.8);
} }
} }

View File

@ -64,6 +64,8 @@ export const environment: Environment = {
} }
}, },
CommonSetting: { CommonSetting: {
defaultFileAllowSize: 100,
editableProfileImage: false, editableProfileImage: false,
useMyDeptGroup: true, useMyDeptGroup: true,

View File

@ -64,6 +64,8 @@ export const environment: Environment = {
} }
}, },
CommonSetting: { CommonSetting: {
defaultFileAllowSize: 100,
editableProfileImage: false, editableProfileImage: false,
useMyDeptGroup: true, useMyDeptGroup: true,

View File

@ -64,6 +64,8 @@ export const environment: Environment = {
} }
}, },
CommonSetting: { CommonSetting: {
defaultFileAllowSize: 100,
editableProfileImage: true, editableProfileImage: true,
useMyDeptGroup: false, useMyDeptGroup: false,

View File

@ -64,6 +64,8 @@ export const environment: Environment = {
} }
}, },
CommonSetting: { CommonSetting: {
defaultFileAllowSize: 100,
editableProfileImage: true, editableProfileImage: true,
useMyDeptGroup: false, useMyDeptGroup: false,

View File

@ -64,6 +64,9 @@ export interface Environment {
defaultSettings: Settings; defaultSettings: Settings;
CommonSetting: { CommonSetting: {
/** 파일업로드 제한 사이즈 (mb) */
defaultFileAllowSize: number;
/** 내 프로필 이미지 수정 가능 여부 */ /** 내 프로필 이미지 수정 가능 여부 */
editableProfileImage: boolean; editableProfileImage: boolean;

View File

@ -0,0 +1,62 @@
.translation-main {
flex-direction: column;
text-align: left;
.original {
padding: 14px;
}
.translation {
padding: 10px;
border-top: 1px solid #dddddd;
}
}
.btn-box {
width: 100%;
height: 40px;
border-top: 1px solid #dddddd;
display: flex;
ul {
width: 100%;
li {
width: 50%;
height: 100%;
display: inline-block;
text-align: center;
align-items: center;
font-size: 13px;
border-right: 1px solid #dddddd;
&:last-child {
border-right: none;
}
.mat-button {
width: 100%;
height: 100%;
display: block;
padding: 0px 6px 4px;
}
}
&.expired {
li {
width: 100%;
white-space: nowrap;
color: #999999;
align-items: center;
line-height: 40px;
}
}
}
}
.translation-main {
.language {
padding: 0px 6px 4px;
background-color: #222222;
border-radius: 4px;
font-size: 1em;
color: #fff;
margin-top: -4px;
margin-right: 6px;
transform: translateY(-2px);
}
}

View File

@ -1,5 +1,7 @@
.translation-main { .translation-main {
flex-direction: column;
text-align: left; text-align: left;
.original { .original {
padding: 14px; padding: 14px;
} }

View File

@ -82,7 +82,9 @@ $meBox-bg: #ffffff;
} }
} }
&.searched { &.searched {
color: red; .bubble {
color: red;
}
} }
} }

View File

@ -11,7 +11,13 @@ import {
Input Input
} from '@angular/core'; } from '@angular/core';
import { ucapAnimations, DialogService } from '@ucap-webmessenger/ui'; import {
ucapAnimations,
DialogService,
AlertDialogResult,
AlertDialogComponent,
AlertDialogData
} from '@ucap-webmessenger/ui';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
@ -36,7 +42,8 @@ import {
} from '../dialogs/schedule-send.dialog.component'; } from '../dialogs/schedule-send.dialog.component';
import { RoleCode } from '@ucap-webmessenger/protocol-authentication'; import { RoleCode } from '@ucap-webmessenger/protocol-authentication';
import { EmployeeType } from '@ucap-webmessenger/protocol-room'; import { EmployeeType } from '@ucap-webmessenger/protocol-room';
import { contentTracing } from 'electron'; import { TranslateService } from '@ngx-translate/core';
import { CommonApiService } from '@ucap-webmessenger/api-common';
const ATTR_FILE = 'UCAP_ATTR_FILE'; const ATTR_FILE = 'UCAP_ATTR_FILE';
@ -79,19 +86,18 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
detailContents?: string; detailContents?: string;
@Input() @Input()
isModify = false; isModify = false;
@Input()
fileAllowSize: number;
@Output() @Output()
send = new EventEmitter<Message | MessageModify>(); send = new EventEmitter<Message | MessageModify>();
@Output() @Output()
cancel = new EventEmitter<void>(); cancel = new EventEmitter<void>();
@Output() @Output()
selectReceiver = new EventEmitter<UserInfo[]>(); selectReceiver = new EventEmitter<UserInfo[]>();
@ViewChild('editor', { static: true }) @ViewChild('editor', { static: true })
editor: ElementRef<HTMLDivElement>; editor: ElementRef<HTMLDivElement>;
@ViewChild('fileInput', { static: true }) @ViewChild('fileInput', { static: true })
fileInput: ElementRef<HTMLInputElement>; fileInput: ElementRef<HTMLInputElement>;
@ -106,6 +112,8 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private dialogService: DialogService, private dialogService: DialogService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private translateService: TranslateService,
private commonApiService: CommonApiService,
private logger: NGXLogger private logger: NGXLogger
) {} ) {}
@ -157,6 +165,10 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
this.fileInput.nativeElement.onchange = async () => { this.fileInput.nativeElement.onchange = async () => {
const fileList: FileList = self.fileInput.nativeElement.files; const fileList: FileList = self.fileInput.nativeElement.files;
if (!this.validUploadFile(fileList)) {
return;
}
for (let i = 0; i < fileList.length; i++) { for (let i = 0; i < fileList.length; i++) {
const file = fileList.item(i); const file = fileList.item(i);
@ -179,6 +191,10 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
this.fileInput.nativeElement.onchange = () => { this.fileInput.nativeElement.onchange = () => {
const fileList: FileList = this.fileInput.nativeElement.files; const fileList: FileList = this.fileInput.nativeElement.files;
if (!this.validUploadFile(fileList)) {
return;
}
if (!self.attachmentList) { if (!self.attachmentList) {
self.attachmentList = []; self.attachmentList = [];
} }
@ -194,6 +210,65 @@ export class WriteComponent implements OnInit, OnDestroy, AfterViewInit {
}; };
} }
validUploadFile(fileList: FileList): boolean {
let valid = true;
if (this.fileAllowSize > 0) {
for (let i = 0; i < fileList.length; i++) {
const file = fileList.item(i);
if (file.size > this.fileAllowSize * 1024 * 1024) {
valid = false;
break;
}
}
if (!valid) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
width: '360px',
data: {
title: '',
message: this.translateService.instant(
'common.file.errors.oversize',
{
maxSize: this.fileAllowSize
}
)
}
});
return valid;
}
}
const checkExt = this.commonApiService.acceptableExtensionForFileTalk(
FileUtil.getExtensions(fileList)
);
if (!checkExt.accept) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: 'Alert',
html: `${this.translateService.instant(
'common.file.errors.notSupporedType'
)} ${
checkExt.reject.length > 0
? '<br/>(' + checkExt.reject.join(',') + ')'
: ''
}`
}
});
return valid;
}
return valid;
}
onPasteEditor(event: ClipboardEvent) { onPasteEditor(event: ClipboardEvent) {
const text = document.createTextNode( const text = document.createTextNode(
event.clipboardData.getData('text/plain') event.clipboardData.getData('text/plain')

View File

@ -20,7 +20,7 @@
position: relative; position: relative;
padding: 20px; padding: 20px;
text-align: right; text-align: right;
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(45, 58, 74, 0.8);
img { img {
margin-right: 40px; margin-right: 40px;
} }

View File

@ -7,15 +7,20 @@
" "
class="translation-preview" class="translation-preview"
> >
<span class="translation-section"> <div class="translation-section">
{{ translationPreviewInfo.previewInfo.translation }} <span class="translate-text">
</span> {{ translationPreviewInfo.previewInfo.translation }}
<div class="btns"> </span>
<button <button
mat-stroked-button mat-stroked-button
class="btn-translation-send"
(click)="onClickSendTranslationMessage(translationPreviewInfo)" (click)="onClickSendTranslationMessage(translationPreviewInfo)"
> >
{{ 'chat.send' | translate }} <!--{{ 'chat.send' | translate }}-->
<svg _ngcontent-smu-c52="" fill="none" height="20" stroke="currentColor" stroke-linecap="butt" stroke-linejoin="round"
stroke-width="2" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg">
<path _ngcontent-smu-c52="" d="M12 19V6M5 12l7-7 7 7"></path>
</svg>
</button> </button>
<button <button
class="btn-close-translatebox bg-accent-dark" class="btn-close-translatebox bg-accent-dark"
@ -39,6 +44,7 @@
</svg> </svg>
</button> </button>
</div> </div>
<!--<span class="btn-close"> <!--<span class="btn-close">
<button <button
mat-button mat-button

View File

@ -3,38 +3,52 @@
display: flex; display: flex;
flex-flow: row; flex-flow: row;
justify-items: flex-end; justify-items: flex-end;
align-items: center;
color: #ffffff; color: #ffffff;
.translation-section { .translation-section {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
font-size: 1.1em; font-size: 1.1em;
padding: 0 20px 0 40px;
} .translate-text {
.btns { margin: 10px 10px 10px 30px;
display: flex; max-height: 100px;
flex-flow: row; word-break: break-all;
margin-left: auto; white-space: pre-wrap;
height: 100%; overflow-y: auto;
button { display: flex;
&.btn-send { flex: 1 1 auto;
width: 80px; }
background-color: #ffffff; .btn-translation-send {
color: #333333; /* min-width: 80px;
} background-color: rgb(255, 255, 255,0.1);
&.btn-close-translatebox { border-radius: 0;
width: 3em; border: none;*/
height: 100%; background-color: #ffffff;
stroke: #ffffff; color: #333333;
border: none; border-radius: 0;
display: flex; width: 40px;
justify-content: center; height: 40px;
justify-items: center; border-radius: 50%;
margin-left: auto; margin-right: 20px;
padding: 0;
min-width: 40px;
align-self: center;
}
.btn-close-translatebox {
height: 100%;
stroke: #ffffff;
border: none;
display: flex;
justify-content: center;
justify-items: center;
margin-left: auto;
svg {
width: 40px;
} }
} }
} }
} }
::ng-deep .translationForm { ::ng-deep .translationForm {
position: relative; position: relative;
display: flex; display: flex;
@ -60,6 +74,13 @@
margin-right: 20px; margin-right: 20px;
.mat-form-field-wrapper { .mat-form-field-wrapper {
width: 100%; width: 100%;
line-height: 0.8em;
.mat-form-field-infix {
padding: 0.2em 0 0;
}
}
.mat-form-field-underline {
bottom: 0.8em;
} }
} }
.mat-slide-toggle { .mat-slide-toggle {