diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html index c9020572..32bc1199 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html @@ -179,7 +179,6 @@
+ (); - @ViewChild('messageBoxContainer', { static: true }) - private messageBoxContainer: ElementRef; - @ViewChild('chatForm', { static: false }) private chatForm: UCapUiChatFormComponent; @@ -159,9 +155,14 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { isShowStickerSelector = false; selectedSticker: StickerFilesInfo; + /** About ReadHere */ + firstcheckReadHere = true; + clearReadHere = false; + snackBarPreviewEvent: MatSnackBarRef; RoomType = RoomType; + CONST = CONST; constructor( private store: Store, @@ -229,10 +230,15 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { }) ); - this.eventListSubscription = this.store + // [Daesang] + this.eventListSubscription = combineLatest([ + this.store.pipe( + select(AppStore.MessengerSelector.EventSelector.selectAllInfoList) + ), + this.store.pipe(select(AppStore.MessengerSelector.RoomSelector.roomInfo)) + ]) .pipe( - select(AppStore.MessengerSelector.EventSelector.selectAllInfoList), - tap(infoList => { + tap(([infoList, roomInfo]) => { if (!!this.eventList && this.eventList.length > 0) { this.eventListNew = infoList.filter(info => { if (info.seq <= this.eventList[this.eventList.length - 1].seq) { @@ -240,7 +246,20 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { } return true; }); + + if ( + !!infoList && + infoList.length > 0 && + !!roomInfo && + !!roomInfo.lastReadEventSeq && + roomInfo.lastReadEventSeq > 0 && + this.baseEventSeq <= roomInfo.lastReadEventSeq + ) { + // 조회된 내용중에 read here 가 있을 경우. + this.firstcheckReadHere = false; + } } + this.eventList = infoList; if (!!infoList && infoList.length > 0) { @@ -251,6 +270,29 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { ) .subscribe(); + // // [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), @@ -296,6 +338,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { // Sticker Selector Clear.. this.isShowStickerSelector = false; this.selectedSticker = undefined; + + this.firstcheckReadHere = true; } get _roomUserInfos() { @@ -395,15 +439,27 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { if (this.psChatContent.directiveRef) { this.psChatContent.directiveRef.update(); - setTimeout(() => { - this.psChatContent.directiveRef.scrollToTop( - this.psChatContent.directiveRef.elementRef.nativeElement - .scrollHeight - this.eventMorePosition, - speed - ); + const element = document.getElementById('message-box-readhere'); + if (!!element && this.firstcheckReadHere) { + setTimeout(() => { + this.psChatContent.directiveRef.scrollToTop( + element.offsetTop - 200, + speed + ); + }); - this.eventMorePosition = 0; - }); + this.firstcheckReadHere = false; + } else { + setTimeout(() => { + this.psChatContent.directiveRef.scrollToTop( + this.psChatContent.directiveRef.elementRef.nativeElement + .scrollHeight - this.eventMorePosition, + speed + ); + + this.eventMorePosition = 0; + }); + } } } else if (this.scrollUpinit) { if (!!this.eventListNew && this.eventListNew.length > 0) { @@ -437,9 +493,21 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { if (this.psChatContent.directiveRef) { this.psChatContent.directiveRef.update(); - setTimeout(() => { - this.psChatContent.directiveRef.scrollToBottom(0, speed); - }); + const element = document.getElementById('message-box-readhere'); + if (!!element && this.firstcheckReadHere) { + setTimeout(() => { + this.psChatContent.directiveRef.scrollToTop( + element.offsetTop - 200, + speed + ); + }); + + this.firstcheckReadHere = false; + } else { + setTimeout(() => { + this.psChatContent.directiveRef.scrollToBottom(0, speed); + }); + } } } } @@ -447,13 +515,19 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { this.scrollUpinit = true; } onScrollReachStart(event: any) { - this.onMoreEvent(this.baseEventSeq); + // 자동 스크롤이 아닌 버튼 방식으로 변경. + // this.onMoreEvent(this.baseEventSeq); } onScrollReachEnd(event: any) { this.setEventMoreInit(); if (!!this.snackBarPreviewEvent) { this.snackBarPreviewEvent.dismiss(); } + + // clear readHere object.. + if (!this.firstcheckReadHere) { + this.clearReadHere = true; + } } /** More Event */ diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts index cc3a7043..8ecf0f6a 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts @@ -32,6 +32,7 @@ export const infoSuccess = createAction( props<{ infoList: Info[]; res: InfoResponse; + remainInfo: boolean; }>() ); export const infoFailure = createAction( @@ -61,6 +62,7 @@ export const infoMoreSuccess = createAction( props<{ infoList: Info[]; res: InfoResponse; + remainInfo: boolean; }>() ); diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts index a666e67c..67ef65ec 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts @@ -106,14 +106,47 @@ import { RoomUserData } from '@ucap-webmessenger/protocol-sync'; @Injectable() export class Effects { + // selectedRoomForInfo$ = createEffect(() => + // this.actions$.pipe( + // ofType(ChatStore.selectedRoom), + // map(action => { + // return info({ + // roomSeq: action.roomSeq, + // baseSeq: 0, + // requestCount: CONST.EVENT_INFO_READ_COUNT + // }); + // }) + // ) + // ); + selectedRoomForInfo$ = createEffect(() => this.actions$.pipe( - ofType(ChatStore.selectedRoom), + ofType(RoomStore.infoSuccess), map(action => { + const roomInfo = action.roomInfo; + let requestCount = 0; + + // 여기까지 읽음 처리.. + if (!!roomInfo.finalEventSeq && !!roomInfo.lastReadEventSeq) { + requestCount = roomInfo.finalEventSeq - roomInfo.lastReadEventSeq; + + // 기존 요청개수보다 요청할 갯수가 적을 경우 기본값. + if (CONST.EVENT_INFO_READ_COUNT >= requestCount) { + requestCount = CONST.EVENT_INFO_READ_COUNT; + } else { + // 여기까지 읽음 처리를 위한 최대 요청 개수 제한. + if (CONST.READ_HERE_MAX_EVENT_INFO_READ_COUNT < requestCount) { + requestCount = CONST.READ_HERE_MAX_EVENT_INFO_READ_REQUEST_COUNT; + } else { + requestCount = requestCount + 5; + } + } + } + return info({ - roomSeq: action.roomSeq, + roomSeq: roomInfo.roomSeq, baseSeq: 0, - requestCount: CONST.EVENT_INFO_READ_COUNT + requestCount }); }) ) @@ -141,14 +174,18 @@ export class Effects { this.store.dispatch( infoSuccess({ infoList, - res: res as InfoResponse + res: res as InfoResponse, + remainInfo: + infoList.length === req.requestCount ? true : false }) ); } else { this.store.dispatch( infoMoreSuccess({ infoList, - res: res as InfoResponse + res: res as InfoResponse, + remainInfo: + infoList.length === req.requestCount ? true : false }) ); } diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/event/reducers.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/event/reducers.ts index 418faec2..9890852b 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/event/reducers.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/event/reducers.ts @@ -37,11 +37,7 @@ export const reducer = createReducer( }), infoStatus: action.res, infoListProcessing: false, - remainInfo: - !!action.infoList && - action.infoList.length === CONST.EVENT_INFO_READ_COUNT - ? true - : false + remainInfo: action.remainInfo }; }), on(infoMoreSuccess, (state, action) => { @@ -52,11 +48,7 @@ export const reducer = createReducer( }), infoStatus: action.res, infoListProcessing: false, - remainInfo: - !!action.infoList && - action.infoList.length === CONST.EVENT_INFO_READ_COUNT - ? true - : false + remainInfo: action.remainInfo }; }), on(infoFailure, (state, action) => { diff --git a/projects/ucap-webmessenger-core/src/lib/types/const.type.ts b/projects/ucap-webmessenger-core/src/lib/types/const.type.ts index 0e94076c..a44096d6 100644 --- a/projects/ucap-webmessenger-core/src/lib/types/const.type.ts +++ b/projects/ucap-webmessenger-core/src/lib/types/const.type.ts @@ -1,10 +1,17 @@ export enum CONST { /** 대용량 텍스트로 보내는 문자열의 길이 기준 */ MASSTEXT_LEN = 800, - /** 대화방의 이벤트를 조회하는 개수 */ + /** 대화방의 이벤트를 조회하는 갯수 */ EVENT_INFO_READ_COUNT = 50, /** Timer Room 최초 오픈시 timer interval */ DEFAULT_TIMER_ROOM_INTERVAL = 24 * 60 * 60, /** 한번에 채팅을 할 수 있는 인원수 제한 */ - CHATROOM_USER = 300 + CHATROOM_USER = 300, + + /** 여기까지 읽음을 표시할때 조회할 최소 이벤트 갯수 */ + READ_HERE_MIN_EVENT_INFO_READ_COUNT = 10, + /** 여기까지 읽음을 표시할때 조회할 최대 이벤트 갯수 */ + READ_HERE_MAX_EVENT_INFO_READ_COUNT = 100, + /** 여기까지 읽음을 표시할때 조회할 최대 이벤트 갯수를 초과 했을 경우 요청할 최초 이벤트 갯수 */ + READ_HERE_MAX_EVENT_INFO_READ_REQUEST_COUNT = 10 } diff --git a/projects/ucap-webmessenger-protocol-room/src/lib/models/room-info.ts b/projects/ucap-webmessenger-protocol-room/src/lib/models/room-info.ts index bfe878d5..cc3a68b4 100644 --- a/projects/ucap-webmessenger-protocol-room/src/lib/models/room-info.ts +++ b/projects/ucap-webmessenger-protocol-room/src/lib/models/room-info.ts @@ -28,4 +28,12 @@ export interface RoomInfo { isTimeRoom: boolean; /** 12. 타이머시간(n) */ timeRoomInterval: number; + + // [Daesang] + /** PIN 정렬정보 */ + pinOrderInfo?: string; + /** 마지막 읽은 이벤트SEQ */ + lastReadEventSeq?: number; + /** 최종대화SEQ */ + finalEventSeq?: number; } diff --git a/projects/ucap-webmessenger-protocol-room/src/lib/protocols/info.ts b/projects/ucap-webmessenger-protocol-room/src/lib/protocols/info.ts index 412cfda9..85622e51 100644 --- a/projects/ucap-webmessenger-protocol-room/src/lib/protocols/info.ts +++ b/projects/ucap-webmessenger-protocol-room/src/lib/protocols/info.ts @@ -94,7 +94,11 @@ export const decodeInfoData: ProtocolDecoder = ( isJoinRoom: info[9] === 'Y' ? true : false, expiredFileStdSeq: Number(info[10]), isTimeRoom: info[11] === 'Y' ? true : false, - timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0 + timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0, + + pinOrderInfo: info[13], + lastReadEventSeq: Number(info[14]), + finalEventSeq: Number(info[15]) }; } } diff --git a/projects/ucap-webmessenger-protocol-sync/src/lib/protocols/room.ts b/projects/ucap-webmessenger-protocol-sync/src/lib/protocols/room.ts index 55c7d729..02e5dd76 100644 --- a/projects/ucap-webmessenger-protocol-sync/src/lib/protocols/room.ts +++ b/projects/ucap-webmessenger-protocol-sync/src/lib/protocols/room.ts @@ -88,7 +88,11 @@ export const decodeRoomData: ProtocolDecoder = ( isJoinRoom: info[9] === 'Y' ? true : false, expiredFileStdSeq: Number(info[10]), isTimeRoom: info[11] === 'Y' ? true : false, - timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0 + timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0, + + pinOrderInfo: info[13], + lastReadEventSeq: Number(info[14]), + finalEventSeq: Number(info[15]) }); } } diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.html b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.html new file mode 100644 index 00000000..dd9c6c4a --- /dev/null +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.html @@ -0,0 +1,5 @@ +
+ + 여기까지 읽었습니다. + +
diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.scss b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.scss new file mode 100644 index 00000000..cc55babf --- /dev/null +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.scss @@ -0,0 +1,18 @@ +.read-here { + display: flex; + align-content: center; + flex-flow: row; + .line { + height: 1px; + background-color: #cccccc; + width: 40%; + flex: 1 1 auto; + margin-bottom: 10px; + } + .date { + width: 160px; + font-size: 13px; + text-align: center; + font-weight: 600; + } +} diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.spec.ts b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.spec.ts new file mode 100644 index 00000000..17691f5c --- /dev/null +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ReadHereComponent } from './read-here.component'; + +describe('Chat::MessageBox::ReadHereComponent', () => { + let component: ReadHereComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ReadHereComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ReadHereComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.ts b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.ts new file mode 100644 index 00000000..74cb1b13 --- /dev/null +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/message-box/read-here.component.ts @@ -0,0 +1,12 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'ucap-chat-message-box-read-here', + templateUrl: './read-here.component.html', + styleUrls: ['./read-here.component.scss'] +}) +export class ReadHereComponent implements OnInit { + constructor() {} + + ngOnInit() {} +} diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/messages.component.html b/projects/ucap-webmessenger-ui-chat/src/lib/components/messages.component.html index 7e84501f..db59b40a 100644 --- a/projects/ucap-webmessenger-ui-chat/src/lib/components/messages.component.html +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/messages.component.html @@ -1,7 +1,20 @@
- +
+ +
+ + + []; + roomInfo: RoomInfo; + @Input() + set eventList(elist: Info[]) { + if (!!elist && elist.length > 0) { + this.firstEventSeq = elist[0].seq; + this.lastEventSeq = elist[elist.length - 1].seq; + } + + this.messages = elist; + } @Input() eventInfoStatus?: InfoResponse; @Input() @@ -44,6 +45,10 @@ export class MessagesComponent implements OnInit { sessionVerInfo: VersionInfo2Response; @Input() isShowUnreadCount = true; + @Input() + clearReadHere: boolean; + @Input() + minShowReadHere = 10; @Output() openProfile = new EventEmitter(); @@ -61,11 +66,17 @@ export class MessagesComponent implements OnInit { message: Info; }>(); + messages: Info[]; + EventType = EventType; CONST = CONST; profileImageRoot: string; moment = moment; + firstEventSeq = 0; + lastEventSeq = 0; + existReadHere = false; + constructor(private logger: NGXLogger, private datePipe: DatePipe) {} ngOnInit() { @@ -165,6 +176,31 @@ export class MessagesComponent implements OnInit { return false; } + getReadHere(messageIndex: number): boolean { + if ( + !!this.roomInfo && + !!this.roomInfo.lastReadEventSeq && + this.roomInfo.lastReadEventSeq > 0 && + this.lastEventSeq - this.roomInfo.lastReadEventSeq > 5 + ) { + if ( + this.roomInfo.roomType === RoomType.Single || + this.roomInfo.roomType === RoomType.Multi + ) { + if (!this.roomInfo.isTimeRoom) { + if ( + this.messages[messageIndex].seq === + this.roomInfo.lastReadEventSeq + 1 + ) { + this.existReadHere = true; + return true; + } + } + } + } + return false; + } + onClickOpenProfile(event: MouseEvent, userInfo: UserInfo) { event.preventDefault(); event.stopPropagation(); diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/ucap-ui-chat.module.ts b/projects/ucap-webmessenger-ui-chat/src/lib/ucap-ui-chat.module.ts index 8fb93cc5..6df9d258 100644 --- a/projects/ucap-webmessenger-ui-chat/src/lib/ucap-ui-chat.module.ts +++ b/projects/ucap-webmessenger-ui-chat/src/lib/ucap-ui-chat.module.ts @@ -23,6 +23,7 @@ import { InformationComponent as MBInformationComponent } from './components/mes import { MassTranslationComponent as MBMassTranslationComponent } from './components/message-box/mass-translation.component'; import { MassComponent as MBMassComponent } from './components/message-box/mass.component'; import { NoticeComponent as MBNoticeComponent } from './components/message-box/notice.component'; +import { ReadHereComponent as MBReadHereComponent } from './components/message-box/read-here.component'; import { RecallComponent as MBRecallComponent } from './components/message-box/recall.component'; import { ScheduleComponent as MBScheduleComponent } from './components/message-box/schedule.component'; import { StickerComponent as MBStickerComponent } from './components/message-box/sticker.component'; @@ -43,6 +44,7 @@ const COMPONENTS = [ MBMassTranslationComponent, MBMassComponent, MBNoticeComponent, + MBReadHereComponent, MBRecallComponent, MBScheduleComponent, MBStickerComponent,