Bot description:

Fix displaying bot description in empty chats
Center align
Fix appearing animation
This commit is contained in:
Eduard Kuzmenko 2021-07-08 03:32:55 +03:00
parent 368254af95
commit 179b3041ac
3 changed files with 87 additions and 47 deletions

View File

@ -25,7 +25,7 @@ import PopupDatePicker from "../popups/datePicker";
import PopupForward from "../popups/forward"; import PopupForward from "../popups/forward";
import PopupStickers from "../popups/stickers"; import PopupStickers from "../popups/stickers";
import ProgressivePreloader from "../preloader"; import ProgressivePreloader from "../preloader";
import Scrollable from "../scrollable"; import Scrollable, { SliceSides } from "../scrollable";
import StickyIntersector from "../stickyIntersector"; import StickyIntersector from "../stickyIntersector";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
import RichTextProcessor from "../../lib/richtextprocessor"; import RichTextProcessor from "../../lib/richtextprocessor";
@ -45,7 +45,7 @@ import { Message, MessageEntity, MessageReplyHeader, Update } from "../../layer
import { REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config"; import { REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { FocusDirection } from "../../helpers/fastSmoothScroll"; import { FocusDirection } from "../../helpers/fastSmoothScroll";
import useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from "../../hooks/useHeavyAnimationCheck"; import useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from "../../hooks/useHeavyAnimationCheck";
import { fastRaf } from "../../helpers/schedulers"; import { fastRaf, fastRafPromise } from "../../helpers/schedulers";
import { deferredPromise } from "../../helpers/cancellablePromise"; import { deferredPromise } from "../../helpers/cancellablePromise";
import RepliesElement from "./replies"; import RepliesElement from "./replies";
import DEBUG from "../../config/debug"; import DEBUG from "../../config/debug";
@ -69,7 +69,7 @@ import whichChild from "../../helpers/dom/whichChild";
import { cancelAnimationByKey } from "../../helpers/animation"; import { cancelAnimationByKey } from "../../helpers/animation";
const USE_MEDIA_TAILS = false; const USE_MEDIA_TAILS = false;
const IGNORE_ACTIONS: Message.messageService['action']['_'][] = [/* 'messageActionHistoryClear' */]; const IGNORE_ACTIONS: Message.messageService['action']['_'][] = ['messageActionHistoryClear'];
const TEST_SCROLL_TIMES: number = undefined; const TEST_SCROLL_TIMES: number = undefined;
let TEST_SCROLL = TEST_SCROLL_TIMES; let TEST_SCROLL = TEST_SCROLL_TIMES;
@ -146,7 +146,7 @@ export default class ChatBubbles {
[_ in MessageEntity['_']]: boolean [_ in MessageEntity['_']]: boolean
}> = {}; }> = {};
private onAnimateLadder: () => void; private onAnimateLadder: () => Promise<any>;
constructor(private chat: Chat, constructor(private chat: Chat,
private appMessagesManager: AppMessagesManager, private appMessagesManager: AppMessagesManager,
@ -1124,7 +1124,7 @@ export default class ChatBubbles {
// if scroll down after search // if scroll down after search
if(history.indexOf(historyStorage.maxId) !== -1) { if(history.indexOf(historyStorage.maxId) !== -1) {
this.scrollable.loadedAll.bottom = true; this.setLoaded('bottom', true);
return; return;
} }
@ -1171,8 +1171,8 @@ export default class ChatBubbles {
public setScroll() { public setScroll() {
this.scrollable = new Scrollable(null, 'IM', /* 10300 */300); this.scrollable = new Scrollable(null, 'IM', /* 10300 */300);
this.scrollable.loadedAll.top = false; this.setLoaded('top', false);
this.scrollable.loadedAll.bottom = false; this.setLoaded('bottom', false);
this.scrollable.container.append(this.chatInner); this.scrollable.container.append(this.chatInner);
@ -1465,8 +1465,8 @@ export default class ChatBubbles {
public cleanup(bubblesToo = false) { public cleanup(bubblesToo = false) {
////console.time('appImManager cleanup'); ////console.time('appImManager cleanup');
this.scrollable.loadedAll.top = false; this.setLoaded('top', false);
this.scrollable.loadedAll.bottom = false; this.setLoaded('bottom', false);
// cancel scroll // cancel scroll
cancelAnimationByKey(this.scrollable.container); cancelAnimationByKey(this.scrollable.container);
@ -1728,7 +1728,7 @@ export default class ChatBubbles {
if(!needFetchNew) { if(!needFetchNew) {
// warning // warning
if(!lastMsgId || this.bubbles[topMessage] || lastMsgId === topMessage) { if(!lastMsgId || this.bubbles[topMessage] || lastMsgId === topMessage) {
this.scrollable.loadedAll.bottom = true; this.setLoaded('bottom', true);
} }
} else { } else {
const middleware = this.getMiddleware(); const middleware = this.getMiddleware();
@ -1756,7 +1756,7 @@ export default class ChatBubbles {
const slice = historyStorage.history.slice; const slice = historyStorage.history.slice;
const isBottomEnd = slice.isEnd(SliceEnd.Bottom); const isBottomEnd = slice.isEnd(SliceEnd.Bottom);
if(this.scrollable.loadedAll.bottom && this.scrollable.loadedAll.bottom !== isBottomEnd) { if(this.scrollable.loadedAll.bottom && this.scrollable.loadedAll.bottom !== isBottomEnd) {
this.scrollable.loadedAll.bottom = isBottomEnd; this.setLoaded('bottom', isBottomEnd);
this.onScroll(); this.onScroll();
} }
@ -1858,7 +1858,7 @@ export default class ChatBubbles {
const middleware = this.getMiddleware(); const middleware = this.getMiddleware();
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
if(!middleware()) { if(!middleware()) {
return Promise.reject('setMessagesQueuePromise: peer changed!'); throw 'setMessagesQueuePromise: peer changed!';
} }
if(this.messagesQueueOnRender) { if(this.messagesQueueOnRender) {
@ -2776,11 +2776,11 @@ export default class ChatBubbles {
const firstSlice = historyStorage.history.first; const firstSlice = historyStorage.history.first;
const lastSlice = historyStorage.history.last; const lastSlice = historyStorage.history.last;
if(firstSlice.isEnd(SliceEnd.Bottom) && (!firstSlice.length || history.includes(firstSlice[0]))) { if(firstSlice.isEnd(SliceEnd.Bottom) && (!firstSlice.length || history.includes(firstSlice[0]))) {
this.scrollable.loadedAll.bottom = true; this.setLoaded('bottom', true);
} }
if(lastSlice.isEnd(SliceEnd.Top) && (!lastSlice.length || history.includes(lastSlice[lastSlice.length - 1]))) { if(lastSlice.isEnd(SliceEnd.Top) && (!lastSlice.length || history.includes(lastSlice[lastSlice.length - 1]))) {
this.scrollable.loadedAll.top = true; this.setLoaded('top', true);
} }
//console.time('appImManager render history'); //console.time('appImManager render history');
@ -2838,6 +2838,14 @@ export default class ChatBubbles {
(this.messagesQueuePromise || Promise.resolve()) (this.messagesQueuePromise || Promise.resolve())
//.then(() => new Promise(resolve => setTimeout(resolve, 100))) //.then(() => new Promise(resolve => setTimeout(resolve, 100)))
.then(() => { .then(() => {
if(this.scrollable.loadedAll.top && this.messagesQueueOnRenderAdditional) {
this.messagesQueueOnRenderAdditional();
if(this.messagesQueueOnRenderAdditional) {
this.messagesQueueOnRenderAdditional();
}
}
if(previousScrollHeightMinusTop !== undefined) { if(previousScrollHeightMinusTop !== undefined) {
/* const scrollHeight = this.scrollable.scrollHeight; /* const scrollHeight = this.scrollable.scrollHeight;
const addedHeight = scrollHeight - previousScrollHeight; const addedHeight = scrollHeight - previousScrollHeight;
@ -2917,22 +2925,18 @@ export default class ChatBubbles {
return promise; return promise;
} else if(this.chat.type === 'scheduled') { } else if(this.chat.type === 'scheduled') {
return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => { return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {
this.scrollable.loadedAll.top = true; this.setLoaded('top', true);
this.scrollable.loadedAll.bottom = true; this.setLoaded('bottom', true);
return {history: mids.slice().reverse()}; return {history: mids.slice().reverse()};
}); });
} }
} }
private animateAsLadder(additionMsgId: number, additionMsgIds: number[], isAdditionRender: boolean, backLimit: number, maxId: number) { private async animateAsLadder(additionMsgId: number, additionMsgIds: number[], isAdditionRender: boolean, backLimit: number, maxId: number) {
if(!Object.keys(this.bubbles).length) { if(!Object.keys(this.bubbles).length) {
return; return;
} }
if(this.onAnimateLadder) {
this.onAnimateLadder();
}
let sortedMids = getObjectKeysAndSort(this.bubbles, 'desc'); let sortedMids = getObjectKeysAndSort(this.bubbles, 'desc');
if(isAdditionRender && additionMsgIds.length) { if(isAdditionRender && additionMsgIds.length) {
@ -3014,11 +3018,17 @@ export default class ChatBubbles {
const promises = [topRes.animationPromise, middleRes.animationPromise, bottomRes.animationPromise]; const promises = [topRes.animationPromise, middleRes.animationPromise, bottomRes.animationPromise];
const delays: number[] = [topRes.lastMsDelay, middleRes.lastMsDelay, bottomRes.lastMsDelay]; const delays: number[] = [topRes.lastMsDelay, middleRes.lastMsDelay, bottomRes.lastMsDelay];
if(this.onAnimateLadder) {
await this.onAnimateLadder();
}
// fastRaf(() => {
fastRaf(() => { fastRaf(() => {
setBubbles.forEach(contentWrapper => { setBubbles.forEach(contentWrapper => {
contentWrapper.classList.remove('zoom-fade'); contentWrapper.classList.remove('zoom-fade');
}); });
}); });
// });
let promise: Promise<any>; let promise: Promise<any>;
if(topIds.length || middleIds.length || bottomIds.length) { if(topIds.length || middleIds.length || bottomIds.length) {
@ -3059,12 +3069,51 @@ export default class ChatBubbles {
this.onAnimateLadder = () => { this.onAnimateLadder = () => {
this.chatInner.prepend(bubble); this.chatInner.prepend(bubble);
this.onAnimateLadder = undefined; this.onAnimateLadder = undefined;
// need raf here because animation won't fire if this message is single
if(!this.messagesQueuePromise) {
return fastRafPromise();
}
}; };
} else { } else {
this.chatInner.prepend(bubble); this.chatInner.prepend(bubble);
} }
} }
private setLoaded(side: SliceSides, value: boolean) {
const willChange = this.scrollable.loadedAll[side] !== value;
if(!willChange) {
return;
}
this.scrollable.loadedAll[side] = value;
if(side === 'top' && value && this.appUsersManager.isBot(this.peerId)) {
this.log('inject bot description');
return this.appProfileManager.getProfile(this.peerId).then(userFull => {
if(!userFull.bot_info?.description) {
return;
}
const offset = this.appMessagesManager.generateMessageId(0);
const message: Message.message = {
_: 'message',
date: 0,
id: -(this.peerId + offset),
message: userFull.bot_info.description,
peer_id: this.appPeersManager.getOutputPeer(this.peerId),
pFlags: {
bot_description: true
}
};
this.appMessagesManager.saveMessages([message]);
this.processLocalMessageRender(message);
});
}
}
/** /**
* Load and render history * Load and render history
* @param maxId max message id * @param maxId max message id
@ -3156,32 +3205,9 @@ export default class ChatBubbles {
const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId]; const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId];
if(serviceStartMessageId) historyResult.history.push(serviceStartMessageId); if(serviceStartMessageId) historyResult.history.push(serviceStartMessageId);
historyResult.history.push(...this.chat.getMidsByMid(this.chat.threadId).reverse()); historyResult.history.push(...this.chat.getMidsByMid(this.chat.threadId).reverse());
} else if(this.appUsersManager.isBot(this.peerId)) {
this.log('inject bot description');
await this.appProfileManager.getProfile(this.peerId).then(userFull => {
if(!userFull.bot_info?.description) {
return;
}
const offset = this.appMessagesManager.generateMessageId(0);
const message: Message.message = {
_: 'message',
date: 0,
id: -(this.peerId + offset),
message: userFull.bot_info.description,
peer_id: this.appPeersManager.getOutputPeer(this.peerId),
pFlags: {
bot_description: true
}
};
this.appMessagesManager.saveMessages([message]);
this.processLocalMessageRender(message);
});
} }
this.scrollable.loadedAll.top = true; await this.setLoaded('top', true);
} }
}; };
@ -3293,7 +3319,7 @@ export default class ChatBubbles {
//ids = ids.slice(-removeCount); //ids = ids.slice(-removeCount);
//ids = ids.slice(removeCount * 2); //ids = ids.slice(removeCount * 2);
ids = ids.slice(safeCount); ids = ids.slice(safeCount);
this.scrollable.loadedAll.bottom = false; this.setLoaded('bottom', false);
//this.log('getHistory: slice bottom messages:', ids.length, loadCount); //this.log('getHistory: slice bottom messages:', ids.length, loadCount);
//this.getHistoryBottomPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд //this.getHistoryBottomPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд
@ -3301,7 +3327,7 @@ export default class ChatBubbles {
//ids = ids.slice(0, removeCount); //ids = ids.slice(0, removeCount);
//ids = ids.slice(0, ids.length - (removeCount * 2)); //ids = ids.slice(0, ids.length - (removeCount * 2));
ids = ids.slice(0, ids.length - safeCount); ids = ids.slice(0, ids.length - safeCount);
this.scrollable.loadedAll.top = false; this.setLoaded('top', false);
//this.log('getHistory: slice up messages:', ids.length, loadCount); //this.log('getHistory: slice up messages:', ids.length, loadCount);
//this.getHistoryTopPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд //this.getHistoryTopPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд

View File

@ -106,6 +106,18 @@ export function fastRaf(callback: NoneToVoidFunction) {
} }
} }
let rafPromise: Promise<DOMHighResTimeStamp>;
export function fastRafPromise() {
if(rafPromise) return rafPromise;
rafPromise = new Promise(requestAnimationFrame);
rafPromise.then(() => {
rafPromise = undefined;
});
return rafPromise;
}
export function doubleRaf() { export function doubleRaf() {
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
fastRaf(() => { fastRaf(() => {

View File

@ -725,6 +725,8 @@ $bubble-margin: .25rem;
order: -1; order: -1;
margin-top: .5rem; margin-top: .5rem;
justify-content: center; justify-content: center;
flex: 1 1 auto;
align-items: center;
.time { .time {
display: none !important; display: none !important;