diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index f1a1f235..39aba081 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -52,7 +52,7 @@ export class AppImManager { public dateMessages: {[timestamp: number]: { div: HTMLDivElement, firstTimestamp: number, - bubble: HTMLDivElement, + container: HTMLDivElement, timeout?: number }} = {}; public unreaded: number[] = []; @@ -102,6 +102,11 @@ export class AppImManager { public bubbleGroups = new BubbleGroups(); private scrolledDown = true; + private onScrollRAF = 0; + private isScrollingTimeout = 0; + + private datesIntersectionObserver: IntersectionObserver = null; + private lastDateMessageDiv: HTMLDivElement = null; constructor() { /* if(!lottieLoader.loaded) { @@ -559,6 +564,26 @@ export class AppImManager { this.setScroll(); apiUpdatesManager.attach(); + + this.datesIntersectionObserver = new IntersectionObserver((entries) => { + this.log('intersection', entries); + + let entry = entries.filter(entry => entry.boundingClientRect.top < 0).sort((a, b) => b.boundingClientRect.top - a.boundingClientRect.top)[0]; + if(!entry) return; + let container = entry.isIntersecting ? entry.target : entry.target.nextElementSibling; + for(let timestamp in this.dateMessages) { + let dateMessage = this.dateMessages[timestamp]; + if(dateMessage.container == container) { + if(this.lastDateMessageDiv) { + this.lastDateMessageDiv.classList.remove('is-sticky'); + } + + dateMessage.div.classList.add('is-sticky'); + this.lastDateMessageDiv = dateMessage.div; + break; + } + } + }/* , {root: this.chatInner} */); } public deleteMessages(revoke = false) { @@ -641,42 +666,59 @@ export class AppImManager { } public onScroll() { - let readed: number[] = []; + if(this.onScrollRAF) window.cancelAnimationFrame(this.onScrollRAF); + + this.onScrollRAF = window.requestAnimationFrame(() => { + let readed: number[] = []; - this.unreaded.forEachReverse((msgID, idx) => { - let bubble = this.bubbles[msgID]; + this.unreaded.forEachReverse((msgID, idx) => { + let bubble = this.bubbles[msgID]; + + if(isElementInViewport(bubble)) { + readed.push(msgID); + this.unreaded.splice(idx, 1); + } + }); - if(isElementInViewport(bubble)) { - readed.push(msgID); - this.unreaded.splice(idx, 1); - } - }); - - lottieLoader.checkAnimations(false, 'chat'); - - if(readed.length) { - let max = Math.max(...readed); - let min = Math.min(...readed); + lottieLoader.checkAnimations(false, 'chat'); - if(this.peerID < 0) { - max = appMessagesIDsManager.getMessageIDInfo(max)[0]; - min = appMessagesIDsManager.getMessageIDInfo(min)[0]; + if(readed.length) { + let max = Math.max(...readed); + let min = Math.min(...readed); + + if(this.peerID < 0) { + max = appMessagesIDsManager.getMessageIDInfo(max)[0]; + min = appMessagesIDsManager.getMessageIDInfo(min)[0]; + } + + //appMessagesManager.readMessages(readed); + appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => { + this.log.error('readHistory err:', err); + appMessagesManager.readHistory(this.peerID, max, min); + }); } - - //appMessagesManager.readMessages(readed); - appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => { - this.log.error('readHistory err:', err); - appMessagesManager.readHistory(this.peerID, max, min); - }); - } - - if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) { - this.scroll.parentElement.classList.add('scrolled-down'); - this.scrolledDown = true; - } else if(this.scroll.parentElement.classList.contains('scrolled-down')) { - this.scroll.parentElement.classList.remove('scrolled-down'); - this.scrolledDown = false; - } + + if(this.isScrollingTimeout) { + clearTimeout(this.isScrollingTimeout); + } else { + this.chatInner.classList.add('is-scrolling'); + } + + this.isScrollingTimeout = setTimeout(() => { + this.chatInner.classList.remove('is-scrolling'); + this.isScrollingTimeout = 0; + }, 300); + + if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) { + this.scroll.parentElement.classList.add('scrolled-down'); + this.scrolledDown = true; + } else if(this.scroll.parentElement.classList.contains('scrolled-down')) { + this.scroll.parentElement.classList.remove('scrolled-down'); + this.scrolledDown = false; + } + + this.onScrollRAF = 0; + }); } public setScroll() { @@ -827,6 +869,9 @@ export class AppImManager { //this.scrollable.setVirtualContainer(this.chatInner); this.scrollable.setVirtualContainer(null); + this.datesIntersectionObserver.disconnect(); + this.lastDateMessageDiv = null; + ////console.timeEnd('appImManager cleanup'); } @@ -1055,6 +1100,60 @@ export class AppImManager { }); if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight; } + + public getDateContainerByMessage(message: any, reverse: boolean) { + let date = new Date(message.date * 1000); + let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + let dateTimestamp = justDate.getTime(); + if(!(dateTimestamp in this.dateMessages)) { + let str = ''; + + let today = new Date(); + today.setHours(0); + today.setMinutes(0); + today.setSeconds(0); + + if(today < date) { + str = 'Today'; + } else { + const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + str = justDate.getFullYear() == new Date().getFullYear() ? + months[justDate.getMonth()] + ' ' + justDate.getDate() : + justDate.toISOString().split('T')[0].split('-').reverse().join('.'); + } + + let div = document.createElement('div'); + div.className = 'bubble service is-date'; + div.innerHTML = `