diff --git a/documents/업무/2월/02_TODO b/documents/업무/2월/02_TODO
index 57d6ac7..ea3c791 100644
--- a/documents/업무/2월/02_TODO
+++ b/documents/업무/2월/02_TODO
@@ -1,5 +1,5 @@
-묶음파일
- 업로드
+묶음파일
+ 업로드 (부분 완료)
묶음파일 request 모델 정의
userSeq: number;
deviceType: DeviceType;
@@ -24,6 +24,12 @@
이벤트 타입별 출력
묶음파일 타입 그리드 썸네일 컴포넌트 정의
그리드 알고리즘 작성
+ 썸네일 출력(완료)
+ 출력 가이드 라인
+ 최대 가로 출력 개수 3개
+ 다음행에 출력 개수가 홀수 일때
+ 빈 공간이 출력되지 않게 조정
+ 최대 width, 최소 height 테스트 후 결정
앨범함
묶음파일 타입 처리
뷰어 컴포넌트 (슬라이드 기능) (진행)
@@ -33,13 +39,6 @@
일반 이미지 출력
동영상인 경우
일반 동영상 썸네일 출력
- 썸네일 출력
- 출력 가이드 라인
- 최대 가로 출력 개수 3개
- 다음행에 출력 개수가 홀수 일때
- 빈 공간이 출력되지 않게 조정
- 최대 width, 최소 height 테스트 후 결정
-
카톡 벤치마킹
묶음파일 전송 후
1개의 이미지 전송
@@ -47,6 +46,7 @@
동영상 전송
동영상 썸네일 출력
동영상은 묶음파일 지원안함
+ 묶음파일 기획은 카톡과 동일하게 진행
원본 출력
//원본 파일 호출할 때 리플레이스
@@ -93,26 +93,67 @@
기능 목록
모바일 주소록 동기화
기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성이 농후)
- PC 서버 요청
- 모바일 노티
- for
- 모바일 주소록 서버 전송
- 모바일 주소록 서버 응답
- 서버가 주소록 리시브 노티
+ 1. PC -> Server
+ 모바일 주소록 동기화 시작
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
+ 2. Server -> Mobile
+ 모바일 주소록 동기화 노티
+ 3. Mobile -> Server
+ 준비 완료 요청
+ 4. Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI
+ 5. PC -> Server
+ 모바일 주소록 받을 준비 완료 요청
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ
+ 6.Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES //사용없음
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI
+ PC가 모바일로부터 준비 확인 NOTI를 받는 처리를 수행
+ 7.Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_RES //사용없음
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI //실데이터받는 프로토콜
박차장님이 제안한 방식
- PC 서버 요청
- 모바일 노티
- 모바일 주소록 JSON 으로 전송
- 새로운 방식
- 생각해봐야함
- 서버에 개인주소록을 저장할 경우
- PC에서 동기화 완료 후 서버 데이터 삭제 고려
- 서버에 개인주소록을 저장하지 않을 경우
- 서버 부하 고려
+ PC -> 서버
+ 개인 주소록 동기화 요청
+ 프로토콜 정의 협의
+ 서버 -> 모바일
+ 개인 주소록 동기화 요청에 대한 푸시
+ 모바일 -> 서버 (REST API)
+ 개인 주소록 POST 전송
+ 데이터 JSON 형태
+ 서버 -> 모바일 (REST API)
+ 개인 주소록 전송에 대한 응답
+ (응답코드, 싱크번호, 시간, 사용자번호)
+ 모바일 -> 서버
+ 개인 주소록 전송 동기화 프로토콜 요청
+ (싱크번호, 시간, 사용자번호)
+ 서버 -> 모바일
+ 개인 주소록 전송 동기화 프로토콜 요청에 대한 응답
+ 서버 -> PC
+ 개인 주소록 동기화 요청 프로토콜에 대한 푸시
+ (싱크번호, 사용자번호)
+ PC -> 서버 (REST API)
+ 개인 주소록 요청
+ (싱크번호, 사용자번호)
+ 서버 -> PC
+ 개인 주소록 JSON
+ (싱크번호, 시간, 사용자 번호)
+
모바일 주소록 초기화
PC에 저장된 모바일 주소록을 삭제
엑샐
Export/Import
템플릿
초기화
-MAC용 빌드
\ No newline at end of file
+MAC용 빌드
+
+대화 저장
+ 두개다 대화내용 암호화?
+ 서버에서 대화내용을 제공
+ 프로토콜 협의
+ PC에서 대화내용 조회후 제공
+ 서버 부하
+
+ 협의 필요
+
+
diff --git a/documents/업무/2월/1번째주/0206.txt b/documents/업무/2월/1째주/0206.txt
similarity index 100%
rename from documents/업무/2월/1번째주/0206.txt
rename to documents/업무/2월/1째주/0206.txt
diff --git a/documents/업무/2월/1번째주/0207.txt b/documents/업무/2월/1째주/0207.txt
similarity index 100%
rename from documents/업무/2월/1번째주/0207.txt
rename to documents/업무/2월/1째주/0207.txt
diff --git a/documents/업무/2월/2번째주/0210.txt b/documents/업무/2월/2째주/0210.txt
similarity index 98%
rename from documents/업무/2월/2번째주/0210.txt
rename to documents/업무/2월/2째주/0210.txt
index d37f824..60ab7ef 100644
--- a/documents/업무/2월/2번째주/0210.txt
+++ b/documents/업무/2월/2째주/0210.txt
@@ -33,4 +33,5 @@
tems[position].FILE_THUMB_URL
.replace("WebFile", "AttFile")
.replace(".thumb.jpg", "")
-클라이언트 참고 사항입니ㅏㄷ..실제 파일 열기 하실때는 실제 업로드된 파일경로로 접속하셔야 합니다.
\ No newline at end of file
+클라이언트 참고 사항입니ㅏㄷ..실제 파일 열기 하실때는 실제 업로드된 파일경로로 접속하셔야 합니다.
+
\ No newline at end of file
diff --git a/documents/업무/2월/2번째주/0211.txt b/documents/업무/2월/2째주/0211.txt
similarity index 100%
rename from documents/업무/2월/2번째주/0211.txt
rename to documents/업무/2월/2째주/0211.txt
diff --git a/documents/업무/2월/2번째주/0212.txt b/documents/업무/2월/2째주/0212.txt
similarity index 99%
rename from documents/업무/2월/2번째주/0212.txt
rename to documents/업무/2월/2째주/0212.txt
index 5998b69..4abab34 100644
--- a/documents/업무/2월/2번째주/0212.txt
+++ b/documents/업무/2월/2째주/0212.txt
@@ -13,7 +13,7 @@
fileInfo 조회
decodeInfoData->
-
+
WARNING in Circular dependency detected:
projects\ucap-webmessenger-protocol-event\src\lib\protocols\event-json\codec.ts ->
projects\ucap-webmessenger-protocol-event\src\lib\protocols\event-json\bundle-image.event-json.ts ->
@@ -64,6 +64,7 @@ projects\ucap-webmessenger-protocol-file\src\public-api.ts -> projects\ucap-webm
1: "16F98292020-02-10 07:09:16{
+
↵"StatusCode":"200",
↵"ErrorMessage":"",
↵"RoomID":"76",
diff --git a/documents/업무/2월/2째주/0213.txt b/documents/업무/2월/2째주/0213.txt
new file mode 100644
index 0000000..50f95ba
--- /dev/null
+++ b/documents/업무/2월/2째주/0213.txt
@@ -0,0 +1,151 @@
+// 그리드 함수 백업
+
+ makeGrid() {
+ const totalCount = this.bundleImageJson.fileCount;
+ const remainder = totalCount % 3;
+ const quotient = Math.floor(totalCount / 3);
+
+ let tile;
+
+ if (remainder === 0) {
+ this.bundleImageJson.thumbUrls.forEach((v, idx) => {
+ tile = {} as Tile;
+ tile.cols = 2;
+ this.getTile(tile, v);
+ });
+ } else if (remainder === 1) {
+ if (quotient === 0) {
+ tile = {} as Tile;
+ this.bundleImageJson.thumbUrls.forEach(v => {
+ this.getTile(tile, v);
+ });
+ tile.cols = 6;
+ return;
+ }
+
+ this.bundleImageJson.thumbUrls.forEach((v, idx) => {
+ tile = {} as Tile;
+ if (quotient <= idx / 3 + 1) {
+ tile.cols = 3;
+ } else {
+ tile.cols = 2;
+ }
+ this.getTile(tile, v);
+ });
+ } else {
+ this.bundleImageJson.thumbUrls.forEach((v, idx) => {
+ tile = {} as Tile;
+ if (quotient <= idx / 3) {
+ tile.cols = 3;
+ } else {
+ tile.cols = 2;
+ }
+ this.getTile(tile, v);
+ });
+ }
+ }
+
+ private getTile(tile: Tile, v: string) {
+ tile.imgSrc = this.baseURL + v;
+ tile.color = 'white';
+ this.tiles.push(tile);
+ }
+
+모바일 개인 주소록을 PC 버전에도 공유
+ PC->Mobile
+ 주소록 요청
+ PC<-Mobile
+ 주소록 전송
+ PC->Mobile
+ 주소록 완료
+
+주소록
+ UI 구성
+ 검색 (이름, 전화번호)
+ 검색 결과
+ 리스트 출력
+ 모바일 주소록 동기화(PC-> Mobile 요청)
+ 모바일 주소록 초기화(PC에서 동기화된 주소록 초기화)
+ 엑샐 탬플릿 (주소록을 입력할 수 있는 액샐 템플릿을 제공)
+ 액샐 업로드 (주소록이 입력된 액샐 템플릿을 업로드 하여 PC 주소록 업데이트)
+ 액샐 데이터 초기화 (액샐 업로드 데이터 초기화)
+ 액셀 내려받기 (주소록 데이터 액셀로 다운로드)
+ 기능 목록
+ 모바일 주소록 동기화
+ 기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성)
+ 1. PC -> Server
+ 모바일 주소록 동기화 시작
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
+ 2. Server -> Mobile
+ 모바일 주소록 동기화 노티
+ 3. Mobile -> Server
+ 모바일 준비 완료 요청 및 데이터 전송 (추측)
+ 4. Server -> PC
+ 4. Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI
+ 5. PC -> Server
+ PC 준비 완료 요청
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ
+ 6.Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES //사용없음
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI
+ PC가 모바일로부터 준비 확인 NOTI를 받는 처리를 수행
+ 7.Server -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_RES //사용없음
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI //실데이터받는 프로토콜
+ 박차장님이 제안한 방식
+ PC -> 서버
+ 개인 주소록 동기화 요청
+ 프로토콜 정의 협의
+ SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
+ (사용자번호)
+ 서버 -> 모바일
+ 개인 주소록 동기화 요청에 대한 푸시
+ 모바일 -> 서버 (REST API)
+ 개인 주소록 POST 전송
+ 데이터 JSON 형태
+ 서버 -> 모바일 (REST API)
+ 개인 주소록 전송에 대한 응답
+ (응답코드, 싱크번호, 시간, 사용자번호)
+ 모바일 -> 서버
+ 개인 주소록 전송 동기화 프로토콜 요청
+ (싱크번호, 시간, 사용자번호)
+ 서버 -> 모바일
+ 개인 주소록 전송 동기화 프로토콜 요청에 대한 응답
+ 서버 -> PC
+ 모바일 개인 주소록 전송 완료 노티
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI
+ (싱크번호, 사용자번호)
+ PC -> 서버 (REST API)
+ 개인 주소록 요청
+ (싱크번호, 사용자번호)
+ 서버 -> PC
+ 개인 주소록 JSON
+ (싱크번호, 시간, 사용자 번호)
+
+ 모바일 주소록 초기화
+ PC에 저장된 모바일 주소록을 삭제
+ 엑샐
+ Export/Import
+ 템플릿
+ 초기화
+
+대화방
+
+TODO 완료
+ 대화 묶음파일 그리드 컴포넌트 리팩토링
+
+ 파일 업로드 큐 컴포넌트 수정
+ 묶음파일 처리 추가
+
+ 묶음파일 업로드 함수 리팩토링
+ 묶음파일 모델링 수정
+ 메세지 전송 컴포넌트 수정
+ 묶음파일 전송 UI 추가
+ 묶음파일 전송 로직 추가
+ 이벤트 타입 추가
+ BundleImage = 'b';
+ 파일 타입 추가
+ Bundle = 'b';
+ 앨범함 컴포넌트 수정
+ 묶음파일 타입 처리 추가
diff --git a/documents/업무/2월/2째주/0214.txt b/documents/업무/2월/2째주/0214.txt
new file mode 100644
index 0000000..9196152
--- /dev/null
+++ b/documents/업무/2월/2째주/0214.txt
@@ -0,0 +1,37 @@
+내일 TODO
+ Call 컴포넌트 작성
+ 다이얼러 컴포넌트 작성
+ 주소록 컴포넌트 작성
+ 최근통화내역 컴포넌트 작성
+요구사항
+ 지역번호-3자리-4자리 /^(0(2|3[1-3]|4[1-4]|5[1-5]|6[1-4]))-(\d{3,4})-(\d{4})$/
+ 010-4자리-4자리 || 011,017,016-3자리-4자리 /^(?:(010-\d{4})|(01[1|6|7|8|9]-\d{3,4}))-(\d{4})$/
+ 기타번호4자리-4자리
+ // 추후에 +국가코드3자리-
+ 입력번호, 출력번호
+ 숫자 버튼,
+ 통화 버튼,
+ 삭제 버튼
+
+ 4행 * 3열 그리드 출력
+
+ 번호 함수
+ 입력 이벤트 마다 지역번호, 핸드폰 번호 추출
+ 하이픈 넣기
+ 입력번호를 출력번호로 변환
+
+ 삭제 함수
+ 이벤트 발생 마다
+ 입력번호 삭제
+ 번호함수 호출
+
+ 통화 함수
+ 클릭투콜 API 호출
+
+주간보고서 작성
+ 묶음파일 업로드 추가
+ 그리드 기능 추가
+ 앨범함 기능 추가
+ 묶음파일 전송 기능 추가
+ 파일 업로드 기능 수정
+
\ No newline at end of file
diff --git a/documents/업무/2월/2째주/LF_개인주소록_프로토콜.txt b/documents/업무/2월/2째주/LF_개인주소록_프로토콜.txt
new file mode 100644
index 0000000..b0477d6
--- /dev/null
+++ b/documents/업무/2월/2째주/LF_개인주소록_프로토콜.txt
@@ -0,0 +1,34 @@
+SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ = 21, || 모바일 주소록 씽크 준비 요청
+ PC -> Server
+ 모바일 온라인 확인 단계 필요
+
+SSVC_TYPE_SYNC_PHONEBOOK_READY_RES = 22, || 모바일 주소록 씽크 준비 요청완료
+ 서버 -> PC
+ SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI 프로토콜을 30초동안 기다림
+
+SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI = 23, || 모바일 주소록 씽크 준비 알림
+
+SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ = 24, || 모바일 주소록 씽크 준비 확인 요청
+ 3
+
+SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES = 25, || 모바일 주소록 씽크 준비 확인 요청완료
+
+SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI = 26, || 모바일 주소록 씽크 준비 확인 알림
+
+SSVC_TYPE_SYNC_PHONEBOOK_SND_REQ = 31, || 모바일 주소록 씽크 요청
+SSVC_TYPE_SYNC_PHONEBOOK_SND_RES = 32, || 모바일 주소록 씽크 완료
+ 데이터는 M->PC 단방향 해당 RES는 PC 에서는 아무의미가 없다.
+
+SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI = 33, || 모바일 주소록 씽크 알림
+ 해당 노티는 PC가 받는 노티(실데이터가 있음)
+
+//** 모바일에서 사용하는 프로토콜 **//
+SSVC_TYPE_SYNC_PHONEBOOK_RCV_REQ = 34, || 모바일 주소록 씽크 확인 요청
+
+SSVC_TYPE_SYNC_PHONEBOOK_RCV_RES = 35, || 모바일 주소록 씽크 확인 요청완료
+ PC 사용 X
+SSVC_TYPE_SYNC_PHONEBOOK_RCV_NOTI = 36, || 모바일 주소록 씽크 확인 알림
+ PC 사용 X
+ 모바일에서 사용한는 프로토콜
+//** 모바일에서 사용하는 프로토콜 **//
+
diff --git a/documents/업무/2월/2째주/묵음파일백업/album-box.component.html b/documents/업무/2월/2째주/묵음파일백업/album-box.component.html
new file mode 100644
index 0000000..9110e07
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/album-box.component.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ 'common.file.selectFiles' | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'common.file.selectFiles' | translate }}
+
+
+
+
+
+
+
+ {{ 'common.file.errors.cantPlay' | translate }}
+
+
+
+ {{ selectedFile.info.name }}
+
+ size :
+ {{ selectedFile.info.size | ucapBytes }}
+
+
+ date :
+ {{ selectedFile.info.sendDate | ucapDate: 'YYYY.MM.DD' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ vertical_align_bottom
+
+
+
+
+
+
+
+
+ 0 ? 'false' : 'true'"
+ class="mat-primary"
+ (click)="onClickDownloadAll()"
+ >
+ {{ 'common.file.downloadSelected' | translate }}
+
+
+ {{ 'common.file.openDownloadFolder' | translate }}
+
+
+
diff --git a/documents/업무/2월/2째주/묵음파일백업/album-box.component.ts b/documents/업무/2월/2째주/묵음파일백업/album-box.component.ts
new file mode 100644
index 0000000..2a579ef
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/album-box.component.ts
@@ -0,0 +1,264 @@
+import {
+ Component,
+ OnInit,
+ OnDestroy,
+ Inject,
+ ElementRef,
+ ViewChild
+} from '@angular/core';
+import {
+ FileInfo,
+ FileDownloadInfo,
+ FileType
+} from '@ucap-webmessenger/protocol-file';
+import { Subscription, combineLatest } from 'rxjs';
+import { Store, select } from '@ngrx/store';
+
+import * as AppStore from '@app/store';
+import { tap } from 'rxjs/operators';
+import { FileUtil } from '@ucap-webmessenger/core';
+import { CommonApiService } from '@ucap-webmessenger/api-common';
+import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
+import { SessionStorageService } from '@ucap-webmessenger/web-storage';
+import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
+import {
+ EnvironmentsInfo,
+ KEY_ENVIRONMENTS_INFO,
+ KEY_VER_INFO
+} from '@app/types';
+import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
+import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';
+import { NGXLogger } from 'ngx-logger';
+import { FileDownloadItem } from '@ucap-webmessenger/api';
+import { ModuleConfig } from '@ucap-webmessenger/api-common';
+import { _MODULE_CONFIG } from 'projects/ucap-webmessenger-api-common/src/lib/config/token';
+import { AppFileService } from '@app/services/file.service';
+
+export interface FileInfoTotal {
+ info: FileInfo;
+ checkInfo: FileDownloadInfo[];
+ fileDownloadItem: FileDownloadItem;
+}
+
+@Component({
+ selector: 'app-layout-chat-right-drawer-album-box',
+ templateUrl: './album-box.component.html',
+ styleUrls: ['./album-box.component.scss']
+})
+export class AlbumBoxComponent implements OnInit, OnDestroy {
+ @ViewChild('videoPlayer', { static: false })
+ videoPlayer: ElementRef;
+
+ filteredList: FileInfoTotal[] = [];
+ fileInfoTotal: FileInfoTotal[];
+ fileInfoList: FileInfo[];
+ fileInfoListSubscription: Subscription;
+
+ selectedFile: FileInfoTotal;
+ selectedFileList: FileInfoTotal[] = [];
+
+ loginRes: LoginResponse;
+ environmentsInfo: EnvironmentsInfo;
+ sessionVerinfo: VersionInfo2Response;
+
+ FileType = FileType;
+ currentTabIndex = 0;
+
+ thumbBaseUrl: string;
+
+ playable = true;
+
+ constructor(
+ private store: Store,
+ private sessionStorageService: SessionStorageService,
+ private commonApiService: CommonApiService,
+ @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
+ private appFileService: AppFileService,
+ @Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
+ private logger: NGXLogger
+ ) {
+ this.loginRes = this.sessionStorageService.get(
+ KEY_LOGIN_RES_INFO
+ );
+ this.environmentsInfo = this.sessionStorageService.get(
+ KEY_ENVIRONMENTS_INFO
+ );
+ this.sessionVerinfo = this.sessionStorageService.get(
+ KEY_VER_INFO
+ );
+
+ this.thumbBaseUrl = `${this.moduleConfig.hostConfig.protocol}://${
+ this.moduleConfig.hostConfig.domain
+ }:${String(this.moduleConfig.hostConfig.port)}`;
+ }
+
+ ngOnInit() {
+ this.fileInfoListSubscription = combineLatest([
+ this.store.pipe(select(AppStore.MessengerSelector.RoomSelector.roomInfo)),
+ this.store.pipe(
+ select(AppStore.MessengerSelector.EventSelector.selectAllFileInfoList)
+ ),
+ this.store.pipe(
+ select(
+ AppStore.MessengerSelector.EventSelector.selectAllFileInfoCheckList
+ )
+ )
+ ])
+ .pipe(
+ tap(() => (this.fileInfoTotal = [])),
+ tap(([roomInfo, fileInfoList, fileInfoCheckList]) => {
+ this.fileInfoList = fileInfoList.filter(fileInfo => {
+ if (
+ !!roomInfo &&
+ fileInfo.roomSeq === roomInfo.roomSeq &&
+ (fileInfo.type === FileType.Image ||
+ fileInfo.type === FileType.Video)
+ ) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ this.fileInfoList.map(fileInfo => {
+ this.fileInfoTotal.push({
+ info: fileInfo,
+ checkInfo: fileInfoCheckList.filter(
+ checkInfo => checkInfo.seq === fileInfo.seq
+ ),
+ fileDownloadItem: new FileDownloadItem()
+ });
+ });
+
+ this.onSelectedIndexChange(this.currentTabIndex);
+ })
+ )
+ .subscribe();
+ }
+
+ ngOnDestroy(): void {
+ if (!!this.fileInfoListSubscription) {
+ this.fileInfoListSubscription.unsubscribe();
+ }
+ }
+
+ getExtention(name: string): string {
+ return FileUtil.getExtension(name);
+ }
+
+ getImageUrl(fileInfo: FileInfoTotal): string {
+ return this.commonApiService.urlForFileTalkDownload(
+ {
+ userSeq: this.loginRes.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginRes.tokenString,
+ attachmentsSeq: fileInfo.info.seq
+ },
+ this.sessionVerinfo.downloadUrl
+ );
+ }
+
+ onErrorThumbnail(el: HTMLElement, fileInfo: FileInfoTotal): void {
+ const iconEl = document.createElement('div');
+ iconEl.setAttribute(
+ 'class',
+ 'mime-icon light ico-' + this.getExtention(fileInfo.info.name)
+ );
+ iconEl.innerHTML = `
`;
+ el.replaceWith(iconEl);
+ }
+
+ onSelectedIndexChange(index: number) {
+ this.selectedFile = null;
+ this.currentTabIndex = index;
+ if (this.currentTabIndex === 0) {
+ // Image
+ this.filteredList = this.fileInfoTotal.filter(
+ fileInfo => fileInfo.info.type === FileType.Image
+ );
+ } else {
+ // Video
+ this.filteredList = this.fileInfoTotal.filter(
+ fileInfo => fileInfo.info.type === FileType.Video
+ );
+ }
+ }
+
+ onClickImage(event: MouseEvent, fileInfo: FileInfoTotal) {
+ if (!!event) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ this.playable = true;
+ this.selectedFile = fileInfo;
+ }
+
+ getCheckItem(fileInfo: FileInfoTotal) {
+ if (this.selectedFileList) {
+ if (
+ this.selectedFileList.filter(
+ info => info.info.seq === fileInfo.info.seq
+ ).length > 0
+ ) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ onCheckItem(value: boolean, fileInfo: FileInfoTotal) {
+ if (value) {
+ this.onClickImage(undefined, fileInfo);
+ this.selectedFileList.push(fileInfo);
+ } else {
+ this.selectedFileList = this.selectedFileList.filter(
+ info => info.info.seq !== fileInfo.info.seq
+ );
+ }
+ }
+
+ onClickDownload(fileInfo: FileInfoTotal) {
+ this.appFileService.fileTalkDownlod({
+ req: {
+ userSeq: this.loginRes.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginRes.tokenString,
+ attachmentsSeq: fileInfo.info.seq,
+ fileDownloadItem: fileInfo.fileDownloadItem
+ },
+ fileName: fileInfo.info.name
+ });
+ }
+
+ onClickDownloadAll(): void {
+ this.selectedFileList.forEach(fileInfo => {
+ this.onClickDownload(fileInfo);
+ });
+ }
+
+ onClickOpenDownloadFolder(): void {
+ this.nativeService
+ .openDefaultDownloadFolder()
+ .then(result => {
+ if (!!result) {
+ } else {
+ throw new Error('response Error');
+ }
+ })
+ .catch(reason => {
+ this.logger.error(reason);
+ });
+ }
+
+ onLoadedDataVideo(): void {
+ if (
+ 0 === this.videoPlayer.nativeElement.videoWidth ||
+ 0 === this.videoPlayer.nativeElement.videoHeight
+ ) {
+ this.playable = false;
+ }
+ }
+}
diff --git a/documents/업무/2월/2째주/묵음파일백업/bundle-image.event-json.ts b/documents/업무/2월/2째주/묵음파일백업/bundle-image.event-json.ts
new file mode 100644
index 0000000..766272a
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/bundle-image.event-json.ts
@@ -0,0 +1,36 @@
+import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
+import { FileType } from '@ucap-webmessenger/protocol-file';
+import { EventJsonDecoder } from './event-json';
+
+export interface BundleImageEventJson {
+ statusCode?: StatusCode;
+ errorMessage?: string;
+ roomSeq?: number;
+ attachmentSeq?: number;
+ fileCount?: number;
+ baseUrl?: string;
+ thumbUrls?: string[];
+ fileType?: FileType;
+}
+
+export const decodeBundleImageEventJson: EventJsonDecoder = (
+ message: string
+) => {
+ try {
+ const json = JsonAnalization.receiveAnalization(message);
+
+ return {
+ statusCode: json.StatusCode,
+ errorMessage: json.ErrorMessage,
+ roomSeq: json.RoomID,
+ attachmentSeq: json.AttSEQ,
+ fileCount: json.FileCount,
+ thumbUrls: json.ThumbURL
+ } as BundleImageEventJson;
+ } catch (e) {
+ return {
+ statusCode: StatusCode.Fail,
+ errorMessage: e.toString()
+ } as BundleImageEventJson;
+ }
+};
diff --git a/documents/업무/2월/2째주/묵음파일백업/common-api.service.ts b/documents/업무/2월/2째주/묵음파일백업/common-api.service.ts
new file mode 100644
index 0000000..b955052
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/common-api.service.ts
@@ -0,0 +1,382 @@
+import { Injectable, Inject } from '@angular/core';
+import {
+ HttpClient,
+ HttpEventType,
+ HttpResponse,
+ HttpRequest
+} from '@angular/common/http';
+
+import { Observable, Subject } from 'rxjs';
+import { map, filter } from 'rxjs/operators';
+
+import {
+ FileProfileSaveRequest,
+ FileProfileSaveResponse,
+ encodeFileProfileSave,
+ decodeFileProfileSave
+} from '../apis/file-profile-save';
+import {
+ FileTalkDownloadRequest,
+ encodeFileTalkDownload,
+ encodeFormDataFileTalkDownload
+} from '../apis/file-talk-download';
+import {
+ FileTalkSaveRequest,
+ FileTalkSaveResponse,
+ encodeFileTalkSave,
+ decodeFileTalkSave
+} from '../apis/file-talk-save';
+import {
+ FileTalkSaveMultiRequest,
+ FileTalkSaveMultiResponse,
+ encodeFileTalkSaveMulti,
+ decodeFileTalkSaveMulti
+} from '../apis/file-talk-save-multi';
+import {
+ FileTalkShareRequest,
+ FileTalkShareResponse,
+ encodeFileTalkShare,
+ decodeFileTalkShare
+} from '../apis/file-talk-share';
+import {
+ MassTalkDownloadRequest,
+ MassTalkDownloadResponse,
+ encodeMassTalkDownload,
+ decodeMassTalkDownload
+} from '../apis/mass-talk-download';
+import {
+ MassTalkSaveRequest,
+ MassTalkSaveResponse,
+ encodeMassTalkSave,
+ decodeMassTalkSave
+} from '../apis/mass-talk-save';
+import {
+ TransMassTalkDownloadRequest,
+ TransMassTalkDownloadResponse,
+ encodeTransMassTalkDownload,
+ decodeTransMassTalkDownload
+} from '../apis/trans-mass-talk-download';
+import {
+ TransMassTalkSaveRequest,
+ TransMassTalkSaveResponse,
+ encodeTransMassTalkSave,
+ decodeTransMassTalkSave
+} from '../apis/trans-mass-talk-save';
+import {
+ TranslationReqRequest,
+ TranslationReqResponse,
+ encodeTranslationReq,
+ decodeTranslationReq
+} from '../apis/translation-req';
+import {
+ TranslationSaveRequest,
+ TranslationSaveResponse,
+ encodeTranslationSave,
+ decodeTranslationSave
+} from '../apis/translation-save';
+
+import { _MODULE_CONFIG } from '../config/token';
+import { ModuleConfig } from '../config/module-config';
+import { Urls } from '../config/urls';
+import { UrlConfig } from '@ucap-webmessenger/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class CommonApiService {
+ readonly urls: Urls;
+
+ constructor(
+ @Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
+ private httpClient: HttpClient
+ ) {
+ this.urls = UrlConfig.getUrls(
+ this.moduleConfig.hostConfig,
+ this.moduleConfig.urls
+ );
+ }
+
+ public fileProfileSave(
+ req: FileProfileSaveRequest,
+ fileProfileSaveUrl?: string
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ !!fileProfileSaveUrl ? fileProfileSaveUrl : this.urls.fileProfileSave,
+ encodeFileProfileSave(req),
+ { reportProgress: true, responseType: 'text' as 'json' }
+ );
+
+ const progress = req.fileUploadItem.uploadStart();
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ } else if (HttpEventType.UploadProgress === event.type) {
+ progress.next(Math.round((100 * event.loaded) / event.total));
+ }
+ return false;
+ }),
+ map((event: HttpResponse) => {
+ req.fileUploadItem.uploadComplete();
+ return decodeFileProfileSave(event.body);
+ })
+ );
+ }
+
+ public urlForFileTalkDownload(
+ req: FileTalkDownloadRequest,
+ fileTalkDownloadUrl?: string
+ ): string {
+ const httpReq = new HttpRequest(
+ 'GET',
+ !!fileTalkDownloadUrl ? fileTalkDownloadUrl : this.urls.fileTalkDownload,
+ {},
+ {
+ params: encodeFileTalkDownload(req)
+ }
+ );
+
+ return httpReq.urlWithParams;
+ }
+
+ public fileTalkDownload(
+ req: FileTalkDownloadRequest,
+ fileTalkDownloadUrl?: string
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ !!fileTalkDownloadUrl ? fileTalkDownloadUrl : this.urls.fileTalkDownload,
+ encodeFormDataFileTalkDownload(req),
+ { reportProgress: true, responseType: 'blob' }
+ );
+
+ let progress: Subject;
+ if (!!req.fileDownloadItem) {
+ progress = req.fileDownloadItem.downloadStart();
+ }
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ } else if (HttpEventType.DownloadProgress === event.type) {
+ if (!!progress) {
+ progress.next(Math.round((100 * event.loaded) / event.total));
+ }
+ }
+ return false;
+ }),
+ map((event: HttpResponse) => {
+ if (!!progress) {
+ req.fileDownloadItem.downloadComplete();
+ }
+ return event.body;
+ })
+ );
+ }
+
+ public fileTalkSaveMulti(
+ req: FileTalkSaveMultiRequest,
+ fileTalkSaveMultiUrl?: string
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ !!fileTalkSaveMultiUrl
+ ? fileTalkSaveMultiUrl
+ : this.urls.fileTalkSaveMulti,
+ encodeFileTalkSaveMulti(req),
+ { reportProgress: true, responseType: 'text' as 'json' }
+ );
+
+ const progressList: Subject[] = [];
+ for (const p of req.fileUploadItems) {
+ progressList.push(p.uploadStart());
+ }
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ } else if (HttpEventType.UploadProgress === event.type) {
+ // progress.next(Math.round((100 * event.loaded) / event.total));
+ for (const progress of progressList) {
+ progress.next(Math.round((100 * event.loaded) / event.total));
+ }
+ }
+ return false;
+ }),
+ map((event: HttpResponse) => {
+ for (const p of req.fileUploadItems) {
+ p.uploadComplete();
+ }
+ return decodeFileTalkSaveMulti(event.body);
+ })
+ );
+ }
+
+ public fileTalkSave(
+ req: FileTalkSaveRequest,
+ fileTalkSaveUrl?: string
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ !!fileTalkSaveUrl ? fileTalkSaveUrl : this.urls.fileTalkSave,
+ encodeFileTalkSave(req),
+ { reportProgress: true, responseType: 'text' as 'json' }
+ );
+
+ const progress = req.fileUploadItem.uploadStart();
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ } else if (HttpEventType.UploadProgress === event.type) {
+ progress.next(Math.round((100 * event.loaded) / event.total));
+ }
+ return false;
+ }),
+ map((event: HttpResponse) => {
+ req.fileUploadItem.uploadComplete();
+ return decodeFileTalkSave(event.body);
+ })
+ );
+ }
+
+ public acceptableExtensionForFileTalk(
+ extensions: string[]
+ ): { accept: boolean; reject: string[] } {
+ let accept = true;
+ const reject: string[] = [];
+ for (const extension of extensions) {
+ if (
+ -1 ===
+ this.moduleConfig.acceptableFileExtensions.indexOf(
+ extension.toLowerCase()
+ )
+ ) {
+ reject.push(extension);
+ accept = false;
+ }
+ }
+ return {
+ accept,
+ reject
+ };
+ }
+
+ public fileTalkShare(
+ req: FileTalkShareRequest
+ ): Observable {
+ return this.httpClient
+ .post(
+ this.urls.fileTalkShare,
+ {},
+ {
+ params: encodeFileTalkShare(req)
+ }
+ )
+ .pipe(map(res => decodeFileTalkShare(res)));
+ }
+
+ public massTalkDownload(
+ req: MassTalkDownloadRequest
+ ): Observable {
+ return this.httpClient
+ .post(
+ this.urls.massTalkDownload,
+ {},
+ {
+ params: encodeMassTalkDownload(req),
+ responseType: 'text' as 'json'
+ }
+ )
+ .pipe(map(res => decodeMassTalkDownload(res)));
+ }
+
+ public massTalkSave(
+ req: MassTalkSaveRequest
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ this.urls.massTalkSave,
+ encodeMassTalkSave(req),
+ { reportProgress: true, responseType: 'text' as 'json' }
+ );
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ }
+ return false;
+ }),
+ map(res => decodeMassTalkSave((res as HttpResponse).body))
+ );
+ }
+
+ public transMassTalkDownload(
+ req: TransMassTalkDownloadRequest
+ ): Observable {
+ return this.httpClient
+ .post(
+ this.urls.transMassTalkDownload,
+ {},
+ {
+ params: encodeTransMassTalkDownload(req)
+ }
+ )
+ .pipe(map(res => decodeTransMassTalkDownload(res)));
+ }
+
+ public transMassTalkSave(
+ req: TransMassTalkSaveRequest
+ ): Observable {
+ return this.httpClient
+ .post(
+ this.urls.transMassTalkSave,
+ {},
+ {
+ params: encodeTransMassTalkSave(req)
+ }
+ )
+ .pipe(map(res => decodeTransMassTalkSave(res)));
+ }
+
+ public translationReq(
+ req: TranslationReqRequest
+ ): Observable {
+ return this.httpClient
+ .post(
+ this.urls.translationReq,
+ {},
+ {
+ params: encodeTranslationReq(req)
+ }
+ )
+ .pipe(map(res => decodeTranslationReq(res)));
+ }
+
+ public translationSave(
+ req: TranslationSaveRequest
+ ): Observable {
+ const httpReq = new HttpRequest(
+ 'POST',
+ this.urls.translationSave,
+ encodeTranslationSave(req),
+ { reportProgress: true }
+ );
+
+ return this.httpClient.request(httpReq).pipe(
+ filter(event => {
+ if (event instanceof HttpResponse) {
+ return true;
+ }
+ return false;
+ }),
+ map(res => decodeTranslationSave((res as HttpResponse).body))
+ );
+ }
+}
diff --git a/documents/업무/2월/2째주/묵음파일백업/file-talk-save-multi.ts b/documents/업무/2월/2째주/묵음파일백업/file-talk-save-multi.ts
new file mode 100644
index 0000000..17a7c71
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/file-talk-save-multi.ts
@@ -0,0 +1,79 @@
+import { DeviceType } from '@ucap-webmessenger/core';
+import {
+ APIRequest,
+ APIResponse,
+ APIEncoder,
+ APIDecoder,
+ ParameterUtil,
+ StatusCode,
+ JsonAnalization,
+ APIFormDataEncoder
+} from '@ucap-webmessenger/api';
+import { FileUploadItem } from '../../../../ucap-webmessenger-api/src/lib/models/file-upload-item';
+
+export interface FileTalkSaveMultiRequest extends APIRequest {
+ userSeq: number;
+ deviceType: DeviceType;
+ token: string;
+ files: File[];
+ fileUploadItems: FileUploadItem[];
+ roomSeq?: string;
+ type?: string;
+}
+
+export interface FileTalkSaveMultiResponse extends APIResponse {
+ roomSeq?: string;
+ attachmentSeq?: string;
+ fileCount?: string;
+ baseUrl?: string;
+ fileType?: string;
+ thumbnailUrls?: string[];
+ returnJson?: string;
+}
+
+const fileTalkSaveEncodeMapTemp = {
+ userSeq: 'p_user_seq',
+ deviceType: 'p_device_type',
+ token: 'p_token',
+ roomSeq: 'p_room_id',
+ files: 'file[]',
+ type: 'p_type'
+};
+
+export const encodeFileTalkSaveMulti: APIFormDataEncoder = (
+ req: FileTalkSaveMultiRequest
+) => {
+ const extraParams: any = {};
+ extraParams.userSeq = String(req.userSeq);
+
+ return ParameterUtil.encodeFormData(
+ fileTalkSaveEncodeMapTemp,
+ req,
+ extraParams
+ );
+};
+
+export const decodeFileTalkSaveMulti: APIDecoder = (
+ res: any
+) => {
+ try {
+ const json = JsonAnalization.receiveAnalization(res);
+ const fileTypeDefault =
+ !json.fileType || json.fileType === '' ? 'b' : json.fileType;
+ return {
+ statusCode: json.StatusCode,
+ roomSeq: json.RoomID,
+ attachmentSeq: json.AttSEQ,
+ fileCount: json.FileCount,
+ fileType: fileTypeDefault,
+ baseUrl: json.BaseURL,
+ thumbnailUrls: json.ThumbURL,
+ returnJson: res
+ } as FileTalkSaveMultiResponse;
+ } catch (e) {
+ return {
+ statusCode: StatusCode.Fail,
+ errorMessage: e
+ } as FileTalkSaveMultiResponse;
+ }
+};
diff --git a/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.html b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.html
new file mode 100644
index 0000000..4895086
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
{{ fileUploadItem.file.name }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'common.file.dropZoneForUpload' | translate }}
+
+
+
+
diff --git a/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.scss b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.scss
new file mode 100644
index 0000000..8d0975c
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.scss
@@ -0,0 +1,55 @@
+@mixin ellipsis($row) {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ @if $row == 1 {
+ display: block;
+ white-space: nowrap;
+ word-wrap: normal;
+ } @else if $row >= 2 {
+ display: -webkit-box;
+ -webkit-line-clamp: $row;
+ -webkit-box-orient: vertical;
+ word-wrap: break-word;
+ }
+}
+
+.ucap-file-upload-queue-container {
+ width: 100%;
+ height: 100%;
+ .file-upload-item {
+ min-width: 200px;
+ margin: 0 1%;
+ margin-bottom: 10px;
+ width: 100%;
+ border-radius: 3px;
+ background-color: #f9f9f9;
+ border: 1px solid #dddddd;
+ .file-upload-info {
+ padding: 10px;
+ svg {
+ margin-right: 6px;
+ }
+ .file-upload-name {
+ height: 20px;
+ @include ellipsis(2);
+ }
+ }
+ .file-upload-progress {
+ padding: 6px 10px;
+ }
+ }
+ .uploadItems {
+ width: 100%;
+ font-size: 0.9em;
+ .msg-guide {
+ display: flex;
+ flex: row;
+ color: #ffffff;
+ justify-content: center;
+ align-items: center;
+ .icon-img {
+ margin-right: 6px;
+ }
+ }
+ }
+}
diff --git a/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.ts b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.ts
new file mode 100644
index 0000000..e62da98
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.ts
@@ -0,0 +1,117 @@
+import {
+ Component,
+ OnInit,
+ Input,
+ ElementRef,
+ AfterViewInit
+} from '@angular/core';
+
+import { NGXLogger } from 'ngx-logger';
+import { FileUploadItem } from '@ucap-webmessenger/api';
+
+@Component({
+ selector: 'ucap-file-upload-queue',
+ templateUrl: './file-upload-queue.component.html',
+ styleUrls: ['./file-upload-queue.component.scss']
+})
+export class FileUploadQueueComponent implements OnInit, AfterViewInit {
+ @Input()
+ dropZoneIncludeParent = false;
+
+ fileUploadItems: FileUploadItem[];
+ uploadItems: DataTransferItem[];
+
+ constructor(
+ private elementRef: ElementRef,
+ private logger: NGXLogger
+ ) {}
+
+ ngOnInit() {}
+
+ ngAfterViewInit(): void {
+ this.changeStyleDisplay(false);
+ }
+
+ onDragEnter(items: DataTransferItemList): void {
+ if (!items || 0 === items.length) {
+ return;
+ }
+
+ const uploadItems: DataTransferItem[] = [];
+ // tslint:disable-next-line: prefer-for-of
+ for (let i = 0; i < items.length; i++) {
+ uploadItems.push(items[i]);
+ }
+ this.uploadItems = [...uploadItems];
+ this.changeStyleDisplay(true);
+ }
+
+ onDragLeave(): void {
+ this.changeStyleDisplay(false);
+ }
+
+ onDrop(fileUploadItems: FileUploadItem[]) {
+ if (!fileUploadItems || 0 === fileUploadItems.length) {
+ return;
+ }
+ this.fileUploadItems = fileUploadItems;
+ this.uploadItems = undefined;
+ }
+
+ onFileSelected(fileUploadItems: FileUploadItem[]): void {
+ if (!fileUploadItems || 0 === fileUploadItems.length) {
+ return;
+ }
+ this.fileUploadItems = fileUploadItems;
+ this.uploadItems = undefined;
+ this.changeStyleDisplay(true);
+ }
+
+ onUploadComplete(): void {
+ setTimeout(() => {
+ this.fileUploadItems = undefined;
+ this.changeStyleDisplay(false);
+ }, 1000);
+ }
+
+ isEventInElement(event: DragEvent): boolean {
+ const rect = this.elementRef.nativeElement.getBoundingClientRect();
+ // const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
+
+ if (
+ event.pageX >= rect.left &&
+ event.pageX <= rect.left + rect.width &&
+ event.pageY >= rect.top &&
+ event.pageY <= rect.top + rect.height
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ private changeStyleDisplay(show: boolean): void {
+ if (show || (!!this.fileUploadItems && 0 < this.fileUploadItems.length)) {
+ if (this.dropZoneIncludeParent) {
+ this.elementRef.nativeElement.parentElement.style.display = '';
+ } else {
+ this.elementRef.nativeElement.style.display = '';
+ }
+ } else {
+ if (this.dropZoneIncludeParent) {
+ this.elementRef.nativeElement.parentElement.style.display = 'none';
+ } else {
+ this.elementRef.nativeElement.style.display = 'none';
+ }
+ }
+ }
+
+ // onClickClear(fileUploadItem: FileUploadItem) {
+ // this.fileUploadItems = this.fileUploadItems.filter(f => {
+ // return (
+ // f.file.name !== fileUploadItem.file.name &&
+ // f.file.path !== fileUploadItem.file.path
+ // );
+ // });
+ // this.filesChange.emit(this.fileUploadItems);
+ // }
+}
diff --git a/documents/업무/2월/2째주/묵음파일백업/messages.component.html b/documents/업무/2월/2째주/묵음파일백업/messages.component.html
new file mode 100644
index 0000000..06b3d64
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/messages.component.html
@@ -0,0 +1,384 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'chat.albumBox.label' | translate }}
+
+
+ {{ 'chat.fileBox.label' | translate }}
+
+
+ {{ 'chat.searchEventByText' | translate }}
+
+
+ {{ 'chat.listOfRoomMember' | translate }}
+
+
+ {{ 'chat.addMemberToRoom' | translate }}
+
+
+ {{ 'chat.addMemberToGroup' | translate }}
+
+
+ {{ 'chat.settingsOfRoom' | translate }}
+
+
+ {{ 'chat.closeRoom' | translate }}
+
+
+
+
+
+
+
+
+ {{ 'chat.copyChatText' | translate }}
+
+
+ {{ 'chat.forwardEventTo' | translate }}
+
+
+ {{ 'chat.forwardEventToMe' | translate }}
+
+
+ {{ 'chat.removeEvent' | translate }}
+
+
+ {{ 'chat.recallEvent' | translate }}
+
+
+
+
diff --git a/documents/업무/2월/2째주/묵음파일백업/messages.component.scss b/documents/업무/2월/2째주/묵음파일백업/messages.component.scss
new file mode 100644
index 0000000..1960830
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/messages.component.scss
@@ -0,0 +1,233 @@
+@charset 'utf-s';
+:host {
+ display: flex;
+ width: 100%;
+ height: 100%;
+}
+@mixin ellipsis($row) {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ @if $row == 1 {
+ display: block;
+ white-space: nowrap;
+ word-wrap: normal;
+ } @else if $row >= 2 {
+ display: -webkit-box;
+ -webkit-line-clamp: $row;
+ -webkit-box-orient: vertical;
+ word-wrap: break-word;
+ }
+}
+.container {
+ position: relative;
+ width: 100%;
+}
+.chat-toolbar {
+ position: relative;
+ display: flex;
+ flex-flow: column;
+ width: 100%;
+ height: auto;
+ align-items: center;
+ background-color: #ffffff !important;
+ border-bottom: 1px solid #dddddd;
+ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
+ z-index: 1;
+ padding: 0;
+ .chat-header {
+ width: 100%;
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ justify-items: center;
+ padding: 4px 20px;
+ .profile-img {
+ margin-right: 10px;
+ width: 30px;
+ height: 30px;
+ .responsive-chats-button {
+ display: none;
+ line-height: normal;
+ cursor: unset;
+ &:last-child {
+ display: block;
+ padding: 0;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ color: #efefef;
+ font-size: 1rem;
+ }
+ }
+ &.thumbnail-mask {
+ border-radius: 50%;
+ overflow: hidden;
+ img {
+ width: 50px;
+ height: auto;
+ }
+ }
+ }
+ .room-info {
+ display: flex;
+ flex-flow: row;
+ overflow: hidden;
+ align-items: center;
+ .room-name {
+ font-size: 0.94rem;
+ line-height: normal;
+ @include ellipsis(1);
+ }
+ .room-type {
+ font-size: 0.9rem;
+ line-height: normal;
+ height: 20px;
+ span {
+ border-radius: 10px;
+ padding: 2px 6px;
+ margin-right: 6px;
+ font-size: 0.7rem;
+ }
+ }
+ }
+ .room-option {
+ margin-left: auto;
+ margin-right: -10px;
+ .icon-button {
+ transform: translateY(-2px);
+ i {
+ font-size: 0.9em;
+ }
+ }
+ }
+ }
+ .chat-search-frame {
+ position: relative;
+ width: 100%;
+ .chat-search {
+ margin: 0 4px 4px;
+ }
+ }
+}
+
+.chat-content {
+ position: relative;
+ background: transparent;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+
+ .file-drop-zone-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: transparent;
+
+ .file-drop-zone {
+ position: absolute;
+ padding: 10px;
+ background-color: rgb(54, 54, 54, 0.8);
+ bottom: 0;
+ width: 100%;
+ }
+ }
+
+ .sticker-selector-container {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background-color: transparent;
+
+ .sticker-selector-zone {
+ position: absolute;
+ padding: 10px 10px 0 10px;
+ background-color: rgba(250, 255, 255, 0.8);
+ bottom: 0;
+ width: 100%;
+ }
+ }
+}
+.translation-container {
+ .translation-section {
+ display: flex;
+ flex-flow: column;
+ border-top: 1px solid #dddddd;
+ .translation-container {
+ position: absolute;
+ 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;
+ padding: 10px 10px 0 10px;
+ background-color: rgba(250, 255, 255, 0.8);
+ bottom: 0;
+ width: 100%;
+ }
+ }
+ }
+}
+//mat-snack-bar
+::ng-deep .cdk-global-overlay-wrapper {
+ .mat-snack-bar-container {
+ margin: 0;
+ padding: 30px;
+ max-width: 60vw;
+ .mat-simple-snackbar {
+ display: flex;
+ justify-content: center;
+ span {
+ @include ellipsis(3);
+ display: inline-block;
+ padding: 7px 20px;
+ border: 1px solid #ffffff;
+ background-color: rgb(255, 255, 255, 0.2);
+ color: #ffffff;
+ margin-right: 4px;
+ flex: 1 1 auto;
+ max-width: 40vw;
+ }
+ &-action {
+ display: inline-flex;
+ margin-left: auto;
+ flex: 0 0 auto;
+ height: 100%;
+ button {
+ //background-color: #00b6d5;
+ border-radius: 2px;
+ span {
+ padding: 0 20px;
+ color: #ffffff;
+ background: none;
+ border: none;
+ font-weight: 500;
+ }
+ }
+ }
+ }
+ }
+}
+
+::ng-deep .chat-header {
+ .profile-img {
+ .chat-timer {
+ .mat-button-wrapper {
+ display: flex;
+ justify-content: center;
+ justify-items: center;
+ .mat-icon {
+ line-height: normal;
+ color: #ffffff;
+ font-size: 20px;
+ transform: translateY(1px);
+ }
+ }
+ }
+ }
+}
diff --git a/documents/업무/2월/2째주/묵음파일백업/messages.component.ts b/documents/업무/2월/2째주/묵음파일백업/messages.component.ts
new file mode 100644
index 0000000..fb0e95f
--- /dev/null
+++ b/documents/업무/2월/2째주/묵음파일백업/messages.component.ts
@@ -0,0 +1,2086 @@
+import {
+ Component,
+ OnInit,
+ OnDestroy,
+ ViewChild,
+ AfterViewInit,
+ Output,
+ EventEmitter,
+ Inject,
+ ChangeDetectorRef,
+ ChangeDetectionStrategy
+} from '@angular/core';
+import {
+ ucapAnimations,
+ SnackBarService,
+ ClipboardService,
+ DialogService,
+ ConfirmDialogComponent,
+ ConfirmDialogData,
+ ConfirmDialogResult,
+ AlertDialogComponent,
+ AlertDialogData,
+ AlertDialogResult,
+ FileUploadQueueComponent,
+ StringUtil
+} from '@ucap-webmessenger/ui';
+import { Store, select } from '@ngrx/store';
+import { NGXLogger } from 'ngx-logger';
+import { Observable, Subscription, forkJoin, of, BehaviorSubject } from 'rxjs';
+
+import {
+ Info,
+ EventType,
+ isRecalled,
+ isCopyable,
+ isRecallable,
+ isForwardable,
+ InfoResponse,
+ EventJson,
+ FileEventJson,
+ StickerEventJson,
+ MassTextEventJson,
+ TranslationEventJson,
+ MassTranslationEventJson
+} from '@ucap-webmessenger/protocol-event';
+
+import * as AppStore from '@app/store';
+import * as EventStore from '@app/store/messenger/event';
+import * as ChatStore from '@app/store/messenger/chat';
+import * as RoomStore from '@app/store/messenger/room';
+import * as SyncStore from '@app/store/messenger/sync';
+import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
+import {
+ SessionStorageService,
+ LocalStorageService
+} from '@ucap-webmessenger/web-storage';
+import {
+ EnvironmentsInfo,
+ KEY_ENVIRONMENTS_INFO,
+ UserSelectDialogType,
+ RightDrawer,
+ KEY_STICKER_HISTORY
+} from '@app/types';
+import {
+ RoomInfo,
+ UserInfo,
+ RoomType,
+ UserInfoShort
+} from '@ucap-webmessenger/protocol-room';
+import { take, map, catchError } from 'rxjs/operators';
+import {
+ FormComponent as UCapUiChatFormComponent,
+ MessagesComponent as UCapUiChatMessagesComponent
+} from '@ucap-webmessenger/ui-chat';
+import { KEY_VER_INFO } from '@app/types';
+import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
+import {
+ MatMenuTrigger,
+ MatSnackBarRef,
+ SimpleSnackBar
+} from '@angular/material';
+import { FileUploadItem, FileDownloadItem } from '@ucap-webmessenger/api';
+import {
+ CommonApiService,
+ FileTalkSaveRequest,
+ FileTalkSaveResponse,
+ FileTalkSaveMultiRequest
+} from '@ucap-webmessenger/api-common';
+import {
+ CreateChatDialogComponent,
+ CreateChatDialogData,
+ CreateChatDialogResult
+} from '../dialogs/chat/create-chat.dialog.component';
+import {
+ FileViewerDialogComponent,
+ FileViewerDialogData,
+ FileViewerDialogResult
+} from '@app/layouts/common/dialogs/file-viewer.dialog.component';
+import { FileUtil, StickerFilesInfo } from '@ucap-webmessenger/core';
+
+import { StatusCode } from '@ucap-webmessenger/api';
+import {
+ EditChatRoomDialogComponent,
+ EditChatRoomDialogResult,
+ EditChatRoomDialogData
+} from '../dialogs/chat/edit-chat-room.dialog.component';
+import {
+ SelectGroupDialogComponent,
+ SelectGroupDialogResult,
+ SelectGroupDialogData
+} from '../dialogs/group/select-group.dialog.component';
+import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
+import { environment } from '../../../../environments/environment';
+import {
+ MassDetailComponent,
+ MassDetailDialogData
+} from '../dialogs/chat/mass-detail.component';
+import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
+import { TranslateService } from '@ngx-translate/core';
+import { TranslatePipe } from 'projects/ucap-webmessenger-ui/src/lib/pipes/translate.pipe';
+import { TranslateService as UiTranslateService } from '@ucap-webmessenger/ui';
+
+import {
+ ClipboardDialogComponent,
+ ClipboardDialogData,
+ ClipboardDialogResult
+} from '../dialogs/chat/clipboard.dialog.component';
+import { AppFileService } from '@app/services/file.service';
+
+@Component({
+ selector: 'app-layout-messenger-messages',
+ templateUrl: './messages.component.html',
+ styleUrls: ['./messages.component.scss'],
+ animations: ucapAnimations,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
+ @Output()
+ openProfile = new EventEmitter<{
+ userSeq: number;
+ }>();
+ @Output()
+ closeRightDrawer = new EventEmitter();
+
+ @ViewChild('chatForm', { static: false })
+ private chatForm: UCapUiChatFormComponent;
+
+ @ViewChild('messageContextMenuTrigger', { static: true })
+ messageContextMenuTrigger: MatMenuTrigger;
+ messageContextMenuPosition = { x: '0px', y: '0px' };
+
+ @ViewChild('fileUploadQueue', { static: true })
+ fileUploadQueue: FileUploadQueueComponent;
+
+ @ViewChild('chatMessages', { static: true })
+ chatMessages: UCapUiChatMessagesComponent;
+
+ environmentsInfo: EnvironmentsInfo;
+
+ loginResSubscription: Subscription;
+ loginResSubject = new BehaviorSubject(undefined);
+
+ roomInfoSubscription: Subscription;
+ roomInfoSubject = new BehaviorSubject(undefined);
+
+ userInfoListSubscription: Subscription;
+ userInfoListSubject = new BehaviorSubject(undefined);
+
+ eventListSubscription: Subscription;
+ eventListSubject = new BehaviorSubject[]>(undefined);
+ eventListNewSubject = new BehaviorSubject[]>(undefined);
+
+ eventInfoStatusSubscription: Subscription;
+ eventInfoStatusSubject = new BehaviorSubject(undefined);
+
+ eventRemainedSubscription: Subscription;
+ eventRemainedSubject = new BehaviorSubject(false); // 이전대화가 남아 있는지 여부
+
+ lockSubject = new BehaviorSubject(false);
+
+ sessionVerInfo: VersionInfo2Response;
+
+ baseEventSeq = 0;
+ eventListProcessing$: Observable;
+ searchEventListProcessing: boolean;
+ searchEventListProcessingSubscription: Subscription;
+
+ isRecalledMessage = isRecalled;
+ isCopyableMessage = isCopyable;
+ isRecallableMessage = isRecallable;
+ isForwardableMessage = isForwardable;
+
+ /** Timer 대화방의 대화 삭제를 위한 interval */
+ interval: any;
+
+ /** About Searching */
+ isShowSearchArea = false;
+ moreSearchProcessing = false;
+ searchText = '';
+ searchedListSubject = new BehaviorSubject[]>(undefined);
+ searchedFocusEvent: Info;
+ searchTotalCount = 0;
+ searchCurrentIndex = 0;
+
+ /** About Sticker */
+ isShowStickerSelector = false;
+ selectedSticker: StickerFilesInfo;
+
+ /** 번역기능 비활성화 2020-02-07
+ * About Translation
+ **/
+ // isTranslationProcess = false;
+ // isShowTranslation = false;
+ // translationSimpleview = false;
+ // translationPreview = false;
+ // destLocale = 'en'; // default English :: en
+ // translationPreviewInfo: {
+ // previewInfo: TranslationSaveResponse | null;
+ // translationType: EventType.Translation | EventType.MassTranslation;
+ // };
+
+ /** About ReadHere */
+ firstCheckReadHere = true;
+ clearReadHere = false;
+ initRoomLastEventSeq: number;
+
+ snackBarPreviewEvent: MatSnackBarRef;
+
+ RoomType = RoomType;
+ environment = environment;
+
+ constructor(
+ private store: Store,
+ private sessionStorageService: SessionStorageService,
+ private localStorageService: LocalStorageService,
+ private commonApiService: CommonApiService,
+ private clipboardService: ClipboardService,
+ private uiTranslateService: UiTranslateService,
+ private translateService: TranslateService,
+ private changeDetectorRef: ChangeDetectorRef,
+ private dialogService: DialogService,
+ private snackBarService: SnackBarService,
+ @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
+ private appFileService: AppFileService,
+ private logger: NGXLogger
+ ) {
+ this.sessionVerInfo = this.sessionStorageService.get(
+ KEY_VER_INFO
+ );
+
+ this.environmentsInfo = this.sessionStorageService.get(
+ KEY_ENVIRONMENTS_INFO
+ );
+ }
+
+ ngOnInit() {
+ this.loginResSubscription = this.store
+ .pipe(select(AppStore.AccountSelector.AuthenticationSelector.loginRes))
+ .subscribe(loginRes => {
+ this.loginResSubject.next(loginRes);
+ });
+
+ this.roomInfoSubscription = this.store
+ .pipe(select(AppStore.MessengerSelector.RoomSelector.roomInfo))
+ .subscribe(roomInfo => {
+ if (
+ !this.roomInfoSubject.value ||
+ (!!this.roomInfoSubject.value &&
+ !!roomInfo &&
+ this.roomInfoSubject.value.roomSeq !== roomInfo.roomSeq)
+ ) {
+ this.clearView();
+
+ if (!!this.roomInfoSubject.value && !!this.interval) {
+ clearInterval(this.interval);
+ this.interval = undefined;
+ }
+
+ if (
+ !!this.roomInfoSubject.value &&
+ !!this.roomInfoSubject.value.isTimeRoom
+ ) {
+ this.interval = setInterval(() => {
+ this.store.dispatch(EventStore.infoIntervalClear({}));
+ }, 1000);
+ }
+
+ this.readyToReply();
+ }
+
+ this.roomInfoSubject.next(roomInfo);
+ });
+
+ this.userInfoListSubscription = this.store
+ .pipe(select(AppStore.MessengerSelector.RoomSelector.selectUserinfolist))
+ .subscribe(userInfoList => {
+ this.userInfoListSubject.next(userInfoList);
+ });
+
+ this.eventListProcessing$ = this.store.pipe(
+ select(AppStore.MessengerSelector.EventSelector.infoListProcessing)
+ );
+
+ this.searchEventListProcessingSubscription = this.store
+ .pipe(
+ select(
+ AppStore.MessengerSelector.EventSelector.infoSearchListProcessing
+ )
+ )
+ .subscribe(process => {
+ this.lockSubject.next(process);
+ this.searchEventListProcessing = process;
+ if (!process && this.isShowSearchArea) {
+ this.doSearchTextInEvent(this.searchText);
+ this.snackBarService.open(
+ this.translateService.instant('chat.searchEventByTextEnd'),
+ this.translateService.instant('common.messages.confirm'),
+ {
+ duration: 3000,
+ verticalPosition: 'top',
+ horizontalPosition: 'center'
+ }
+ );
+ }
+ });
+
+ this.eventRemainedSubscription = this.store
+ .pipe(select(AppStore.MessengerSelector.EventSelector.remainInfo))
+ .subscribe(remained => {
+ this.eventRemainedSubject.next(remained);
+ });
+
+ // [Daesang]
+ this.eventListSubscription = this.store
+ .pipe(select(AppStore.MessengerSelector.EventSelector.selectAllInfoList))
+ .subscribe(infoList => {
+ if (
+ !!this.eventListSubject.value &&
+ this.eventListSubject.value.length > 0
+ ) {
+ this.eventListNewSubject.next(
+ infoList.filter(info => {
+ if (
+ info.seq <=
+ this.eventListSubject.value[
+ this.eventListSubject.value.length - 1
+ ].seq
+ ) {
+ return false;
+ }
+ return true;
+ })
+ );
+
+ if (
+ !!infoList &&
+ infoList.length > 0 &&
+ !!this.roomInfoSubject.value &&
+ !!this.roomInfoSubject.value.lastReadEventSeq &&
+ this.baseEventSeq <= this.roomInfoSubject.value.lastReadEventSeq
+ ) {
+ // 조회된 내용중에 read here 가 있을 경우.
+ this.firstCheckReadHere = false;
+ }
+ }
+
+ this.eventListSubject.next(infoList);
+
+ if (this.moreSearchProcessing) {
+ const baseseq = this.baseEventSeq;
+ // setTimeout(() => {
+ // this.doSearchTextInEvent(this.searchText, baseseq);
+ // }, 800);
+ this.baseEventSeq = infoList[0].seq;
+ } else {
+ if (!!infoList && infoList.length > 0) {
+ this.baseEventSeq = infoList[0].seq;
+ }
+ }
+ });
+
+ // // [GROUP]
+ // this.eventListSubscription = this.store
+ // .pipe(
+ // select(AppStore.MessengerSelector.EventSelector.selectAllInfoList),
+ // tap(infoList => {
+ // if (!!this.eventList && this.eventList.length > 0) {
+ // this.eventListNew = infoList.filter(info => {
+ // if (info.seq <= this.eventList[this.eventList.length - 1].seq) {
+ // return false;
+ // }
+ // return true;
+ // });
+ // }
+ // this.eventList = infoList;
+
+ // if (!!infoList && infoList.length > 0) {
+ // this.baseEventSeq = infoList[0].seq;
+ // this.readyToReply();
+ // }
+ // })
+ // )
+ // .subscribe();
+
+ this.eventInfoStatusSubscription = this.store
+ .pipe(select(AppStore.MessengerSelector.EventSelector.infoStatus))
+ .subscribe(res => {
+ this.eventInfoStatusSubject.next(res);
+
+ if (!!res) {
+ const elist = this.eventListSubject.value;
+ if (res.baseSeq === 0 && elist.length > 0) {
+ this.initRoomLastEventSeq = elist[elist.length - 1].seq;
+ }
+ }
+ });
+ }
+
+ ngOnDestroy(): void {
+ if (!!this.loginResSubscription) {
+ this.loginResSubscription.unsubscribe();
+ }
+ if (!!this.roomInfoSubscription) {
+ this.roomInfoSubscription.unsubscribe();
+ }
+ if (!!this.userInfoListSubscription) {
+ this.userInfoListSubscription.unsubscribe();
+ }
+ if (!!this.eventListSubscription) {
+ this.eventListSubscription.unsubscribe();
+ }
+ if (!!this.eventInfoStatusSubscription) {
+ this.eventInfoStatusSubscription.unsubscribe();
+ }
+ if (!!this.eventRemainedSubscription) {
+ this.eventRemainedSubscription.unsubscribe();
+ }
+ if (!!this.searchEventListProcessingSubscription) {
+ this.searchEventListProcessingSubscription.unsubscribe();
+ }
+
+ if (!!this.interval) {
+ clearInterval(this.interval);
+ }
+ }
+
+ ngAfterViewInit(): void {
+ // this.readyToReply();
+ }
+
+ /**
+ * 채팅방의 여러 팝업들을 닫아준다.
+ */
+ clearView() {
+ // Right Drawer closed..
+ this.closeRightDrawer.emit();
+
+ // Sticker Selector Clear..
+ this.isShowStickerSelector = false;
+ this.selectedSticker = undefined;
+
+ // Chat Search Clear..
+ this.onCloseSearchArea();
+
+ // 번역기능 비활성화 2020-02-07
+ // Translate Clear..
+ // this.isTranslationProcess = false;
+ // this.isShowTranslation = false;
+ // this.translationSimpleview = false;
+ // this.translationPreview = false;
+ // this.destLocale = 'en'; // default English :: en
+ // this.translationPreviewInfo = null;
+
+ // Read here Clear..
+ this.firstCheckReadHere = true;
+
+ // Chat Formfield Clear..
+ if (!!this.chatForm) {
+ this.chatForm.replyInput.nativeElement.value = '';
+ }
+ }
+
+ get _roomUserInfos() {
+ if (this.roomInfoSubject.value.roomType === RoomType.Single) {
+ return this.userInfoListSubject.value.filter(roomUserInfo => {
+ return this.loginResSubject.value.userSeq !== roomUserInfo.seq;
+ });
+ } else {
+ return this.userInfoListSubject.value
+ .filter(roomUserInfo => {
+ return (
+ this.loginResSubject.value.userSeq !== roomUserInfo.seq &&
+ roomUserInfo.isJoinRoom
+ );
+ })
+ .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
+ }
+ }
+
+ getRoomNameByRoomUser(roomUserInfos: (UserInfo | UserInfoShort)[]) {
+ let roomName = new TranslatePipe(
+ this.uiTranslateService,
+ this.changeDetectorRef
+ ).transform(roomUserInfos, 'name', ',');
+
+ if (!roomName || roomName.trim().length === 0) {
+ roomName = this.translateService.instant('chat.noRoomUser');
+ }
+ return roomName;
+ }
+
+ /** 대화전송 가능한 방인지 판단 */
+ getEnableSend() {
+ if (!this.roomInfoSubject.value) {
+ return false;
+ }
+
+ if (
+ [
+ RoomType.Bot,
+ RoomType.Allim,
+ RoomType.Link,
+ RoomType.Allim_Elephant,
+ RoomType.Allim_TMS
+ ].some(v => v === this.roomInfoSubject.value.roomType)
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ getConvertTimer(timerInterval: number, unit: number = 1) {
+ if (timerInterval >= 0 && timerInterval < 60 * unit) {
+ return Math.floor((timerInterval / 1) * unit) + ' 초';
+ } else if (timerInterval >= 60 * unit && timerInterval < 3600 * unit) {
+ return Math.floor(((timerInterval / 1) * unit) / 60) + ' 분';
+ } else if (timerInterval >= 3600 * unit && timerInterval <= 86400 * unit) {
+ return Math.floor(((timerInterval / 1) * unit) / 60 / 60) + ' 시간';
+ } else {
+ return '';
+ }
+ }
+
+ getShowContextMenu(menuType: string) {
+ if (
+ ['OPEN_ROOM_USER', 'ADD_MEMBER', 'ADD_GROUP', 'EDIT_ROOM'].some(
+ v => v === menuType
+ )
+ ) {
+ if (
+ !this.roomInfoSubject.value ||
+ !this.roomInfoSubject.value.roomType ||
+ [
+ RoomType.Mytalk,
+ RoomType.Allim,
+ RoomType.Bot,
+ RoomType.Link,
+ RoomType.Allim_Elephant,
+ RoomType.Allim_TMS
+ ].some(v => v === this.roomInfoSubject.value.roomType)
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ getShowUnreadCount(): boolean {
+ if (
+ !this.roomInfoSubject.value ||
+ this.roomInfoSubject.value === undefined
+ ) {
+ return true;
+ }
+ if (
+ [
+ RoomType.Mytalk,
+ RoomType.Allim,
+ RoomType.Bot,
+ RoomType.Link,
+ RoomType.Allim_Elephant,
+ RoomType.Allim_TMS
+ ].some(v => v === this.roomInfoSubject.value.roomType)
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ readyToReply(): void {
+ setTimeout(() => {
+ this.focusReplyInput();
+ });
+ }
+
+ focusReplyInput(): void {
+ setTimeout(() => {
+ if (!!this.chatForm) {
+ this.chatForm.focus();
+ }
+ });
+ }
+
+ onScrollupMessages(event: any) {}
+ onYReachStartMessages(event: any) {
+ // 자동 스크롤이 아닌 버튼 방식으로 변경.
+ // this.onMoreEvent(this.baseEventSeq);
+ }
+ onYReachEndMessages(event: any) {
+ this.chatMessages.initEventMore();
+ if (!!this.snackBarPreviewEvent) {
+ this.snackBarPreviewEvent.dismiss();
+ }
+
+ // // clear readHere object.. 정책상 클리어 하지 않도록 함.
+ // if (!this.firstCheckReadHere) {
+ // this.clearReadHere = true;
+ // }
+ }
+
+ /** More Event */
+ onMoreEvent(seq: number) {
+ this.store.dispatch(
+ EventStore.info({
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ baseSeq: seq,
+ requestCount:
+ environment.productConfig.CommonSetting.eventRequestDefaultCount
+ })
+ );
+ }
+
+ /** Send Event */
+ async onSendMessage(message: string) {
+ this.chatMessages.initEventMore();
+
+ if (!this.selectedSticker) {
+ if (!message || message.trim().length === 0) {
+ const result = await this.dialogService.open<
+ AlertDialogComponent,
+ AlertDialogData,
+ AlertDialogResult
+ >(AlertDialogComponent, {
+ width: '360px',
+ data: {
+ title: this.translateService.instant('chat.errors.label'),
+ message: this.translateService.instant(
+ 'chat.errors.inputChatMessage'
+ )
+ }
+ });
+ return;
+ }
+ }
+
+ // 번역기능 비활성화 2020-02-07
+ // if (!!this.isShowTranslation && this.destLocale.trim().length > 0) {
+ // /** CASE : Translation */
+ // // 번역할 대화 없이 스티커만 전송할 경우.
+ // if (!message || message.trim().length === 0) {
+ // this.sendMessageOfSticker(message);
+ // } else {
+ // this.sendMessageOfTranslate(message);
+ // }
+ // } else
+
+ if (!!this.selectedSticker) {
+ /** CASE : Sticker */
+ this.sendMessageOfSticker(message);
+ } else if (
+ message.trim().length >
+ environment.productConfig.CommonSetting.masstextLength
+ ) {
+ /** CASE : MASS TEXT */
+ this.sendMessageOfMassText(message);
+ } else {
+ /** CASE : Normal Text */
+ this.sendMessageOfNormal(message);
+ }
+ }
+
+ /** Send Normal message */
+ sendMessageOfNormal(message: string) {
+ this.store.dispatch(
+ EventStore.send({
+ senderSeq: this.loginResSubject.value.userSeq,
+ req: {
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ eventType: EventType.Character,
+ sentMessage: StringUtil.escapeHtml(message)
+ }
+ })
+ );
+ }
+ /** Send Sticker message */
+ async sendMessageOfSticker(message: string, isCheck: boolean = true) {
+ if (
+ !!isCheck &&
+ !!message &&
+ message.trim().length >
+ environment.productConfig.CommonSetting.masstextLength
+ ) {
+ const result = await this.dialogService.open<
+ AlertDialogComponent,
+ AlertDialogData,
+ AlertDialogResult
+ >(AlertDialogComponent, {
+ width: '360px',
+ data: {
+ title: this.translateService.instant('chat.errors.label'),
+ message: this.translateService.instant(
+ 'chat.errors.maxLengthOfMassText',
+ {
+ maxLength: environment.productConfig.CommonSetting.masstextLength
+ }
+ )
+ }
+ });
+ return;
+ }
+
+ const stickerJson: StickerEventJson = {
+ name: '스티커',
+ file: this.selectedSticker.index,
+ chat: !!message ? StringUtil.escapeHtml(message.trim()) : ''
+ };
+ this.store.dispatch(
+ EventStore.send({
+ senderSeq: this.loginResSubject.value.userSeq,
+ req: {
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ eventType: EventType.Sticker,
+ sentMessage: JSON.stringify(stickerJson)
+ }
+ })
+ );
+ this.isShowStickerSelector = false;
+ this.setStickerHistory(this.selectedSticker);
+ this.selectedSticker = null;
+ }
+ /** Send Masstext message */
+ sendMessageOfMassText(message: string) {
+ this.store.dispatch(
+ EventStore.sendMass({
+ senderSeq: this.loginResSubject.value.userSeq,
+ req: {
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ eventType: EventType.MassText,
+ // sentMessage: message.replace(/\n/gi, '\r\n')
+ sentMessage: StringUtil.escapeHtml(message)
+ }
+ })
+ );
+ }
+ /**
+ * 번역기능 비활성화 2020-02-07
+ * Send Translation message
+ **/
+ // sendMessageOfTranslate(message: string) {
+ // const destLocale = this.destLocale;
+ // const original = StringUtil.escapeHtml(message);
+ // const roomSeq = this.roomInfoSubject.value.roomSeq;
+
+ // if (!!this.isTranslationProcess) {
+ // return;
+ // }
+
+ // this.isTranslationProcess = true;
+ // this.commonApiService
+ // .translationSave({
+ // userSeq: this.loginResSubject.value.userSeq,
+ // deviceType: this.environmentsInfo.deviceType,
+ // token: this.loginResSubject.value.tokenString,
+ // roomSeq,
+ // original,
+ // srcLocale: '',
+ // destLocale
+ // } as TranslationSaveRequest)
+ // .pipe(
+ // take(1),
+ // map(res => {
+ // if (res.statusCode === StatusCode.Success) {
+ // let sentMessage = '';
+ // let eventType = EventType.Translation;
+ // let previewObject: TranslationEventJson | MassTranslationEventJson;
+
+ // if (res.translationSeq > 0) {
+ // // Mass Text Translation
+ // previewObject = res;
+ // sentMessage = res.returnJson;
+ // eventType = EventType.MassTranslation;
+ // } else {
+ // // Normal Text Translation
+ // previewObject = {
+ // locale: destLocale,
+ // original,
+ // translation: res.translation,
+ // stickername: '',
+ // stickerfile: !!this.selectedSticker
+ // ? this.selectedSticker.index
+ // : ''
+ // };
+
+ // sentMessage = JSON.stringify(previewObject);
+ // eventType = EventType.Translation;
+ // }
+
+ // if (!!this.translationPreview) {
+ // // preview
+ // this.translationPreviewInfo = {
+ // previewInfo: res,
+ // translationType: eventType
+ // };
+ // } else {
+ // // direct send
+ // this.store.dispatch(
+ // EventStore.send({
+ // senderSeq: this.loginResSubject.value.userSeq,
+ // req: {
+ // roomSeq,
+ // eventType,
+ // sentMessage
+ // }
+ // })
+ // );
+
+ // if (!!this.translationPreviewInfo) {
+ // this.translationPreviewInfo = null;
+ // }
+ // }
+
+ // if (!!this.selectedSticker) {
+ // this.isShowStickerSelector = false;
+ // this.setStickerHistory(this.selectedSticker);
+ // this.selectedSticker = null;
+ // }
+ // } else {
+ // this.isTranslationProcess = false;
+ // this.dialogService.open<
+ // AlertDialogComponent,
+ // AlertDialogData,
+ // AlertDialogResult
+ // >(AlertDialogComponent, {
+ // width: '360px',
+ // data: {
+ // title: '',
+ // message: this.translateService.instant(
+ // 'chat.error.translateServerError'
+ // )
+ // }
+ // });
+ // this.logger.error('res', res);
+ // }
+ // }),
+ // catchError(error => {
+ // this.isTranslationProcess = false;
+ // this.dialogService.open<
+ // AlertDialogComponent,
+ // AlertDialogData,
+ // AlertDialogResult
+ // >(AlertDialogComponent, {
+ // width: '360px',
+ // data: {
+ // title: '',
+ // message: this.translateService.instant(
+ // 'chat.error.translateServerError'
+ // )
+ // }
+ // });
+ // return of(this.logger.error('error', error));
+ // })
+ // )
+ // .subscribe(() => {
+ // this.isTranslationProcess = false;
+ // });
+ // }
+
+ onClickReceiveAlarm() {
+ this.store.dispatch(
+ RoomStore.updateOnlyAlarm({ roomInfo: this.roomInfoSubject.value })
+ );
+ }
+
+ /** MassText Detail View */
+ onMassDetail(value: number) {
+ this.store.dispatch(
+ ChatStore.selectedMassDetail({
+ massEventSeq: value
+ })
+ );
+ }
+
+ onMassTranslationDetail(params: {
+ message: Info;
+ contentsType: string;
+ }) {
+ this.commonApiService
+ .transMassTalkDownload({
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ eventTransSeq: params.message.sentMessageJson.translationSeq.toString()
+ })
+ .pipe(take(1))
+ .subscribe(res => {
+ let contents = '';
+ if (res.statusCode === StatusCode.Success) {
+ contents =
+ params.contentsType === 'T' ? res.translation : res.original;
+ } else {
+ contents =
+ params.contentsType === 'T'
+ ? params.message.sentMessageJson.translation
+ : params.message.sentMessageJson.original;
+ }
+
+ this.dialogService.open(
+ MassDetailComponent,
+ {
+ disableClose: false,
+ width: '550px',
+ data: {
+ title: this.translateService.instant('chat.detailView'),
+ contents
+ }
+ }
+ );
+ });
+ }
+
+ async onFileViewer(fileInfo: FileEventJson) {
+ const result = await this.dialogService.open<
+ FileViewerDialogComponent,
+ FileViewerDialogData,
+ FileViewerDialogResult
+ >(FileViewerDialogComponent, {
+ position: {
+ top: '50px'
+ },
+ maxWidth: '100vw',
+ maxHeight: '100vh',
+ height: 'calc(100% - 50px)',
+ width: '100%',
+ hasBackdrop: false,
+ panelClass: 'app-dialog-full',
+ data: {
+ fileInfo,
+ downloadUrl: this.sessionVerInfo.downloadUrl,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ userSeq: this.loginResSubject.value.userSeq
+ }
+ });
+ }
+
+ /** File Save, Save As */
+ onSave(value: {
+ fileInfo: FileEventJson;
+ fileDownloadItem: FileDownloadItem;
+ type: string;
+ }) {
+ this.logger.debug('fileSave', value);
+ if (value.type === 'saveAs') {
+ this.nativeService
+ .selectSaveFilePath(value.fileInfo.fileName)
+ .then(result => {
+ if (!result) {
+ return;
+ }
+
+ if (result.canceled) {
+ // this.snackBarService.open(
+ // this.translateService.instant('common.file.results.canceled'),
+ // this.translateService.instant('common.file.errors.label'),
+ // {
+ // duration: 1000
+ // }
+ // );
+ } else {
+ this.saveFile(value, result.filePath);
+ }
+ })
+ .catch(reason => {
+ this.snackBarService.open(
+ this.translateService.instant(
+ 'common.file.errors.failToSpecifyPath'
+ ),
+ this.translateService.instant('common.file.errors.label')
+ );
+ });
+ } else {
+ this.saveFile(value);
+ }
+ }
+
+ onFileDragEnter(items: DataTransferItemList) {
+ this.clearView();
+ this.logger.debug('onFileDragEnter', items);
+ }
+
+ onFileDragOver() {
+ this.logger.debug('onFileDragOver');
+ }
+
+ onFileDragLeave() {
+ this.logger.debug('onFileDragLeave');
+ }
+
+ onExistNewMessage(info: Info) {
+ let message = '';
+
+ const contents = StringUtil.convertFinalEventMessage(
+ info.type,
+ info.sentMessageJson || info.sentMessage
+ );
+
+ if (!!contents) {
+ const senderUser = this.userInfoListSubject.value.filter(
+ user => user.seq === info.senderSeq
+ );
+ if (!!senderUser && senderUser.length > 0) {
+ message += `${senderUser[0].name} : `;
+ }
+ message += contents;
+
+ this.snackBarPreviewEvent = this.snackBarService.open(
+ message,
+ this.translateService.instant('common.messages.confirm'),
+ {
+ // duration: 3000,
+ verticalPosition: 'bottom',
+ horizontalPosition: 'center',
+ panelClass: ['chat-snackbar-class']
+ }
+ );
+ this.snackBarPreviewEvent.onAction().subscribe(() => {
+ this.chatMessages.initEventMore();
+ this.chatMessages.scrollToBottom();
+ this.snackBarPreviewEvent.dismiss();
+ });
+ }
+ }
+
+ saveFile(
+ value: {
+ fileInfo: FileEventJson;
+ fileDownloadItem: FileDownloadItem;
+ type: string;
+ },
+ savePath?: string
+ ) {
+ this.appFileService.fileTalkDownlod({
+ req: {
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ attachmentsSeq: value.fileInfo.attachmentSeq,
+ fileDownloadItem: value.fileDownloadItem
+ },
+ fileName: value.fileInfo.fileName,
+ savePath
+ });
+ }
+
+ async onFileSelected(fileUploadItems: FileUploadItem[]) {
+ this.logger.debug('onFileSelected', fileUploadItems);
+ this.clearView();
+
+ const info = {
+ senderSeq: this.loginResSubject.value.userSeq,
+ roomSeq: this.roomInfoSubject.value.roomSeq
+ };
+
+ const allObservables: Observable[] = [];
+
+ 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.snackBarService.open(
+ this.translateService.instant('common.file.errors.oversize', {
+ maxSize: fileAllowSize
+ }),
+ '',
+ {
+ duration: 1000,
+ verticalPosition: 'bottom',
+ horizontalPosition: 'center'
+ }
+ );
+
+ 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.snackBarService.open(
+ this.translateService.instant('common.file.errors.notSupporedType', {
+ supporedType:
+ checkExt.reject.length > 0 ? checkExt.reject.join(',') : ''
+ }),
+ '',
+ {
+ duration: 1000,
+ verticalPosition: 'bottom',
+ horizontalPosition: 'center'
+ }
+ );
+
+ return;
+ }
+ // 멀티 파일 업로드
+ const isFileTalkSaveMulti = this.getSaveFileMulti(fileUploadItems);
+
+ if (!!isFileTalkSaveMulti) {
+ this.fileTalkSaveMulti(fileUploadItems);
+ return;
+ }
+ // 일반 업로드
+ for (const fileUploadItem of fileUploadItems) {
+ let thumbnail: File;
+ if (
+ -1 !==
+ [
+ '3gp',
+ 'avi',
+ 'm4v',
+ 'mkv',
+ 'mov',
+ 'mp4',
+ 'mpeg',
+ 'mpg',
+ 'rv',
+ 'ts',
+ 'webm',
+ 'wmv'
+ ].indexOf(FileUtil.getExtension(fileUploadItem.file.name))
+ ) {
+ thumbnail = await FileUtil.thumbnail(fileUploadItem.file);
+ this.logger.debug('thumbnail', thumbnail);
+ }
+
+ const req: FileTalkSaveRequest = {
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ file: fileUploadItem.file,
+ fileName: fileUploadItem.file.name,
+ thumb: thumbnail,
+ fileUploadItem
+ };
+
+ allObservables.push(
+ this.commonApiService.fileTalkSave(req, null).pipe(
+ map(res => {
+ if (!res) {
+ return;
+ }
+ if (StatusCode.Success === res.statusCode) {
+ return res;
+ } else {
+ throw res;
+ }
+ })
+ )
+ );
+ }
+
+ forkJoin(allObservables)
+ .pipe(take(1))
+ .subscribe(
+ resList => {
+ for (const res of resList) {
+ this.store.dispatch(
+ EventStore.send({
+ senderSeq: info.senderSeq,
+ req: {
+ roomSeq: info.roomSeq,
+ eventType: EventType.File,
+ sentMessage: res.returnJson
+ }
+ })
+ );
+ }
+ },
+ error => {
+ this.logger.debug('onFileSelected error', error);
+ this.snackBarService.open(
+ this.translateService.instant('common.file.errors.failToUpload'),
+ this.translateService.instant('common.file.errors.label')
+ );
+
+ if (!!this.fileUploadQueue) {
+ this.fileUploadQueue.onUploadComplete();
+ }
+ },
+ () => {
+ this.fileUploadQueue.onUploadComplete();
+ }
+ );
+ }
+
+ private fileTalkSaveMulti(fileUploadItemList: FileUploadItem[]) {
+ const fileList: File[] = [];
+ const info = {
+ senderSeq: this.loginResSubject.value.userSeq,
+ roomSeq: this.roomInfoSubject.value.roomSeq
+ };
+ for (const fileUploadItem of fileUploadItemList) {
+ fileList.push(fileUploadItem.file);
+ }
+ const req: FileTalkSaveMultiRequest = {
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ fileUploadItems: fileUploadItemList,
+ files: fileList,
+ type: 'b'
+ };
+
+ this.commonApiService
+ .fileTalkSaveMulti(req, null)
+ .pipe(
+ map(res => {
+ if (!res) {
+ return;
+ }
+ if (StatusCode.Success === res.statusCode) {
+ return res;
+ } else {
+ throw res;
+ }
+ })
+ )
+ .subscribe(
+ res => {
+ this.logger.debug('fileTalkSaveMulti', res);
+
+ this.store.dispatch(
+ EventStore.send({
+ senderSeq: info.senderSeq,
+ req: {
+ roomSeq: info.roomSeq,
+ eventType: EventType.BundleImage,
+ sentMessage: res.returnJson
+ }
+ })
+ );
+ },
+ error => {
+ this.logger.debug('onFileSelected error', error);
+ this.snackBarService.open(
+ this.translateService.instant('common.file.errors.failToUpload'),
+ this.translateService.instant('common.file.errors.label')
+ );
+
+ if (!!this.fileUploadQueue) {
+ this.fileUploadQueue.onUploadComplete();
+ }
+ },
+ () => {
+ this.fileUploadQueue.onUploadComplete();
+ }
+ );
+ }
+
+ private getSaveFileMulti(fileUploadItems: FileUploadItem[]): boolean {
+ for (const fileUploadItem of fileUploadItems) {
+ if (
+ fileUploadItems.length <= 1 ||
+ -1 ===
+ ['jpg', 'jpeg', 'jpe', 'png', 'gif'].indexOf(
+ FileUtil.getExtension(fileUploadItem.file.name)
+ )
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ onContextMenuMessage(params: {
+ event: MouseEvent;
+ message: Info;
+ type?: string;
+ }) {
+ params.event.preventDefault();
+ params.event.stopPropagation();
+
+ this.messageContextMenuPosition.x = params.event.clientX + 'px';
+ this.messageContextMenuPosition.y = params.event.clientY + 'px';
+ this.messageContextMenuTrigger.menu.focusFirstItem('mouse');
+ this.messageContextMenuTrigger.menuData = {
+ message: params.message,
+ loginRes: this.loginResSubject.value,
+ clicktype: params.type
+ };
+ this.messageContextMenuTrigger.openMenu();
+ }
+
+ async onClickMessageContextMenu(
+ menuType: string,
+ message: Info,
+ clicktype?: string
+ ) {
+ switch (menuType) {
+ case 'COPY':
+ {
+ switch (message.type) {
+ case EventType.Character:
+ {
+ if (
+ this.clipboardService.copyFromContent(
+ (message as Info).sentMessage
+ )
+ ) {
+ this.snackBarService.open(
+ this.translateService.instant(
+ 'common.clipboard.results.copied'
+ ),
+ '',
+ {
+ duration: 3000,
+ verticalPosition: 'top',
+ horizontalPosition: 'center'
+ }
+ );
+ }
+ }
+ break;
+ case EventType.MassText:
+ {
+ this.commonApiService
+ .massTalkDownload({
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ eventMassSeq: message.seq
+ })
+ .pipe(take(1))
+ .subscribe(res => {
+ if (this.clipboardService.copyFromContent(res.content)) {
+ this.snackBarService.open(
+ this.translateService.instant(
+ 'common.clipboard.results.copied'
+ ),
+ '',
+ {
+ duration: 3000,
+ verticalPosition: 'top',
+ horizontalPosition: 'center'
+ }
+ );
+ }
+ });
+ }
+ break;
+ case EventType.Translation:
+ {
+ let trgtStr = '';
+ if (clicktype === 'translation') {
+ // translation
+ trgtStr = (message.sentMessageJson as TranslationEventJson)
+ .translation;
+ } else {
+ // original
+ trgtStr = (message.sentMessageJson as TranslationEventJson)
+ .original;
+ }
+
+ if (this.clipboardService.copyFromContent(trgtStr)) {
+ this.snackBarService.open(
+ this.translateService.instant(
+ 'common.clipboard.results.copied'
+ ),
+ '',
+ {
+ duration: 3000,
+ verticalPosition: 'top',
+ horizontalPosition: 'center'
+ }
+ );
+ }
+ }
+ break;
+ case EventType.MassTranslation:
+ {
+ const sentMessageJson: MassTranslationEventJson = message.sentMessageJson as MassTranslationEventJson;
+ this.commonApiService
+ .transMassTalkDownload({
+ userSeq: this.loginResSubject.value.userSeq,
+ deviceType: this.environmentsInfo.deviceType,
+ token: this.loginResSubject.value.tokenString,
+ eventTransSeq: sentMessageJson.translationSeq.toString()
+ })
+ .pipe(take(1))
+ .subscribe(res => {
+ let contents = '';
+ if (res.statusCode === StatusCode.Success) {
+ contents =
+ clicktype === 'translation'
+ ? res.translation
+ : res.original;
+ } else {
+ contents =
+ clicktype === 'translation'
+ ? sentMessageJson.translation
+ : sentMessageJson.original;
+ }
+
+ if (this.clipboardService.copyFromContent(contents)) {
+ this.snackBarService.open(
+ this.translateService.instant(
+ 'common.clipboard.results.copied'
+ ),
+ '',
+ {
+ duration: 3000,
+ verticalPosition: 'top',
+ horizontalPosition: 'center'
+ }
+ );
+ }
+ });
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 'FORWARD':
+ {
+ const result = await this.dialogService.open<
+ CreateChatDialogComponent,
+ CreateChatDialogData,
+ CreateChatDialogResult
+ >(CreateChatDialogComponent, {
+ width: '600px',
+ data: {
+ type: UserSelectDialogType.MessageForward,
+ title: this.translateService.instant('chat.forwardEventTo'),
+ ignoreRoom: [this.roomInfoSubject.value]
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ const userSeqs: number[] = [];
+ let roomSeq = '';
+ if (
+ !!result.selectedUserList &&
+ result.selectedUserList.length > 0
+ ) {
+ result.selectedUserList.map(user => userSeqs.push(user.seq));
+ }
+
+ if (!!result.selectedRoom) {
+ roomSeq = result.selectedRoom.roomSeq;
+ }
+
+ if (userSeqs.length > 0 || roomSeq.trim().length > 0) {
+ this.store.dispatch(
+ EventStore.forward({
+ senderSeq: this.loginResSubject.value.userSeq,
+ req: {
+ roomSeq: '-999',
+ eventType: message.type,
+ sentMessage: message.sentMessage
+ },
+ trgtUserSeqs: userSeqs,
+ trgtRoomSeq: roomSeq
+ })
+ );
+ }
+ }
+ }
+ break;
+ case 'FORWARD_TO_ME':
+ {
+ if (this.loginResSubject.value.talkWithMeBotSeq > -1) {
+ this.store.dispatch(
+ EventStore.forward({
+ senderSeq: this.loginResSubject.value.userSeq,
+ req: {
+ roomSeq: '-999',
+ eventType: message.type,
+ sentMessage: message.sentMessage
+ },
+ trgtUserSeqs: [this.loginResSubject.value.talkWithMeBotSeq]
+ })
+ );
+ }
+ }
+ break;
+ case 'DELETE':
+ {
+ const result = await this.dialogService.open<
+ ConfirmDialogComponent,
+ ConfirmDialogData,
+ ConfirmDialogResult
+ >(ConfirmDialogComponent, {
+ width: '400px',
+ data: {
+ title: this.translateService.instant('chat.removeEvent'),
+ html: this.translateService.instant('chat.confirmRemoveEvent')
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ this.store.dispatch(
+ EventStore.del({
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ eventSeq: message.seq
+ })
+ );
+ }
+ }
+ break;
+ case 'RECALL':
+ {
+ const result = await this.dialogService.open<
+ ConfirmDialogComponent,
+ ConfirmDialogData,
+ ConfirmDialogResult
+ >(ConfirmDialogComponent, {
+ width: '400px',
+ data: {
+ title: this.translateService.instant('chat.recallEvent'),
+ html: this.translateService.instant('chat.confirmRecallEvent')
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ this.store.dispatch(
+ EventStore.cancel({
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ eventSeq: message.seq,
+ deviceType: this.environmentsInfo.deviceType
+ })
+ );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ async onClickContextMenu(menuType: string) {
+ switch (menuType) {
+ case 'OPEN_ALBUM_LIST':
+ {
+ this.store.dispatch(
+ ChatStore.selectedRightDrawer({
+ req: RightDrawer.AlbumBox
+ })
+ );
+ }
+ break;
+ case 'OPEN_FILE_LIST':
+ {
+ this.store.dispatch(
+ ChatStore.selectedRightDrawer({
+ req: RightDrawer.FileBox
+ })
+ );
+ }
+ break;
+ case 'CHAT_SEARCH':
+ {
+ this.onShowToggleSearchArea();
+ }
+ break;
+ case 'OPEN_ROOM_USER':
+ {
+ this.store.dispatch(
+ ChatStore.selectedRightDrawer({
+ req: RightDrawer.RoomUser
+ })
+ );
+ }
+ break;
+ case 'ADD_MEMBER':
+ {
+ const curRoomUser = this.userInfoListSubject.value.filter(
+ user =>
+ user.seq !== this.loginResSubject.value.userSeq && user.isJoinRoom
+ );
+
+ const result = await this.dialogService.open<
+ CreateChatDialogComponent,
+ CreateChatDialogData,
+ CreateChatDialogResult
+ >(CreateChatDialogComponent, {
+ width: '600px',
+ data: {
+ type: UserSelectDialogType.EditChatMember,
+ title: this.translateService.instant('chat.modifyRoomMember'),
+ curRoomUser
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ if (
+ !!result.selectedUserList &&
+ result.selectedUserList.length > 0 &&
+ curRoomUser
+ .map(user => user.seq)
+ .sort()
+ .join('|') ===
+ result.selectedUserList
+ .map(user => user.seq)
+ .sort()
+ .join('|')
+ ) {
+ // 변경된 것이 없다면 중지.
+ return;
+ }
+
+ // include me here..
+ const userSeqs: number[] = this.userInfoListSubject.value
+ .filter(userInfo => userInfo.isJoinRoom)
+ .map(userInfo => userInfo.seq);
+
+ if (
+ !!result.selectedUserList &&
+ result.selectedUserList.length > 0
+ ) {
+ result.selectedUserList.forEach(user => {
+ if (userSeqs.indexOf(user.seq) < 0) {
+ userSeqs.push(user.seq);
+ }
+ });
+ }
+
+ if (userSeqs.length > 0) {
+ // include me
+ const myUserSeq = this.loginResSubject.value.userSeq;
+ if (!!myUserSeq && userSeqs.indexOf(myUserSeq) < 0) {
+ userSeqs.push(myUserSeq);
+ }
+
+ this.store.dispatch(
+ RoomStore.inviteOrOpen({
+ req: {
+ divCd: 'Invite',
+ userSeqs
+ }
+ })
+ );
+ }
+ }
+ }
+ break;
+ case 'ADD_GROUP':
+ {
+ const result = await this.dialogService.open<
+ SelectGroupDialogComponent,
+ SelectGroupDialogData,
+ SelectGroupDialogResult
+ >(SelectGroupDialogComponent, {
+ width: '600px',
+ data: {
+ title: this.translateService.instant('chat.addMemberToGroup')
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ if (!!result.group) {
+ const oldGroup: GroupDetailData = result.group;
+ const trgtUserSeq: number[] = [];
+ result.group.userSeqs.map(seq => trgtUserSeq.push(seq));
+ this.userInfoListSubject.value
+ .filter(v => v.isJoinRoom)
+ .filter(v => result.group.userSeqs.indexOf(v.seq) < 0)
+ .forEach(user => {
+ trgtUserSeq.push(user.seq);
+ });
+
+ this.store.dispatch(
+ SyncStore.updateGroupMember({
+ oldGroup,
+ trgtUserSeq
+ })
+ );
+ }
+ }
+ }
+ break;
+ case 'EDIT_ROOM':
+ {
+ const result = await this.dialogService.open<
+ EditChatRoomDialogComponent,
+ EditChatRoomDialogData,
+ EditChatRoomDialogResult
+ >(EditChatRoomDialogComponent, {
+ width: '600px',
+ data: {
+ title: this.translateService.instant('chat.settingsOfRoom'),
+ roomInfo: this.roomInfoSubject.value
+ }
+ });
+
+ if (!!result && !!result.choice && result.choice) {
+ const roomName: string = result.roomName;
+ const roomNameChangeTarget: string = result.roomNameChangeTarget;
+ const timeRoomInterval: number = result.timeRoomInterval;
+ const roomInfo: RoomInfo = result.roomInfo;
+
+ // 방제목 업데이트.
+ this.store.dispatch(
+ RoomStore.update({
+ req: {
+ roomSeq: roomInfo.roomSeq,
+ roomName,
+ receiveAlarm: roomInfo.receiveAlarm,
+ syncAll:
+ roomNameChangeTarget.toUpperCase() === 'ALL' ? true : false
+ }
+ })
+ );
+
+ if (
+ roomInfo.isTimeRoom &&
+ timeRoomInterval > 0 &&
+ roomInfo.timeRoomInterval !== timeRoomInterval
+ ) {
+ this.store.dispatch(
+ RoomStore.updateTimeRoomInterval({
+ roomSeq: roomInfo.roomSeq,
+ timerInterval: timeRoomInterval
+ })
+ );
+ }
+ }
+ }
+ break;
+ case 'CLOSE_ROOM':
+ {
+ this.store.dispatch(ChatStore.clearSelectedRoom());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ onClickOpenProfile(userSeq: number) {
+ const roomType = this.roomInfoSubject.value.roomType;
+ if (
+ roomType !== RoomType.Allim &&
+ roomType !== RoomType.Bot &&
+ roomType !== RoomType.Link &&
+ roomType !== RoomType.Allim_Elephant &&
+ roomType !== RoomType.Allim_TMS
+ ) {
+ this.openProfile.emit({ userSeq });
+ }
+ }
+
+ /** About Sticker */
+ onShowToggleStickerSelector() {
+ this.isShowStickerSelector = !this.isShowStickerSelector;
+ if (!this.isShowStickerSelector) {
+ this.selectedSticker = null;
+ }
+ }
+ onSelectedSticker(stickerInfo: StickerFilesInfo) {
+ this.selectedSticker = stickerInfo;
+ }
+ setStickerHistory(sticker: StickerFilesInfo) {
+ const history = this.localStorageService.get(KEY_STICKER_HISTORY);
+
+ if (!!history && history.length > 0) {
+ const stickers: string[] = [];
+ [sticker.index, ...history.filter(hist => hist !== sticker.index)].map(
+ (s, i) => {
+ if (i < 10) {
+ stickers.push(s);
+ }
+ }
+ );
+
+ this.localStorageService.set(KEY_STICKER_HISTORY, stickers);
+ } else {
+ this.localStorageService.set(KEY_STICKER_HISTORY, [
+ sticker.index
+ ]);
+ }
+ }
+ getStickerHistory(): string[] {
+ return this.localStorageService.get(KEY_STICKER_HISTORY);
+ }
+
+ /** About Chat Search */
+ onShowToggleSearchArea() {
+ this.isShowSearchArea = !this.isShowSearchArea;
+
+ if (!this.isShowSearchArea) {
+ this.searchedListSubject.next([]);
+ this.searchedFocusEvent = null;
+ this.searchText = '';
+ }
+ }
+ onCloseSearchArea() {
+ this.isShowSearchArea = false;
+ this.searchedListSubject.next([]);
+ this.searchedFocusEvent = null;
+ this.searchText = '';
+
+ this.moreSearchProcessing = false;
+ this.searchTotalCount = 0;
+ this.searchCurrentIndex = 0;
+
+ this.store.dispatch(EventStore.infoForSearchEnd({}));
+ }
+ onSearchChat(searchText: string, baseSeq?: number) {
+ this.searchText = searchText;
+
+ // CASE :: searching text after retrieve All event Infos.
+ this.store.dispatch(
+ EventStore.infoAll({
+ req: {
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ baseSeq: this.eventListSubject.value[0].seq,
+ requestCount:
+ environment.productConfig.CommonSetting.eventRequestDefaultCount * 2
+ },
+ infoList: undefined
+ })
+ );
+
+ // this.doSearchTextInEvent(searchText);
+ }
+ doSearchTextInEvent(searchText: string, baseSeq?: number): void {
+ this.searchedListSubject.next(
+ this.eventListSubject.value.filter(event => {
+ let contents = '';
+ if (event.type === EventType.Character) {
+ contents = event.sentMessage;
+ } else if (
+ event.type === EventType.Sticker &&
+ !!event.sentMessageJson
+ ) {
+ contents = (event.sentMessageJson as StickerEventJson).chat;
+ } else if (event.type === EventType.File && !!event.sentMessageJson) {
+ contents = (event.sentMessageJson as FileEventJson).fileName;
+ } else if (
+ event.type === EventType.MassText &&
+ !!event.sentMessageJson
+ ) {
+ contents = (event.sentMessageJson as MassTextEventJson).content;
+ } else if (
+ (event.type === EventType.Translation ||
+ event.type === EventType.MassTranslation) &&
+ !!event.sentMessageJson
+ ) {
+ contents = (event.sentMessageJson as TranslationEventJson).original;
+ contents += (event.sentMessageJson as TranslationEventJson)
+ .translation;
+ }
+
+ return contents.indexOf(searchText) > -1;
+ })
+ );
+
+ if (
+ !!this.searchedListSubject.value &&
+ this.searchedListSubject.value.length > 0
+ ) {
+ this.searchTotalCount = this.searchedListSubject.value.length;
+
+ if (!!baseSeq && baseSeq > 0) {
+ this.searchedListSubject.value.forEach((searched, index) => {
+ if (searched.seq <= baseSeq) {
+ this.searchCurrentIndex = index + 1;
+ this.searchedFocusEvent = searched;
+ }
+ });
+ } else {
+ this.searchCurrentIndex = this.searchedListSubject.value.length;
+ this.searchedFocusEvent = this.searchedListSubject.value[
+ this.searchedListSubject.value.length - 1
+ ];
+ }
+
+ this.store.dispatch(EventStore.infoForSearchEnd({}));
+
+ // this.chatMessages.gotoPosition(this.searchedFocusEvent.seq);
+ this.chatMessages.initEventMore(this.searchedFocusEvent.seq);
+ } else {
+ this.searchTotalCount = 0;
+ this.searchCurrentIndex = 0;
+
+ this.searchedFocusEvent = null;
+ }
+ }
+ onPrevSearch() {
+ this.searchedListSubject.value.forEach((event, index) => {
+ if (event.seq === this.searchedFocusEvent.seq && index > 0) {
+ this.searchCurrentIndex = this.searchCurrentIndex - 1;
+ this.searchedFocusEvent = this.searchedListSubject.value[index - 1];
+ this.chatMessages.gotoPosition(this.searchedFocusEvent.seq);
+ }
+ });
+ }
+ onNextSearch() {
+ // let exist = false;
+ // this.searchedList.forEach((event, index) => {
+ // if (
+ // event.seq === this.searchedFocusEvent.seq &&
+ // index < this.searchedList.length - 2 &&
+ // !exist
+ // ) {
+ // exist = true;
+ // this.searchCurrentIndex = this.searchCurrentIndex + 1;
+ // this.searchedFocusEvent = this.searchedList[index + 1];
+ // this.goSearchPosition(this.searchedFocusEvent.seq);
+ // }
+ // });
+
+ if (this.searchCurrentIndex < this.searchedListSubject.value.length) {
+ this.searchedFocusEvent = this.searchedListSubject.value[
+ this.searchCurrentIndex
+ ];
+ this.searchCurrentIndex = this.searchCurrentIndex + 1;
+ this.chatMessages.gotoPosition(this.searchedFocusEvent.seq);
+ }
+ }
+ onSearchAndPrev() {
+ if (
+ !!this.searchText &&
+ this.searchText.trim().length > 0 &&
+ this.eventRemainedSubject.value
+ ) {
+ this.moreSearchProcessing = true;
+ this.chatMessages.storeScrollPosition();
+
+ // Case :: retrieve event infos step by step until include searchtext in event..
+ this.store.dispatch(
+ EventStore.infoForSearch({
+ req: {
+ roomSeq: this.roomInfoSubject.value.roomSeq,
+ baseSeq: this.eventListSubject.value[0].seq,
+ requestCount:
+ environment.productConfig.CommonSetting.eventRequestDefaultCount
+ },
+ searchText: this.searchText
+ })
+ );
+ }
+ }
+
+ /**
+ * 번역기능 비활성화 2020-02-07
+ * About Translation */
+ // onShowToggleTranslation() {
+ // this.isShowTranslation = !this.isShowTranslation;
+ // if (!this.isShowTranslation) {
+ // }
+ // }
+ // onChangeTranslationSimpleView(value: boolean) {
+ // this.translationSimpleview = value;
+ // }
+ // onChangeTranslationPreView(value: boolean) {
+ // this.translationPreview = value;
+ // }
+ // onChangeDestLocale(destLocale: string) {
+ // this.destLocale = destLocale;
+ // }
+ // onCancelTranslation() {
+ // this.isTranslationProcess = false;
+ // this.translationPreviewInfo = null;
+ // }
+
+ // onSendTranslationMessage(params: {
+ // previewInfo: TranslationSaveResponse | null;
+ // translationType: EventType.Translation | EventType.MassTranslation;
+ // }) {
+ // let sentMessage = '';
+ // if (params.translationType === EventType.MassTranslation) {
+ // // Mass Text Translation
+ // sentMessage = params.previewInfo.returnJson;
+ // } else {
+ // // Normal Text Translation
+ // sentMessage = JSON.stringify({
+ // locale: params.previewInfo.destLocale,
+ // original: params.previewInfo.original,
+ // translation: params.previewInfo.translation,
+ // stickername: '',
+ // stickerfile: !!this.selectedSticker ? this.selectedSticker.index : ''
+ // });
+ // }
+
+ // this.store.dispatch(
+ // EventStore.send({
+ // senderSeq: this.loginResSubject.value.userSeq,
+ // req: {
+ // roomSeq: this.roomInfoSubject.value.roomSeq,
+ // eventType: params.translationType,
+ // sentMessage
+ // }
+ // })
+ // );
+
+ // this.isTranslationProcess = false;
+ // this.translationPreviewInfo = null;
+ // }
+
+ onClipboardPaste(event: ClipboardEvent) {
+ this.nativeService.readFromClipboard().then(async data => {
+ if (!!data.image && !!data.text) {
+ const result = await this.dialogService.open<
+ ClipboardDialogComponent,
+ ClipboardDialogData,
+ ClipboardDialogResult
+ >(ClipboardDialogComponent, {
+ width: '800px',
+ maxWidth: '800px',
+ height: '800px',
+ minHeight: '800px',
+ disableClose: false,
+ data: {
+ content: data
+ }
+ });
+
+ if (result.selected.text) {
+ this.onSendMessage(data.text.replace(/\t/g, ' '));
+ }
+
+ if (result.selected.image) {
+ const fileUploadItems = FileUploadItem.fromDataUrls(
+ 'clipboard',
+ data.imageDataUrl
+ );
+
+ this.onFileSelected(fileUploadItems);
+ }
+ } else if (!!data.image && !data.text) {
+ const fileUploadItems = FileUploadItem.fromDataUrls(
+ 'clipboard',
+ data.imageDataUrl
+ );
+
+ this.onFileSelected(fileUploadItems);
+ } else {
+ const v = this.chatForm.replyInput.nativeElement.value;
+ const selectionStart = this.chatForm.replyInput.nativeElement
+ .selectionStart;
+ const selectionEnd = this.chatForm.replyInput.nativeElement
+ .selectionEnd;
+
+ const start = v.substr(0, selectionStart);
+ const end = v.substr(selectionEnd);
+
+ this.chatForm.replyInput.nativeElement.value = `${start}${data.text}${end}`;
+
+ event.preventDefault();
+ }
+ });
+ }
+}
diff --git a/documents/업무/2월/2째주/묶음파일변경사항.txt b/documents/업무/2월/2째주/묶음파일변경사항.txt
new file mode 100644
index 0000000..71ae742
--- /dev/null
+++ b/documents/업무/2월/2째주/묶음파일변경사항.txt
@@ -0,0 +1 @@
+c:\projects\work\next-ucap-messenger\projects\ucap-webmessenger-api-common\src\lib\services\common-api.service.ts
\ No newline at end of file
diff --git a/weekly-report/주간보고_박병은_2020.0110.pptx b/weekly-report/1월/주간보고_박병은_2020.0110.pptx
similarity index 100%
rename from weekly-report/주간보고_박병은_2020.0110.pptx
rename to weekly-report/1월/주간보고_박병은_2020.0110.pptx
diff --git a/weekly-report/주간보고_박병은_2020.0117.pptx b/weekly-report/1월/주간보고_박병은_2020.0117.pptx
similarity index 100%
rename from weekly-report/주간보고_박병은_2020.0117.pptx
rename to weekly-report/1월/주간보고_박병은_2020.0117.pptx
diff --git a/weekly-report/주간보고_박병은_2020.0123.pptx b/weekly-report/1월/주간보고_박병은_2020.0123.pptx
similarity index 100%
rename from weekly-report/주간보고_박병은_2020.0123.pptx
rename to weekly-report/1월/주간보고_박병은_2020.0123.pptx
diff --git a/weekly-report/주간보고_박병은_2020.0131.pptx b/weekly-report/1월/주간보고_박병은_2020.0131.pptx
similarity index 100%
rename from weekly-report/주간보고_박병은_2020.0131.pptx
rename to weekly-report/1월/주간보고_박병은_2020.0131.pptx
diff --git a/weekly-report/주간보고_박병은_2020.0207.pptx b/weekly-report/2월/주간보고_박병은_2020.0207.pptx
similarity index 100%
rename from weekly-report/주간보고_박병은_2020.0207.pptx
rename to weekly-report/2월/주간보고_박병은_2020.0207.pptx
diff --git a/weekly-report/2월/주간보고_박병은_2020.0214.pptx b/weekly-report/2월/주간보고_박병은_2020.0214.pptx
new file mode 100644
index 0000000..99572b9
Binary files /dev/null and b/weekly-report/2월/주간보고_박병은_2020.0214.pptx differ