FIx unneeded webPage refresh
Fix locking scroll due to tab swipe on iOS
This commit is contained in:
parent
667fc3c9c6
commit
304bec801f
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/11.a97ce9270440a6cd8a3e.chunk.js
Normal file
2
public/11.a97ce9270440a6cd8a3e.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
public/11.a97ce9270440a6cd8a3e.chunk.js.map
Normal file
1
public/11.a97ce9270440a6cd8a3e.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/12.4f99b7f2fc6ca6315f85.chunk.js.map
Normal file
1
public/12.4f99b7f2fc6ca6315f85.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/14.3605b12524afb83c7e7d.chunk.js.map
Normal file
1
public/14.3605b12524afb83c7e7d.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/16.670a778fca8f140ea429.chunk.js
Normal file
2
public/16.670a778fca8f140ea429.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
public/16.670a778fca8f140ea429.chunk.js.map
Normal file
1
public/16.670a778fca8f140ea429.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/2.75b8ff80988010af15d6.chunk.js.map
Normal file
1
public/2.75b8ff80988010af15d6.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/3.d145506249c94d56cfe3.chunk.js
Normal file
2
public/3.d145506249c94d56cfe3.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
public/3.d145506249c94d56cfe3.chunk.js.map
Normal file
1
public/3.d145506249c94d56cfe3.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
public/6.5d3f830909ca4a58dd19.chunk.js
Normal file
2
public/6.5d3f830909ca4a58dd19.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
public/6.5d3f830909ca4a58dd19.chunk.js.map
Normal file
1
public/6.5d3f830909ca4a58dd19.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5
public/main.eb9b80adcd9d9c506f0c.css
Normal file
5
public/main.eb9b80adcd9d9c506f0c.css
Normal file
File diff suppressed because one or more lines are too long
1
public/main.eb9b80adcd9d9c506f0c.css.map
Normal file
1
public/main.eb9b80adcd9d9c506f0c.css.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -133,7 +133,7 @@ export default class ChatBubbles {
|
|||
private loadedTopTimes = 0;
|
||||
private loadedBottomTimes = 0;
|
||||
|
||||
private messagesQueuePromise: Promise<void> = null;
|
||||
public messagesQueuePromise: Promise<void> = null;
|
||||
private messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = [];
|
||||
private messagesQueueOnRender: () => void = null;
|
||||
private messagesQueueOnRenderAdditional: () => void = null;
|
||||
|
@ -1409,6 +1409,10 @@ export default class ChatBubbles {
|
|||
if(msgId > 0 && msgId <= maxId) {
|
||||
const bubble = this.bubbles[msgId];
|
||||
if(bubble) {
|
||||
if(bubble.classList.contains('is-sending')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bubble.classList.remove('is-sent', 'is-sending'); // is-sending can be when there are bulk of updates (e.g. sending command to Stickers bot)
|
||||
bubble.classList.add('is-read');
|
||||
}
|
||||
|
@ -1533,7 +1537,25 @@ export default class ChatBubbles {
|
|||
}
|
||||
}
|
||||
|
||||
return this.scrollable.scrollIntoViewNew(element, position, 4, undefined, forceDirection, forceDuration);
|
||||
return this.scrollable.scrollIntoViewNew(
|
||||
element,
|
||||
position,
|
||||
4,
|
||||
undefined,
|
||||
forceDirection,
|
||||
forceDuration,
|
||||
'y',
|
||||
({rect}) => {
|
||||
let height = windowSize.windowH;
|
||||
height -= this.chat.topbar.container.getBoundingClientRect().height;
|
||||
height -= 78;
|
||||
return height;
|
||||
|
||||
const rowsWrapperHeight = this.chat.input.rowsWrapper.getBoundingClientRect().height;
|
||||
const diff = rowsWrapperHeight - 54;
|
||||
return rect.height + diff;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public scrollToBubbleEnd(bubble = this.getLastBubble()) {
|
||||
|
|
|
@ -82,7 +82,6 @@ import PopupPeer from '../popups/peer';
|
|||
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
||||
import appMediaPlaybackController from '../appMediaPlaybackController';
|
||||
import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
|
||||
import replaceContent from '../../helpers/dom/replaceContent';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
|
@ -776,6 +775,14 @@ export default class ChatInput {
|
|||
draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);
|
||||
|
||||
if(!draft) {
|
||||
if(force) { // this situation can only happen when sending message with clearDraft
|
||||
((this.chat.bubbles.messagesQueuePromise || Promise.resolve()) as Promise<any>).then(() => {
|
||||
fastRaf(() => {
|
||||
this.onMessageSent();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -921,6 +928,7 @@ export default class ChatInput {
|
|||
private attachMessageInputListeners() {
|
||||
this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {
|
||||
if(isSendShortcutPressed(e)) {
|
||||
cancelEvent(e);
|
||||
this.sendMessage();
|
||||
} else if(e.ctrlKey || e.metaKey) {
|
||||
this.handleMarkdownShortcut(e);
|
||||
|
@ -1758,6 +1766,8 @@ export default class ChatInput {
|
|||
entities,
|
||||
noWebPage: this.noWebPage
|
||||
});
|
||||
|
||||
this.onMessageSent();
|
||||
} else {
|
||||
new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);
|
||||
|
||||
|
@ -1774,6 +1784,9 @@ export default class ChatInput {
|
|||
silent: this.sendSilent,
|
||||
clearDraft: true
|
||||
});
|
||||
|
||||
this.onMessageSent(false, false);
|
||||
// this.onMessageSent();
|
||||
}
|
||||
|
||||
// * wait for sendText set messageId for invokeAfterMsg
|
||||
|
@ -1792,7 +1805,7 @@ export default class ChatInput {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
this.onMessageSent();
|
||||
// this.onMessageSent();
|
||||
}
|
||||
|
||||
public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {
|
||||
|
@ -1934,12 +1947,12 @@ export default class ChatInput {
|
|||
if(message._ === 'messageEmpty') { // load missing replying message
|
||||
peerTitleEl = i18n('Loading');
|
||||
|
||||
this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then(() => {
|
||||
this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then((_message) => {
|
||||
if(this.replyToMsgId !== mid) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = this.chat.getMessage(mid);
|
||||
message = _message;
|
||||
if(message._ === 'messageEmpty') {
|
||||
this.clearHelper('reply');
|
||||
} else {
|
||||
|
|
|
@ -93,7 +93,7 @@ class InputField {
|
|||
public validate: () => boolean;
|
||||
|
||||
//public onLengthChange: (length: number, isOverflow: boolean) => void;
|
||||
protected wasInputFakeClientHeight: number;
|
||||
// protected wasInputFakeClientHeight: number;
|
||||
// protected showScrollDebounced: () => void;
|
||||
|
||||
constructor(public options: InputFieldOptions = {}) {
|
||||
|
@ -147,7 +147,7 @@ class InputField {
|
|||
|
||||
if(options.animate) {
|
||||
input.classList.add('scrollable', 'scrollable-y');
|
||||
this.wasInputFakeClientHeight = 0;
|
||||
// this.wasInputFakeClientHeight = 0;
|
||||
// this.showScrollDebounced = debounce(() => this.input.classList.remove('no-scrollbar'), 150, false, true);
|
||||
this.inputFake = document.createElement('div');
|
||||
this.inputFake.setAttribute('contenteditable', 'true');
|
||||
|
@ -237,14 +237,21 @@ class InputField {
|
|||
}
|
||||
|
||||
public onFakeInput() {
|
||||
const {scrollHeight, clientHeight} = this.inputFake;
|
||||
const {scrollHeight: newHeight/* , clientHeight */} = this.inputFake;
|
||||
/* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {
|
||||
this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow.
|
||||
this.showScrollDebounced();
|
||||
} */
|
||||
|
||||
this.wasInputFakeClientHeight = clientHeight;
|
||||
this.input.style.height = scrollHeight ? scrollHeight + 'px' : '';
|
||||
const TRANSITION_DURATION_FACTOR = 50;
|
||||
const currentHeight = +this.input.style.height.replace('px', '');
|
||||
const transitionDuration = Math.round(
|
||||
TRANSITION_DURATION_FACTOR * Math.log(Math.abs(newHeight - currentHeight)),
|
||||
);
|
||||
|
||||
// this.wasInputFakeClientHeight = clientHeight;
|
||||
this.input.style.transitionDuration = `${transitionDuration}ms`;
|
||||
this.input.style.height = newHeight ? newHeight + 'px' : '';
|
||||
}
|
||||
|
||||
get value() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
|
||||
import { logger, LogTypes } from "../lib/logger";
|
||||
import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll";
|
||||
import fastSmoothScroll, { FocusDirection, ScrollGetNormalSizeCallback } from "../helpers/fastSmoothScroll";
|
||||
import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck";
|
||||
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||
/*
|
||||
|
@ -106,10 +106,11 @@ export class ScrollableBase {
|
|||
maxDistance?: number,
|
||||
forceDirection?: FocusDirection,
|
||||
forceDuration?: number,
|
||||
axis?: 'x' | 'y'
|
||||
axis?: 'x' | 'y',
|
||||
getNormalSize?: ScrollGetNormalSizeCallback
|
||||
) {
|
||||
//return Promise.resolve();
|
||||
return fastSmoothScroll(this.container, element, position, margin, maxDistance, forceDirection, forceDuration, axis);
|
||||
return fastSmoothScroll(this.container, element, position, margin, maxDistance, forceDirection, forceDuration, axis, getNormalSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import SwipeHandler, { SwipeHandlerOptions } from "../../components/swipeHandler";
|
||||
import { IS_APPLE_MOBILE, IS_SAFARI } from "../../environment/userAgent";
|
||||
import { cancelEvent } from "./cancelEvent";
|
||||
import findUpClassName from "./findUpClassName";
|
||||
import isSwipingBackSafari from "./isSwipingBackSafari";
|
||||
|
@ -45,6 +44,6 @@ export default function handleHorizontalSwipe(options: SwipeHandlerHorizontalOpt
|
|||
cancelY = false;
|
||||
options.onReset && options.onReset();
|
||||
},
|
||||
cancelEvent: true
|
||||
cancelEvent: false // cannot use cancelEvent on Safari iOS because scroll will be canceled too
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,9 +12,10 @@ import { animateSingle, cancelAnimationByKey } from './animation';
|
|||
import rootScope from '../lib/rootScope';
|
||||
import isInDOM from './dom/isInDOM';
|
||||
|
||||
const MAX_DISTANCE = 1500;
|
||||
const MIN_JS_DURATION = 250;
|
||||
const MAX_JS_DURATION = 600;
|
||||
const LONG_TRANSITION_MAX_DISTANCE = 1500;
|
||||
const SHORT_TRANSITION_MAX_DISTANCE = 500;
|
||||
|
||||
export enum FocusDirection {
|
||||
Up,
|
||||
|
@ -22,15 +23,18 @@ export enum FocusDirection {
|
|||
Static,
|
||||
};
|
||||
|
||||
export type ScrollGetNormalSizeCallback = (options: {rect: DOMRect}) => number;
|
||||
|
||||
export default function fastSmoothScroll(
|
||||
container: HTMLElement,
|
||||
element: HTMLElement,
|
||||
position: ScrollLogicalPosition,
|
||||
margin = 0,
|
||||
maxDistance = MAX_DISTANCE,
|
||||
maxDistance = LONG_TRANSITION_MAX_DISTANCE,
|
||||
forceDirection?: FocusDirection,
|
||||
forceDuration?: number,
|
||||
axis: 'x' | 'y' = 'y'
|
||||
axis: 'x' | 'y' = 'y',
|
||||
getNormalSize?: ScrollGetNormalSizeCallback
|
||||
) {
|
||||
//return;
|
||||
|
||||
|
@ -40,7 +44,7 @@ export default function fastSmoothScroll(
|
|||
|
||||
if(forceDirection === FocusDirection.Static) {
|
||||
forceDuration = 0;
|
||||
return scrollWithJs(container, element, position, margin, forceDuration, axis);
|
||||
return scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize);
|
||||
/* return Promise.resolve();
|
||||
|
||||
element.scrollIntoView({ block: position });
|
||||
|
@ -82,9 +86,9 @@ export default function fastSmoothScroll(
|
|||
} */
|
||||
}
|
||||
|
||||
const promise = new Promise((resolve) => {
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
fastRaf(() => {
|
||||
scrollWithJs(container, element, position, margin, forceDuration, axis)
|
||||
scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize)
|
||||
.then(resolve);
|
||||
});
|
||||
});
|
||||
|
@ -93,7 +97,13 @@ export default function fastSmoothScroll(
|
|||
}
|
||||
|
||||
function scrollWithJs(
|
||||
container: HTMLElement, element: HTMLElement, position: ScrollLogicalPosition, margin = 0, forceDuration?: number, axis: 'x' | 'y' = 'y'
|
||||
container: HTMLElement,
|
||||
element: HTMLElement,
|
||||
position: ScrollLogicalPosition,
|
||||
margin = 0,
|
||||
forceDuration?: number,
|
||||
axis: 'x' | 'y' = 'y',
|
||||
getNormalSize?: ScrollGetNormalSizeCallback
|
||||
) {
|
||||
if(!isInDOM(element)) {
|
||||
cancelAnimationByKey(container);
|
||||
|
@ -115,7 +125,7 @@ function scrollWithJs(
|
|||
const elementPosition = elementRect[rectStartKey] - containerRect[rectStartKey];
|
||||
const elementSize = element[scrollSizeKey]; // margin is exclusive in DOMRect
|
||||
|
||||
const containerSize = containerRect[sizeKey];
|
||||
const containerSize = getNormalSize ? getNormalSize({rect: containerRect}) : containerRect[sizeKey];
|
||||
|
||||
const scrollPosition = container[scrollPositionKey];
|
||||
const scrollSize = container[scrollSizeKey];
|
||||
|
@ -177,8 +187,9 @@ function scrollWithJs(
|
|||
}
|
||||
|
||||
const target = container[scrollPositionKey] + path;
|
||||
const absPath = Math.abs(path);
|
||||
const duration = forceDuration ?? (
|
||||
MIN_JS_DURATION + (Math.abs(path) / MAX_DISTANCE) * (MAX_JS_DURATION - MIN_JS_DURATION)
|
||||
MIN_JS_DURATION + (absPath / LONG_TRANSITION_MAX_DISTANCE) * (MAX_JS_DURATION - MIN_JS_DURATION)
|
||||
);
|
||||
const startAt = Date.now();
|
||||
|
||||
|
@ -222,6 +233,7 @@ function scrollWithJs(
|
|||
//transformable.style.minHeight = `${transformableHeight}px`;
|
||||
*/
|
||||
|
||||
const transition = absPath < SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
|
||||
const tick = () => {
|
||||
const t = duration ? Math.min((Date.now() - startAt) / duration, 1) : 1;
|
||||
|
||||
|
@ -258,6 +270,10 @@ function scrollWithJs(
|
|||
return animateSingle(tick, container);
|
||||
}
|
||||
|
||||
function transition(t: number) {
|
||||
function longTransition(t: number) {
|
||||
return 1 - ((1 - t) ** 5);
|
||||
}
|
||||
|
||||
function shortTransition(t: number) {
|
||||
return 1 - ((1 - t) ** 3.5);
|
||||
}
|
||||
|
|
4
src/layer.d.ts
vendored
4
src/layer.d.ts
vendored
|
@ -816,7 +816,9 @@ export namespace Message {
|
|||
flags?: number,
|
||||
id: number,
|
||||
peer_id?: Peer,
|
||||
deleted?: boolean
|
||||
deleted?: boolean,
|
||||
mid?: number,
|
||||
pFlags?: {}
|
||||
};
|
||||
|
||||
export type message = {
|
||||
|
|
|
@ -251,7 +251,7 @@ export class AppDraftsManager {
|
|||
if(threadId) {
|
||||
this.syncDraft(peerId, threadId);
|
||||
} else {
|
||||
this.saveDraft(peerId, threadId, null, {notify: true/* , force: true */});
|
||||
this.saveDraft(peerId, threadId, null, {notify: true, force: true});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -501,16 +501,22 @@ export class AppImManager {
|
|||
return;
|
||||
}
|
||||
|
||||
if(chat.input.messageInput &&
|
||||
if(
|
||||
chat?.input?.messageInput &&
|
||||
e.target !== chat.input.messageInput &&
|
||||
target.tagName !== 'INPUT' &&
|
||||
!target.hasAttribute('contenteditable') &&
|
||||
!IS_TOUCH_SUPPORTED &&
|
||||
(!mediaSizes.isMobile || this.tabId === 1) &&
|
||||
!this.chat.selection.isSelecting &&
|
||||
!this.chat.input.recording) {
|
||||
!chat.selection.isSelecting &&
|
||||
!chat.input.recording
|
||||
) {
|
||||
chat.input.messageInput.focus();
|
||||
placeCaretAtEnd(chat.input.messageInput);
|
||||
|
||||
// clone and dispatch same event to new input. it is needed for sending message if input was blurred
|
||||
const newEvent = new KeyboardEvent(e.type, e);
|
||||
chat.input.messageInput.dispatchEvent(newEvent);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1073,7 +1073,7 @@ export class AppMessagesManager {
|
|||
|
||||
const messages = files.map((file, idx) => {
|
||||
const details = options.sendFileDetails[idx];
|
||||
const o: any = {
|
||||
const o: Parameters<AppMessagesManager['sendFile']>[2] = {
|
||||
isGroupedItem: true,
|
||||
isMedia: options.isMedia,
|
||||
scheduleDate: options.scheduleDate,
|
||||
|
@ -1094,7 +1094,9 @@ export class AppMessagesManager {
|
|||
});
|
||||
|
||||
if(options.clearDraft) {
|
||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||
setTimeout(() => {
|
||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// * test pending
|
||||
|
@ -1407,10 +1409,6 @@ export class AppMessagesManager {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
if(!options.isGroupedItem && options.clearDraft) {
|
||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||
}
|
||||
|
||||
this.pendingByRandomId[message.random_id] = {
|
||||
peerId,
|
||||
tempId: messageId,
|
||||
|
@ -1419,9 +1417,13 @@ export class AppMessagesManager {
|
|||
};
|
||||
|
||||
if(!options.isGroupedItem && message.send) {
|
||||
setTimeout(message.send, 0);
|
||||
//setTimeout(message.send, 4000);
|
||||
//setTimeout(message.send, 7000);
|
||||
setTimeout(() => {
|
||||
if(options.clearDraft) {
|
||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||
}
|
||||
|
||||
message.send();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1966,15 +1968,20 @@ export class AppMessagesManager {
|
|||
return promise;
|
||||
}
|
||||
|
||||
public getMessageFromStorage(storage: MessagesStorage, mid: number) {
|
||||
return storage && storage.get(mid) || {
|
||||
public generateEmptyMessage(mid: number): Message.messageEmpty {
|
||||
return {
|
||||
_: 'messageEmpty',
|
||||
id: mid,
|
||||
id: appMessagesIdsManager.getServerMessageId(mid),
|
||||
mid,
|
||||
deleted: true,
|
||||
pFlags: {}
|
||||
};
|
||||
}
|
||||
|
||||
public getMessageFromStorage(storage: MessagesStorage, mid: number) {
|
||||
return storage && storage.get(mid) || this.generateEmptyMessage(mid);
|
||||
}
|
||||
|
||||
private createMessageStorage() {
|
||||
const storage: MessagesStorage = new Map();
|
||||
|
||||
|
@ -5455,7 +5462,6 @@ export class AppMessagesManager {
|
|||
|
||||
for(const [peerId, map] of this.needSingleMessages) {
|
||||
const mids = [...map.keys()];
|
||||
const promises = [...map.values()];
|
||||
const msgIds: InputMessage[] = mids.map((mid) => {
|
||||
return {
|
||||
_: 'inputMessageID',
|
||||
|
@ -5483,8 +5489,17 @@ export class AppMessagesManager {
|
|||
this.saveMessages(getMessagesResult.messages);
|
||||
|
||||
for(let i = 0; i < getMessagesResult.messages.length; ++i) {
|
||||
const promise = promises[i];
|
||||
const message = getMessagesResult.messages[i];
|
||||
const mid = appMessagesIdsManager.generateMessageId(message.id);
|
||||
const promise = map.get(mid);
|
||||
promise.resolve(getMessagesResult.messages[i]);
|
||||
map.delete(mid);
|
||||
}
|
||||
|
||||
if(map.size) {
|
||||
for(const [mid, promise] of map) {
|
||||
promise.resolve(this.generateEmptyMessage(mid));
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
rootScope.dispatchEvent('messages_downloaded', {peerId, mids});
|
||||
|
@ -5497,7 +5512,7 @@ export class AppMessagesManager {
|
|||
|
||||
Promise.all(requestPromises).finally(() => {
|
||||
this.fetchSingleMessagesPromise = null;
|
||||
if(Object.keys(this.needSingleMessages).length) this.fetchSingleMessages();
|
||||
if(this.needSingleMessages.size) this.fetchSingleMessages();
|
||||
resolve();
|
||||
});
|
||||
}, 0);
|
||||
|
|
|
@ -43,6 +43,13 @@ export class AppWebPagesManager {
|
|||
if(apiWebPage._ === 'webPageNotModified') return;
|
||||
const {id} = apiWebPage;
|
||||
|
||||
const oldWebPage = this.webpages[id];
|
||||
if(oldWebPage &&
|
||||
oldWebPage._ === apiWebPage._ &&
|
||||
(oldWebPage as WebPage.webPage).hash === (oldWebPage as WebPage.webPage).hash) {
|
||||
return oldWebPage;
|
||||
}
|
||||
|
||||
if(apiWebPage._ === 'webPage') {
|
||||
if(apiWebPage.photo?._ === 'photo') {
|
||||
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
|
||||
|
@ -97,10 +104,10 @@ export class AppWebPagesManager {
|
|||
pendingSet.add(messageKey);
|
||||
}
|
||||
|
||||
if(this.webpages[id] === undefined) {
|
||||
if(oldWebPage === undefined) {
|
||||
this.webpages[id] = apiWebPage;
|
||||
} else {
|
||||
safeReplaceObject(this.webpages[id], apiWebPage);
|
||||
safeReplaceObject(oldWebPage, apiWebPage);
|
||||
}
|
||||
|
||||
if(!messageKey && pendingSet !== undefined) {
|
||||
|
|
|
@ -99,7 +99,9 @@
|
|||
}, {
|
||||
"predicate": "messageEmpty",
|
||||
"params": [
|
||||
{"name": "deleted", "type": "boolean"}
|
||||
{"name": "deleted", "type": "boolean"},
|
||||
{"name": "mid", "type": "number"},
|
||||
{"name": "pFlags", "type": "{}"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "userFull",
|
||||
|
|
|
@ -917,7 +917,8 @@ $chat-helper-size: 36px;
|
|||
pointer-events: none;
|
||||
|
||||
@include animation-level(2) {
|
||||
transition: height var(--layer-transition), opacity var(--layer-transition);
|
||||
// transition: height var(--layer-transition), opacity var(--layer-transition);
|
||||
transition: height .15s ease-out, opacity .15s ease-out;
|
||||
}
|
||||
|
||||
@include respond-to(esg-bottom-new) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user