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