Date messages in chat
This commit is contained in:
parent
8972c69a9a
commit
bd0a2bdf39
@ -52,7 +52,7 @@ export class AppImManager {
|
|||||||
public dateMessages: {[timestamp: number]: {
|
public dateMessages: {[timestamp: number]: {
|
||||||
div: HTMLDivElement,
|
div: HTMLDivElement,
|
||||||
firstTimestamp: number,
|
firstTimestamp: number,
|
||||||
bubble: HTMLDivElement,
|
container: HTMLDivElement,
|
||||||
timeout?: number
|
timeout?: number
|
||||||
}} = {};
|
}} = {};
|
||||||
public unreaded: number[] = [];
|
public unreaded: number[] = [];
|
||||||
@ -102,6 +102,11 @@ export class AppImManager {
|
|||||||
public bubbleGroups = new BubbleGroups();
|
public bubbleGroups = new BubbleGroups();
|
||||||
|
|
||||||
private scrolledDown = true;
|
private scrolledDown = true;
|
||||||
|
private onScrollRAF = 0;
|
||||||
|
private isScrollingTimeout = 0;
|
||||||
|
|
||||||
|
private datesIntersectionObserver: IntersectionObserver = null;
|
||||||
|
private lastDateMessageDiv: HTMLDivElement = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
/* if(!lottieLoader.loaded) {
|
/* if(!lottieLoader.loaded) {
|
||||||
@ -559,6 +564,26 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.setScroll();
|
this.setScroll();
|
||||||
apiUpdatesManager.attach();
|
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) {
|
public deleteMessages(revoke = false) {
|
||||||
@ -641,42 +666,59 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onScroll() {
|
public onScroll() {
|
||||||
let readed: number[] = [];
|
if(this.onScrollRAF) window.cancelAnimationFrame(this.onScrollRAF);
|
||||||
|
|
||||||
|
this.onScrollRAF = window.requestAnimationFrame(() => {
|
||||||
|
let readed: number[] = [];
|
||||||
|
|
||||||
this.unreaded.forEachReverse((msgID, idx) => {
|
this.unreaded.forEachReverse((msgID, idx) => {
|
||||||
let bubble = this.bubbles[msgID];
|
let bubble = this.bubbles[msgID];
|
||||||
|
|
||||||
if(isElementInViewport(bubble)) {
|
if(isElementInViewport(bubble)) {
|
||||||
readed.push(msgID);
|
readed.push(msgID);
|
||||||
this.unreaded.splice(idx, 1);
|
this.unreaded.splice(idx, 1);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
lottieLoader.checkAnimations(false, 'chat');
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
lottieLoader.checkAnimations(false, 'chat');
|
||||||
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) {
|
|
||||||
this.scroll.parentElement.classList.add('scrolled-down');
|
if(readed.length) {
|
||||||
this.scrolledDown = true;
|
let max = Math.max(...readed);
|
||||||
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
|
let min = Math.min(...readed);
|
||||||
this.scroll.parentElement.classList.remove('scrolled-down');
|
|
||||||
this.scrolledDown = false;
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
public setScroll() {
|
||||||
@ -827,6 +869,9 @@ export class AppImManager {
|
|||||||
//this.scrollable.setVirtualContainer(this.chatInner);
|
//this.scrollable.setVirtualContainer(this.chatInner);
|
||||||
this.scrollable.setVirtualContainer(null);
|
this.scrollable.setVirtualContainer(null);
|
||||||
|
|
||||||
|
this.datesIntersectionObserver.disconnect();
|
||||||
|
this.lastDateMessageDiv = null;
|
||||||
|
|
||||||
////console.timeEnd('appImManager cleanup');
|
////console.timeEnd('appImManager cleanup');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,6 +1100,60 @@ export class AppImManager {
|
|||||||
});
|
});
|
||||||
if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
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 = `<div class="bubble__container"><div class="service-msg">${str}</div></div>`;
|
||||||
|
////////this.log('need to render date message', dateTimestamp, str);
|
||||||
|
|
||||||
|
let container = document.createElement('div');
|
||||||
|
container.className = 'bubbles-date-group';
|
||||||
|
|
||||||
|
this.dateMessages[dateTimestamp] = {
|
||||||
|
div,
|
||||||
|
container,
|
||||||
|
firstTimestamp: date.getTime()
|
||||||
|
};
|
||||||
|
|
||||||
|
container.append(div);
|
||||||
|
|
||||||
|
if(reverse) {
|
||||||
|
let scrollTopPrevious = this.scrollable.scrollTop;
|
||||||
|
this.scrollable.prepend(container);
|
||||||
|
|
||||||
|
if(!scrollTopPrevious) {
|
||||||
|
this.scrollable.scrollTop += container.scrollHeight;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.scrollable.append(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.datesIntersectionObserver.observe(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dateMessages[dateTimestamp];
|
||||||
|
}
|
||||||
|
|
||||||
// reverse means top
|
// reverse means top
|
||||||
public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
|
public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
|
||||||
@ -1118,6 +1217,15 @@ export class AppImManager {
|
|||||||
this.scrollable.append(bubble);
|
this.scrollable.append(bubble);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
let dateContainer = this.getDateContainerByMessage(message, reverse);
|
||||||
|
if(!updatePosition) {
|
||||||
|
|
||||||
|
} else if(reverse) {
|
||||||
|
dateContainer.container.insertBefore(bubble, dateContainer.div.nextSibling);
|
||||||
|
} else {
|
||||||
|
dateContainer.container.append(bubble);
|
||||||
|
}
|
||||||
|
|
||||||
return bubble;
|
return bubble;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1538,62 +1646,21 @@ export class AppImManager {
|
|||||||
} else {
|
} else {
|
||||||
this.scrollable.appendByBatch(bubble);
|
this.scrollable.appendByBatch(bubble);
|
||||||
} */
|
} */
|
||||||
if(!multipleRender) {
|
// раскомментировать ////// если рендер должен быть в другой функции (если хочешь сделать через requestAnimationFrame)
|
||||||
if(reverse) {
|
//////if(!multipleRender) {
|
||||||
|
/* if(reverse) {
|
||||||
this.scrollable.prepend(bubble);
|
this.scrollable.prepend(bubble);
|
||||||
} else {
|
} else {
|
||||||
this.scrollable.append(bubble);
|
this.scrollable.append(bubble);
|
||||||
}
|
} */
|
||||||
}
|
//////}
|
||||||
//});
|
//});
|
||||||
|
|
||||||
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
let dateMessage = this.getDateContainerByMessage(message, reverse);
|
||||||
let dateTimestamp = justDate.getTime();
|
if(reverse) {
|
||||||
let needUpdatePos = false;
|
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
|
||||||
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';
|
|
||||||
div.innerHTML = `<div class="service-msg">${str}</div>`;
|
|
||||||
////////this.log('need to render date message', dateTimestamp, str);
|
|
||||||
|
|
||||||
this.dateMessages[dateTimestamp] = {
|
|
||||||
div,
|
|
||||||
bubble,
|
|
||||||
firstTimestamp: date.getTime()
|
|
||||||
};
|
|
||||||
|
|
||||||
needUpdatePos = true;
|
|
||||||
} else {
|
} else {
|
||||||
let dateMessage = this.dateMessages[dateTimestamp];
|
dateMessage.container.append(bubble);
|
||||||
if(dateMessage.firstTimestamp > date.getTime()) {
|
|
||||||
dateMessage.bubble = bubble;
|
|
||||||
needUpdatePos = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let dateMessage = this.dateMessages[dateTimestamp];
|
|
||||||
if(needUpdatePos && !dateMessage.timeout) {
|
|
||||||
//dateMessage.timeout = setTimeout(() => {
|
|
||||||
delete dateMessage.timeout;
|
|
||||||
|
|
||||||
//this.scrollable.insertBefore(dateMessage.div, dateMessage.bubble);
|
|
||||||
//}, 0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.bubbleGroups.updateGroupByMessageID(message.mid);
|
this.bubbleGroups.updateGroupByMessageID(message.mid);
|
||||||
@ -1684,7 +1751,7 @@ export class AppImManager {
|
|||||||
let bubble = this.renderMessage(message, reverse, true);
|
let bubble = this.renderMessage(message, reverse, true);
|
||||||
if(bubble) {
|
if(bubble) {
|
||||||
if(reverse) {
|
if(reverse) {
|
||||||
this.scrollable.prepend(bubble);
|
////////this.scrollable.prepend(bubble);
|
||||||
|
|
||||||
//this.log('performHistoryResult scrollTop', this.scrollable.scrollTop, bubble.scrollHeight);
|
//this.log('performHistoryResult scrollTop', this.scrollable.scrollTop, bubble.scrollHeight);
|
||||||
|
|
||||||
@ -1712,7 +1779,7 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.scrollable.append(bubble);
|
////////this.scrollable.append(bubble);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//} while(cached && !this.scrollable.scrollTop);
|
//} while(cached && !this.scrollable.scrollTop);
|
||||||
|
@ -171,6 +171,10 @@ $chat-max-width: 696px;
|
|||||||
margin-left: 45px;
|
margin-left: 45px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-scrolling .is-sticky {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#bubbles-go-down {
|
#bubbles-go-down {
|
||||||
@ -225,6 +229,20 @@ $chat-max-width: 696px;
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr $chat-max-width 1fr;
|
grid-template-columns: 1fr $chat-max-width 1fr;
|
||||||
grid-row-gap: 0px;
|
grid-row-gap: 0px;
|
||||||
|
|
||||||
|
&.is-date {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 5px;
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.is-sticky {
|
||||||
|
-webkit-transition: opacity .3s ease;
|
||||||
|
transition: opacity .3s ease;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:before, &:after {
|
&:before, &:after {
|
||||||
content: " ";
|
content: " ";
|
||||||
@ -245,10 +263,11 @@ $chat-max-width: 696px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.service {
|
&.service {
|
||||||
display: block;
|
//padding: 1rem 0;
|
||||||
padding: 1rem 0;
|
padding: 5px 0;
|
||||||
|
|
||||||
.bubble__container {
|
.bubble__container {
|
||||||
|
justify-self: center;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user