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. 26
      src/components/appSearch.ts
  3. 464
      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. 107
      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 @@ -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
});
});
}
};

26
src/components/appSearch.ts

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

464
src/components/appSearchSuper..ts

@ -28,7 +28,7 @@ import I18n, { LangPackKey, i18n } from "../lib/langPack"; @@ -28,7 +28,7 @@ import I18n, { LangPackKey, i18n } from "../lib/langPack";
import findUpClassName from "../helpers/dom/findUpClassName";
import { getMiddleware } from "../helpers/middleware";
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 findUpTag from "../helpers/dom/findUpTag";
import appSidebarRight from "./sidebarRight";
@ -222,6 +222,15 @@ class SearchContextMenu { @@ -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 {
public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;
@ -655,6 +664,217 @@ export default class AppSearchSuper { @@ -655,6 +664,217 @@ export default class AppSearchSuper {
return filtered;
}
private processEmptyFilter({message, searchGroup}: ProcessSearchSuperResult) {
const {dialog, dom} = appDialogsManager.addDialogNew({
dialog: message.peerId,
container: searchGroup.list,
drawStatus: false,
avatarSize: 54
});
appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
}
private processPhotoVideoFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {
const media = appMessagesManager.getMediaFromMessage(message);
const div = document.createElement('div');
div.classList.add('grid-item');
//this.log(message, photo);
let wrapped: ReturnType<typeof wrapPhoto>;
const size = appPhotosManager.choosePhotoSize(media, 200, 200);
if(media._ !== 'photo') {
wrapped = wrapVideo({
doc: media,
message,
container: div,
boxWidth: 0,
boxHeight: 0,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
onlyPreview: true,
withoutPreloader: true,
noPlayButton: true,
size
}).thumb;
} else {
wrapped = wrapPhoto({
photo: media,
message,
container: div,
boxWidth: 0,
boxHeight: 0,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
withoutPreloader: true,
noBlur: true,
size
});
}
[wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {
image.classList.add('grid-item-media');
});
promises.push(wrapped.loadPromises.thumb);
elemsToAppend.push({element: div, message});
}
private processDocumentFilter({message, elemsToAppend, inputFilter}: ProcessSearchSuperResult) {
const document = appMessagesManager.getMediaFromMessage(message);
const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(document.type);
const div = wrapDocument({
message,
withTime: !showSender,
fontWeight: 400,
voiceAsMusic: true,
showSender,
searchContext: this.copySearchContext(inputFilter),
lazyLoadQueue: this.lazyLoadQueue,
noAutoDownload: true
});
if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(document.type)) {
div.classList.add('audio-48');
}
elemsToAppend.push({element: div, message});
}
private processUrlFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {
let webpage = (message.media as MessageMedia.messageMediaWebPage)?.webpage as WebPage.webPage;
if(!webpage) {
const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;
let url: string, display_url: string, sliced: string;
if(!entity) {
//this.log.error('NO ENTITY:', message);
const match = RichTextProcessor.matchUrl(message.message);
if(!match) {
//this.log.error('NO ENTITY AND NO MATCH:', message);
return;
}
url = match[0];
} else {
sliced = message.message.slice(entity.offset, entity.offset + entity.length);
}
if(entity?._ === 'messageEntityTextUrl') {
url = entity.url;
//display_url = sliced;
} else {
url = url || sliced;
}
display_url = url;
const same = message.message === url;
if(!url.match(/^(ftp|http|https):\/\//)) {
display_url = 'https://' + url;
url = url.includes('@') ? url : 'https://' + url;
}
display_url = new URL(display_url).hostname;
webpage = {
_: 'webPage',
url,
display_url,
id: '',
hash: 0
};
if(!same) {
webpage.description = message.message;
webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));
}
}
let previewDiv = document.createElement('div');
previewDiv.classList.add('preview', 'row-media');
//this.log('wrapping webpage', webpage);
if(webpage.photo) {
const res = wrapPhoto({
container: previewDiv,
message: null,
photo: webpage.photo as Photo.photo,
boxWidth: 0,
boxHeight: 0,
withoutPreloader: true,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
size: appPhotosManager.choosePhotoSize(webpage.photo as Photo.photo, 60, 60, false),
loadPromises: promises,
noBlur: true
});
} else {
previewDiv.classList.add('empty');
previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);
}
let title = webpage.rTitle || '';
let subtitle = webpage.rDescription || '';
const subtitleFragment = htmlToDocumentFragment(subtitle);
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
const a = aFragment.firstElementChild;
if(a instanceof HTMLAnchorElement) {
try { // can have 'URIError: URI malformed'
a.innerText = decodeURIComponent(a.href);
} catch(err) {
}
}
if(subtitleFragment.firstChild) {
subtitleFragment.append('\n');
}
subtitleFragment.append(a);
if(this.showSender) {
subtitleFragment.append('\n', appMessagesManager.wrapSenderToPeer(message));
}
if(!title) {
//title = new URL(webpage.url).hostname;
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
}
const row = new Row({
title,
titleRight: appMessagesManager.wrapSentTime(message),
subtitle: subtitleFragment,
havePadding: true,
clickable: true,
noRipple: true
});
/* const mediaDiv = document.createElement('div');
mediaDiv.classList.add('row-media'); */
row.container.append(previewDiv);
/* ripple(div);
div.append(previewDiv);
div.insertAdjacentHTML('beforeend', `
<div class="title">${title}${titleAdditionHTML}</div>
<div class="subtitle">${subtitle}</div>
<div class="url">${url}</div>
${sender}
`); */
if(row.container.innerText.trim().length) {
elemsToAppend.push({element: row.container, message});
}
}
public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {
const elemsToAppend: {element: HTMLElement, message: any}[] = [];
@ -674,73 +894,26 @@ export default class AppSearchSuper { @@ -674,73 +894,26 @@ export default class AppSearchSuper {
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': {
for(const message of messages) {
const {dialog, dom} = appDialogsManager.addDialogNew({
dialog: message.peerId,
container: searchGroup.list,
drawStatus: false,
avatarSize: 54
});
appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
}
if(searchGroup.list.childElementCount) {
searchGroup.setActive();
}
processCallback = this.processEmptyFilter;
break;
}
case 'inputMessagesFilterPhotoVideo': {
for(const message of messages) {
const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);
const div = document.createElement('div');
div.classList.add('grid-item');
//this.log(message, photo);
let wrapped: ReturnType<typeof wrapPhoto>;
const size = appPhotosManager.choosePhotoSize(media, 200, 200);
if(media._ !== 'photo') {
wrapped = wrapVideo({
doc: media,
message,
container: div,
boxWidth: 0,
boxHeight: 0,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
onlyPreview: true,
withoutPreloader: true,
noPlayButton: true,
size
}).thumb;
} else {
wrapped = wrapPhoto({
photo: media,
message,
container: div,
boxWidth: 0,
boxHeight: 0,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
withoutPreloader: true,
noBlur: true,
size
});
}
[wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {
image.classList.add('grid-item-media');
});
promises.push(wrapped.loadPromises.thumb);
elemsToAppend.push({element: div, message});
}
processCallback = this.processPhotoVideoFilter;
break;
}
@ -748,158 +921,12 @@ export default class AppSearchSuper { @@ -748,158 +921,12 @@ export default class AppSearchSuper {
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({
message,
withTime: !showSender,
fontWeight: 400,
voiceAsMusic: true,
showSender,
searchContext: this.copySearchContext(inputFilter),
lazyLoadQueue: this.lazyLoadQueue,
noAutoDownload: true
});
if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) {
div.classList.add('audio-48');
}
elemsToAppend.push({element: div, message});
}
processCallback = this.processDocumentFilter;
break;
}
case 'inputMessagesFilterUrl': {
for(let message of messages) {
let webpage: any;
if(message.media?.webpage && message.media.webpage._ !== 'webPageEmpty') {
webpage = message.media.webpage;
} else {
const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;
let url: string, display_url: string, sliced: string;
if(!entity) {
//this.log.error('NO ENTITY:', message);
const match = RichTextProcessor.matchUrl(message.message);
if(!match) {
//this.log.error('NO ENTITY AND NO MATCH:', message);
continue;
}
url = match[0];
} else {
sliced = message.message.slice(entity.offset, entity.offset + entity.length);
}
if(entity?._ === 'messageEntityTextUrl') {
url = entity.url;
//display_url = sliced;
} else {
url = url || sliced;
}
display_url = url;
const same = message.message === url;
if(!url.match(/^(ftp|http|https):\/\//)) {
display_url = 'https://' + url;
url = url.includes('@') ? url : 'https://' + url;
}
display_url = new URL(display_url).hostname;
webpage = {
url,
display_url
};
if(!same) {
webpage.description = message.message;
webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));
}
}
let div = document.createElement('div');
let previewDiv = document.createElement('div');
previewDiv.classList.add('preview', 'row-media');
//this.log('wrapping webpage', webpage);
if(webpage.photo) {
const res = wrapPhoto({
container: previewDiv,
message: null,
photo: webpage.photo,
boxWidth: 0,
boxHeight: 0,
withoutPreloader: true,
lazyLoadQueue: this.lazyLoadQueue,
middleware,
size: appPhotosManager.choosePhotoSize(webpage.photo, 60, 60, false),
loadPromises: promises,
noBlur: true
});
} else {
previewDiv.classList.add('empty');
previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);
}
let title = webpage.rTitle || '';
let subtitle = webpage.rDescription || '';
const subtitleFragment = htmlToDocumentFragment(subtitle);
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
const a = aFragment.firstElementChild;
if(a instanceof HTMLAnchorElement) {
a.innerText = decodeURIComponent(a.href);
}
if(subtitleFragment.firstChild) {
subtitleFragment.append('\n');
}
subtitleFragment.append(a);
if(this.showSender) {
subtitleFragment.append('\n', appMessagesManager.wrapSenderToPeer(message));
}
if(!title) {
//title = new URL(webpage.url).hostname;
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
}
const row = new Row({
title,
titleRight: appMessagesManager.wrapSentTime(message),
subtitle: subtitleFragment,
havePadding: true,
clickable: true,
noRipple: true
});
/* const mediaDiv = document.createElement('div');
mediaDiv.classList.add('row-media'); */
row.container.append(previewDiv);
/* ripple(div);
div.append(previewDiv);
div.insertAdjacentHTML('beforeend', `
<div class="title">${title}${titleAdditionHTML}</div>
<div class="subtitle">${subtitle}</div>
<div class="url">${url}</div>
${sender}
`); */
if(row.container.innerText.trim().length) {
elemsToAppend.push({element: row.container, message});
}
}
processCallback = this.processUrlFilter;
break;
}
@ -908,6 +935,23 @@ export default class AppSearchSuper { @@ -908,6 +935,23 @@ export default class AppSearchSuper {
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) {
promises.push(this.loadMutex);
}
@ -1163,7 +1207,7 @@ export default class AppSearchSuper { @@ -1163,7 +1207,7 @@ export default class AppSearchSuper {
}
promise.then(() => {
appImManager.setInnerPeer(peerId);
appImManager.setInnerPeer({peerId});
});
});
mediaTab.contentTab.append(this.membersList.list);

29
src/components/chat/bubbles.ts

@ -1011,7 +1011,9 @@ export default class ChatBubbles { @@ -1011,7 +1011,9 @@ export default class ChatBubbles {
const contactDiv: HTMLElement = findUpClassName(target, 'contact');
if(contactDiv) {
this.chat.appImManager.setInnerPeer(contactDiv.dataset.peerId.toPeerId());
this.chat.appImManager.setInnerPeer({
peerId: contactDiv.dataset.peerId.toPeerId()
});
return;
}
@ -1035,7 +1037,11 @@ export default class ChatBubbles { @@ -1035,7 +1037,11 @@ export default class ChatBubbles {
const replies = message.replies;
if(replies) {
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 { @@ -1064,11 +1070,14 @@ export default class ChatBubbles {
if(savedFrom) {
const [peerId, mid] = savedFrom.split('_');
this.chat.appImManager.setInnerPeer(peerId.toPeerId(), +mid);
this.chat.appImManager.setInnerPeer({
peerId: peerId.toPeerId(),
lastMsgId: +mid
});
} else {
const peerId = peerIdStr.toPeerId();
if(peerId !== NULL_PEER_ID) {
this.chat.appImManager.setInnerPeer(peerId);
this.chat.appImManager.setInnerPeer({peerId});
} else {
toast(I18n.format('HidAccount', true));
}
@ -1213,7 +1222,10 @@ export default class ChatBubbles { @@ -1213,7 +1222,10 @@ export default class ChatBubbles {
const savedFrom = bubble.dataset.savedFrom;
const [peerId, mid] = savedFrom.split('_');
////this.log('savedFrom', peerId, msgID);
this.chat.appImManager.setInnerPeer(peerId.toPeerId(), +mid);
this.chat.appImManager.setInnerPeer({
peerId: peerId.toPeerId(),
lastMsgId: +mid
});
return;
} else if(target.classList.contains('forward')) {
const mid = +bubble.dataset.mid;
@ -1240,7 +1252,12 @@ export default class ChatBubbles { @@ -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 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') {
this.chat.appImManager.setMessageId(, originalMessageId);

7
src/components/chat/chat.ts

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

2
src/components/chat/input.ts

@ -805,7 +805,7 @@ export default class ChatInput { @@ -805,7 +805,7 @@ export default class ChatInput {
const peerId = this.chat.peerId;
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;

26
src/components/chat/topbar.ts

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

17
src/components/peerTitle.ts

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

2
src/components/popups/forward.ts

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

4
src/components/sidebarLeft/index.ts

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

51
src/lib/appManagers/appDialogsManager.ts

@ -1358,9 +1358,11 @@ export class AppDialogsManager { @@ -1358,9 +1358,11 @@ export class AppDialogsManager {
const peerId = elem.dataset.peerId.toPeerId();
const lastMsgId = +elem.dataset.mid || undefined;
setPeerFunc(peerId, lastMsgId);
setPeerFunc({
peerId, lastMsgId
});
} else {
setPeerFunc(NULL_PEER_ID);
setPeerFunc();
}
}, {capture: true});
@ -1641,12 +1643,13 @@ export class AppDialogsManager { @@ -1641,12 +1643,13 @@ export class AppDialogsManager {
}
private getDialog(dialog: Dialog | PeerId): Dialog {
if(typeof(dialog) !== 'object' && dialog) {
if(typeof(dialog) !== 'object') {
const originalDialog = appMessagesManager.getDialogOnly(dialog);
if(!originalDialog) {
const peerId = dialog || NULL_PEER_ID;
return {
peerId: dialog,
peer: appPeersManager.getOutputPeer(dialog),
peerId,
peer: appPeersManager.getOutputPeer(peerId),
pFlags: {}
} as any;
}
@ -1712,6 +1715,30 @@ export class AppDialogsManager { @@ -1712,6 +1715,30 @@ export class AppDialogsManager {
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: {
dialog: Parameters<AppDialogsManager['addDialog']>[0],
container?: Parameters<AppDialogsManager['addDialog']>[1],
@ -1723,12 +1750,14 @@ export class AppDialogsManager { @@ -1723,12 +1750,14 @@ export class AppDialogsManager {
avatarSize?: number,
autonomous?: boolean,
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,
drawStatus = true,
rippleEnabled = true,
@ -1738,7 +1767,9 @@ export class AppDialogsManager { @@ -1738,7 +1767,9 @@ export class AppDialogsManager {
avatarSize = 54,
autonomous = !!container,
lazyLoadQueue?: LazyLoadQueueIntersector,
loadPromises?: Promise<any>[]) {
loadPromises?: Promise<any>[],
fromName?: string
) {
const dialog = this.getDialog(_dialog);
const peerId = dialog.peerId;
@ -1746,6 +1777,7 @@ export class AppDialogsManager { @@ -1746,6 +1777,7 @@ export class AppDialogsManager {
avatarEl.loadPromises = loadPromises;
avatarEl.lazyLoadQueue = lazyLoadQueue;
avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');
if(fromName !== undefined) avatarEl.setAttribute('peer-title', fromName);
avatarEl.setAttribute('peer', '' + peerId);
avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);
@ -1764,6 +1796,7 @@ export class AppDialogsManager { @@ -1764,6 +1796,7 @@ export class AppDialogsManager {
const peerTitle = new PeerTitle({
peerId,
fromName,
dialog: meAsSaved,
onlyFirstName,
plainText: false

107
src/lib/appManagers/appImManager.ts

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

20
src/lib/appManagers/appMessagesManager.ts

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

3
src/lib/appManagers/internalLink.ts

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

Loading…
Cancel
Save