Preserve scroll position on reactions update
This commit is contained in:
parent
16015b9c13
commit
46f759f0f4
@ -93,6 +93,7 @@ import type ReactionElement from "./reaction";
|
|||||||
import type { AppReactionsManager } from "../../lib/appManagers/appReactionsManager";
|
import type { AppReactionsManager } from "../../lib/appManagers/appReactionsManager";
|
||||||
import RLottiePlayer from "../../lib/rlottie/rlottiePlayer";
|
import RLottiePlayer from "../../lib/rlottie/rlottiePlayer";
|
||||||
import { pause } from "../../helpers/schedulers/pause";
|
import { pause } from "../../helpers/schedulers/pause";
|
||||||
|
import ScrollSaver from "../../helpers/scrollSaver";
|
||||||
|
|
||||||
const USE_MEDIA_TAILS = false;
|
const USE_MEDIA_TAILS = false;
|
||||||
const IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([
|
const IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([
|
||||||
@ -426,11 +427,11 @@ export default class ChatBubbles {
|
|||||||
if(!mounted) return;
|
if(!mounted) return;
|
||||||
|
|
||||||
const updatePosition = this.chat.type === 'scheduled';
|
const updatePosition = this.chat.type === 'scheduled';
|
||||||
const scrolledDown = this.scrolledDown;
|
|
||||||
|
const scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||||
|
scrollSaver.save();
|
||||||
this.safeRenderMessage(mounted.message, true, false, mounted.bubble, updatePosition);
|
this.safeRenderMessage(mounted.message, true, false, mounted.bubble, updatePosition);
|
||||||
if(scrolledDown) {
|
scrollSaver.restore();
|
||||||
this.scrollToBubbleIfLast(mounted.bubble);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(updatePosition) {
|
if(updatePosition) {
|
||||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
||||||
@ -464,26 +465,25 @@ export default class ChatBubbles {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrolledDown = this.scrolledDown;
|
const scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||||
let bubble: HTMLElement;
|
const bubble = this.getBubbleByMessage(message);
|
||||||
if(scrolledDown) {
|
if(!bubble) {
|
||||||
bubble = this.getBubbleByMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = message.peerId + '_' + message.mid;
|
|
||||||
const set = REACTIONS_ELEMENTS.get(key);
|
|
||||||
if(!set) {
|
|
||||||
rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const element of set) {
|
scrollSaver.save();
|
||||||
element.update(message, changedResults);
|
|
||||||
|
const key = message.peerId + '_' + message.mid;
|
||||||
|
const set = REACTIONS_ELEMENTS.get(key);
|
||||||
|
if(set) {
|
||||||
|
for(const element of set) {
|
||||||
|
element.update(message, changedResults);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scrolledDown && bubble) {
|
scrollSaver.restore();
|
||||||
this.scrollToBubbleIfLast(bubble);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3845,32 +3845,11 @@ export default class ChatBubbles {
|
|||||||
this.log('performHistoryResult: will render some messages:', history.length, this.isHeavyAnimationInProgress, this.messagesQueuePromise);
|
this.log('performHistoryResult: will render some messages:', history.length, this.isHeavyAnimationInProgress, this.messagesQueuePromise);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
//const padding = 10000;
|
let scrollSaver: ScrollSaver;
|
||||||
//const realLength = this.scrollable.container.childElementCount;
|
this.messagesQueueOnRender = () => {
|
||||||
let previousScrollHeightMinusTop: number/* , previousScrollHeight: number */;
|
scrollSaver = new ScrollSaver(this.scrollable, reverse);
|
||||||
//if(realLength > 0/* && (reverse || isSafari) */) { // for safari need set when scrolling bottom too
|
scrollSaver.save();
|
||||||
//if(!this.scrollable.isHeavyScrolling) {
|
};
|
||||||
this.messagesQueueOnRender = () => {
|
|
||||||
const {scrollTop, scrollHeight} = this.scrollable;
|
|
||||||
|
|
||||||
//previousScrollHeight = scrollHeight;
|
|
||||||
//previousScrollHeight = scrollHeight + padding;
|
|
||||||
previousScrollHeightMinusTop = reverse ? scrollHeight - scrollTop : scrollTop;
|
|
||||||
|
|
||||||
//this.chatInner.style.paddingTop = padding + 'px';
|
|
||||||
/* if(reverse) {
|
|
||||||
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
|
||||||
} else {
|
|
||||||
previousScrollHeightMinusTop = scrollTop;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* if(DEBUG) {
|
|
||||||
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);
|
|
||||||
} */
|
|
||||||
this.messagesQueueOnRender = undefined;
|
|
||||||
};
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
if(this.needReflowScroll) {
|
if(this.needReflowScroll) {
|
||||||
reflowScrollableElement(this.scrollable.container);
|
reflowScrollableElement(this.scrollable.container);
|
||||||
@ -3916,44 +3895,8 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(previousScrollHeightMinusTop !== undefined) {
|
if(scrollSaver) {
|
||||||
/* const scrollHeight = this.scrollable.scrollHeight;
|
scrollSaver.restore();
|
||||||
const addedHeight = scrollHeight - previousScrollHeight;
|
|
||||||
|
|
||||||
this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */
|
|
||||||
/* const scrollHeight = this.scrollable.scrollHeight;
|
|
||||||
const addedHeight = scrollHeight - previousScrollHeight;
|
|
||||||
|
|
||||||
this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';
|
|
||||||
|
|
||||||
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
|
||||||
const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
|
||||||
this.log('performHistoryResult: will set scrollTop',
|
|
||||||
previousScrollHeightMinusTop, this.scrollable.scrollHeight,
|
|
||||||
newScrollTop, this.scrollable.container.clientHeight); */
|
|
||||||
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
|
||||||
const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
|
||||||
|
|
||||||
/* if(DEBUG) {
|
|
||||||
this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);
|
|
||||||
} */
|
|
||||||
|
|
||||||
// touchSupport for safari iOS
|
|
||||||
//isTouchSupported && isApple && (this.scrollable.container.style.overflow = 'hidden');
|
|
||||||
this.scrollable.scrollTop = newScrollTop;
|
|
||||||
//this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
|
||||||
//isTouchSupported && isApple && (this.scrollable.container.style.overflow = '');
|
|
||||||
|
|
||||||
this.scrollable.lastScrollPosition = newScrollTop;
|
|
||||||
this.scrollable.lastScrollDirection = 0;
|
|
||||||
|
|
||||||
if(IS_SAFARI/* && !isAppleMobile */) { // * fix blinking and jumping
|
|
||||||
reflowScrollableElement(this.scrollable.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if(DEBUG) {
|
|
||||||
this.log('performHistoryResult: have set up scrollTop:', newScrollTop, this.scrollable.scrollTop, this.scrollable.scrollHeight, this.isHeavyAnimationInProgress);
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
88
src/helpers/scrollSaver.ts
Normal file
88
src/helpers/scrollSaver.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Scrollable from "../components/scrollable";
|
||||||
|
import { IS_SAFARI } from "../environment/userAgent";
|
||||||
|
import reflowScrollableElement from "./dom/reflowScrollableElement";
|
||||||
|
|
||||||
|
export default class ScrollSaver {
|
||||||
|
private previousScrollHeightMinusTop: number/* , previousScrollHeight: number */;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param scrollable to reset scroll position and direction
|
||||||
|
* @param reverse true means top
|
||||||
|
*/
|
||||||
|
constructor(private scrollable: Scrollable, private reverse: boolean) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private get container() {
|
||||||
|
return this.scrollable.container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public save() {
|
||||||
|
const {scrollTop, scrollHeight} = this.container;
|
||||||
|
|
||||||
|
//previousScrollHeight = scrollHeight;
|
||||||
|
//previousScrollHeight = scrollHeight + padding;
|
||||||
|
this.previousScrollHeightMinusTop = this.reverse ? scrollHeight - scrollTop : scrollTop;
|
||||||
|
|
||||||
|
//this.chatInner.style.paddingTop = padding + 'px';
|
||||||
|
/* if(reverse) {
|
||||||
|
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
||||||
|
} else {
|
||||||
|
previousScrollHeightMinusTop = scrollTop;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* if(DEBUG) {
|
||||||
|
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
public restore() {
|
||||||
|
const {container, previousScrollHeightMinusTop, scrollable} = this;
|
||||||
|
if(previousScrollHeightMinusTop !== undefined) {
|
||||||
|
/* const scrollHeight = container.scrollHeight;
|
||||||
|
const addedHeight = scrollHeight - previousScrollHeight;
|
||||||
|
|
||||||
|
this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */
|
||||||
|
/* const scrollHeight = container.scrollHeight;
|
||||||
|
const addedHeight = scrollHeight - previousScrollHeight;
|
||||||
|
|
||||||
|
this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';
|
||||||
|
|
||||||
|
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
|
const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
|
this.log('performHistoryResult: will set scrollTop',
|
||||||
|
previousScrollHeightMinusTop, container.scrollHeight,
|
||||||
|
newScrollTop, container.container.clientHeight); */
|
||||||
|
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
|
const newScrollTop = this.reverse ? container.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
|
|
||||||
|
/* if(DEBUG) {
|
||||||
|
this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);
|
||||||
|
} */
|
||||||
|
|
||||||
|
// touchSupport for safari iOS
|
||||||
|
//isTouchSupported && isApple && (container.container.style.overflow = 'hidden');
|
||||||
|
container.scrollTop = newScrollTop;
|
||||||
|
//container.scrollTop = container.scrollHeight;
|
||||||
|
//isTouchSupported && isApple && (container.container.style.overflow = '');
|
||||||
|
|
||||||
|
scrollable.lastScrollPosition = newScrollTop;
|
||||||
|
scrollable.lastScrollDirection = 0;
|
||||||
|
|
||||||
|
if(IS_SAFARI/* && !isAppleMobile */) { // * fix blinking and jumping
|
||||||
|
reflowScrollableElement(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if(DEBUG) {
|
||||||
|
this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user