FIx unneeded webPage refresh
Fix locking scroll due to tab swipe on iOS
This commit is contained in:
parent
5e02b7dce9
commit
409f30d806
@ -133,7 +133,7 @@ export default class ChatBubbles {
|
|||||||
private loadedTopTimes = 0;
|
private loadedTopTimes = 0;
|
||||||
private loadedBottomTimes = 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 messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = [];
|
||||||
private messagesQueueOnRender: () => void = null;
|
private messagesQueueOnRender: () => void = null;
|
||||||
private messagesQueueOnRenderAdditional: () => void = null;
|
private messagesQueueOnRenderAdditional: () => void = null;
|
||||||
@ -1409,6 +1409,10 @@ export default class ChatBubbles {
|
|||||||
if(msgId > 0 && msgId <= maxId) {
|
if(msgId > 0 && msgId <= maxId) {
|
||||||
const bubble = this.bubbles[msgId];
|
const bubble = this.bubbles[msgId];
|
||||||
if(bubble) {
|
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.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');
|
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()) {
|
public scrollToBubbleEnd(bubble = this.getLastBubble()) {
|
||||||
|
@ -82,7 +82,6 @@ import PopupPeer from '../popups/peer';
|
|||||||
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
||||||
import appMediaPlaybackController from '../appMediaPlaybackController';
|
import appMediaPlaybackController from '../appMediaPlaybackController';
|
||||||
import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
|
import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
|
||||||
import replaceContent from '../../helpers/dom/replaceContent';
|
|
||||||
|
|
||||||
const RECORD_MIN_TIME = 500;
|
const RECORD_MIN_TIME = 500;
|
||||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
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);
|
draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);
|
||||||
|
|
||||||
if(!draft) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -921,6 +928,7 @@ export default class ChatInput {
|
|||||||
private attachMessageInputListeners() {
|
private attachMessageInputListeners() {
|
||||||
this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {
|
this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {
|
||||||
if(isSendShortcutPressed(e)) {
|
if(isSendShortcutPressed(e)) {
|
||||||
|
cancelEvent(e);
|
||||||
this.sendMessage();
|
this.sendMessage();
|
||||||
} else if(e.ctrlKey || e.metaKey) {
|
} else if(e.ctrlKey || e.metaKey) {
|
||||||
this.handleMarkdownShortcut(e);
|
this.handleMarkdownShortcut(e);
|
||||||
@ -1758,6 +1766,8 @@ export default class ChatInput {
|
|||||||
entities,
|
entities,
|
||||||
noWebPage: this.noWebPage
|
noWebPage: this.noWebPage
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.onMessageSent();
|
||||||
} else {
|
} else {
|
||||||
new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);
|
new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);
|
||||||
|
|
||||||
@ -1774,6 +1784,9 @@ export default class ChatInput {
|
|||||||
silent: this.sendSilent,
|
silent: this.sendSilent,
|
||||||
clearDraft: true
|
clearDraft: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.onMessageSent(false, false);
|
||||||
|
// this.onMessageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// * wait for sendText set messageId for invokeAfterMsg
|
// * wait for sendText set messageId for invokeAfterMsg
|
||||||
@ -1792,7 +1805,7 @@ export default class ChatInput {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onMessageSent();
|
// this.onMessageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {
|
public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {
|
||||||
@ -1934,12 +1947,12 @@ export default class ChatInput {
|
|||||||
if(message._ === 'messageEmpty') { // load missing replying message
|
if(message._ === 'messageEmpty') { // load missing replying message
|
||||||
peerTitleEl = i18n('Loading');
|
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) {
|
if(this.replyToMsgId !== mid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message = this.chat.getMessage(mid);
|
message = _message;
|
||||||
if(message._ === 'messageEmpty') {
|
if(message._ === 'messageEmpty') {
|
||||||
this.clearHelper('reply');
|
this.clearHelper('reply');
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +93,7 @@ class InputField {
|
|||||||
public validate: () => boolean;
|
public validate: () => boolean;
|
||||||
|
|
||||||
//public onLengthChange: (length: number, isOverflow: boolean) => void;
|
//public onLengthChange: (length: number, isOverflow: boolean) => void;
|
||||||
protected wasInputFakeClientHeight: number;
|
// protected wasInputFakeClientHeight: number;
|
||||||
// protected showScrollDebounced: () => void;
|
// protected showScrollDebounced: () => void;
|
||||||
|
|
||||||
constructor(public options: InputFieldOptions = {}) {
|
constructor(public options: InputFieldOptions = {}) {
|
||||||
@ -147,7 +147,7 @@ class InputField {
|
|||||||
|
|
||||||
if(options.animate) {
|
if(options.animate) {
|
||||||
input.classList.add('scrollable', 'scrollable-y');
|
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.showScrollDebounced = debounce(() => this.input.classList.remove('no-scrollbar'), 150, false, true);
|
||||||
this.inputFake = document.createElement('div');
|
this.inputFake = document.createElement('div');
|
||||||
this.inputFake.setAttribute('contenteditable', 'true');
|
this.inputFake.setAttribute('contenteditable', 'true');
|
||||||
@ -237,14 +237,21 @@ class InputField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onFakeInput() {
|
public onFakeInput() {
|
||||||
const {scrollHeight, clientHeight} = this.inputFake;
|
const {scrollHeight: newHeight/* , clientHeight */} = this.inputFake;
|
||||||
/* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {
|
/* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {
|
||||||
this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow.
|
this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow.
|
||||||
this.showScrollDebounced();
|
this.showScrollDebounced();
|
||||||
} */
|
} */
|
||||||
|
|
||||||
this.wasInputFakeClientHeight = clientHeight;
|
const TRANSITION_DURATION_FACTOR = 50;
|
||||||
this.input.style.height = scrollHeight ? scrollHeight + 'px' : '';
|
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() {
|
get value() {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
|
import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
|
||||||
import { logger, LogTypes } from "../lib/logger";
|
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 useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck";
|
||||||
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||||
/*
|
/*
|
||||||
@ -106,10 +106,11 @@ export class ScrollableBase {
|
|||||||
maxDistance?: number,
|
maxDistance?: number,
|
||||||
forceDirection?: FocusDirection,
|
forceDirection?: FocusDirection,
|
||||||
forceDuration?: number,
|
forceDuration?: number,
|
||||||
axis?: 'x' | 'y'
|
axis?: 'x' | 'y',
|
||||||
|
getNormalSize?: ScrollGetNormalSizeCallback
|
||||||
) {
|
) {
|
||||||
//return Promise.resolve();
|
//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 SwipeHandler, { SwipeHandlerOptions } from "../../components/swipeHandler";
|
||||||
import { IS_APPLE_MOBILE, IS_SAFARI } from "../../environment/userAgent";
|
|
||||||
import { cancelEvent } from "./cancelEvent";
|
import { cancelEvent } from "./cancelEvent";
|
||||||
import findUpClassName from "./findUpClassName";
|
import findUpClassName from "./findUpClassName";
|
||||||
import isSwipingBackSafari from "./isSwipingBackSafari";
|
import isSwipingBackSafari from "./isSwipingBackSafari";
|
||||||
@ -45,6 +44,6 @@ export default function handleHorizontalSwipe(options: SwipeHandlerHorizontalOpt
|
|||||||
cancelY = false;
|
cancelY = false;
|
||||||
options.onReset && options.onReset();
|
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 rootScope from '../lib/rootScope';
|
||||||
import isInDOM from './dom/isInDOM';
|
import isInDOM from './dom/isInDOM';
|
||||||
|
|
||||||
const MAX_DISTANCE = 1500;
|
|
||||||
const MIN_JS_DURATION = 250;
|
const MIN_JS_DURATION = 250;
|
||||||
const MAX_JS_DURATION = 600;
|
const MAX_JS_DURATION = 600;
|
||||||
|
const LONG_TRANSITION_MAX_DISTANCE = 1500;
|
||||||
|
const SHORT_TRANSITION_MAX_DISTANCE = 500;
|
||||||
|
|
||||||
export enum FocusDirection {
|
export enum FocusDirection {
|
||||||
Up,
|
Up,
|
||||||
@ -22,15 +23,18 @@ export enum FocusDirection {
|
|||||||
Static,
|
Static,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ScrollGetNormalSizeCallback = (options: {rect: DOMRect}) => number;
|
||||||
|
|
||||||
export default function fastSmoothScroll(
|
export default function fastSmoothScroll(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
position: ScrollLogicalPosition,
|
position: ScrollLogicalPosition,
|
||||||
margin = 0,
|
margin = 0,
|
||||||
maxDistance = MAX_DISTANCE,
|
maxDistance = LONG_TRANSITION_MAX_DISTANCE,
|
||||||
forceDirection?: FocusDirection,
|
forceDirection?: FocusDirection,
|
||||||
forceDuration?: number,
|
forceDuration?: number,
|
||||||
axis: 'x' | 'y' = 'y'
|
axis: 'x' | 'y' = 'y',
|
||||||
|
getNormalSize?: ScrollGetNormalSizeCallback
|
||||||
) {
|
) {
|
||||||
//return;
|
//return;
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ export default function fastSmoothScroll(
|
|||||||
|
|
||||||
if(forceDirection === FocusDirection.Static) {
|
if(forceDirection === FocusDirection.Static) {
|
||||||
forceDuration = 0;
|
forceDuration = 0;
|
||||||
return scrollWithJs(container, element, position, margin, forceDuration, axis);
|
return scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize);
|
||||||
/* return Promise.resolve();
|
/* return Promise.resolve();
|
||||||
|
|
||||||
element.scrollIntoView({ block: position });
|
element.scrollIntoView({ block: position });
|
||||||
@ -82,9 +86,9 @@ export default function fastSmoothScroll(
|
|||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
const promise = new Promise((resolve) => {
|
const promise = new Promise<void>((resolve) => {
|
||||||
fastRaf(() => {
|
fastRaf(() => {
|
||||||
scrollWithJs(container, element, position, margin, forceDuration, axis)
|
scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize)
|
||||||
.then(resolve);
|
.then(resolve);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -93,7 +97,13 @@ export default function fastSmoothScroll(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function scrollWithJs(
|
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)) {
|
if(!isInDOM(element)) {
|
||||||
cancelAnimationByKey(container);
|
cancelAnimationByKey(container);
|
||||||
@ -115,7 +125,7 @@ function scrollWithJs(
|
|||||||
const elementPosition = elementRect[rectStartKey] - containerRect[rectStartKey];
|
const elementPosition = elementRect[rectStartKey] - containerRect[rectStartKey];
|
||||||
const elementSize = element[scrollSizeKey]; // margin is exclusive in DOMRect
|
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 scrollPosition = container[scrollPositionKey];
|
||||||
const scrollSize = container[scrollSizeKey];
|
const scrollSize = container[scrollSizeKey];
|
||||||
@ -177,8 +187,9 @@ function scrollWithJs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const target = container[scrollPositionKey] + path;
|
const target = container[scrollPositionKey] + path;
|
||||||
|
const absPath = Math.abs(path);
|
||||||
const duration = forceDuration ?? (
|
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();
|
const startAt = Date.now();
|
||||||
|
|
||||||
@ -222,6 +233,7 @@ function scrollWithJs(
|
|||||||
//transformable.style.minHeight = `${transformableHeight}px`;
|
//transformable.style.minHeight = `${transformableHeight}px`;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const transition = absPath < SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
const t = duration ? Math.min((Date.now() - startAt) / duration, 1) : 1;
|
const t = duration ? Math.min((Date.now() - startAt) / duration, 1) : 1;
|
||||||
|
|
||||||
@ -258,6 +270,10 @@ function scrollWithJs(
|
|||||||
return animateSingle(tick, container);
|
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);
|
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,
|
flags?: number,
|
||||||
id: number,
|
id: number,
|
||||||
peer_id?: Peer,
|
peer_id?: Peer,
|
||||||
deleted?: boolean
|
deleted?: boolean,
|
||||||
|
mid?: number,
|
||||||
|
pFlags?: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type message = {
|
export type message = {
|
||||||
|
@ -251,7 +251,7 @@ export class AppDraftsManager {
|
|||||||
if(threadId) {
|
if(threadId) {
|
||||||
this.syncDraft(peerId, threadId);
|
this.syncDraft(peerId, threadId);
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chat.input.messageInput &&
|
if(
|
||||||
|
chat?.input?.messageInput &&
|
||||||
e.target !== chat.input.messageInput &&
|
e.target !== chat.input.messageInput &&
|
||||||
target.tagName !== 'INPUT' &&
|
target.tagName !== 'INPUT' &&
|
||||||
!target.hasAttribute('contenteditable') &&
|
!target.hasAttribute('contenteditable') &&
|
||||||
!IS_TOUCH_SUPPORTED &&
|
!IS_TOUCH_SUPPORTED &&
|
||||||
(!mediaSizes.isMobile || this.tabId === 1) &&
|
(!mediaSizes.isMobile || this.tabId === 1) &&
|
||||||
!this.chat.selection.isSelecting &&
|
!chat.selection.isSelecting &&
|
||||||
!this.chat.input.recording) {
|
!chat.input.recording
|
||||||
|
) {
|
||||||
chat.input.messageInput.focus();
|
chat.input.messageInput.focus();
|
||||||
placeCaretAtEnd(chat.input.messageInput);
|
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 messages = files.map((file, idx) => {
|
||||||
const details = options.sendFileDetails[idx];
|
const details = options.sendFileDetails[idx];
|
||||||
const o: any = {
|
const o: Parameters<AppMessagesManager['sendFile']>[2] = {
|
||||||
isGroupedItem: true,
|
isGroupedItem: true,
|
||||||
isMedia: options.isMedia,
|
isMedia: options.isMedia,
|
||||||
scheduleDate: options.scheduleDate,
|
scheduleDate: options.scheduleDate,
|
||||||
@ -1094,7 +1094,9 @@ export class AppMessagesManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(options.clearDraft) {
|
if(options.clearDraft) {
|
||||||
|
setTimeout(() => {
|
||||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// * test pending
|
// * test pending
|
||||||
@ -1407,10 +1409,6 @@ export class AppMessagesManager {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!options.isGroupedItem && options.clearDraft) {
|
|
||||||
appDraftsManager.clearDraft(peerId, options.threadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pendingByRandomId[message.random_id] = {
|
this.pendingByRandomId[message.random_id] = {
|
||||||
peerId,
|
peerId,
|
||||||
tempId: messageId,
|
tempId: messageId,
|
||||||
@ -1419,9 +1417,13 @@ export class AppMessagesManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if(!options.isGroupedItem && message.send) {
|
if(!options.isGroupedItem && message.send) {
|
||||||
setTimeout(message.send, 0);
|
setTimeout(() => {
|
||||||
//setTimeout(message.send, 4000);
|
if(options.clearDraft) {
|
||||||
//setTimeout(message.send, 7000);
|
appDraftsManager.clearDraft(peerId, options.threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
message.send();
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1966,15 +1968,20 @@ export class AppMessagesManager {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMessageFromStorage(storage: MessagesStorage, mid: number) {
|
public generateEmptyMessage(mid: number): Message.messageEmpty {
|
||||||
return storage && storage.get(mid) || {
|
return {
|
||||||
_: 'messageEmpty',
|
_: 'messageEmpty',
|
||||||
id: mid,
|
id: appMessagesIdsManager.getServerMessageId(mid),
|
||||||
|
mid,
|
||||||
deleted: true,
|
deleted: true,
|
||||||
pFlags: {}
|
pFlags: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getMessageFromStorage(storage: MessagesStorage, mid: number) {
|
||||||
|
return storage && storage.get(mid) || this.generateEmptyMessage(mid);
|
||||||
|
}
|
||||||
|
|
||||||
private createMessageStorage() {
|
private createMessageStorage() {
|
||||||
const storage: MessagesStorage = new Map();
|
const storage: MessagesStorage = new Map();
|
||||||
|
|
||||||
@ -5455,7 +5462,6 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
for(const [peerId, map] of this.needSingleMessages) {
|
for(const [peerId, map] of this.needSingleMessages) {
|
||||||
const mids = [...map.keys()];
|
const mids = [...map.keys()];
|
||||||
const promises = [...map.values()];
|
|
||||||
const msgIds: InputMessage[] = mids.map((mid) => {
|
const msgIds: InputMessage[] = mids.map((mid) => {
|
||||||
return {
|
return {
|
||||||
_: 'inputMessageID',
|
_: 'inputMessageID',
|
||||||
@ -5483,8 +5489,17 @@ export class AppMessagesManager {
|
|||||||
this.saveMessages(getMessagesResult.messages);
|
this.saveMessages(getMessagesResult.messages);
|
||||||
|
|
||||||
for(let i = 0; i < getMessagesResult.messages.length; ++i) {
|
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]);
|
promise.resolve(getMessagesResult.messages[i]);
|
||||||
|
map.delete(mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map.size) {
|
||||||
|
for(const [mid, promise] of map) {
|
||||||
|
promise.resolve(this.generateEmptyMessage(mid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
rootScope.dispatchEvent('messages_downloaded', {peerId, mids});
|
rootScope.dispatchEvent('messages_downloaded', {peerId, mids});
|
||||||
@ -5497,7 +5512,7 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
Promise.all(requestPromises).finally(() => {
|
Promise.all(requestPromises).finally(() => {
|
||||||
this.fetchSingleMessagesPromise = null;
|
this.fetchSingleMessagesPromise = null;
|
||||||
if(Object.keys(this.needSingleMessages).length) this.fetchSingleMessages();
|
if(this.needSingleMessages.size) this.fetchSingleMessages();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -43,6 +43,13 @@ export class AppWebPagesManager {
|
|||||||
if(apiWebPage._ === 'webPageNotModified') return;
|
if(apiWebPage._ === 'webPageNotModified') return;
|
||||||
const {id} = apiWebPage;
|
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._ === 'webPage') {
|
||||||
if(apiWebPage.photo?._ === 'photo') {
|
if(apiWebPage.photo?._ === 'photo') {
|
||||||
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
|
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
|
||||||
@ -97,10 +104,10 @@ export class AppWebPagesManager {
|
|||||||
pendingSet.add(messageKey);
|
pendingSet.add(messageKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.webpages[id] === undefined) {
|
if(oldWebPage === undefined) {
|
||||||
this.webpages[id] = apiWebPage;
|
this.webpages[id] = apiWebPage;
|
||||||
} else {
|
} else {
|
||||||
safeReplaceObject(this.webpages[id], apiWebPage);
|
safeReplaceObject(oldWebPage, apiWebPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!messageKey && pendingSet !== undefined) {
|
if(!messageKey && pendingSet !== undefined) {
|
||||||
|
@ -99,7 +99,9 @@
|
|||||||
}, {
|
}, {
|
||||||
"predicate": "messageEmpty",
|
"predicate": "messageEmpty",
|
||||||
"params": [
|
"params": [
|
||||||
{"name": "deleted", "type": "boolean"}
|
{"name": "deleted", "type": "boolean"},
|
||||||
|
{"name": "mid", "type": "number"},
|
||||||
|
{"name": "pFlags", "type": "{}"}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
"predicate": "userFull",
|
"predicate": "userFull",
|
||||||
|
@ -917,7 +917,8 @@ $chat-helper-size: 36px;
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
@include animation-level(2) {
|
@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) {
|
@include respond-to(esg-bottom-new) {
|
||||||
|
Loading…
Reference in New Issue
Block a user