Browse Source

Fix broken profile & shared media

master
Eduard Kuzmenko 3 years ago
parent
commit
7b0ab07255
  1. 53
      src/components/chat/bubbles.ts
  2. 89
      src/components/chat/chat.ts
  3. 8
      src/helpers/middlewarePromise.ts

53
src/components/chat/bubbles.ts

@ -32,11 +32,11 @@ import ListenerSetter from "../../helpers/listenerSetter"; @@ -32,11 +32,11 @@ import ListenerSetter from "../../helpers/listenerSetter";
import PollElement from "../poll";
import AudioElement from "../audio";
import { ChatInvite, Document, Message, MessageEntity, MessageMedia, MessageReplyHeader, Photo, PhotoSize, ReactionCount, ReplyMarkup, SponsoredMessage, Update, User, WebPage } from "../../layer";
import { NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { FocusDirection, ScrollStartCallbackDimensions } from "../../helpers/fastSmoothScroll";
import useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from "../../hooks/useHeavyAnimationCheck";
import { fastRaf, fastRafPromise } from "../../helpers/schedulers";
import deferredPromise from "../../helpers/cancellablePromise";
import deferredPromise, { CancellablePromise } from "../../helpers/cancellablePromise";
import RepliesElement from "./replies";
import DEBUG from "../../config/debug";
import { SliceEnd } from "../../helpers/slicedArray";
@ -251,6 +251,8 @@ export default class ChatBubbles { @@ -251,6 +251,8 @@ export default class ChatBubbles {
private updatePlaceholderPosition: () => void;
private setPeerOptions: {lastMsgId: number; topMessage: number;};
private setPeerTempId: number = 0;
// private reactions: Map<number, ReactionsElement>;
constructor(
@ -2522,6 +2524,8 @@ export default class ChatBubbles { @@ -2522,6 +2524,8 @@ export default class ChatBubbles {
}
public async setPeer(samePeer: boolean, peerId: PeerId, lastMsgId?: number, startParam?: string): Promise<{cached?: boolean, promise: Chat['setPeerPromise']}> {
const tempId = ++this.setPeerTempId;
if(!peerId) {
this.cleanup(true);
this.preloader.detach();
@ -2532,6 +2536,16 @@ export default class ChatBubbles { @@ -2532,6 +2536,16 @@ export default class ChatBubbles {
const log = this.log.bindPrefix('setPeer');
log.warn('start');
const middleware = () => {
return this.setPeerTempId === tempId;
};
const m = middlewarePromise(middleware, PEER_CHANGED_ERROR);
if(!samePeer) {
await m(this.chat.onChangePeer(m));
}
/* if(samePeer && this.chat.setPeerPromise) {
return {cached: true, promise: this.chat.setPeerPromise};
} */
@ -2542,8 +2556,8 @@ export default class ChatBubbles { @@ -2542,8 +2556,8 @@ export default class ChatBubbles {
lastMsgId = 0;
}
const historyStorage = await this.chat.getHistoryStorage();
let topMessage = chatType === 'pinned' ? await this.managers.appMessagesManager.getPinnedMessagesMaxId(peerId) : historyStorage.maxId ?? 0;
const historyStorage = await m(this.chat.getHistoryStorage());
let topMessage = chatType === 'pinned' ? await m(this.managers.appMessagesManager.getPinnedMessagesMaxId(peerId)) : historyStorage.maxId ?? 0;
const isTarget = lastMsgId !== undefined;
// * this one will fix topMessage for null message in history (e.g. channel comments with only 1 comment and it is a topMessage)
@ -2561,8 +2575,8 @@ export default class ChatBubbles { @@ -2561,8 +2575,8 @@ export default class ChatBubbles {
if(savedPosition) {
} else if(topMessage) {
readMaxId = await this.managers.appMessagesManager.getReadMaxIdIfUnread(peerId, this.chat.threadId);
const dialog = await this.managers.appMessagesManager.getDialogOnly(peerId);
readMaxId = await m(this.managers.appMessagesManager.getReadMaxIdIfUnread(peerId, this.chat.threadId));
const dialog = await m(this.managers.appMessagesManager.getDialogOnly(peerId));
if(/* dialog.unread_count */readMaxId && !samePeer && (!dialog || dialog.unread_count !== 1)) {
const foundSlice = historyStorage.history.findSliceOffset(readMaxId);
if(foundSlice && foundSlice.slice.isEnd(SliceEnd.Bottom)) {
@ -2580,8 +2594,12 @@ export default class ChatBubbles { @@ -2580,8 +2594,12 @@ export default class ChatBubbles {
const isJump = lastMsgId !== topMessage/* && overrideAdditionMsgId === undefined */;
if(startParam === undefined && await m(this.chat.isStartButtonNeeded())) {
startParam = BOT_START_PARAM;
}
if(samePeer) {
const mounted = await this.getMountedBubble(lastMsgId);
const mounted = await m(this.getMountedBubble(lastMsgId));
if(mounted) {
if(isTarget) {
this.scrollToBubble(mounted.bubble, 'center');
@ -2609,7 +2627,7 @@ export default class ChatBubbles { @@ -2609,7 +2627,7 @@ export default class ChatBubbles {
this.replyFollowHistory.length = 0;
this.passEntities = {
messageEntityBotCommand: await this.managers.appPeersManager.isAnyGroup(peerId) || await this.managers.appUsersManager.isBot(peerId)
messageEntityBotCommand: await m(this.managers.appPeersManager.isAnyGroup(peerId)) || await m(this.managers.appUsersManager.isBot(peerId))
};
}
@ -2636,13 +2654,9 @@ export default class ChatBubbles { @@ -2636,13 +2654,9 @@ export default class ChatBubbles {
this.destroyResizeObserver();
}
// const oldContainer = this.container;
const oldChatInner = this.chatInner;
const oldPlaceholderBubble = this.emptyPlaceholderBubble;
this.cleanup();
// this.constructBubbles();
// const container = this.container;
// const chatInner = this.chatInner;/* = document.createElement('div'); */
const chatInner = this.chatInner = document.createElement('div');
if(samePeer) {
chatInner.className = oldChatInner.className;
@ -2667,7 +2681,7 @@ export default class ChatBubbles { @@ -2667,7 +2681,7 @@ export default class ChatBubbles {
let result: Awaited<ReturnType<ChatBubbles['getHistory']>>;
if(!savedPosition) {
result = await this.getHistory1(lastMsgId, true, isJump, additionMsgId);
result = await m(this.getHistory1(lastMsgId, true, isJump, additionMsgId));
} else {
result = {
promise: getHeavyAnimationPromise().then(() => {
@ -2684,10 +2698,8 @@ export default class ChatBubbles { @@ -2684,10 +2698,8 @@ export default class ChatBubbles {
const {promise, cached} = result;
const middleware = this.getMiddleware();
if(!cached && !samePeer) {
await this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam);
if(!middleware()) throw PEER_CHANGED_ERROR;
await m(this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam));
this.scrollable.container.textContent = '';
// oldContainer.textContent = '';
//oldChatInner.remove();
@ -2698,14 +2710,13 @@ export default class ChatBubbles { @@ -2698,14 +2710,13 @@ export default class ChatBubbles {
this.ladderDeferred = deferredPromise<void>(); */
animationIntersector.lockGroup(CHAT_ANIMATION_GROUP);
const setPeerPromise = promise.then(async() => {
const setPeerPromise = m(promise).then(async() => {
log.warn('promise fulfilled');
let mountedByLastMsgId = haveToScrollToBubble ? await (lastMsgId ? this.getMountedBubble(lastMsgId) : {bubble: this.getLastBubble()}) : undefined;
let mountedByLastMsgId = haveToScrollToBubble ? await m(lastMsgId ? this.getMountedBubble(lastMsgId) : {bubble: this.getLastBubble()}) : undefined;
if(cached && !samePeer) {
log.warn('finishing peer change');
await this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam); // * костыль
if(!middleware()) throw PEER_CHANGED_ERROR;
await m(this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam)); // * костыль
log.warn('finished peer change');
}
@ -2838,7 +2849,7 @@ export default class ChatBubbles { @@ -2838,7 +2849,7 @@ export default class ChatBubbles {
}
if(chatType === 'chat') {
const dialog = await this.managers.appMessagesManager.getDialogOnly(peerId);
const dialog = await m(this.managers.appMessagesManager.getDialogOnly(peerId));
if(dialog?.pFlags.unread_mark) {
this.managers.appMessagesManager.markDialogUnread(peerId, true);
}

89
src/components/chat/chat.ts

@ -16,7 +16,7 @@ import ChatContextMenu from "./contextMenu"; @@ -16,7 +16,7 @@ import ChatContextMenu from "./contextMenu";
import ChatInput from "./input";
import ChatSelection from "./selection";
import ChatTopbar from "./topbar";
import { BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import SetTransition from "../singleTransition";
import AppPrivateSearchTab from "../sidebarRight/tabs/search";
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
@ -32,6 +32,8 @@ import SlicedArray from "../../helpers/slicedArray"; @@ -32,6 +32,8 @@ import SlicedArray from "../../helpers/slicedArray";
import themeController from "../../helpers/themeController";
import AppSharedMediaTab from "../sidebarRight/tabs/sharedMedia";
import noop from "../../helpers/noop";
import middlewarePromise from "../../helpers/middlewarePromise";
import indexOfAndSplice from "../../helpers/array/indexOfAndSplice";
export type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';
@ -74,6 +76,7 @@ export default class Chat extends EventListenerBase<{ @@ -74,6 +76,7 @@ export default class Chat extends EventListenerBase<{
public backgroundTempId: number;
public setBackgroundPromise: Promise<void>;
public sharedMediaTab: AppSharedMediaTab;
public sharedMediaTabs: AppSharedMediaTab[];
// public renderDarkPattern: () => Promise<void>;
public isAnyGroup: boolean;
@ -103,6 +106,7 @@ export default class Chat extends EventListenerBase<{ @@ -103,6 +106,7 @@ export default class Chat extends EventListenerBase<{
this.appImManager.chatsContainer.append(this.container);
this.backgroundTempId = 0;
this.sharedMediaTabs = [];
}
public setBackground(url: string, skipAnimation?: boolean): Promise<void> {
@ -388,6 +392,35 @@ export default class Chat extends EventListenerBase<{ @@ -388,6 +392,35 @@ export default class Chat extends EventListenerBase<{
this.topbar.cleanup();
this.selection.cleanup();
}
public async onChangePeer(m: ReturnType<typeof middlewarePromise>) {
const {peerId} = this;
const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);
if(searchTab) {
searchTab.close();
}
const [noForwards, isRestricted, isAnyGroup] = await m(Promise.all([
this.managers.appPeersManager.noForwards(peerId),
this.managers.appPeersManager.isRestricted(peerId),
this._isAnyGroup(peerId),
this.setAutoDownloadMedia()
]));
this.noForwards = noForwards;
this.isRestricted = isRestricted;
this.isAnyGroup = isAnyGroup;
this.container.classList.toggle('no-forwards', this.noForwards);
this.sharedMediaTab = appSidebarRight.createSharedMediaTab();
this.sharedMediaTabs.push(this.sharedMediaTab);
this.sharedMediaTab.setPeer(peerId, this.threadId);
this.input.clearHelper(); // костыль
this.selection.cleanup(); // TODO: REFACTOR !!!!!!
}
public async setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string) {
if(!peerId) {
@ -418,59 +451,11 @@ export default class Chat extends EventListenerBase<{ @@ -418,59 +451,11 @@ export default class Chat extends EventListenerBase<{
return;
}
let sharedMediaTabs: AppSharedMediaTab[], sharedMediaTab = this.sharedMediaTab;
// set new
if(!samePeer) {
const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);
if(searchTab) {
searchTab.close();
}
const [noForwards, isRestricted, isAnyGroup] = await Promise.all([
this.managers.appPeersManager.noForwards(peerId),
this.managers.appPeersManager.isRestricted(peerId),
this._isAnyGroup(peerId),
this.setAutoDownloadMedia()
]);
this.noForwards = noForwards;
this.isRestricted = isRestricted;
this.isAnyGroup = isAnyGroup;
this.container.classList.toggle('no-forwards', this.noForwards);
sharedMediaTabs = [
sharedMediaTab,
sharedMediaTab = this.sharedMediaTab = appSidebarRight.createSharedMediaTab()
];
sharedMediaTab.setPeer(peerId, this.threadId);
this.input.clearHelper(); // костыль
this.selection.cleanup(); // TODO: REFACTOR !!!!!!
}
this.peerChanged = samePeer;
if(startParam === undefined && await this.isStartButtonNeeded()) {
startParam = BOT_START_PARAM;
}
const bubblesSetPeerPromise = this.bubbles.setPeer(samePeer, peerId, lastMsgId, startParam);
const setPeerPromise = this.setPeerPromise = bubblesSetPeerPromise.then((result) => {
if(!result) {
return;
}
if(!samePeer) {
sharedMediaTab.setLoadMutex(setPeerPromise);
sharedMediaTab.loadSidebarMedia(true);
}
return result.promise.catch(noop).finally(() => {
if(sharedMediaTabs) {
sharedMediaTabs.filter((tab) => tab && this.sharedMediaTab !== tab).forEach((tab) => this.destroySharedMediaTab(tab));
}
});
return result.promise;
}).catch(noop).finally(() => {
if(this.setPeerPromise === setPeerPromise) {
this.setPeerPromise = null;
@ -481,6 +466,7 @@ export default class Chat extends EventListenerBase<{ @@ -481,6 +466,7 @@ export default class Chat extends EventListenerBase<{
}
public destroySharedMediaTab(tab = this.sharedMediaTab) {
indexOfAndSplice(this.sharedMediaTabs, tab);
tab.destroy();
}
@ -504,6 +490,7 @@ export default class Chat extends EventListenerBase<{ @@ -504,6 +490,7 @@ export default class Chat extends EventListenerBase<{
this.cleanup(false);
const sharedMediaTab = this.sharedMediaTab;
sharedMediaTab.loadSidebarMedia(true);
const callbacksPromise = Promise.all([
this.topbar.finishPeerChange(isTarget),
@ -526,6 +513,8 @@ export default class Chat extends EventListenerBase<{ @@ -526,6 +513,8 @@ export default class Chat extends EventListenerBase<{
appSidebarRight.replaceSharedMediaTab(sharedMediaTab);
this.sharedMediaTabs.filter((tab) => tab !== sharedMediaTab).forEach((tab) => this.destroySharedMediaTab(tab));
this.log.setPrefix('CHAT-' + peerId + '-' + this.type);
this.appImManager.dispatchEvent('peer_changed', peerId);

8
src/helpers/middlewarePromise.ts

@ -6,6 +6,14 @@ @@ -6,6 +6,14 @@
export default function middlewarePromise(middleware: () => boolean, throwWhat: any = '') {
return <T>(promise: T): T => {
if(!(promise instanceof Promise)) {
if(promise instanceof Error) {
throw promise;
} else {
return promise;
}
}
return (promise as any as Promise<any>).then((result) => {
if(!middleware()) {
throw throwWhat;

Loading…
Cancel
Save