Browse Source

Fix rendering bugged webpages

Fix rendering search results from hidden sender
master
morethanwords 3 years ago
parent
commit
8d7dd98df8
  1. 7
      src/components/appMediaViewer.ts
  2. 16
      src/components/appSearch.ts
  3. 158
      src/components/appSearchSuper..ts
  4. 29
      src/components/chat/bubbles.ts
  5. 7
      src/components/chat/chat.ts
  6. 2
      src/components/chat/input.ts
  7. 26
      src/components/chat/topbar.ts
  8. 17
      src/components/peerTitle.ts
  9. 2
      src/components/popups/forward.ts
  10. 4
      src/components/sidebarLeft/index.ts
  11. 51
      src/lib/appManagers/appDialogsManager.ts
  12. 105
      src/lib/appManagers/appImManager.ts
  13. 20
      src/lib/appManagers/appMessagesManager.ts
  14. 3
      src/lib/appManagers/internalLink.ts

7
src/components/appMediaViewer.ts

@ -205,7 +205,12 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
} }
} }
appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId); appImManager.setInnerPeer({
peerId: message.peerId,
lastMsgId: mid,
type: threadId ? 'discussion' : undefined,
threadId
});
}); });
} }
}; };

16
src/components/appSearch.ts

@ -184,20 +184,20 @@ export default class AppSearch {
const searchGroup = this.searchGroups.messages; const searchGroup = this.searchGroups.messages;
history.forEach((message) => { history.forEach((message) => {
try {
const peerId = this.peerId ? message.fromId : message.peerId; const peerId = this.peerId ? message.fromId : message.peerId;
const {dialog, dom} = appDialogsManager.addDialogNew({ appDialogsManager.addDialogAndSetLastMessage({
dialog: peerId, peerId,
container: this.scrollable/* searchGroup.list */, container: this.scrollable/* searchGroup.list */,
drawStatus: false, drawStatus: false,
avatarSize: 54, avatarSize: 54,
meAsSaved: false meAsSaved: false,
message,
query
}); });
} catch(err) {
if(message.peerId !== peerId) { console.error('[appSearch] render search result', err);
dom.listEl.dataset.peerId = '' + message.peerId;
} }
appDialogsManager.setLastMessage(dialog, message, dom, query);
}); });
searchGroup.toggle(); searchGroup.toggle();

158
src/components/appSearchSuper..ts

@ -28,7 +28,7 @@ import I18n, { LangPackKey, i18n } from "../lib/langPack";
import findUpClassName from "../helpers/dom/findUpClassName"; import findUpClassName from "../helpers/dom/findUpClassName";
import { getMiddleware } from "../helpers/middleware"; import { getMiddleware } from "../helpers/middleware";
import appProfileManager from "../lib/appManagers/appProfileManager"; import appProfileManager from "../lib/appManagers/appProfileManager";
import { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants } from "../layer"; import { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants, Message, MessageMedia, Photo, WebPage } from "../layer";
import SortedUserList from "./sortedUserList"; import SortedUserList from "./sortedUserList";
import findUpTag from "../helpers/dom/findUpTag"; import findUpTag from "../helpers/dom/findUpTag";
import appSidebarRight from "./sidebarRight"; import appSidebarRight from "./sidebarRight";
@ -222,6 +222,15 @@ class SearchContextMenu {
}; };
} }
export type ProcessSearchSuperResult = {
message: Message.message,
middleware: () => boolean,
promises: Promise<any>[],
elemsToAppend: {element: HTMLElement, message: any}[],
inputFilter: MyInputMessagesFilter,
searchGroup?: SearchGroup
};
export default class AppSearchSuper { export default class AppSearchSuper {
public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any; public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;
@ -656,46 +665,19 @@ export default class AppSearchSuper {
return filtered; return filtered;
} }
public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) { private processEmptyFilter({message, searchGroup}: ProcessSearchSuperResult) {
const elemsToAppend: {element: HTMLElement, message: any}[] = [];
const sharedMediaDiv: HTMLElement = mediaTab.contentTab;
const promises: Promise<any>[] = [];
const middleware = this.middleware.get();
let inputFilter = mediaTab.inputFilter;
await getHeavyAnimationPromise();
let searchGroup: SearchGroup;
if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {
inputFilter = 'inputMessagesFilterEmpty';
searchGroup = this.searchGroupMedia;
sharedMediaDiv.append(searchGroup.container);
} else if(inputFilter === 'inputMessagesFilterEmpty') {
searchGroup = this.searchGroups.messages;
}
// https://core.telegram.org/type/MessagesFilter
switch(inputFilter) {
case 'inputMessagesFilterEmpty': {
for(const message of messages) {
const {dialog, dom} = appDialogsManager.addDialogNew({ const {dialog, dom} = appDialogsManager.addDialogNew({
dialog: message.peerId, dialog: message.peerId,
container: searchGroup.list, container: searchGroup.list,
drawStatus: false, drawStatus: false,
avatarSize: 54 avatarSize: 54
}); });
appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
}
if(searchGroup.list.childElementCount) { appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
searchGroup.setActive();
}
break;
} }
case 'inputMessagesFilterPhotoVideo': { private processPhotoVideoFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {
for(const message of messages) { const media = appMessagesManager.getMediaFromMessage(message);
const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('grid-item'); div.classList.add('grid-item');
@ -741,15 +723,9 @@ export default class AppSearchSuper {
elemsToAppend.push({element: div, message}); elemsToAppend.push({element: div, message});
} }
break; private processDocumentFilter({message, elemsToAppend, inputFilter}: ProcessSearchSuperResult) {
} const document = appMessagesManager.getMediaFromMessage(message);
const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(document.type);
case 'inputMessagesFilterVoice':
case 'inputMessagesFilterRoundVoice':
case 'inputMessagesFilterMusic':
case 'inputMessagesFilterDocument': {
for(const message of messages) {
const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type);
const div = wrapDocument({ const div = wrapDocument({
message, message,
withTime: !showSender, withTime: !showSender,
@ -761,22 +737,17 @@ export default class AppSearchSuper {
noAutoDownload: true noAutoDownload: true
}); });
if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) { if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(document.type)) {
div.classList.add('audio-48'); div.classList.add('audio-48');
} }
elemsToAppend.push({element: div, message}); elemsToAppend.push({element: div, message});
} }
break;
}
case 'inputMessagesFilterUrl': { private processUrlFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {
for(let message of messages) { let webpage = (message.media as MessageMedia.messageMediaWebPage)?.webpage as WebPage.webPage;
let webpage: any;
if(message.media?.webpage && message.media.webpage._ !== 'webPageEmpty') { if(!webpage) {
webpage = message.media.webpage;
} else {
const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null; const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;
let url: string, display_url: string, sliced: string; let url: string, display_url: string, sliced: string;
@ -785,7 +756,7 @@ export default class AppSearchSuper {
const match = RichTextProcessor.matchUrl(message.message); const match = RichTextProcessor.matchUrl(message.message);
if(!match) { if(!match) {
//this.log.error('NO ENTITY AND NO MATCH:', message); //this.log.error('NO ENTITY AND NO MATCH:', message);
continue; return;
} }
url = match[0]; url = match[0];
@ -811,8 +782,11 @@ export default class AppSearchSuper {
display_url = new URL(display_url).hostname; display_url = new URL(display_url).hostname;
webpage = { webpage = {
_: 'webPage',
url, url,
display_url display_url,
id: '',
hash: 0
}; };
if(!same) { if(!same) {
@ -821,8 +795,6 @@ export default class AppSearchSuper {
} }
} }
let div = document.createElement('div');
let previewDiv = document.createElement('div'); let previewDiv = document.createElement('div');
previewDiv.classList.add('preview', 'row-media'); previewDiv.classList.add('preview', 'row-media');
@ -832,13 +804,13 @@ export default class AppSearchSuper {
const res = wrapPhoto({ const res = wrapPhoto({
container: previewDiv, container: previewDiv,
message: null, message: null,
photo: webpage.photo, photo: webpage.photo as Photo.photo,
boxWidth: 0, boxWidth: 0,
boxHeight: 0, boxHeight: 0,
withoutPreloader: true, withoutPreloader: true,
lazyLoadQueue: this.lazyLoadQueue, lazyLoadQueue: this.lazyLoadQueue,
middleware, middleware,
size: appPhotosManager.choosePhotoSize(webpage.photo, 60, 60, false), size: appPhotosManager.choosePhotoSize(webpage.photo as Photo.photo, 60, 60, false),
loadPromises: promises, loadPromises: promises,
noBlur: true noBlur: true
}); });
@ -854,7 +826,11 @@ export default class AppSearchSuper {
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || '')); const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
const a = aFragment.firstElementChild; const a = aFragment.firstElementChild;
if(a instanceof HTMLAnchorElement) { if(a instanceof HTMLAnchorElement) {
try { // can have 'URIError: URI malformed'
a.innerText = decodeURIComponent(a.href); a.innerText = decodeURIComponent(a.href);
} catch(err) {
}
} }
if(subtitleFragment.firstChild) { if(subtitleFragment.firstChild) {
@ -900,6 +876,57 @@ export default class AppSearchSuper {
} }
} }
public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {
const elemsToAppend: {element: HTMLElement, message: any}[] = [];
const sharedMediaDiv: HTMLElement = mediaTab.contentTab;
const promises: Promise<any>[] = [];
const middleware = this.middleware.get();
let inputFilter = mediaTab.inputFilter;
await getHeavyAnimationPromise();
let searchGroup: SearchGroup;
if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {
inputFilter = 'inputMessagesFilterEmpty';
searchGroup = this.searchGroupMedia;
sharedMediaDiv.append(searchGroup.container);
} else if(inputFilter === 'inputMessagesFilterEmpty') {
searchGroup = this.searchGroups.messages;
}
const options: ProcessSearchSuperResult = {
elemsToAppend,
inputFilter,
message: undefined,
middleware,
promises,
searchGroup
};
let processCallback: (options: ProcessSearchSuperResult) => any;
// https://core.telegram.org/type/MessagesFilter
switch(inputFilter) {
case 'inputMessagesFilterEmpty': {
processCallback = this.processEmptyFilter;
break;
}
case 'inputMessagesFilterPhotoVideo': {
processCallback = this.processPhotoVideoFilter;
break;
}
case 'inputMessagesFilterVoice':
case 'inputMessagesFilterRoundVoice':
case 'inputMessagesFilterMusic':
case 'inputMessagesFilterDocument': {
processCallback = this.processDocumentFilter;
break;
}
case 'inputMessagesFilterUrl': {
processCallback = this.processUrlFilter;
break; break;
} }
@ -908,6 +935,23 @@ export default class AppSearchSuper {
break; break;
} }
if(processCallback) {
processCallback = processCallback.bind(this);
for(const message of messages) {
try {
options.message = message;
processCallback(options);
} catch(err) {
this.log.error('error rendering filter', inputFilter, options, message, err);
}
}
}
if(searchGroup && searchGroup.list.childElementCount) {
searchGroup.setActive();
}
if(this.loadMutex) { if(this.loadMutex) {
promises.push(this.loadMutex); promises.push(this.loadMutex);
} }
@ -1163,7 +1207,7 @@ export default class AppSearchSuper {
} }
promise.then(() => { promise.then(() => {
appImManager.setInnerPeer(peerId); appImManager.setInnerPeer({peerId});
}); });
}); });
mediaTab.contentTab.append(this.membersList.list); mediaTab.contentTab.append(this.membersList.list);

29
src/components/chat/bubbles.ts

@ -1011,7 +1011,9 @@ export default class ChatBubbles {
const contactDiv: HTMLElement = findUpClassName(target, 'contact'); const contactDiv: HTMLElement = findUpClassName(target, 'contact');
if(contactDiv) { if(contactDiv) {
this.chat.appImManager.setInnerPeer(contactDiv.dataset.peerId.toPeerId()); this.chat.appImManager.setInnerPeer({
peerId: contactDiv.dataset.peerId.toPeerId()
});
return; return;
} }
@ -1035,7 +1037,11 @@ export default class ChatBubbles {
const replies = message.replies; const replies = message.replies;
if(replies) { if(replies) {
this.appMessagesManager.getDiscussionMessage(this.peerId, message.mid).then(message => { this.appMessagesManager.getDiscussionMessage(this.peerId, message.mid).then(message => {
this.chat.appImManager.setInnerPeer(replies.channel_id.toPeerId(true), undefined, 'discussion', (message as MyMessage).mid); this.chat.appImManager.setInnerPeer({
peerId: replies.channel_id.toPeerId(true),
type: 'discussion',
threadId: (message as MyMessage).mid
});
}); });
} }
} }
@ -1064,11 +1070,14 @@ export default class ChatBubbles {
if(savedFrom) { if(savedFrom) {
const [peerId, mid] = savedFrom.split('_'); const [peerId, mid] = savedFrom.split('_');
this.chat.appImManager.setInnerPeer(peerId.toPeerId(), +mid); this.chat.appImManager.setInnerPeer({
peerId: peerId.toPeerId(),
lastMsgId: +mid
});
} else { } else {
const peerId = peerIdStr.toPeerId(); const peerId = peerIdStr.toPeerId();
if(peerId !== NULL_PEER_ID) { if(peerId !== NULL_PEER_ID) {
this.chat.appImManager.setInnerPeer(peerId); this.chat.appImManager.setInnerPeer({peerId});
} else { } else {
toast(I18n.format('HidAccount', true)); toast(I18n.format('HidAccount', true));
} }
@ -1213,7 +1222,10 @@ export default class ChatBubbles {
const savedFrom = bubble.dataset.savedFrom; const savedFrom = bubble.dataset.savedFrom;
const [peerId, mid] = savedFrom.split('_'); const [peerId, mid] = savedFrom.split('_');
////this.log('savedFrom', peerId, msgID); ////this.log('savedFrom', peerId, msgID);
this.chat.appImManager.setInnerPeer(peerId.toPeerId(), +mid); this.chat.appImManager.setInnerPeer({
peerId: peerId.toPeerId(),
lastMsgId: +mid
});
return; return;
} else if(target.classList.contains('forward')) { } else if(target.classList.contains('forward')) {
const mid = +bubble.dataset.mid; const mid = +bubble.dataset.mid;
@ -1240,7 +1252,12 @@ export default class ChatBubbles {
const replyToPeerId = message.reply_to.reply_to_peer_id ? this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : this.peerId; const replyToPeerId = message.reply_to.reply_to_peer_id ? this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : this.peerId;
const replyToMid = message.reply_to.reply_to_msg_id; const replyToMid = message.reply_to.reply_to_msg_id;
this.chat.appImManager.setInnerPeer(replyToPeerId, replyToMid, this.chat.type, this.chat.threadId); this.chat.appImManager.setInnerPeer({
peerId: replyToPeerId,
lastMsgId: replyToMid,
type: this.chat.type,
threadId: this.chat.threadId
});
/* if(this.chat.type === 'discussion') { /* if(this.chat.type === 'discussion') {
this.chat.appImManager.setMessageId(, originalMessageId); this.chat.appImManager.setMessageId(, originalMessageId);

7
src/components/chat/chat.ts

@ -223,7 +223,7 @@ export default class Chat extends EventListenerBase<{
this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => { this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => {
if(e.peerId === this.peerId) { if(e.peerId === this.peerId) {
this.appImManager.setPeer(NULL_PEER_ID); this.appImManager.setPeer();
} }
}); });
} }
@ -271,8 +271,6 @@ export default class Chat extends EventListenerBase<{
if(!samePeer) { if(!samePeer) {
rootScope.dispatchEvent('peer_changing', this); rootScope.dispatchEvent('peer_changing', this);
this.peerId = peerId; this.peerId = peerId;
this.noForwards = this.appPeersManager.noForwards(peerId);
this.container.classList.toggle('no-forwards', this.noForwards);
} else if(this.setPeerPromise) { } else if(this.setPeerPromise) {
return; return;
} }
@ -297,6 +295,9 @@ export default class Chat extends EventListenerBase<{
searchTab.close(); searchTab.close();
} }
this.noForwards = this.appPeersManager.noForwards(peerId);
this.container.classList.toggle('no-forwards', this.noForwards);
appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId); appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);
this.input.clearHelper(); // костыль this.input.clearHelper(); // костыль
this.selection.cleanup(); // TODO: REFACTOR !!!!!! this.selection.cleanup(); // TODO: REFACTOR !!!!!!

2
src/components/chat/input.ts

@ -805,7 +805,7 @@ export default class ChatInput {
const peerId = this.chat.peerId; const peerId = this.chat.peerId;
new PopupPinMessage(peerId, 0, true, () => { new PopupPinMessage(peerId, 0, true, () => {
this.chat.appImManager.setPeer(NULL_PEER_ID); // * close tab this.chat.appImManager.setPeer(); // * close tab
// ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится
const originalChat = this.chat.appImManager.chat; const originalChat = this.chat.appImManager.chat;

26
src/components/chat/topbar.ts

@ -202,12 +202,12 @@ export default class ChatTopbar {
} else { } else {
const peerId = container.dataset.peerId.toPeerId(); const peerId = container.dataset.peerId.toPeerId();
const searchContext = appMediaPlaybackController.getSearchContext(); const searchContext = appMediaPlaybackController.getSearchContext();
this.chat.appImManager.setInnerPeer( this.chat.appImManager.setInnerPeer({
peerId, peerId,
mid, lastMsgId: mid,
searchContext.isScheduled ? 'scheduled' : (searchContext.threadId ? 'discussion' : undefined), type: searchContext.isScheduled ? 'scheduled' : (searchContext.threadId ? 'discussion' : undefined),
searchContext.threadId threadId: searchContext.threadId
); });
} }
} else { } else {
if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) { if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {
@ -228,7 +228,7 @@ export default class ChatTopbar {
//const item = appNavigationController.findItemByType('chat'); //const item = appNavigationController.findItemByType('chat');
// * return manually to chat by arrow, since can't get back to // * return manually to chat by arrow, since can't get back to
if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) { if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {
this.chat.appImManager.setPeer(this.peerId); this.chat.appImManager.setPeer({peerId: this.peerId});
} else { } else {
const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0; const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0;
appNavigationController.back(isFirstChat ? 'im' : 'chat'); appNavigationController.back(isFirstChat ? 'im' : 'chat');
@ -337,7 +337,9 @@ export default class ChatTopbar {
const middleware = this.chat.bubbles.getMiddleware(); const middleware = this.chat.bubbles.getMiddleware();
this.appProfileManager.getChannelFull(this.peerId.toChatId()).then(channelFull => { this.appProfileManager.getChannelFull(this.peerId.toChatId()).then(channelFull => {
if(middleware() && channelFull.linked_chat_id) { if(middleware() && channelFull.linked_chat_id) {
this.chat.appImManager.setInnerPeer(channelFull.linked_chat_id.toPeerId(true)); this.chat.appImManager.setInnerPeer({
peerId: channelFull.linked_chat_id.toPeerId(true)
});
} }
}); });
}, },
@ -426,7 +428,7 @@ export default class ChatTopbar {
resolve(); resolve();
this.appMessagesManager.sendOther(peerId, this.appUsersManager.getContactMediaInput(contactPeerId)); this.appMessagesManager.sendOther(peerId, this.appUsersManager.getContactMediaInput(contactPeerId));
this.chat.appImManager.setInnerPeer(peerId); this.chat.appImManager.setInnerPeer({peerId});
} }
}, { }, {
langKey: 'Cancel', langKey: 'Cancel',
@ -640,7 +642,11 @@ export default class ChatTopbar {
} }
public openPinned(byCurrent: boolean) { public openPinned(byCurrent: boolean) {
this.chat.appImManager.setInnerPeer(this.peerId, byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0, 'pinned'); this.chat.appImManager.setInnerPeer({
peerId: this.peerId,
lastMsgId: byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0,
type: 'pinned'
});
} }
private onResize = () => { private onResize = () => {
@ -748,7 +754,7 @@ export default class ChatTopbar {
// ! костыль х2, это нужно делать в другом месте // ! костыль х2, это нужно делать в другом месте
if(!count) { if(!count) {
this.chat.appImManager.setPeer(NULL_PEER_ID); // * close tab this.chat.appImManager.setPeer(); // * close tab
// ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится
const originalChat = this.chat.appImManager.chat; const originalChat = this.chat.appImManager.chat;

17
src/components/peerTitle.ts

@ -10,9 +10,12 @@ import rootScope from "../lib/rootScope";
import { i18n } from "../lib/langPack"; import { i18n } from "../lib/langPack";
import replaceContent from "../helpers/dom/replaceContent"; import replaceContent from "../helpers/dom/replaceContent";
import appUsersManager from "../lib/appManagers/appUsersManager"; import appUsersManager from "../lib/appManagers/appUsersManager";
import RichTextProcessor from "../lib/richtextprocessor";
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
export type PeerTitleOptions = { export type PeerTitleOptions = {
peerId: PeerId, peerId?: PeerId,
fromName?: string,
plainText?: boolean, plainText?: boolean,
onlyFirstName?: boolean, onlyFirstName?: boolean,
dialog?: boolean dialog?: boolean
@ -37,6 +40,7 @@ rootScope.addEventListener('peer_title_edit', (peerId) => {
export default class PeerTitle { export default class PeerTitle {
public element: HTMLElement; public element: HTMLElement;
public peerId: PeerId; public peerId: PeerId;
public fromName: string;
public plainText = false; public plainText = false;
public onlyFirstName = false; public onlyFirstName = false;
public dialog = false; public dialog = false;
@ -54,12 +58,21 @@ export default class PeerTitle {
if(options) { if(options) {
for(let i in options) { for(let i in options) {
// @ts-ignore // @ts-ignore
this.element.dataset[i] = options[i] ? '' + (typeof(options[i]) === 'boolean' ? +options[i] : options[i]) : '0'; // this.element.dataset[i] = options[i] ? '' + (typeof(options[i]) === 'boolean' ? +options[i] : options[i]) : '0';
// @ts-ignore // @ts-ignore
this[i] = options[i]; this[i] = options[i];
} }
} }
if(this.fromName !== undefined) {
this.element.innerHTML = RichTextProcessor.wrapEmojiText(this.fromName);
return;
}
if(this.peerId === undefined) {
this.peerId = NULL_PEER_ID;
}
if(this.peerId !== rootScope.myId || !this.dialog) { if(this.peerId !== rootScope.myId || !this.dialog) {
if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) { if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {
replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName')); replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));

2
src/components/popups/forward.ts

@ -23,7 +23,7 @@ export default class PopupForward extends PopupPickUser {
} }
} }
appImManager.setInnerPeer(peerId); appImManager.setInnerPeer({peerId});
appImManager.chat.input.initMessagesForward(peerIdMids); appImManager.chat.input.initMessagesForward(peerIdMids);
}, },
placeholder: 'ShareModal.Search.ForwardPlaceholder', placeholder: 'ShareModal.Search.ForwardPlaceholder',

4
src/components/sidebarLeft/index.ts

@ -122,7 +122,9 @@ export class AppSidebarLeft extends SidebarSlider {
text: 'SavedMessages', text: 'SavedMessages',
onClick: () => { onClick: () => {
setTimeout(() => { // menu doesn't close if no timeout (lol) setTimeout(() => { // menu doesn't close if no timeout (lol)
appImManager.setPeer(appImManager.myId); appImManager.setPeer({
peerId: appImManager.myId
});
}, 0); }, 0);
} }
}, btnArchive, { }, btnArchive, {

51
src/lib/appManagers/appDialogsManager.ts

@ -1358,9 +1358,11 @@ export class AppDialogsManager {
const peerId = elem.dataset.peerId.toPeerId(); const peerId = elem.dataset.peerId.toPeerId();
const lastMsgId = +elem.dataset.mid || undefined; const lastMsgId = +elem.dataset.mid || undefined;
setPeerFunc(peerId, lastMsgId); setPeerFunc({
peerId, lastMsgId
});
} else { } else {
setPeerFunc(NULL_PEER_ID); setPeerFunc();
} }
}, {capture: true}); }, {capture: true});
@ -1641,12 +1643,13 @@ export class AppDialogsManager {
} }
private getDialog(dialog: Dialog | PeerId): Dialog { private getDialog(dialog: Dialog | PeerId): Dialog {
if(typeof(dialog) !== 'object' && dialog) { if(typeof(dialog) !== 'object') {
const originalDialog = appMessagesManager.getDialogOnly(dialog); const originalDialog = appMessagesManager.getDialogOnly(dialog);
if(!originalDialog) { if(!originalDialog) {
const peerId = dialog || NULL_PEER_ID;
return { return {
peerId: dialog, peerId,
peer: appPeersManager.getOutputPeer(dialog), peer: appPeersManager.getOutputPeer(peerId),
pFlags: {} pFlags: {}
} as any; } as any;
} }
@ -1712,6 +1715,30 @@ export class AppDialogsManager {
this.setCallStatus(dom, !!(chat.pFlags.call_active && chat.pFlags.call_not_empty)); this.setCallStatus(dom, !!(chat.pFlags.call_active && chat.pFlags.call_not_empty));
} }
/**
* use for rendering search result
*/
public addDialogAndSetLastMessage(options: Omit<Parameters<AppDialogsManager['addDialogNew']>[0], 'dialog'> & {
message: MyMessage,
peerId: PeerId,
query?: string
}) {
const {peerId, message, query} = options;
const ret = appDialogsManager.addDialogNew({
...options,
...appMessagesManager.getMessageSenderPeerIdOrName(message),
dialog: this.getDialog(peerId),
});
this.setLastMessage(ret.dialog, message, ret.dom, query);
if(message.peerId !== peerId) {
ret.dom.listEl.dataset.peerId = '' + message.peerId;
}
return ret;
}
public addDialogNew(options: { public addDialogNew(options: {
dialog: Parameters<AppDialogsManager['addDialog']>[0], dialog: Parameters<AppDialogsManager['addDialog']>[0],
container?: Parameters<AppDialogsManager['addDialog']>[1], container?: Parameters<AppDialogsManager['addDialog']>[1],
@ -1723,12 +1750,14 @@ export class AppDialogsManager {
avatarSize?: number, avatarSize?: number,
autonomous?: boolean, autonomous?: boolean,
lazyLoadQueue?: LazyLoadQueueIntersector, lazyLoadQueue?: LazyLoadQueueIntersector,
loadPromises?: Promise<any>[] loadPromises?: Promise<any>[],
fromName?: string
}) { }) {
return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises); return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises, options.fromName);
} }
public addDialog(_dialog: Parameters<AppDialogsManager['getDialog']>[0], public addDialog(
_dialog: Parameters<AppDialogsManager['getDialog']>[0],
container?: HTMLElement | Scrollable | DocumentFragment | false, container?: HTMLElement | Scrollable | DocumentFragment | false,
drawStatus = true, drawStatus = true,
rippleEnabled = true, rippleEnabled = true,
@ -1738,7 +1767,9 @@ export class AppDialogsManager {
avatarSize = 54, avatarSize = 54,
autonomous = !!container, autonomous = !!container,
lazyLoadQueue?: LazyLoadQueueIntersector, lazyLoadQueue?: LazyLoadQueueIntersector,
loadPromises?: Promise<any>[]) { loadPromises?: Promise<any>[],
fromName?: string
) {
const dialog = this.getDialog(_dialog); const dialog = this.getDialog(_dialog);
const peerId = dialog.peerId; const peerId = dialog.peerId;
@ -1746,6 +1777,7 @@ export class AppDialogsManager {
avatarEl.loadPromises = loadPromises; avatarEl.loadPromises = loadPromises;
avatarEl.lazyLoadQueue = lazyLoadQueue; avatarEl.lazyLoadQueue = lazyLoadQueue;
avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0'); avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');
if(fromName !== undefined) avatarEl.setAttribute('peer-title', fromName);
avatarEl.setAttribute('peer', '' + peerId); avatarEl.setAttribute('peer', '' + peerId);
avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize); avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);
@ -1764,6 +1796,7 @@ export class AppDialogsManager {
const peerTitle = new PeerTitle({ const peerTitle = new PeerTitle({
peerId, peerId,
fromName,
dialog: meAsSaved, dialog: meAsSaved,
onlyFirstName, onlyFirstName,
plainText: false plainText: false

105
src/lib/appManagers/appImManager.ts

@ -43,7 +43,7 @@ import appNavigationController from '../../components/appNavigationController';
import appNotificationsManager from './appNotificationsManager'; import appNotificationsManager from './appNotificationsManager';
import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search'; import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';
import I18n, { i18n, join, LangPackKey } from '../langPack'; import I18n, { i18n, join, LangPackKey } from '../langPack';
import { ChatInvite, Dialog, SendMessageAction } from '../../layer'; import { ChatInvite, Dialog, Message, SendMessageAction } from '../../layer';
import { hslaStringToHex } from '../../helpers/color'; import { hslaStringToHex } from '../../helpers/color';
import { copy, getObjectKeysAndSort } from '../../helpers/object'; import { copy, getObjectKeysAndSort } from '../../helpers/object';
import { getFilesFromEvent } from '../../helpers/files'; import { getFilesFromEvent } from '../../helpers/files';
@ -79,6 +79,7 @@ import IS_GROUP_CALL_SUPPORTED from '../../environment/groupCallSupport';
import appAvatarsManager from './appAvatarsManager'; import appAvatarsManager from './appAvatarsManager';
import IS_CALL_SUPPORTED from '../../environment/callSupport'; import IS_CALL_SUPPORTED from '../../environment/callSupport';
import { CallType } from '../calls/types'; import { CallType } from '../calls/types';
import { Modify } from '../../types';
//console.log('appImManager included33!'); //console.log('appImManager included33!');
@ -92,6 +93,19 @@ export type ChatSavedPosition = {
top: number top: number
}; };
export type ChatSetPeerOptions = {
peerId?: PeerId,
lastMsgId?: number,
threadId?: number,
startParam?: string
};
export type ChatSetInnerPeerOptions = Modify<ChatSetPeerOptions, {
peerId: PeerId
}> & {
type?: ChatType
};
export class AppImManager { export class AppImManager {
public columnEl = document.getElementById('column-center') as HTMLDivElement; public columnEl = document.getElementById('column-center') as HTMLDivElement;
public chatsContainer: HTMLElement; public chatsContainer: HTMLElement;
@ -197,7 +211,12 @@ export class AppImManager {
if(threadId) threadId = appMessagesIdsManager.generateMessageId(threadId); if(threadId) threadId = appMessagesIdsManager.generateMessageId(threadId);
if(mid) mid = appMessagesIdsManager.generateMessageId(mid); // because mid can come from notification, i.e. server message id if(mid) mid = appMessagesIdsManager.generateMessageId(mid); // because mid can come from notification, i.e. server message id
this.setInnerPeer(peerId, mid, threadId ? 'discussion' : undefined, threadId); this.setInnerPeer({
peerId,
lastMsgId: mid,
type: threadId ? 'discussion' : undefined,
threadId
});
}); });
rootScope.addEventListener('peer_changing', (chat) => { rootScope.addEventListener('peer_changing', (chat) => {
@ -374,7 +393,7 @@ export class AppImManager {
// pathnameParams: [string, string?], // pathnameParams: [string, string?],
// uriParams: {comment?: number} // uriParams: {comment?: number}
pathnameParams: ['c', string, string] | [string, string?], pathnameParams: ['c', string, string] | [string, string?],
uriParams: {thread?: string, comment?: string} | {comment?: string} uriParams: {thread?: string, comment?: string} | {comment?: string, start?: string}
}>({ }>({
name: 'im', name: 'im',
callback: async({pathnameParams, uriParams}) => { callback: async({pathnameParams, uriParams}) => {
@ -384,7 +403,7 @@ export class AppImManager {
_: INTERNAL_LINK_TYPE.PRIVATE_POST, _: INTERNAL_LINK_TYPE.PRIVATE_POST,
channel: pathnameParams[1], channel: pathnameParams[1],
post: pathnameParams[2], post: pathnameParams[2],
thread: 'thread' in uriParams ? uriParams.thread : undefined, thread: 'thread' in uriParams && uriParams.thread,
comment: uriParams.comment comment: uriParams.comment
}; };
} else { } else {
@ -392,7 +411,8 @@ export class AppImManager {
_: INTERNAL_LINK_TYPE.MESSAGE, _: INTERNAL_LINK_TYPE.MESSAGE,
domain: pathnameParams[0], domain: pathnameParams[0],
post: pathnameParams[1], post: pathnameParams[1],
comment: uriParams.comment comment: uriParams.comment,
start: 'start' in uriParams && uriParams.start
}; };
} }
@ -514,7 +534,7 @@ export class AppImManager {
} }
if(nextDialog) { if(nextDialog) {
this.setPeer(nextDialog.peerId); this.setPeer({peerId: nextDialog.peerId});
} }
} else if(key === 'ArrowUp') { } else if(key === 'ArrowUp') {
if(!chat.input.editMsgId && chat.input.isInputEmpty()) { if(!chat.input.editMsgId && chat.input.isInputEmpty()) {
@ -606,7 +626,11 @@ export class AppImManager {
const threadId = link.thread ? appMessagesIdsManager.generateMessageId(+link.thread) : undefined; const threadId = link.thread ? appMessagesIdsManager.generateMessageId(+link.thread) : undefined;
if(threadId) this.openThread(peerId, postId, threadId); if(threadId) this.openThread(peerId, postId, threadId);
else this.setInnerPeer(peerId, postId); else this.setInnerPeer({
peerId,
lastMsgId: postId,
threadId
});
break; break;
} }
@ -627,7 +651,9 @@ export class AppImManager {
if(chatInvite._ === 'chatInviteAlready' || if(chatInvite._ === 'chatInviteAlready' ||
chatInvite._ === 'chatInvitePeek'/* && chatInvite.expires > tsNow(true) */) { chatInvite._ === 'chatInvitePeek'/* && chatInvite.expires > tsNow(true) */) {
this.setInnerPeer(chatInvite.chat.id.toPeerId(true)); this.setInnerPeer({
peerId: chatInvite.chat.id.toPeerId(true)
});
return; return;
} }
@ -719,7 +745,10 @@ export class AppImManager {
} }
default: { // peerId default: { // peerId
this.setInnerPeer(postId ? p.toPeerId(true) : p.toPeerId(), postId); this.setInnerPeer({
peerId: postId ? p.toPeerId(true) : p.toPeerId(),
lastMsgId: postId
});
break; break;
} }
} }
@ -730,14 +759,21 @@ export class AppImManager {
//location.hash = ''; //location.hash = '';
}; };
public openUsername(username: string, msgId?: number, threadId?: number, commentId?: number) { public openUsername(username: string, lastMsgId?: number, threadId?: number, commentId?: number) {
return appUsersManager.resolveUsername(username).then(peer => { return appUsersManager.resolveUsername(username).then(peer => {
const isUser = peer._ === 'user'; const isUser = peer._ === 'user';
const peerId = isUser ? peer.id.toPeerId() : peer.id.toPeerId(true); const peerId = peer.id.toPeerId(!isUser);
if(threadId) {
return this.openThread(peerId, lastMsgId, threadId);
} else if(commentId) {
return this.openComment(peerId, lastMsgId, commentId);
}
if(threadId) return this.openThread(peerId, msgId, threadId); return this.setInnerPeer({
else if(commentId) return this.openComment(peerId, msgId, commentId); peerId,
else return this.setInnerPeer(peerId, msgId); lastMsgId
});
}, (err) => { }, (err) => {
if(err.type === 'USERNAME_NOT_OCCUPIED') { if(err.type === 'USERNAME_NOT_OCCUPIED') {
toastNew({langPackKey: 'NoUsernameFound'}); toastNew({langPackKey: 'NoUsernameFound'});
@ -752,10 +788,19 @@ export class AppImManager {
*/ */
public openThread(peerId: PeerId, lastMsgId: number, threadId: number) { public openThread(peerId: PeerId, lastMsgId: number, threadId: number) {
return appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => { return appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {
const message = appMessagesManager.getMessageByPeer(peerId, threadId); const message: Message = appMessagesManager.getMessageByPeer(peerId, threadId);
if(message._ === 'messageEmpty') {
lastMsgId = undefined;
} else {
appMessagesManager.generateThreadServiceStartMessage(message); appMessagesManager.generateThreadServiceStartMessage(message);
}
return this.setInnerPeer(peerId, lastMsgId, 'discussion', threadId); return this.setInnerPeer({
peerId,
lastMsgId,
threadId,
type: 'discussion'
});
}); });
} }
@ -1044,7 +1089,7 @@ export class AppImManager {
appNavigationController.pushItem({ appNavigationController.pushItem({
type: 'chat', type: 'chat',
onPop: (canAnimate) => { onPop: (canAnimate) => {
this.setPeer(NULL_PEER_ID, undefined, canAnimate); this.setPeer({}, canAnimate);
blurActiveElement(); blurActiveElement();
} }
}); });
@ -1270,7 +1315,7 @@ export class AppImManager {
type: 'im', type: 'im',
onPop: (canAnimate) => { onPop: (canAnimate) => {
//this.selectTab(prevTabId, !isSafari); //this.selectTab(prevTabId, !isSafari);
this.setPeer(NULL_PEER_ID, undefined, canAnimate); this.setPeer({}, canAnimate);
} }
}); });
} }
@ -1382,12 +1427,14 @@ export class AppImManager {
}, 250 + 100); }, 250 + 100);
} }
public setPeer(peerId: PeerId, lastMsgId?: number, animate?: boolean): boolean { public setPeer(options: ChatSetPeerOptions = {}, animate?: boolean): boolean {
if(this.init) { if(this.init) {
this.init(); this.init();
this.init = null; this.init = null;
} }
const {peerId, lastMsgId} = options;
const chat = this.chat; const chat = this.chat;
const chatIndex = this.chats.indexOf(chat); const chatIndex = this.chats.indexOf(chat);
@ -1411,7 +1458,7 @@ export class AppImManager {
this.spliceChats(0, true, true, spliced); this.spliceChats(0, true, true, spliced);
return; return;
} else { } else {
const ret = this.setPeer(peerId, lastMsgId); const ret = this.setPeer(options);
this.spliceChats(0, false, false, spliced); this.spliceChats(0, false, false, spliced);
return ret; return ret;
} }
@ -1452,16 +1499,19 @@ export class AppImManager {
} }
} }
public setInnerPeer(peerId: PeerId, lastMsgId?: number, type: ChatType = 'chat', threadId?: number) { public setInnerPeer(options: ChatSetInnerPeerOptions) {
const {peerId} = options;
if(peerId === NULL_PEER_ID || !peerId) { if(peerId === NULL_PEER_ID || !peerId) {
return; return;
} }
const type = options.type ??= 'chat';
// * prevent opening already opened peer // * prevent opening already opened peer
const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type); const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type);
if(existingIndex !== -1) { if(existingIndex !== -1) {
this.spliceChats(existingIndex + 1); this.spliceChats(existingIndex + 1);
return this.setPeer(peerId, lastMsgId); return this.setPeer(options);
} }
const oldChat = this.chat; const oldChat = this.chat;
@ -1473,8 +1523,8 @@ export class AppImManager {
if(type) { if(type) {
chat.setType(type); chat.setType(type);
if(threadId) { if(options.threadId) {
chat.threadId = threadId; chat.threadId = options.threadId;
} }
} }
@ -1482,11 +1532,14 @@ export class AppImManager {
//this.chatsSelectTab(chat.container); //this.chatsSelectTab(chat.container);
return this.setPeer(peerId, lastMsgId); return this.setPeer(options);
} }
public openScheduled(peerId: PeerId) { public openScheduled(peerId: PeerId) {
this.setInnerPeer(peerId, undefined, 'scheduled'); this.setInnerPeer({
peerId,
type: 'scheduled'
});
} }
private getTypingElement(action: SendMessageAction) { private getTypingElement(action: SendMessageAction) {

20
src/lib/appManagers/appMessagesManager.ts

@ -2357,8 +2357,8 @@ export class AppMessagesManager {
//return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b); //return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b);
} }
public getMidsByMessage(message: Message.message) { public getMidsByMessage(message: Message) {
if(message?.grouped_id) return this.getMidsByAlbum(message.grouped_id); if((message as Message.message)?.grouped_id) return this.getMidsByAlbum((message as Message.message).grouped_id);
else return [message.mid]; else return [message.mid];
} }
@ -2949,7 +2949,7 @@ export class AppMessagesManager {
fromMe ? fromMe ?
i18n('FromYou') : i18n('FromYou') :
new PeerTitle({ new PeerTitle({
peerId: message.fromId, ...this.getMessageSenderPeerIdOrName(message),
dialog: message.peerId === rootScope.myId dialog: message.peerId === rootScope.myId
}).element }).element
); );
@ -2962,6 +2962,18 @@ export class AppMessagesManager {
return senderTitle; return senderTitle;
} }
public getMessageSenderPeerIdOrName(message: MyMessage) {
if(message.fromId) {
return {
peerId: message.fromId
};
} else {
return {
fromName: (message as Message.message).fwd_from?.from_name
};
}
}
public wrapSentTime(message: MyMessage) { public wrapSentTime(message: MyMessage) {
const el: HTMLElement = document.createElement('span'); const el: HTMLElement = document.createElement('span');
el.classList.add('sent-time'); el.classList.add('sent-time');
@ -3844,7 +3856,7 @@ export class AppMessagesManager {
this.getDiscussionMessage(peerId, mid); this.getDiscussionMessage(peerId, mid);
} }
public generateThreadServiceStartMessage(message: Message.message) { public generateThreadServiceStartMessage(message: Message.message | Message.messageService) {
const threadKey = message.peerId + '_' + message.mid; const threadKey = message.peerId + '_' + message.mid;
if(this.threadsServiceMessagesIdsStorage[threadKey]) return; if(this.threadsServiceMessagesIdsStorage[threadKey]) return;

3
src/lib/appManagers/internalLink.ts

@ -19,7 +19,8 @@ export namespace InternalLink {
_: INTERNAL_LINK_TYPE.MESSAGE, _: INTERNAL_LINK_TYPE.MESSAGE,
domain: string, domain: string,
post?: string, post?: string,
comment?: string comment?: string,
start?: string
} }
export interface InternalLinkPrivatePost { export interface InternalLinkPrivatePost {

Loading…
Cancel
Save