Chatlist media preview
This commit is contained in:
parent
caa4e63189
commit
35d8775e77
@ -803,7 +803,7 @@ export default class AppSearchSuper {
|
||||
}
|
||||
}),
|
||||
|
||||
appMessagesManager.getConversations(query, 0, 20, 0)
|
||||
appMessagesManager.getConversations(query, 0, 20, 0).promise
|
||||
.then(onLoad)
|
||||
.then(value => {
|
||||
if(value) {
|
||||
|
@ -261,7 +261,7 @@ export default class AppSelectPeers {
|
||||
const pageCount = windowSize.windowH / 72 * 1.25 | 0;
|
||||
|
||||
const tempId = this.getTempId('dialogs');
|
||||
const promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId, true);
|
||||
const promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId, true).promise;
|
||||
this.promise = promise;
|
||||
const value = await promise;
|
||||
if(this.tempIds.dialogs !== tempId) {
|
||||
|
@ -212,11 +212,11 @@ export default class Scrollable extends ScrollableBase {
|
||||
}
|
||||
};
|
||||
|
||||
public prepend(...elements: HTMLElement[]) {
|
||||
public prepend(...elements: (HTMLElement | DocumentFragment)[]) {
|
||||
(this.splitUp || this.padding || this.container).prepend(...elements);
|
||||
}
|
||||
|
||||
public append(...elements: HTMLElement[]) {
|
||||
public append(...elements: (HTMLElement | DocumentFragment)[]) {
|
||||
(this.splitUp || this.padding || this.container).append(...elements);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,14 @@
|
||||
|
||||
import rootScope from "../lib/rootScope";
|
||||
|
||||
const SetTransition = (element: HTMLElement, className: string, forwards: boolean, duration: number, onTransitionEnd?: () => void, useRafs?: number) => {
|
||||
const SetTransition = (
|
||||
element: HTMLElement,
|
||||
className: string,
|
||||
forwards: boolean,
|
||||
duration: number,
|
||||
onTransitionEnd?: () => void,
|
||||
useRafs?: number
|
||||
) => {
|
||||
const {timeout, raf} = element.dataset;
|
||||
if(timeout !== undefined) {
|
||||
clearTimeout(+timeout);
|
||||
@ -19,7 +26,7 @@ const SetTransition = (element: HTMLElement, className: string, forwards: boolea
|
||||
}
|
||||
}
|
||||
|
||||
if(useRafs) {
|
||||
if(useRafs && rootScope.settings.animationsEnabled && duration) {
|
||||
element.dataset.raf = '' + window.requestAnimationFrame(() => {
|
||||
delete element.dataset.raf;
|
||||
SetTransition(element, className, forwards, duration, onTransitionEnd, useRafs - 1);
|
||||
@ -43,7 +50,7 @@ const SetTransition = (element: HTMLElement, className: string, forwards: boolea
|
||||
onTransitionEnd && onTransitionEnd();
|
||||
};
|
||||
|
||||
if(!rootScope.settings.animationsEnabled) {
|
||||
if(!rootScope.settings.animationsEnabled || !duration) {
|
||||
element.classList.remove('animating', 'backwards');
|
||||
afterTimeout();
|
||||
return;
|
||||
|
@ -16,7 +16,7 @@ export const MAIN_DOMAIN = 'web.telegram.org';
|
||||
const App = {
|
||||
id: 1025907,
|
||||
hash: '452b0359b988148995f22ff0f4229750',
|
||||
version: '0.8.0',
|
||||
version: '0.8.1',
|
||||
langPackVersion: '0.3.3',
|
||||
langPack: 'macos',
|
||||
langPackCode: 'en',
|
||||
|
@ -4,6 +4,8 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
// import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
|
||||
|
||||
export const loadedURLs: {[url: string]: boolean} = {};
|
||||
const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => {
|
||||
if(elem instanceof HTMLImageElement || elem instanceof HTMLVideoElement) elem.src = url;
|
||||
@ -12,8 +14,12 @@ const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoE
|
||||
};
|
||||
|
||||
// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз.
|
||||
export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement,
|
||||
url: string, callback?: (err?: Event) => void, useCache = true) {
|
||||
export default function renderImageFromUrl(
|
||||
elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement,
|
||||
url: string,
|
||||
callback?: (err?: Event) => void,
|
||||
useCache = true
|
||||
) {
|
||||
if(!url) {
|
||||
console.error('renderImageFromUrl: no url?', elem, url);
|
||||
callback && callback();
|
||||
@ -26,6 +32,7 @@ export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement
|
||||
}
|
||||
|
||||
callback && callback();
|
||||
// callback && getHeavyAnimationPromise().then(() => callback());
|
||||
} else {
|
||||
const isImage = elem instanceof HTMLImageElement;
|
||||
const loader = isImage ? elem as HTMLImageElement : new Image();
|
||||
@ -39,16 +46,10 @@ export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement
|
||||
|
||||
loadedURLs[url] = true;
|
||||
//console.log('onload:', url, performance.now() - perf);
|
||||
if(callback) {
|
||||
// TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются
|
||||
/* getHeavyAnimationPromise().then(() => {
|
||||
callback();
|
||||
}); */
|
||||
callback();
|
||||
}
|
||||
|
||||
//callback && callback();
|
||||
});
|
||||
// TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются
|
||||
// callback && getHeavyAnimationPromise().then(() => callback());
|
||||
callback && callback();
|
||||
}, {once: true});
|
||||
|
||||
if(callback) {
|
||||
loader.addEventListener('error', callback);
|
||||
|
@ -4,6 +4,9 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import type DialogsStorage from "../storages/dialogs";
|
||||
import type {MyDialogFilter as DialogFilter, MyDialogFilter} from "../storages/filters";
|
||||
import type { LazyLoadQueueIntersector } from "../../components/lazyLoadQueue";
|
||||
import AvatarElement from "../../components/avatar";
|
||||
import DialogsContextMenu from "../../components/dialogsContextMenu";
|
||||
import { horizontalMenu } from "../../components/horizontalMenu";
|
||||
@ -20,7 +23,6 @@ import apiUpdatesManager from "./apiUpdatesManager";
|
||||
import appPeersManager from './appPeersManager';
|
||||
import appImManager from "./appImManager";
|
||||
import appMessagesManager, { Dialog } from "./appMessagesManager";
|
||||
import {MyDialogFilter as DialogFilter, MyDialogFilter} from "../storages/filters";
|
||||
import appStateManager, { State } from "./appStateManager";
|
||||
import appUsersManager from "./appUsersManager";
|
||||
import Button from "../../components/button";
|
||||
@ -31,7 +33,6 @@ import appNotificationsManager from "./appNotificationsManager";
|
||||
import PeerTitle from "../../components/peerTitle";
|
||||
import I18n, { FormatterArguments, i18n, LangPackKey, _i18n } from "../langPack";
|
||||
import findUpTag from "../../helpers/dom/findUpTag";
|
||||
import { LazyLoadQueueIntersector } from "../../components/lazyLoadQueue";
|
||||
import lottieLoader from "../lottieLoader";
|
||||
import { wrapLocalSticker, wrapPhoto } from "../../components/wrappers";
|
||||
import AppEditFolderTab from "../../components/sidebarLeft/tabs/editFolder";
|
||||
@ -48,8 +49,8 @@ import { isTouchSupported } from "../../helpers/touchSupport";
|
||||
import handleTabSwipe from "../../helpers/dom/handleTabSwipe";
|
||||
import windowSize from "../../helpers/windowSize";
|
||||
import isInDOM from "../../helpers/dom/isInDOM";
|
||||
import appPhotosManager from "./appPhotosManager";
|
||||
import DialogsStorage from "../storages/dialogs";
|
||||
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
|
||||
import { MyDocument } from "./appDocsManager";
|
||||
|
||||
export type DialogDom = {
|
||||
avatarEl: AvatarElement,
|
||||
@ -515,7 +516,7 @@ export class AppDialogsManager {
|
||||
|
||||
if(this.isDialogMustBeInViewport(dialog)) {
|
||||
if(!this.doms.hasOwnProperty(dialog.peerId)) {
|
||||
const ret = this.addDialogNew({dialog});
|
||||
const ret = this.addListDialog({dialog});
|
||||
if(ret) {
|
||||
const idx = appMessagesManager.getDialogByPeerId(dialog.peerId)[1];
|
||||
positionElementByIndex(ret.dom.listEl, this.chatList, idx);
|
||||
@ -749,11 +750,12 @@ export class AppDialogsManager {
|
||||
try {
|
||||
//console.time('getDialogs time');
|
||||
|
||||
const getConversationPromise = (this.filterId > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => {
|
||||
return appMessagesManager.getConversations('', offsetIndex, loadCount, filterId, true);
|
||||
});
|
||||
const getConversationsResult = appMessagesManager.getConversations('', offsetIndex, loadCount, filterId, true);
|
||||
if(getConversationsResult.cached) {
|
||||
this.chatsPreloader.remove();
|
||||
}
|
||||
|
||||
const result = await getConversationPromise;
|
||||
const result = await getConversationsResult.promise;
|
||||
|
||||
if(this.loadDialogsPromise !== promise) {
|
||||
return;
|
||||
@ -779,12 +781,26 @@ export class AppDialogsManager {
|
||||
if(result.dialogs.length) {
|
||||
const dialogs = side === 'top' ? result.dialogs.slice().reverse() : result.dialogs;
|
||||
|
||||
const container = document.createDocumentFragment();
|
||||
const loadPromises: Promise<any>[] = [];
|
||||
const append = side === 'bottom';
|
||||
dialogs.forEach((dialog) => {
|
||||
this.addDialogNew({
|
||||
this.addListDialog({
|
||||
dialog,
|
||||
append: side === 'bottom'
|
||||
container,
|
||||
append,
|
||||
loadPromises,
|
||||
isBatch: true
|
||||
});
|
||||
});
|
||||
|
||||
if(container.childElementCount) {
|
||||
if(loadPromises.length) {
|
||||
await Promise.all(loadPromises).finally();
|
||||
}
|
||||
|
||||
this.scroll[append ? 'append' : 'prepend'](container);
|
||||
}
|
||||
}
|
||||
|
||||
const offsetDialog = result.dialogs[side === 'top' ? 0 : result.dialogs.length - 1];
|
||||
@ -1215,11 +1231,28 @@ export class AppDialogsManager {
|
||||
private reorderDialogs() {
|
||||
//const perf = performance.now();
|
||||
if(this.reorderDialogsTimeout) {
|
||||
window.cancelAnimationFrame(this.reorderDialogsTimeout);
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.loadDialogsPromise) {
|
||||
this.loadDialogsPromise.then(() => {
|
||||
this.reorderDialogs();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.reorderDialogsTimeout = window.requestAnimationFrame(() => {
|
||||
this.reorderDialogsTimeout = 0;
|
||||
|
||||
if(this.loadDialogsPromise) {
|
||||
this.loadDialogsPromise.then(() => {
|
||||
this.reorderDialogs();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const dialogs = appMessagesManager.dialogsStorage.getFolder(this.filterId);
|
||||
|
||||
const currentOrder = (Array.from(this.chatList.children) as HTMLElement[]).map(el => +el.dataset.peerId);
|
||||
@ -1253,7 +1286,14 @@ export class AppDialogsManager {
|
||||
});
|
||||
}
|
||||
|
||||
public setLastMessage(dialog: Dialog, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
|
||||
public setLastMessage(
|
||||
dialog: Dialog,
|
||||
lastMessage?: any,
|
||||
dom?: DialogDom,
|
||||
highlightWord?: string,
|
||||
loadPromises?: Promise<any>[],
|
||||
isBatch = false
|
||||
) {
|
||||
///////console.log('setlastMessage:', lastMessage);
|
||||
if(!dom) {
|
||||
dom = this.getDialogDom(dialog.peerId);
|
||||
@ -1280,7 +1320,6 @@ export class AppDialogsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const peer = dialog.peer;
|
||||
const peerId = dialog.peerId;
|
||||
//let peerId = appMessagesManager.getMessagePeer(lastMessage);
|
||||
|
||||
@ -1288,35 +1327,49 @@ export class AppDialogsManager {
|
||||
|
||||
/* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {
|
||||
|
||||
let mediaContainer: HTMLElement;
|
||||
if(!lastMessage.deleted && !draftMessage) {
|
||||
const media: MyDocument | MyPhoto = appMessagesManager.getMediaFromMessage(lastMessage);
|
||||
if(media && (media._ === 'photo' || (['video', 'gif'] as MyDocument['type'][]).includes(media.type))) {
|
||||
const size = appPhotosManager.choosePhotoSize(media, 20, 20);
|
||||
|
||||
if(size._ !== 'photoSizeEmpty') {
|
||||
mediaContainer = document.createElement('div');
|
||||
mediaContainer.classList.add('dialog-subtitle-media');
|
||||
|
||||
wrapPhoto({
|
||||
photo: media,
|
||||
message: lastMessage,
|
||||
container: mediaContainer,
|
||||
withoutPreloader: true,
|
||||
size,
|
||||
loadPromises
|
||||
});
|
||||
|
||||
if((media as MyDocument).type === 'video') {
|
||||
const playIcon = document.createElement('span');
|
||||
playIcon.classList.add('tgico-play');
|
||||
|
||||
mediaContainer.append(playIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withoutMediaType = !!mediaContainer && !!lastMessage?.message;
|
||||
|
||||
let fragment: DocumentFragment;
|
||||
if(highlightWord && lastMessage.message) {
|
||||
fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord);
|
||||
fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord, withoutMediaType);
|
||||
} else if(draftMessage) {
|
||||
fragment = appMessagesManager.wrapMessageForReply(draftMessage);
|
||||
} else if(!lastMessage.deleted) {
|
||||
fragment = appMessagesManager.wrapMessageForReply(lastMessage);
|
||||
fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, undefined, withoutMediaType);
|
||||
}
|
||||
|
||||
/* if(!lastMessage.deleted && !draftMessage) {
|
||||
const photo = lastMessage.media?.photo;
|
||||
if(photo) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('dialog-subtitle-media');
|
||||
|
||||
const size = appPhotosManager.choosePhotoSize(photo, 20, 20);
|
||||
|
||||
wrapPhoto({
|
||||
photo,
|
||||
message: lastMessage,
|
||||
container: div,
|
||||
withoutPreloader: true,
|
||||
size
|
||||
});
|
||||
|
||||
fragment.prepend(div);
|
||||
// dom.subtitleEl.prepend(div);
|
||||
}
|
||||
} */
|
||||
if(mediaContainer) {
|
||||
fragment.prepend(mediaContainer);
|
||||
}
|
||||
|
||||
replaceContent(dom.lastMessageSpan, fragment);
|
||||
|
||||
@ -1326,7 +1379,7 @@ export class AppDialogsManager {
|
||||
bold.classList.add('danger');
|
||||
bold.append(i18n('Draft'), ': ');
|
||||
dom.lastMessageSpan.prepend(bold);
|
||||
} else if(peer._ !== 'peerUser' && peerId !== lastMessage.fromId && !lastMessage.action) {
|
||||
} else if(peerId < 0 && peerId !== lastMessage.fromId && !lastMessage.action) {
|
||||
const sender = appPeersManager.getPeer(lastMessage.fromId);
|
||||
if(sender && sender.id) {
|
||||
const senderBold = document.createElement('b');
|
||||
@ -1354,13 +1407,13 @@ export class AppDialogsManager {
|
||||
} else dom.lastTimeSpan.textContent = '';
|
||||
|
||||
if(this.doms[peerId] === dom) {
|
||||
this.setUnreadMessages(dialog);
|
||||
this.setUnreadMessages(dialog, isBatch);
|
||||
} else { // means search
|
||||
dom.listEl.dataset.mid = lastMessage.mid;
|
||||
}
|
||||
}
|
||||
|
||||
private setUnreadMessages(dialog: Dialog) {
|
||||
private setUnreadMessages(dialog: Dialog, isBatch = false) {
|
||||
const dom = this.getDialogDom(dialog.peerId);
|
||||
|
||||
if(dialog.folder_id === 1) {
|
||||
@ -1372,10 +1425,12 @@ export class AppDialogsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);
|
||||
const wasMuted = dom.listEl.classList.contains('is-muted');
|
||||
if(isMuted !== wasMuted) {
|
||||
SetTransition(dom.listEl, 'is-muted', isMuted, 200);
|
||||
if(!isBatch) {
|
||||
const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);
|
||||
const wasMuted = dom.listEl.classList.contains('is-muted');
|
||||
if(isMuted !== wasMuted) {
|
||||
SetTransition(dom.listEl, 'is-muted', isMuted, 200);
|
||||
}
|
||||
}
|
||||
|
||||
const lastMessage = dialog.draft?._ === 'draftMessage' ?
|
||||
@ -1422,12 +1477,14 @@ export class AppDialogsManager {
|
||||
}
|
||||
}
|
||||
|
||||
SetTransition(dom.unreadBadge, 'is-visible', hasUnreadBadge, 200, hasUnreadBadge ? undefined : () => {
|
||||
const transitionDuration = isBatch ? 0 : 200;
|
||||
|
||||
SetTransition(dom.unreadBadge, 'is-visible', hasUnreadBadge, transitionDuration, hasUnreadBadge ? undefined : () => {
|
||||
dom.unreadBadge.remove();
|
||||
}, !isUnreadBadgeMounted ? 2 : 0);
|
||||
|
||||
if(dom.mentionsBadge) {
|
||||
SetTransition(dom.mentionsBadge, 'is-visible', hasMentionsBadge, 200, hasMentionsBadge ? undefined : () => {
|
||||
SetTransition(dom.mentionsBadge, 'is-visible', hasMentionsBadge, transitionDuration, hasMentionsBadge ? undefined : () => {
|
||||
dom.mentionsBadge.remove();
|
||||
delete dom.mentionsBadge;
|
||||
}, !isMentionBadgeMounted ? 2 : 0);
|
||||
@ -1474,9 +1531,55 @@ export class AppDialogsManager {
|
||||
return this.doms[peerId];
|
||||
}
|
||||
|
||||
private getDialog(dialog: Dialog | number): Dialog {
|
||||
if(typeof(dialog) === 'number') {
|
||||
const originalDialog = appMessagesManager.getDialogOnly(dialog);
|
||||
if(!originalDialog) {
|
||||
return {
|
||||
peerId: dialog,
|
||||
peer: appPeersManager.getOutputPeer(dialog),
|
||||
pFlags: {}
|
||||
} as any;
|
||||
}
|
||||
|
||||
return originalDialog;
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private addListDialog(options: Parameters<AppDialogsManager['addDialogNew']>[0] & {isBatch?: boolean}) {
|
||||
const dialog = this.getDialog(options.dialog);
|
||||
|
||||
const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);
|
||||
if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) ||
|
||||
(!filter && this.filterId !== dialog.folder_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!options.container) {
|
||||
options.container = this.scroll;
|
||||
}
|
||||
|
||||
const ret = this.addDialogNew(options);
|
||||
|
||||
if(ret) {
|
||||
this.doms[dialog.peerId] = ret.dom;
|
||||
|
||||
const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);
|
||||
if(isMuted) {
|
||||
ret.dom.listEl.classList.add('is-muted');
|
||||
}
|
||||
|
||||
this.setLastMessage(dialog, undefined, undefined, undefined, options.loadPromises, options.isBatch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public addDialogNew(options: {
|
||||
dialog: Dialog | number,
|
||||
container?: HTMLUListElement | Scrollable | false,
|
||||
container?: Parameters<AppDialogsManager['addDialog']>[1],
|
||||
drawStatus?: boolean,
|
||||
rippleEnabled?: boolean,
|
||||
onlyFirstName?: boolean,
|
||||
@ -1485,60 +1588,40 @@ export class AppDialogsManager {
|
||||
avatarSize?: number,
|
||||
autonomous?: boolean,
|
||||
lazyLoadQueue?: LazyLoadQueueIntersector,
|
||||
loadPromises?: Promise<any>[]
|
||||
}) {
|
||||
return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue);
|
||||
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);
|
||||
}
|
||||
|
||||
public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable | false, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true, append = true, avatarSize = 54, autonomous = !!container, lazyLoadQueue?: LazyLoadQueueIntersector) {
|
||||
let dialog: Dialog;
|
||||
|
||||
if(typeof(_dialog) === 'number') {
|
||||
let originalDialog = appMessagesManager.getDialogOnly(_dialog);
|
||||
if(!originalDialog) {
|
||||
originalDialog = {
|
||||
peerId: _dialog,
|
||||
peer: appPeersManager.getOutputPeer(_dialog),
|
||||
pFlags: {}
|
||||
} as any;
|
||||
}
|
||||
|
||||
dialog = originalDialog;
|
||||
} else {
|
||||
dialog = _dialog;
|
||||
}
|
||||
|
||||
const peerId: number = dialog.peerId;
|
||||
|
||||
if(container === undefined) {
|
||||
if(this.doms[peerId] || dialog.migratedTo !== undefined) return;
|
||||
|
||||
const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);
|
||||
if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterId !== dialog.folder_id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
public addDialog(_dialog: Dialog | number,
|
||||
container?: HTMLElement | Scrollable | DocumentFragment | false,
|
||||
drawStatus = true,
|
||||
rippleEnabled = true,
|
||||
onlyFirstName = false,
|
||||
meAsSaved = true,
|
||||
append = true,
|
||||
avatarSize = 54,
|
||||
autonomous = !!container,
|
||||
lazyLoadQueue?: LazyLoadQueueIntersector,
|
||||
loadPromises?: Promise<any>[]) {
|
||||
const dialog = this.getDialog(_dialog);
|
||||
const peerId = dialog.peerId;
|
||||
|
||||
const avatarEl = new AvatarElement();
|
||||
avatarEl.loadPromises = loadPromises;
|
||||
avatarEl.lazyLoadQueue = lazyLoadQueue;
|
||||
avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');
|
||||
avatarEl.setAttribute('peer', '' + peerId);
|
||||
avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);
|
||||
|
||||
if(drawStatus && peerId !== rootScope.myId && dialog.peer) {
|
||||
const peer = dialog.peer;
|
||||
if(drawStatus && peerId !== rootScope.myId) {
|
||||
if(peerId > 0) {
|
||||
const user = appUsersManager.getUser(peerId);
|
||||
//console.log('found user', user);
|
||||
|
||||
switch(peer._) {
|
||||
case 'peerUser':
|
||||
const user = appUsersManager.getUser(peerId);
|
||||
//console.log('found user', user);
|
||||
|
||||
if(user.status && user.status._ === 'userStatusOnline') {
|
||||
avatarEl.classList.add('is-online');
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if(user.status && user.status._ === 'userStatusOnline') {
|
||||
avatarEl.classList.add('is-online');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1629,23 +1712,8 @@ export class AppDialogsManager {
|
||||
good = true;
|
||||
}
|
||||
} */
|
||||
const method: 'append' | 'prepend' = append ? 'append' : 'prepend';
|
||||
if(container === undefined/* || good */) {
|
||||
this.scroll[method](li);
|
||||
|
||||
this.doms[dialog.peerId] = dom;
|
||||
|
||||
/* if(container) {
|
||||
container.append(li);
|
||||
} */
|
||||
|
||||
const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);
|
||||
if(isMuted) {
|
||||
li.classList.add('is-muted');
|
||||
}
|
||||
|
||||
this.setLastMessage(dialog);
|
||||
} else if(container) {
|
||||
if(container) {
|
||||
const method = append ? 'append' : 'prepend';
|
||||
container[method](li);
|
||||
}
|
||||
|
||||
|
@ -1639,7 +1639,7 @@ export class AppMessagesManager {
|
||||
for(; folderId < 2; ++folderId) {
|
||||
let offsetIndex = 0;
|
||||
for(;;) {
|
||||
const {dialogs} = await appMessagesManager.getConversations(query, offsetIndex, limit, folderId);
|
||||
const {dialogs} = await appMessagesManager.getConversations(query, offsetIndex, limit, folderId).promise;
|
||||
|
||||
if(dialogs.length) {
|
||||
outDialogs.push(...dialogs);
|
||||
@ -2508,9 +2508,9 @@ export class AppMessagesManager {
|
||||
message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities); // ! only in this order, otherwise bold and emoji formatting won't work
|
||||
}
|
||||
|
||||
public wrapMessageForReply(message: any, text: string, usingMids: number[], plain: true, highlightWord?: string): string;
|
||||
public wrapMessageForReply(message: any, text?: string, usingMids?: number[], plain?: false, highlightWord?: string): DocumentFragment;
|
||||
public wrapMessageForReply(message: any, text: string = message.message, usingMids?: number[], plain?: boolean, highlightWord?: string): DocumentFragment | string {
|
||||
public wrapMessageForReply(message: any, text: string, usingMids: number[], plain: true, highlightWord?: string, withoutMediaType?: boolean): string;
|
||||
public wrapMessageForReply(message: any, text?: string, usingMids?: number[], plain?: false, highlightWord?: string, withoutMediaType?: boolean): DocumentFragment;
|
||||
public wrapMessageForReply(message: any, text: string = message.message, usingMids?: number[], plain?: boolean, highlightWord?: string, withoutMediaType?: boolean): DocumentFragment | string {
|
||||
const parts: (HTMLElement | string)[] = [];
|
||||
|
||||
const addPart = (langKey: LangPackKey, part?: string | HTMLElement, text?: string) => {
|
||||
@ -2557,7 +2557,7 @@ export class AppMessagesManager {
|
||||
usingFullAlbum = false;
|
||||
}
|
||||
|
||||
if(!usingFullAlbum) {
|
||||
if(!usingFullAlbum && !withoutMediaType) {
|
||||
const media = message.media;
|
||||
switch(media._) {
|
||||
case 'messageMediaPhoto':
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
import { filterUnique } from "../../helpers/array";
|
||||
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
||||
import cleanSearchText from "../../helpers/cleanSearchText";
|
||||
import cleanUsername from "../../helpers/cleanUsername";
|
||||
import { tsNow } from "../../helpers/date";
|
||||
@ -42,7 +43,7 @@ export class AppUsersManager {
|
||||
private users: {[userId: number]: User};
|
||||
private usernames: {[username: string]: number};
|
||||
private contactsIndex: SearchIndex<number>;
|
||||
private contactsFillPromise: Promise<Set<number>>;
|
||||
private contactsFillPromise: CancellablePromise<Set<number>>;
|
||||
private contactsList: Set<number>;
|
||||
private updatedContactsList: boolean;
|
||||
|
||||
@ -138,7 +139,8 @@ export class AppUsersManager {
|
||||
});
|
||||
|
||||
if(contactsList.length) {
|
||||
this.contactsFillPromise = Promise.resolve(this.contactsList);
|
||||
this.contactsFillPromise = deferredPromise();
|
||||
this.contactsFillPromise.resolve(this.contactsList);
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,13 +200,19 @@ export class AppUsersManager {
|
||||
|
||||
public fillContacts() {
|
||||
if(this.contactsFillPromise && this.updatedContactsList) {
|
||||
return this.contactsFillPromise;
|
||||
return {
|
||||
cached: this.contactsFillPromise.isFulfilled,
|
||||
promise: this.contactsFillPromise
|
||||
};
|
||||
}
|
||||
|
||||
this.updatedContactsList = true;
|
||||
|
||||
const promise = apiManager.invokeApi('contacts.getContacts').then((result) => {
|
||||
const promise = deferredPromise<Set<number>>();
|
||||
apiManager.invokeApi('contacts.getContacts').then((result) => {
|
||||
if(result._ === 'contacts.contacts') {
|
||||
this.contactsList.clear();
|
||||
|
||||
this.saveApiUsers(result.users);
|
||||
|
||||
result.contacts.forEach((contact) => {
|
||||
@ -212,14 +220,19 @@ export class AppUsersManager {
|
||||
});
|
||||
|
||||
this.onContactsModified();
|
||||
|
||||
this.contactsFillPromise = promise;
|
||||
}
|
||||
|
||||
this.contactsFillPromise = promise;
|
||||
|
||||
return this.contactsList;
|
||||
promise.resolve(this.contactsList);
|
||||
}, () => {
|
||||
this.updatedContactsList = false;
|
||||
});
|
||||
|
||||
return this.contactsFillPromise || (this.contactsFillPromise = promise);
|
||||
return {
|
||||
cached: this.contactsFillPromise?.isFulfilled,
|
||||
promise: this.contactsFillPromise || (this.contactsFillPromise = promise)
|
||||
};
|
||||
}
|
||||
|
||||
public resolveUsername(username: string): Promise<Chat | User> {
|
||||
@ -265,7 +278,7 @@ export class AppUsersManager {
|
||||
}
|
||||
|
||||
public getContacts(query?: string, includeSaved = false, sortBy: 'name' | 'online' | 'none' = 'name') {
|
||||
return this.fillContacts().then(_contactsList => {
|
||||
return this.fillContacts().promise.then(_contactsList => {
|
||||
let contactsList = [..._contactsList];
|
||||
if(query) {
|
||||
const results = this.contactsIndex.search(query);
|
||||
|
@ -599,7 +599,26 @@ export default class DialogsStorage {
|
||||
return indexStr;
|
||||
}
|
||||
|
||||
public getDialogs(query = '', offsetIndex?: number, limit = 20, folderId = 0, skipMigrated = false) {
|
||||
public getDialogs(query = '', offsetIndex?: number, limit = 20, folderId = 0, skipMigrated = false): {
|
||||
cached: boolean;
|
||||
promise: Promise<{
|
||||
dialogs: Dialog[];
|
||||
count: number;
|
||||
isEnd: boolean;
|
||||
}>;
|
||||
} {
|
||||
if(folderId > 1) {
|
||||
const fillContactsResult = this.appUsersManager.fillContacts();
|
||||
if(!fillContactsResult.cached) {
|
||||
return {
|
||||
cached: false,
|
||||
promise: fillContactsResult.promise.then(() => {
|
||||
return this.getDialogs(query, offsetIndex, limit, folderId, skipMigrated).promise;
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const realFolderId = folderId > 1 ? 0 : folderId;
|
||||
let curDialogStorage = this.getFolder(folderId, skipMigrated);
|
||||
|
||||
@ -641,37 +660,43 @@ export default class DialogsStorage {
|
||||
|
||||
const loadedAll = this.isDialogsLoaded(realFolderId);
|
||||
if(query || loadedAll || curDialogStorage.length >= offset + limit) {
|
||||
return Promise.resolve({
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit),
|
||||
count: loadedAll ? curDialogStorage.length : null,
|
||||
isEnd: loadedAll && (offset + limit) >= curDialogStorage.length
|
||||
});
|
||||
return {
|
||||
cached: true,
|
||||
promise: Promise.resolve({
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit),
|
||||
count: loadedAll ? curDialogStorage.length : null,
|
||||
isEnd: loadedAll && (offset + limit) >= curDialogStorage.length
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
return this.appMessagesManager.getTopMessages(limit, realFolderId).then(result => {
|
||||
//const curDialogStorage = this[folderId];
|
||||
if(skipMigrated) {
|
||||
curDialogStorage = this.getFolder(folderId, skipMigrated);
|
||||
}
|
||||
return {
|
||||
cached: false,
|
||||
promise: this.appMessagesManager.getTopMessages(limit, realFolderId).then(result => {
|
||||
//const curDialogStorage = this[folderId];
|
||||
if(skipMigrated) {
|
||||
curDialogStorage = this.getFolder(folderId, skipMigrated);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if(offsetIndex > 0) {
|
||||
for(let length = curDialogStorage.length; offset < length; ++offset) {
|
||||
if(offsetIndex > curDialogStorage[offset][indexStr]) {
|
||||
break;
|
||||
offset = 0;
|
||||
if(offsetIndex > 0) {
|
||||
for(let length = curDialogStorage.length; offset < length; ++offset) {
|
||||
if(offsetIndex > curDialogStorage[offset][indexStr]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//this.log.warn(offset, offset + limit, curDialogStorage.dialogs.length, this.dialogs.length);
|
||||
//this.log.warn(offset, offset + limit, curDialogStorage.dialogs.length, this.dialogs.length);
|
||||
|
||||
return {
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit),
|
||||
count: result.count === undefined ? curDialogStorage.length : result.count,
|
||||
// isEnd: this.isDialogsLoaded(realFolderId) && (offset + limit) >= curDialogStorage.length
|
||||
isEnd: result.isEnd
|
||||
};
|
||||
});
|
||||
return {
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit),
|
||||
count: result.count === undefined ? curDialogStorage.length : result.count,
|
||||
// isEnd: this.isDialogsLoaded(realFolderId) && (offset + limit) >= curDialogStorage.length
|
||||
isEnd: result.isEnd
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
// only 0 and 1 folders
|
||||
|
@ -2049,6 +2049,14 @@ $bubble-margin: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.sticker,
|
||||
&.round,
|
||||
&.emoji-big {
|
||||
.message {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-border,
|
||||
.quote:before {
|
||||
background-color: var(--message-out-primary-color);
|
||||
|
@ -307,6 +307,17 @@ ul.chatlist {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
.tgico-play {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
line-height: 1;
|
||||
font-size: .625rem;
|
||||
}
|
||||
|
||||
.media-photo {
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
|
Loading…
Reference in New Issue
Block a user