design changes

fixes
This commit is contained in:
Eduard Kuzmenko 2022-11-27 17:09:10 +04:00
parent 4609f6cac5
commit 8e4b9687ce
60 changed files with 5753 additions and 821 deletions

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 496 KiB

View File

@ -204,7 +204,7 @@ export default class AppSearch {
appDialogsManager.addDialogAndSetLastMessage({
peerId,
container: this.scrollable/* searchGroup.list */,
avatarSize: 54,
avatarSize: 'bigger',
meAsSaved: false,
message,
query,

View File

@ -73,6 +73,7 @@ import SwipeHandler from './swipeHandler';
import wrapDocument from './wrappers/document';
import wrapPhoto from './wrappers/photo';
import wrapVideo from './wrappers/video';
import noop from '../helpers/noop';
// const testScroll = false;
@ -610,7 +611,7 @@ export default class AppSearchSuper {
const {dom} = appDialogsManager.addDialogNew({
peerId: message.peerId,
container: searchGroup.list,
avatarSize: 54,
avatarSize: 'bigger',
loadPromises
});
@ -625,7 +626,7 @@ export default class AppSearchSuper {
});
loadPromises.push(setLastMessagePromise);
return Promise.all(loadPromises);
return Promise.all(loadPromises).then(noop);
}
private async processPhotoVideoFilter({message, promises, middleware}: ProcessSearchSuperResult) {
@ -705,10 +706,8 @@ export default class AppSearchSuper {
let url: string, display_url: string, sliced: string;
if(!entity) {
// this.log.error('NO ENTITY:', message);
const match = matchUrl(message.message);
if(!match) {
// this.log.error('NO ENTITY AND NO MATCH:', message);
return;
}
@ -748,7 +747,7 @@ export default class AppSearchSuper {
}
const previewDiv = document.createElement('div');
previewDiv.classList.add('preview', 'row-media', 'row-media-big');
previewDiv.classList.add('preview');
// this.log('wrapping webpage', webpage);
@ -808,19 +807,7 @@ export default class AppSearchSuper {
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}
`); */
row.applyMediaElement(previewDiv, 'big');
if(row.container.innerText.trim().length) {
return {message, element: row.container};
@ -923,6 +910,10 @@ export default class AppSearchSuper {
const method = append ? 'append' : 'prepend';
elemsToAppend.forEach((details) => {
const {element, message} = details;
if(!message) {
debugger;
}
const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, inputFilter);
element.classList.add('search-super-item');
element.dataset.mid = '' + message.mid;
@ -982,12 +973,12 @@ export default class AppSearchSuper {
const {dom} = appDialogsManager.addDialogNew({
peerId: peerId,
container: group.list,
avatarSize: 48,
avatarSize: 'abitbigger',
autonomous: group.autonomous
});
return {dom, peerId};
}).forEach(async({dom, peerId}) => {
}).filter(Boolean).forEach(async({dom, peerId}) => {
const peer = await this.managers.appPeersManager.getPeer(peerId);
if(showMembersCount && (peer.participants_count || peer.participants)) {
const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(cleanSearchText(query))})`, 'gi');
@ -1006,7 +997,7 @@ export default class AppSearchSuper {
username = '@' + username;
}
dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
dom.lastMessageSpan.textContent = username;
}
});
@ -1024,7 +1015,7 @@ export default class AppSearchSuper {
};
return Promise.all([
this.managers.appUsersManager.getContactsPeerIds(query, true)
this.managers.appUsersManager.getContactsPeerIds(query, true, undefined, 10)
.then(onLoad)
.then((contacts) => {
if(contacts) {
@ -1084,7 +1075,7 @@ export default class AppSearchSuper {
peerId: peerId,
container: this.searchGroups.recent.list,
meAsSaved: true,
avatarSize: 48,
avatarSize: 'abitbigger',
autonomous: true
});
@ -1113,14 +1104,16 @@ export default class AppSearchSuper {
// console.log('got top categories:', categories);
if(peers.length) {
peers.forEach((peer) => {
appDialogsManager.addDialogNew({
const {dom} = appDialogsManager.addDialogNew({
peerId: peer.id,
container: this.searchGroups.people.list,
onlyFirstName: true,
avatarSize: 54,
avatarSize: 'bigger',
autonomous: false,
noIcons: this.searchGroups.people.noIcons
});
dom.subtitleEl.remove();
});
}

View File

@ -6,7 +6,7 @@
import type {ChatRights} from '../lib/appManagers/appChatsManager';
import type {Dialog} from '../lib/appManagers/appMessagesManager';
import appDialogsManager from '../lib/appManagers/appDialogsManager';
import appDialogsManager, {DialogElementSize as DialogElementSize} from '../lib/appManagers/appDialogsManager';
import rootScope from '../lib/rootScope';
import Scrollable from './scrollable';
import {FocusDirection} from '../helpers/fastSmoothScroll';
@ -77,7 +77,7 @@ export default class AppSelectPeers {
private chatRightsAction: ChatRights;
private multiSelect = true;
private rippleEnabled = true;
private avatarSize = 48;
private avatarSize: DialogElementSize = 'abitbigger';
private exceptSelf = false;
private filterPeerTypeBy: IsPeerType[];
@ -94,6 +94,8 @@ export default class AppSelectPeers {
private managers: AppManagers;
private design: 'round' | 'square' = 'round';
constructor(options: {
appendTo: AppSelectPeers['appendTo'],
onChange?: AppSelectPeers['onChange'],
@ -110,11 +112,12 @@ export default class AppSelectPeers {
exceptSelf?: AppSelectPeers['exceptSelf'],
filterPeerTypeBy?: AppSelectPeers['filterPeerTypeBy'],
sectionNameLangPackKey?: AppSelectPeers['sectionNameLangPackKey'],
managers: AppSelectPeers['managers']
managers: AppSelectPeers['managers'],
design?: AppSelectPeers['design']
}) {
safeAssign(this, options);
this.container.classList.add('selector');
this.container.classList.add('selector', 'selector-' + this.design);
const f = (this.renderResultsFunc || this.renderResults).bind(this);
this.renderResultsFunc = async(peerIds) => {
@ -313,7 +316,7 @@ export default class AppSelectPeers {
}
// в десктопе - сначала без группы, потом архивные, потом контакты без сообщений
const pageCount = windowSize.height / 72 * 1.25 | 0;
const pageCount = windowSize.height / 56 * 1.25 | 0;
const tempId = this.getTempId('dialogs');
const promise = this.managers.appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId, true);
@ -420,7 +423,7 @@ export default class AppSelectPeers {
}
// if(this.cachedContacts.length) {
const pageCount = windowSize.height / 72 * 1.25 | 0;
const pageCount = windowSize.height / 56 * 1.25 | 0;
const arr = this.cachedContacts.splice(0, pageCount);
this.renderResultsFunc(arr);
// }

View File

@ -289,7 +289,11 @@ export default class BubbleGroups {
removeAndUnmountBubble(bubble: HTMLElement) {
const item = this.getItemByBubble(bubble);
if(!item) {
return;
if(bubble.parentElement) {
bubble.remove(); // * can be a placeholder
}
return false;
}
const items = this.itemsArr;
@ -320,6 +324,8 @@ export default class BubbleGroups {
}
this.mountUnmountGroups(Array.from(modifiedGroups));
return true;
}
mountUnmountGroups(groups: BubbleGroup[]) {

View File

@ -2046,23 +2046,15 @@ export default class ChatBubbles {
// return;
if(this.isHeavyAnimationInProgress) {
if(this.sliceViewportDebounced) {
this.sliceViewportDebounced.clearTimeout();
}
this.sliceViewportDebounced?.clearTimeout();
// * В таком случае, кнопка не будет моргать если чат в самом низу, и правильно отработает случай написания нового сообщения и проскролла вниз
if(this.scrolledDown && !ignoreHeavyAnimation) {
return;
}
} else {
if(this.chat.topbar.pinnedMessage) {
this.chat.topbar.pinnedMessage.setCorrectIndexThrottled(this.scrollable.lastScrollDirection);
}
if(this.sliceViewportDebounced) {
this.sliceViewportDebounced();
}
this.chat.topbar.pinnedMessage?.setCorrectIndexThrottled(this.scrollable.lastScrollDirection);
this.sliceViewportDebounced?.();
this.setStickyDateManually();
}
@ -2172,41 +2164,46 @@ export default class ChatBubbles {
}
}
public destroyBubble(bubble: HTMLElement, mid = +bubble.dataset.mid) {
// this.log.warn('destroy bubble', bubble, mid);
bubble.middlewareHelper.destroy();
/* const mounted = this.getMountedBubble(mid);
if(!mounted) return; */
if(this.bubbles[mid] === bubble) { // have to check because can clear bubble with same id later
delete this.bubbles[mid];
}
this.skippedMids.delete(mid);
if(this.firstUnreadBubble === bubble) {
this.firstUnreadBubble = null;
}
this.bubbleGroups.removeAndUnmountBubble(bubble);
if(this.observer) {
this.observer.unobserve(bubble, this.unreadedObserverCallback);
this.unreaded.delete(bubble);
this.observer.unobserve(bubble, this.viewsObserverCallback);
this.viewsMids.delete(mid);
this.observer.unobserve(bubble, this.stickerEffectObserverCallback);
}
// this.reactions.delete(mid);
}
public deleteMessagesByIds(mids: number[], permanent = true, ignoreOnScroll?: boolean) {
let deleted = false;
mids.forEach((mid) => {
const bubble = this.bubbles[mid];
if(!bubble) return;
bubble.middlewareHelper.destroy();
this.destroyBubble(bubble, mid);
deleted = true;
/* const mounted = this.getMountedBubble(mid);
if(!mounted) return; */
delete this.bubbles[mid];
this.skippedMids.delete(mid);
if(this.firstUnreadBubble === bubble) {
this.firstUnreadBubble = null;
}
this.bubbleGroups.removeAndUnmountBubble(bubble);
if(this.observer) {
this.observer.unobserve(bubble, this.unreadedObserverCallback);
this.unreaded.delete(bubble);
this.observer.unobserve(bubble, this.viewsObserverCallback);
this.viewsMids.delete(mid);
this.observer.unobserve(bubble, this.stickerEffectObserverCallback);
}
if(this.emptyPlaceholderBubble === bubble) {
this.emptyPlaceholderBubble = undefined;
}
// this.reactions.delete(mid);
});
if(!deleted) {
@ -2552,53 +2549,54 @@ export default class ChatBubbles {
public getDateContainerByTimestamp(timestamp: number) {
const {date, dateTimestamp} = this.getDateForDateContainer(timestamp);
if(!this.dateMessages[dateTimestamp]) {
const bubble = this.createDateBubble(timestamp, date);
// bubble.classList.add('is-sticky');
const fakeBubble = this.createDateBubble(timestamp, date);
fakeBubble.classList.add('is-fake');
let ret = this.dateMessages[dateTimestamp];
if(ret) {
return ret;
}
const container = document.createElement('section');
container.className = 'bubbles-date-group';
container.append(bubble, fakeBubble);
const bubble = this.createDateBubble(timestamp, date);
// bubble.classList.add('is-sticky');
const fakeBubble = this.createDateBubble(timestamp, date);
fakeBubble.classList.add('is-fake');
this.dateMessages[dateTimestamp] = {
div: bubble,
container,
firstTimestamp: date.getTime()
};
const container = document.createElement('section');
container.className = 'bubbles-date-group';
container.append(bubble, fakeBubble);
const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');
const length = haveTimestamps.length;
let i = 0, insertBefore: HTMLElement; // there can be 'first bubble' (e.g. bot description) so can't insert by index
for(; i < haveTimestamps.length; ++i) {
const t = haveTimestamps[i];
insertBefore = this.dateMessages[t].container;
if(dateTimestamp < t) {
break;
}
}
ret = this.dateMessages[dateTimestamp] = {
div: bubble,
container,
firstTimestamp: date.getTime()
};
if(i === length && insertBefore) {
insertBefore = insertBefore.nextElementSibling as HTMLElement;
}
if(!insertBefore) {
this.chatInner.append(container);
} else {
this.chatInner.insertBefore(container, insertBefore);
}
if(this.stickyIntersector) {
this.stickyIntersector.observeStickyHeaderChanges(container);
}
if(this.chatInner.parentElement) {
this.container.classList.add('has-groups');
const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');
const length = haveTimestamps.length;
let i = 0, insertBefore: HTMLElement; // there can be 'first bubble' (e.g. bot description) so can't insert by index
for(; i < haveTimestamps.length; ++i) {
const t = haveTimestamps[i];
insertBefore = this.dateMessages[t].container;
if(dateTimestamp < t) {
break;
}
}
return this.dateMessages[dateTimestamp];
if(i === length && insertBefore) {
insertBefore = insertBefore.nextElementSibling as HTMLElement;
}
if(!insertBefore) {
this.chatInner.append(container);
} else {
this.chatInner.insertBefore(container, insertBefore);
}
this.stickyIntersector?.observeStickyHeaderChanges(container);
if(this.chatInner.parentElement) {
this.container.classList.add('has-groups');
}
return ret;
}
private destroyScrollable() {
@ -2622,6 +2620,8 @@ export default class ChatBubbles {
}
public cleanup(bubblesToo = false) {
this.log('cleanup');
this.bubbles = {}; // clean it before so sponsored message won't be deleted faster on peer changing
// //console.time('appImManager cleanup');
this.setLoaded('top', false, false);
@ -2707,11 +2707,7 @@ export default class ChatBubbles {
private cleanupPlaceholders(bubble = this.emptyPlaceholderBubble) {
if(bubble) {
bubble.remove();
if(this.emptyPlaceholderBubble === bubble) {
this.emptyPlaceholderBubble = undefined;
}
this.destroyBubble(bubble);
}
}
@ -4748,9 +4744,12 @@ export default class ChatBubbles {
};
}
public async performHistoryResult(historyResult: HistoryResult | {history: (Message.message | Message.messageService | number)[]}, reverse: boolean) {
public async performHistoryResult(
historyResult: HistoryResult | {history: (Message.message | Message.messageService | number)[]},
reverse: boolean
) {
const log = false ? this.log.bindPrefix('perform-' + (Math.random() * 1000 | 0)) : undefined;
log && log('start', this.chatInner.parentElement);
log?.('start', this.chatInner.parentElement);
let history = historyResult.history;
history = history.slice(); // need
@ -4817,13 +4816,10 @@ export default class ChatBubbles {
if(this.scrollable.loadedAll.top && this.messagesQueueOnRenderAdditional) {
this.messagesQueueOnRenderAdditional();
if(this.messagesQueueOnRenderAdditional) {
this.messagesQueueOnRenderAdditional();
}
this.messagesQueueOnRenderAdditional?.(); // * can set it second time
}
log && log('performHistoryResult end');
log?.('performHistoryResult end');
}
private onRenderScrollSet(state?: {scrollHeight: number, clientHeight: number}) {
@ -5174,16 +5170,22 @@ export default class ChatBubbles {
elements.forEach((element: any) => element.classList.add(BASE_CLASS + '-line'));
}
private async processLocalMessageRender(message: Message.message | Message.messageService, animate?: boolean) {
private async processLocalMessageRender(
message: Message.message | Message.messageService,
animate?: boolean,
middleware = this.getMiddleware()
) {
const isSponsored = !!(message as Message.message).pFlags.sponsored;
const middleware = this.getMiddleware();
const m = middlewarePromise(middleware);
return this.safeRenderMessage(message, isSponsored ? false : true, undefined, isSponsored, async(result) => {
const p: Parameters<ChatBubbles['safeRenderMessage']>[4] = async(result) => {
const {bubble} = await m(result);
if(!bubble) {
return result;
}
(bubble as any).message = message;
bubble.classList.add('is-group-last', 'is-group-first');
const updatePosition = () => {
@ -5208,6 +5210,7 @@ export default class ChatBubbles {
let text: LangPackKey, mid: number, startParam: string, callback: () => void;
bubble.classList.add('avoid-selection');
bubble.style.order = '999999';
const sponsoredMessage = this.sponsoredMessage = (message as Message.message).sponsoredMessage;
const peerId = getPeerId(sponsoredMessage.from_id);
@ -5257,14 +5260,18 @@ export default class ChatBubbles {
bubble.querySelector('.bubble-content').prepend(button);
return result;
appendTo = this.chatInner;
method = 'append';
animate = false;
// return result;
} else if(isBot && message._ === 'message') {
const b = document.createElement('b');
b.append(i18n('BotInfoTitle'));
elements.push(b, '\n\n');
appendTo = this.chatInner;
method = 'prepend';
} else if(await m(this.managers.appPeersManager.isAnyGroup(this.peerId)) && (await m(this.managers.appPeersManager.getPeer(this.peerId))).pFlags.creator) {
} else if(this.chat.isAnyGroup && (await m(this.managers.appPeersManager.getPeer(this.peerId))).pFlags.creator) {
renderPromise = this.renderEmptyPlaceholder('group', bubble, message, elements);
} else if(this.chat.type === 'scheduled') {
renderPromise = this.renderEmptyPlaceholder('noScheduledMessages', bubble, message, elements);
@ -5332,12 +5339,24 @@ export default class ChatBubbles {
this.animateAsLadder(message.mid, additionMsgIds, false, 0, 0);
}
// if(!isSponsored) {
bubble.middlewareHelper.onDestroy(() => {
if(this.emptyPlaceholderBubble === bubble) {
this.emptyPlaceholderBubble = undefined;
}
});
this.emptyPlaceholderBubble = bubble;
// }
return result;
});
};
return this.safeRenderMessage(
message,
!isSponsored,
undefined,
false,
p
);
}
private generateLocalMessageId(addOffset = 0) {
@ -5471,19 +5490,23 @@ export default class ChatBubbles {
}
private async toggleSponsoredMessage(value: boolean) {
const _log = this.log.bindPrefix('sponsored');
_log('checking');
const log = this.log.bindPrefix('sponsored');
log('checking');
const {mid} = this.generateLocalMessageId(SPONSORED_MESSAGE_ID_OFFSET);
if(value) {
const middleware = this.getMiddleware(() => {
return this.scrollable.loadedAll.bottom && !this.bubbles[mid] && this.getSponsoredMessagePromise === promise;
return this.scrollable.loadedAll.bottom && this.getSponsoredMessagePromise === promise;
});
const promise = this.getSponsoredMessagePromise = this.managers.appChatsManager.getSponsoredMessage(this.peerId.toChatId())
.then(async(sponsoredMessages) => {
if(!middleware()) {
return;
}
const sponsoredMessage = sponsoredMessages.messages[0];
if(!sponsoredMessage) {
_log('no message');
log('no message');
return;
}
@ -5502,16 +5525,18 @@ export default class ChatBubbles {
]).then(([message]) => {
if(!middleware()) return;
// this.processLocalMessageRender(message);
_log('rendering', message);
const promise = this.performHistoryResult({history: [message]}, false);
log('rendering', message);
return this.performHistoryResult({history: [message]}, false);
});
}).finally(() => {
this.getSponsoredMessagePromise = undefined;
if(this.getSponsoredMessagePromise === promise) {
this.getSponsoredMessagePromise = undefined;
}
});
} else {
_log('clearing rendered', mid);
this.deleteMessagesByIds([mid]);
log('clearing rendered', mid);
this.getSponsoredMessagePromise = undefined;
this.deleteMessagesByIds([mid]);
}
}
@ -5565,7 +5590,7 @@ export default class ChatBubbles {
this.chat.isRestricted ||
!(await this.chat.getHistoryStorage()).count ||
(
!Object.keys(this.bubbles).length ||
// !Object.keys(this.bubbles).length ||
// ! WARNING ! ! ! ! ! ! REPLACE LINE ABOVE WITH THESE
Object.keys(this.bubbles).length &&
!this.getRenderedLength()

View File

@ -398,6 +398,7 @@ export default class Chat extends EventListenerBase<{
public destroy() {
// const perf = performance.now();
this.destroySharedMediaTab();
this.topbar.destroy();
this.bubbles.destroy();
this.input.destroy();
@ -523,6 +524,10 @@ export default class Chat extends EventListenerBase<{
}
public destroySharedMediaTab(tab = this.sharedMediaTab) {
if(!tab) {
return;
}
indexOfAndSplice(this.sharedMediaTabs, tab);
tab.destroy();
}

View File

@ -184,7 +184,7 @@ export default class ChatContextMenu {
}
this.isSelected = this.chat.selection.isMidSelected(this.peerId, this.mid);
this.message = await this.chat.getMessage(this.mid);
this.message = (bubble as any).message || await this.chat.getMessage(this.mid);
this.noForwards = !isSponsored && !(await this.managers.appMessagesManager.canForward(this.message));
this.viewerPeerId = undefined;
this.canOpenReactedList = undefined;
@ -703,7 +703,13 @@ export default class ChatContextMenu {
let menuPadding: MenuPositionPadding;
let reactionsMenu: ChatReactionsMenu;
let reactionsMenuPosition: 'horizontal' | 'vertical';
if(this.message._ === 'message' && !this.chat.selection.isSelecting && !this.message.pFlags.is_outgoing && !this.message.pFlags.is_scheduled) {
if(
this.message._ === 'message' &&
!this.chat.selection.isSelecting &&
!this.message.pFlags.is_outgoing &&
!this.message.pFlags.is_scheduled &&
!this.message.pFlags.local
) {
reactionsMenuPosition = (IS_APPLE || IS_TOUCH_SUPPORTED)/* && false */ ? 'horizontal' : 'vertical';
reactionsMenu = this.reactionsMenu = new ChatReactionsMenu(this.managers, reactionsMenuPosition, this.middleware);
reactionsMenu.init(await this.managers.appMessagesManager.getGroupsFirstMessage(this.message));
@ -876,11 +882,11 @@ export default class ChatContextMenu {
};
private onRetractVote = () => {
this.managers.appPollsManager.sendVote(this.message, []);
this.managers.appPollsManager.sendVote(this.message as Message.message, []);
};
private onStopPoll = () => {
this.managers.appPollsManager.stopPoll(this.message);
this.managers.appPollsManager.stopPoll(this.message as Message.message);
};
private onForwardClick = async() => {

View File

@ -8,8 +8,7 @@ import positionElementByIndex from '../../helpers/dom/positionElementByIndex';
import replaceContent from '../../helpers/dom/replaceContent';
import {fastRaf} from '../../helpers/schedulers';
import SortedList, {SortedElementBase} from '../../helpers/sortedList';
import {GroupCallParticipant} from '../../layer';
import appDialogsManager, {DialogDom, AppDialogsManager} from '../../lib/appManagers/appDialogsManager';
import appDialogsManager, {DialogDom, AppDialogsManager, DialogElementSize} from '../../lib/appManagers/appDialogsManager';
import {getGroupCallParticipantMutedState} from '.';
import GroupCallParticipantMutedIcon from './participantMutedIcon';
import GroupCallParticipantStatusElement from './participantStatus';
@ -26,7 +25,7 @@ export default class GroupCallParticipantsList extends SortedList<SortedParticip
public list: HTMLUListElement;
protected lazyLoadQueue: LazyLoadQueue;
protected avatarSize = 54;
protected avatarSize: DialogElementSize = 'abitbigger';
protected rippleEnabled = true;
protected autonomous = true;
protected createChatListOptions: Parameters<AppDialogsManager['createChatList']>[0] = {/* new: true, */dialogSize: 72};

View File

@ -442,9 +442,7 @@ export default class PeerProfile {
public setPeer(peerId: PeerId, threadId = 0) {
if(this.peerId === peerId && this.threadId === threadId) return;
if(this.init) {
this.init();
}
this.init?.();
this.peerId = peerId;
this.threadId = threadId;
@ -460,6 +458,7 @@ export default class PeerProfile {
}
public destroy() {
this.peerId = this.threadId = undefined;
this.clearSetMoreDetailsTimeout();
clearInterval(this.setPeerStatusInterval);
this.avatars?.cleanup();

View File

@ -30,5 +30,8 @@ export default class PopupForward extends PopupPickUser {
chatRightsAction: 'send_messages',
selfPresence: 'ChatYourSelf'
});
this.scrollable = this.selector.scrollable;
this.attachScrollableListeners(this.scrollable);
}
}

View File

@ -159,12 +159,7 @@ export default class PopupElement<T extends EventListenerListeners = {}> extends
if(options.scrollable) {
const scrollable = this.scrollable = new Scrollable(this.body);
scrollable.onAdditionalScroll = () => {
scrollable.container.classList.toggle('scrolled-top', !scrollable.scrollTop);
scrollable.container.classList.toggle('scrolled-bottom', scrollable.isScrolledDown);
};
scrollable.container.classList.add('scrolled-top', 'scrolled-bottom', 'scrollable-y-bordered');
this.attachScrollableListeners(scrollable);
if(!this.body) {
this.container.insertBefore(scrollable.container, this.header.nextSibling);
@ -215,6 +210,17 @@ export default class PopupElement<T extends EventListenerListeners = {}> extends
PopupElement.POPUPS.push(this);
}
protected attachScrollableListeners(scrollable: Scrollable) {
const cb = scrollable.onAdditionalScroll;
scrollable.onAdditionalScroll = () => {
cb?.();
scrollable.container.classList.toggle('scrolled-top', !scrollable.scrollTop);
scrollable.container.classList.toggle('scrolled-bottom', scrollable.isScrolledDown);
};
scrollable.container.classList.add('scrolled-top', 'scrolled-bottom', 'scrollable-y-bordered');
}
protected onContentUpdate() {
if(this.scrollable) {
this.scrollable.onAdditionalScroll();
@ -290,6 +296,7 @@ export default class PopupElement<T extends EventListenerListeners = {}> extends
this.element.remove();
this.dispatchEvent<PopupListeners>('closeAfterTimeout');
this.cleanup();
this.scrollable?.destroy();
if(!this.withoutOverlay) {
animationIntersector.checkAnimations2(false);

View File

@ -54,7 +54,7 @@ export default class PopupPickUser extends PopupElement {
chatRightsAction: options.chatRightsAction,
multiSelect: false,
rippleEnabled: false,
avatarSize: 46,
avatarSize: 'abitbigger',
peerId: options.peerId,
placeholder: options.placeholder,
selfPresence: options.selfPresence,

View File

@ -144,7 +144,7 @@ export default class PopupReactedList extends PopupElement {
peerId: peerId,
autonomous: true,
container: chatlist,
avatarSize: 54,
avatarSize: 'abitbigger',
rippleEnabled: false,
meAsSaved: false
});

View File

@ -16,12 +16,30 @@ import {attachClickEvent} from '../helpers/dom/clickEvent';
import ListenerSetter from '../helpers/listenerSetter';
import Button from './button';
type K = string | HTMLElement | DocumentFragment | true;
const setContent = (element: HTMLElement, content: K) => {
if(content === true) {
} else if(typeof(content) === 'string') {
setInnerHTML(element, content);
} else {
element.append(content);
}
};
export type RowMediaSizeType = 'small' | 'medium' | 'big' | 'abitbigger' | 'bigger';
export default class Row {
public container: HTMLElement;
public title: HTMLDivElement;
public title: HTMLElement;
public titleRow: HTMLElement;
public titleRight: HTMLElement;
public media: HTMLElement;
public subtitleRow: HTMLElement;
public subtitleRight: HTMLElement;
public checkboxField: CheckboxField;
public radioField: RadioField;
@ -33,17 +51,18 @@ export default class Row {
constructor(options: Partial<{
icon: string,
subtitle: string | HTMLElement | DocumentFragment,
subtitle: K,
subtitleLangKey: LangPackKey,
subtitleLangArgs: any[],
subtitleRight: K,
radioField: Row['radioField'],
checkboxField: Row['checkboxField'],
checkboxFieldOptions: CheckboxFieldOptions,
withCheckboxSubtitle: boolean,
title: string | HTMLElement | DocumentFragment,
title: K,
titleLangKey: LangPackKey,
titleRight: string | HTMLElement,
titleRightSecondary: string | HTMLElement,
titleRight: K,
titleRightSecondary: K,
clickable: boolean | ((e: Event) => void),
navigationTab: SliderSuperTab,
havePadding: boolean,
@ -51,7 +70,8 @@ export default class Row {
noWrap: boolean,
listenerSetter: ListenerSetter,
buttonRight?: HTMLElement | boolean,
buttonRightLangKey: LangPackKey
buttonRightLangKey: LangPackKey,
asLink: boolean
}> = {}) {
if(options.checkboxFieldOptions) {
options.checkboxField = new CheckboxField({
@ -60,14 +80,28 @@ export default class Row {
});
}
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
const tagName = options.asLink ? 'a' : (options.radioField || options.checkboxField ? 'label' : 'div');
this.container = document.createElement(tagName);
this.container.classList.add('row', 'no-subtitle');
if(options.noWrap) {
this.container.classList.add('no-wrap');
}
if(options.subtitle) {
if(typeof(options.subtitle) === 'string') {
setInnerHTML(this.subtitle, options.subtitle);
} else {
this.subtitle.append(options.subtitle);
const subtitle = this.subtitle;
setContent(subtitle, options.subtitle);
if(options.noWrap) subtitle.classList.add('no-wrap');
if(options.subtitleRight) {
this.container.append(this.subtitleRow = this.createRow());
this.subtitleRow.classList.add('row-subtitle-row');
const subtitleRight = this.subtitleRight = document.createElement('div');
subtitleRight.classList.add('row-subtitle', 'row-subtitle-right');
setContent(subtitleRight, options.subtitleRight);
this.subtitleRow.append(subtitle, subtitleRight);
}
} else if(options.subtitleLangKey) {
this.subtitle.append(i18n(options.subtitleLangKey, options.subtitleLangArgs));
@ -109,45 +143,34 @@ export default class Row {
if(options.title || options.titleLangKey) {
let c: HTMLElement;
const titleRight = options.titleRight || options.titleRightSecondary;
if(titleRight) {
c = document.createElement('div');
c.classList.add('row-title-row');
this.container.append(c);
const titleRightContent = options.titleRight || options.titleRightSecondary;
if(titleRightContent) {
this.container.append(c = this.titleRow = this.createRow());
this.titleRow.classList.add('row-title-row');
} else {
c = this.container;
}
this.title = document.createElement('div');
this.title.classList.add('row-title');
this.title.setAttribute('dir', 'auto');
this.title = this.createTitle();
if(options.noWrap) this.title.classList.add('no-wrap');
if(options.title) {
if(typeof(options.title) === 'string') {
this.title.innerHTML = options.title;
} else {
this.title.append(options.title);
}
} else {
setContent(this.title, options.title);
} else if(options.titleLangKey) {
this.title.append(i18n(options.titleLangKey));
}
c.append(this.title);
if(titleRight) {
const titleRightEl = this.titleRight = document.createElement('div');
titleRightEl.classList.add('row-title', 'row-title-right');
if(titleRightContent) {
const titleRight = this.titleRight = document.createElement('div');
titleRight.classList.add('row-title', 'row-title-right');
if(options.titleRightSecondary) {
titleRightEl.classList.add('row-title-right-secondary');
titleRight.classList.add('row-title-right-secondary');
}
if(typeof(titleRight) === 'string') {
titleRightEl.innerHTML = titleRight;
} else {
titleRightEl.append(titleRight);
}
c.append(titleRightEl);
setContent(titleRight, titleRightContent);
c.append(titleRight);
}
}
@ -196,6 +219,19 @@ export default class Row {
return this._subtitle ?? (this._subtitle = this.createSubtitle());
}
private createRow() {
const c = document.createElement('div');
c.classList.add('row-row');
return c;
}
private createTitle() {
const title = document.createElement('div');
title.classList.add('row-title');
title.setAttribute('dir', 'auto');
return title;
}
private createSubtitle() {
const subtitle = document.createElement('div');
subtitle.classList.add('row-subtitle');
@ -206,10 +242,15 @@ export default class Row {
return subtitle;
}
public createMedia(size?: 'small') {
public createMedia(size?: RowMediaSizeType) {
const media = document.createElement('div');
return this.applyMediaElement(media, size);
}
public applyMediaElement(media: HTMLElement, size?: RowMediaSizeType) {
this.container.classList.add('row-with-padding');
const media = this.media = document.createElement('div');
this.media = media;
media.classList.add('row-media');
if(size) {

View File

@ -59,7 +59,8 @@ export default class AppAddMembersTab extends SliderSuperTab {
placeholder: options.placeholder,
exceptSelf: isPrivacy,
filterPeerTypeBy: isPrivacy ? ['isAnyGroup', 'isUser'] : undefined,
managers: this.managers
managers: this.managers,
design: 'square'
});
if(options.selectedPeerIds) {

View File

@ -59,7 +59,7 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
peerId: peerId,
container: list,
rippleEnabled: true,
avatarSize: 48,
avatarSize: 'abitbigger',
append
});

View File

@ -75,7 +75,7 @@ export default class AppContactsTab extends SliderSuperTab {
protected onClose() {
this.middleware.clean();
/* // need to clear, and left 1 page for smooth slide
let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
let pageCount = appPhotosManager.windowH / 56 * 1.25 | 0;
(Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach((el) => el.remove()); */
}
@ -98,7 +98,7 @@ export default class AppContactsTab extends SliderSuperTab {
const sortedUserList = this.sortedUserList = this.createList();
let renderPage = () => {
const pageCount = windowSize.height / 72 * 1.25 | 0;
const pageCount = windowSize.height / 56 * 1.25 | 0;
const arr = contacts.splice(0, pageCount); // надо splice!
arr.forEach((peerId) => {

View File

@ -317,7 +317,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
container: ul,
rippleEnabled: false,
meAsSaved: true,
avatarSize: 32
avatarSize: 'small'
});
dom.lastMessageSpan.parentElement.remove();
}

View File

@ -12,6 +12,7 @@ import {i18n, i18n_} from '../../../lib/langPack';
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
import rootScope from '../../../lib/rootScope';
import {generateSection, SettingSection} from '..';
import anchorCopy from '../../../helpers/dom/anchorCopy';
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)
@ -114,10 +115,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
const profileUrlContainer = this.profileUrlContainer = document.createElement('div');
profileUrlContainer.classList.add('profile-url-container');
const profileUrlAnchor = this.profileUrlAnchor = document.createElement('a');
profileUrlAnchor.classList.add('profile-url');
profileUrlAnchor.href = '#';
profileUrlAnchor.target = '_blank';
const profileUrlAnchor = this.profileUrlAnchor = anchorCopy();
profileUrlContainer.append(i18n('UsernameHelpLink', [profileUrlAnchor]));
@ -173,9 +171,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
this.profileUrlContainer.style.display = 'none';
} else {
this.profileUrlContainer.style.display = '';
const url = 'https://t.me/' + this.usernameInputField.value;
this.profileUrlAnchor.innerText = url;
this.profileUrlAnchor.href = url;
this.profileUrlAnchor.replaceWith(this.profileUrlAnchor = anchorCopy({mePath: this.usernameInputField.value}));
}
}
}

View File

@ -163,7 +163,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
peerId: peerId,
container: this.selector.scrollable,
rippleEnabled: true,
avatarSize: 46
avatarSize: 'abitbigger'
});
const selected = this.selector.selected.has(peerId);

View File

@ -166,7 +166,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
peerId: userId,
container: this.list,
rippleEnabled: false,
avatarSize: 48
avatarSize: 'abitbigger'
});
dom.lastMessageSpan.append(getUserStatusString(await this.managers.appUsersManager.getUser(userId)));

View File

@ -52,7 +52,7 @@ export class AppSidebarRight extends SidebarSlider {
const idx = this.historyTabIds.indexOf(previousTab);
if(this._selectTab.getFrom() === previousTab.container) {
this._selectTab.setFrom(tab.container);
this._selectTab.setFrom(tab?.container);
}
if(tab) {

View File

@ -264,7 +264,7 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
peerId: getPeerId(participant.peer),
container: list,
rippleEnabled: true,
avatarSize: 48,
avatarSize: 'abitbigger',
append
});

View File

@ -8,15 +8,16 @@ import {SliderSuperTab} from '../../slider';
import appSidebarRight from '..';
import {roundPercents} from '../../poll';
import appDialogsManager from '../../../lib/appManagers/appDialogsManager';
import ripple from '../../ripple';
import {i18n} from '../../../lib/langPack';
import setInnerHTML from '../../../helpers/dom/setInnerHTML';
import wrapEmojiText from '../../../lib/richTextProcessor/wrapEmojiText';
import Button from '../../button';
import {Message, MessageMedia} from '../../../layer';
export default class AppPollResultsTab extends SliderSuperTab {
private resultsDiv: HTMLElement;
public async init(message: any) {
public async init(message: Message.message) {
this.container.id = 'poll-results-container';
this.container.classList.add('chatlist-container');
@ -24,7 +25,7 @@ export default class AppPollResultsTab extends SliderSuperTab {
this.resultsDiv.classList.add('poll-results');
this.scrollable.append(this.resultsDiv);
const poll = await this.managers.appPollsManager.getPoll(message.media.poll.id);
const poll = await this.managers.appPollsManager.getPoll((message.media as MessageMedia.messageMediaPoll).poll.id);
this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');
@ -62,11 +63,11 @@ export default class AppPollResultsTab extends SliderSuperTab {
appSidebarRight.onCloseBtnClick();
}, undefined, true);
list.style.minHeight = Math.min(result.voters, 4) * 50 + 'px';
list.style.minHeight = Math.min(result.voters, 4) * 48 + 'px';
fragment.append(hr, answerEl, list);
let offset: string, limit = 4, loading = false, left = result.voters - 4;
let offset: string, limit = 4, loading = false, left = Math.max(0, result.voters - 4);
const load = () => {
if(loading) return;
loading = true;
@ -78,14 +79,17 @@ export default class AppPollResultsTab extends SliderSuperTab {
container: list,
rippleEnabled: false,
meAsSaved: false,
avatarSize: 32
avatarSize: 'small'
});
dom.lastMessageSpan.parentElement.remove();
});
if(offset) {
left -= votesList.votes.length;
(showMore.lastElementChild as HTMLElement).replaceWith(i18n('PollResults.LoadMore', [Math.min(20, left)]));
left = Math.max(0, left - votesList.votes.length);
if(left) {
(showMore.lastElementChild as HTMLElement).replaceWith(i18n('PollResults.LoadMore', [Math.min(20, left)]));
}
}
offset = votesList.next_offset;
@ -99,19 +103,13 @@ export default class AppPollResultsTab extends SliderSuperTab {
});
};
load();
if(left <= 0) return;
const showMore = document.createElement('div');
showMore.classList.add('poll-results-more', 'show-more', 'rp-overflow');
const showMore = Button('poll-results-more btn btn-primary btn-transparent', {icon: 'down'});
showMore.addEventListener('click', load);
ripple(showMore);
const down = document.createElement('div');
down.classList.add('tgico-down');
showMore.append(down, i18n('PollResults.LoadMore', [Math.min(20, left)]));
showMore.append(i18n('PollResults.LoadMore', [Math.min(20, left)]));
fragment.append(showMore);
load();
});
this.resultsDiv.append(title, fragment);

View File

@ -42,7 +42,7 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
peerId: this.userId.toPeerId(false),
container: list,
rippleEnabled: true,
avatarSize: 48
avatarSize: 'abitbigger'
});
dom.lastMessageSpan.append(getUserStatusString(await this.managers.appUsersManager.getUser(this.userId)));

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import appDialogsManager, {AppDialogsManager, DialogDom} from '../lib/appManagers/appDialogsManager';
import appDialogsManager, {AppDialogsManager, DialogDom, DialogElementSize} from '../lib/appManagers/appDialogsManager';
import {getHeavyAnimationPromise} from '../hooks/useHeavyAnimationCheck';
import isInDOM from '../helpers/dom/isInDOM';
import positionElementByIndex from '../helpers/dom/positionElementByIndex';
@ -25,7 +25,7 @@ export default class SortedUserList extends SortedList<SortedUser> {
public list: HTMLUListElement;
protected lazyLoadQueue: LazyLoadQueue;
protected avatarSize = 48;
protected avatarSize: DialogElementSize = 'abitbigger';
protected rippleEnabled = true;
protected autonomous = true;
protected createChatListOptions: Parameters<AppDialogsManager['createChatList']>[0];

View File

@ -5,7 +5,7 @@
*/
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
import {formatTime} from '../../helpers/date';
import {formatTime, ONE_DAY} from '../../helpers/date';
import htmlToSpan from '../../helpers/dom/htmlToSpan';
import setInnerHTML from '../../helpers/dom/setInnerHTML';
import formatCallDuration from '../../helpers/formatCallDuration';
@ -18,16 +18,21 @@ import wrapEmojiText from '../../lib/richTextProcessor/wrapEmojiText';
import wrapPlainText from '../../lib/richTextProcessor/wrapPlainText';
import wrapRichText from '../../lib/richTextProcessor/wrapRichText';
import rootScope from '../../lib/rootScope';
import PeerTitle from '../peerTitle';
import getPeerTitle from './getPeerTitle';
import wrapJoinVoiceChatAnchor from './joinVoiceChatAnchor';
import wrapMessageForReply from './messageForReply';
import wrapPeerTitle from './peerTitle';
async function wrapLinkToMessage(message: Message.message | Message.messageService, plain?: boolean) {
const wrapped = await wrapMessageForReply(message, undefined, undefined, plain as any);
if(plain) {
return wrapped;
}
const a = document.createElement('i');
a.dataset.savedFrom = message.peerId + '_' + message.mid;
a.dir = 'auto';
a.append(await wrapMessageForReply(message, undefined, undefined, plain as any));
a.append(wrapped);
return a;
}
@ -53,8 +58,8 @@ export default async function wrapMessageActionTextNewUnsafe(message: MyMessage,
const managers = rootScope.managers;
const getNameDivHTML = async(peerId: PeerId, plain: boolean) => {
return plain ? getPeerTitle(peerId, plain) : (new PeerTitle({peerId})).element;
const getNameDivHTML = (peerId: PeerId, plain: boolean) => {
return plain ? getPeerTitle(peerId, plain) : wrapPeerTitle({peerId});
};
switch(action._) {
@ -268,7 +273,10 @@ export default async function wrapMessageActionTextNewUnsafe(message: MyMessage,
} else {
langPackKey = isRecurringUsed ? 'Chat.Service.PaymentSentRecurringUsed' : (isRecurringInit ? 'Chat.Service.PaymentSentRecurringInit' : 'Chat.Service.PaymentSent1');
args.push(wrapLinkToMessage(invoiceMessage, plain).then((el) => {
el.classList.add('is-receipt-link');
if(el instanceof HTMLElement) {
el.classList.add('is-receipt-link');
}
return el;
}));
}
@ -277,6 +285,52 @@ export default async function wrapMessageActionTextNewUnsafe(message: MyMessage,
break;
}
case 'messageActionSetMessagesTTL': {
args = [];
const isBroadcast = await managers.appPeersManager.isBroadcast(message.peerId);
if(action.period) {
if(isBroadcast) {
langPackKey = 'ActionTTLChannelChanged';
} else if(message.fromId === rootScope.myId) {
langPackKey = 'ActionTTLYouChanged';
} else {
langPackKey = 'ActionTTLChanged';
args.push(getNameDivHTML(message.fromId, plain));
}
let duration: ReturnType<typeof formatCallDuration>;
if(action.period > 1814400) {
let key: LangPackKey;
const args: FormatterArguments = [];
const year = 31536000;
if(action.period >= year) {
key = 'Years';
args.push(action.period / year | 0);
} else {
key = 'Months';
args.push(action.period / (ONE_DAY * 30) | 0);
}
duration = plain ? I18n.format(key, true, args) : i18n(key, args);
} else {
duration = formatCallDuration(action.period, plain);
}
args.push(duration);
} else {
if(isBroadcast) {
langPackKey = 'ActionTTLChannelDisabled';
} else if(message.fromId === rootScope.myId) {
langPackKey = 'ActionTTLYouDisabled';
} else {
langPackKey = 'ActionTTLDisabled';
args.push(getNameDivHTML(message.fromId, plain));
}
}
break;
}
default:
langPackKey = (langPack[_] || `[${action._}]`) as any;
break;

View File

@ -40,7 +40,7 @@ export default async function wrapMessageForReply(message: MyMessage | MyDraftMe
if(plain) {
parts.push(part);
} else {
const el = document.createElement('i');
const el = document.createElement('span');
if(typeof(part) === 'string') el.innerHTML = part;
else el.append(part);
parts.push(el);

View File

@ -704,14 +704,48 @@ export async function onEmojiStickerClick({event, container, managers, peerId, m
peerId: PeerId,
middleware: Middleware
}) {
if(!peerId.isUser()) {
return;
}
cancelEvent(event);
const bubble = findUpClassName(container, 'bubble');
const emoji = container.dataset.stickerEmoji;
const animation = !container.classList.contains('custom-emoji') ? lottieLoader.getAnimation(container) : undefined;
if(animation?.paused) {
const doc = await managers.appStickersManager.getAnimatedEmojiSoundDocument(emoji);
if(doc) {
const audio = document.createElement('audio');
audio.style.display = 'none';
container.parentElement.append(audio);
try {
const url = await appDownloadManager.downloadMediaURL({media: doc});
audio.src = url;
audio.play();
await onMediaLoad(audio, undefined, true);
audio.addEventListener('ended', () => {
audio.src = '';
audio.remove();
}, {once: true});
} catch(err) {
}
}
animation.autoplay = true;
animation.restart();
}
if(!peerId.isUser()) {
return;
}
const doc = await managers.appStickersManager.getAnimatedEmojiSticker(emoji, true);
if(!doc) {
return;
}
const data: SendMessageEmojiInteractionData = (container as any).emojiData ??= {
a: [],
v: 1
@ -743,39 +777,6 @@ export async function onEmojiStickerClick({event, container, managers, peerId, m
data.a.length = 0;
}, 1000, false);
const animation = !container.classList.contains('custom-emoji') ? lottieLoader.getAnimation(container) : undefined;
if(animation?.paused) {
const doc = await managers.appStickersManager.getAnimatedEmojiSoundDocument(emoji);
if(doc) {
const audio = document.createElement('audio');
audio.style.display = 'none';
container.parentElement.append(audio);
try {
const url = await appDownloadManager.downloadMediaURL({media: doc});
audio.src = url;
audio.play();
await onMediaLoad(audio, undefined, true);
audio.addEventListener('ended', () => {
audio.src = '';
audio.remove();
}, {once: true});
} catch(err) {
}
}
animation.autoplay = true;
animation.restart();
}
const doc = await managers.appStickersManager.getAnimatedEmojiSticker(emoji, true);
if(!doc) {
return;
}
const isOut = bubble ? bubble.classList.contains('is-out') : undefined;
const {animationDiv} = wrapStickerAnimation({
doc,

View File

@ -24,7 +24,9 @@ export default class SuperIntersectionObserver {
const entry = entries[i];
const callbacks = observing.get(entry.target);
if(!callbacks) {
console.error('intersection process no callbacks:', entry);
debugger;
continue;
}
for(const callback of callbacks) {

View File

@ -12,7 +12,9 @@ const CALL_DURATION_LANG_KEYS: {[type in DurationType]: LangPackKey} = {
m: 'Minutes',
h: 'Hours',
d: 'Days',
w: 'Weeks'
w: 'Weeks',
mm: 'Months',
y: 'Years'
};
export default function formatCallDuration(duration: number, plain?: boolean) {
const a = formatDuration(duration, 2);

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export type DurationType = 's' | 'm' | 'h' | 'd' | 'w';
export type DurationType = 's' | 'm' | 'h' | 'd' | 'w' | 'mm' | 'y';
export default function formatDuration(duration: number, showLast = 2) {
if(!duration) {
duration = 1;
@ -21,7 +21,7 @@ export default function formatDuration(duration: number, showLast = 2) {
const s = 1;
let t = s;
p.forEach((o, idx) => {
t *= o.m;
t = Math.round(t * o.m);
if(duration < t) {
return;

View File

@ -504,6 +504,14 @@ const lang = {
'one_value': '%1$d week',
'other_value': '%1$d weeks'
},
'Months': {
'one_value': '%1$d month',
'other_value': '%1$d months'
},
'Years': {
'one_value': '%1$d year',
'other_value': '%1$d years'
},
'TodayAtFormattedWithToday': 'today at %1$s',
'formatDateAtTime': '%1$s at %2$s',
'JoinByPeekChannelTitle': 'Join Channel',
@ -791,6 +799,12 @@ const lang = {
'IncreaseLimit': 'Increase Limit',
'LimitFree': 'Free',
'LimitPremium': 'Premium',
'ActionTTLChanged': 'un1 set messages to auto-delete in %1$s',
'ActionTTLYouChanged': 'You set messages to auto-delete in %1$s',
'ActionTTLChannelChanged': 'Messages in this channel will be automatically deleted after %1$s',
'ActionTTLChannelDisabled': 'Messages in this channel will no longer be automatically deleted',
'ActionTTLDisabled': 'un1 disabled the auto-delete timer',
'ActionTTLYouDisabled': 'You disabled the auto-delete timer',
// * macos
'AccountSettings.Filters': 'Chat Folders',

View File

@ -12,7 +12,7 @@
import deepEqual from '../../helpers/object/deepEqual';
import isObject from '../../helpers/object/isObject';
import safeReplaceObject from '../../helpers/object/safeReplaceObject';
import {ChannelParticipant, ChannelsCreateChannel, Chat, ChatAdminRights, ChatBannedRights, ChatInvite, ChatPhoto, ChatReactions, InputChannel, InputChatPhoto, InputFile, InputPeer, SponsoredMessage, Update, Updates} from '../../layer';
import {ChannelParticipant, ChannelsCreateChannel, Chat, ChatAdminRights, ChatBannedRights, ChatInvite, ChatPhoto, ChatReactions, InputChannel, InputChatPhoto, InputFile, InputPeer, MessagesSponsoredMessages, SponsoredMessage, Update, Updates} from '../../layer';
import {isRestricted} from '../../helpers/restrictions';
import {AppManager} from './manager';
import hasRights from './utils/chats/hasRights';
@ -694,9 +694,93 @@ export class AppChatsManager extends AppManager {
}
public getSponsoredMessage(chatId: ChatId) {
return this.apiManager.invokeApiCacheable('channels.getSponsoredMessages', {
// const s: MessagesSponsoredMessages.messagesSponsoredMessages = {
// '_': 'messages.sponsoredMessages',
// 'messages': [
// {
// '_': 'sponsoredMessage',
// 'pFlags': {},
// 'flags': 9,
// 'random_id': new Uint8Array([
// 80,
// 5,
// 249,
// 174,
// 44,
// 73,
// 173,
// 14,
// 246,
// 81,
// 187,
// 182,
// 223,
// 5,
// 4,
// 128
// ]),
// 'from_id': {
// '_': 'peerUser',
// 'user_id': 983000232
// },
// 'start_param': 'GreatMinds',
// 'message': 'This is a long sponsored message. In fact, it has the maximum length allowed on the platform  160 characters 😬😬. It\'s promoting a bot with a start parameter.' + chatId
// }
// ],
// 'chats': [],
// 'users': [
// {
// '_': 'user',
// 'pFlags': {
// 'bot': true,
// 'verified': true,
// 'apply_min_photo': true
// },
// 'flags': 34226219,
// 'id': 983000232,
// 'access_hash': '-294959558742535650',
// 'first_name': 'Quiz Bot',
// 'username': 'QuizBot',
// 'photo': {
// '_': 'userProfilePhoto',
// 'pFlags': {},
// 'flags': 2,
// 'photo_id': '4221953848856651689',
// 'stripped_thumb': new Uint8Array([
// 1,
// 8,
// 8,
// 155,
// 247,
// 95,
// 103,
// 255,
// 0,
// 110,
// 138,
// 40,
// 174,
// 132,
// 142,
// 6,
// 238,
// 127
// ]),
// 'dc_id': 2
// },
// 'bot_info_version': 11,
// 'bot_inline_placeholder': 'Search a quiz...',
// 'sortName': 'quiz bot'
// }
// ]
// };
// const promise = Promise.resolve(s);
const promise = this.apiManager.invokeApiCacheable('channels.getSponsoredMessages', {
channel: this.getChannelInput(chatId)
}, {cacheSeconds: 300}).then((sponsoredMessages) => {
}, {cacheSeconds: 300});
return promise.then((sponsoredMessages) => {
this.appUsersManager.saveApiUsers(sponsoredMessages.users);
this.appChatsManager.saveApiChats(sponsoredMessages.chats);

View File

@ -86,12 +86,13 @@ import whichChild from '../../helpers/dom/whichChild';
import {MiddlewareHelper} from '../../helpers/middleware';
import makeError from '../../helpers/makeError';
import getUnsafeRandomInt from '../../helpers/number/getUnsafeRandomInt';
import Row, {RowMediaSizeType} from '../../components/row'
export const DIALOG_LIST_ELEMENT_TAG = 'A';
export type DialogDom = {
avatarEl: AvatarElement,
captionDiv: HTMLDivElement,
captionDiv: HTMLElement,
titleSpan: HTMLSpanElement,
titleSpanContainer: HTMLSpanElement,
statusSpan: HTMLSpanElement,
@ -128,6 +129,8 @@ function setPromiseMiddleware<T extends {[smth in K as K]?: CancellablePromise<v
return {deferred, middleware};
}
const BADGE_SIZE = 22;
class SortedDialogList extends SortedList<SortedDialog> {
constructor(
public managers: AppManagers,
@ -170,6 +173,151 @@ class SortedDialogList extends SortedList<SortedDialog> {
}
}
export type DialogElementSize = RowMediaSizeType;
class DialogElement extends Row {
public dom: DialogDom;
constructor({
peerId,
rippleEnabled = true,
onlyFirstName = false,
meAsSaved = true,
avatarSize = 'bigger',
autonomous,
lazyLoadQueue,
loadPromises,
fromName,
noIcons
}: {
peerId: PeerId,
rippleEnabled?: boolean,
onlyFirstName?: boolean,
meAsSaved?: boolean,
avatarSize?: RowMediaSizeType,
autonomous?: boolean,
lazyLoadQueue?: LazyLoadQueue,
loadPromises?: Promise<any>[],
fromName?: string,
noIcons?: boolean
}) {
super({
clickable: true,
noRipple: !rippleEnabled,
havePadding: true,
title: true,
titleRightSecondary: true,
subtitle: true,
subtitleRight: true,
noWrap: true,
asLink: true
});
const avatarEl = new AvatarElement();
const avatarSizeMap: {[k in DialogElementSize]?: number} = {
bigger: 54,
abitbigger: 42,
small: 32
};
const s = avatarSizeMap[avatarSize];
avatarEl.classList.add('dialog-avatar', 'avatar-' + s);
avatarEl.updateWithOptions({
loadPromises,
lazyLoadQueue,
isDialog: !!meAsSaved,
peerId,
peerTitle: fromName
});
const captionDiv = this.container;
const titleSpanContainer = this.title;
titleSpanContainer.classList.add('user-title');
this.titleRow.classList.add('dialog-title');
const peerTitle = new PeerTitle();
const peerTitlePromise = peerTitle.update({
peerId,
fromName,
dialog: meAsSaved,
onlyFirstName,
plainText: false,
withIcons: !noIcons
});
loadPromises?.push(peerTitlePromise);
titleSpanContainer.append(peerTitle.element);
// for muted icon
titleSpanContainer.classList.add('tgico'); // * эта строка будет актуальна только для !container, но ладно
// const titleIconsPromise = generateTitleIcons(peerId).then((elements) => {
// titleSpanContainer.append(...elements);
// });
// if(loadPromises) {
// loadPromises.push(titleIconsPromise);
// }
// }
const span = this.subtitle;
// span.classList.add('user-last-message');
const li = this.container;
li.classList.add('chatlist-chat', 'chatlist-chat-' + avatarSize);
if(!autonomous) (li as HTMLAnchorElement).href = '#' + peerId;
// if(rippleEnabled) {
// ripple(li);
// }
if(avatarSize === 'bigger') {
this.container.classList.add('row-big');
} else if(avatarSize === 'small') {
this.container.classList.add('row-small');
}
this.applyMediaElement(avatarEl, avatarSize);
li.dataset.peerId = '' + peerId;
const statusSpan = document.createElement('span');
statusSpan.classList.add('message-status', 'sending-status'/* , 'transition', 'reveal' */);
const lastTimeSpan = document.createElement('span');
lastTimeSpan.classList.add('message-time');
const unreadBadge = document.createElement('div');
unreadBadge.className = 'dialog-subtitle-badge badge badge-' + BADGE_SIZE;
const rightSpan = this.titleRight;
rightSpan.classList.add('dialog-title-details');
rightSpan.append(statusSpan, lastTimeSpan);
this.subtitleRow.classList.add('dialog-subtitle');
const dom: DialogDom = this.dom = {
avatarEl,
captionDiv,
titleSpan: peerTitle.element,
titleSpanContainer,
statusSpan,
lastTimeSpan,
unreadBadge,
lastMessageSpan: span,
containerEl: li,
listEl: li,
subtitleEl: this.subtitleRow
};
if(!autonomous) {
(li as any).dialogDom = dom;
if(appImManager.chat?.peerId === peerId) {
appDialogsManager.setDialogActive(li, true);
}
}
}
}
// const testScroll = false;
// let testTopSlice = 1;
@ -316,6 +464,7 @@ export class AppDialogsManager {
// setTimeout(() =>
apiManagerProxy.getState().then(async(state) => {
this.loadedDialogsAtLeastOnce = false;
this.showFiltersPromise = undefined;
/* const clearPromises: Promise<any>[] = [];
for(const name in this.managers.appStateManager.storagesResults) {
@ -659,9 +808,8 @@ export class AppDialogsManager {
});
}
private setDialogActive(listEl: HTMLElement, active: boolean) {
// @ts-ignore
const dom = listEl.dialogDom as DialogDom;
public setDialogActive(listEl: HTMLElement, active: boolean) {
const dom = (listEl as any).dialogDom as DialogDom;
listEl.classList.toggle('active', active);
if(active) {
this.lastActiveElements.add(listEl);
@ -955,31 +1103,29 @@ export class AppDialogsManager {
}
private onFiltersLengthChange() {
if(!this.showFiltersPromise) {
this.showFiltersPromise = new Promise<void>((resolve) => {
window.setTimeout(() => {
const length = Object.keys(this.filtersRendered).length;
const show = length > 1;
const wasShowing = !this.folders.menuScrollContainer.classList.contains('hide');
let promise = this.showFiltersPromise;
return promise ??= this.showFiltersPromise = pause(0).then(() => {
if(this.showFiltersPromise !== promise) {
return;
}
if(show !== wasShowing) {
this.folders.menuScrollContainer.classList.toggle('hide', !show);
if(show && !wasShowing) {
this.setFiltersUnreadCount();
}
const length = Object.keys(this.filtersRendered).length;
const show = length > 1;
const wasShowing = !this.folders.menuScrollContainer.classList.contains('hide');
this.chatsContainer.classList.toggle('has-filters', show);
}
if(show !== wasShowing) {
this.folders.menuScrollContainer.classList.toggle('hide', !show);
if(show && !wasShowing) {
this.setFiltersUnreadCount();
}
this.changeFiltersAllChatsKey();
this.chatsContainer.classList.toggle('has-filters', show);
}
this.showFiltersPromise = undefined;
resolve();
}, 0);
});
}
this.changeFiltersAllChatsKey();
return this.showFiltersPromise;
this.showFiltersPromise = undefined;
});
}
private loadDialogs(side: SliceSides) {
@ -1341,7 +1487,7 @@ export class AppDialogsManager {
};
const sortedUserList = new SortedUserList({
avatarSize: 42,
avatarSize: 'abitbigger',
createChatListOptions: {
dialogSize: 48,
new: true
@ -1737,30 +1883,31 @@ export class AppDialogsManager {
/* if(lastMessage.from_id === auth.id) { // You: */
if(draftMessage) {
const bold = document.createElement('b');
bold.classList.add('danger');
bold.append(i18n('Draft'), ': ');
willPrepend.unshift(bold);
const span = document.createElement('span');
span.classList.add('danger');
span.append(i18n('Draft'), ': ');
willPrepend.unshift(span);
} else if(peerId.isAnyChat() && peerId !== lastMessage.fromId && !(lastMessage as Message.messageService).action) {
const senderBold = document.createElement('b');
const span = document.createElement('span');
span.classList.add('primary-text');
if(lastMessage.fromId === rootScope.myId) {
senderBold.append(i18n('FromYou'));
willPrepend.unshift(senderBold);
span.append(i18n('FromYou'));
willPrepend.unshift(span);
} else {
// str = sender.first_name || sender.last_name || sender.username;
const p = middleware(wrapPeerTitle({
peerId: lastMessage.fromId,
onlyFirstName: true
})).then((element) => {
senderBold.prepend(element);
return senderBold;
span.prepend(element);
return span;
}, noop);
willPrepend.unshift(p);
}
senderBold.append(': ');
span.append(': ');
// console.log(sender, senderBold.innerText);
}
@ -1870,7 +2017,7 @@ export class AppDialogsManager {
if(hasMentionsBadge) {
if(!dom.mentionsBadge) {
dom.mentionsBadge = document.createElement('div');
dom.mentionsBadge.className = 'dialog-subtitle-badge badge badge-24 mention mention-badge';
dom.mentionsBadge.className = `dialog-subtitle-badge badge badge-${BADGE_SIZE} mention mention-badge`;
dom.mentionsBadge.innerText = '@';
dom.subtitleEl.insertBefore(dom.mentionsBadge, dom.lastMessageSpan.nextSibling);
}
@ -2041,14 +2188,27 @@ export class AppDialogsManager {
onlyFirstName?: boolean,
meAsSaved?: boolean,
append?: boolean,
avatarSize?: number,
avatarSize?: RowMediaSizeType,
autonomous?: boolean,
lazyLoadQueue?: LazyLoadQueue,
loadPromises?: Promise<any>[],
fromName?: string,
noIcons?: boolean
}) {
return this.addDialog(options.peerId, options.container, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises, options.fromName, options.noIcons);
const d = new DialogElement({
autonomous: !!options.container,
avatarSize: 'bigger',
...options
// avatarSize: !options.avatarSize || options.avatarSize >= 54 ? 'bigger' : 'abitbigger',
});
if(options.container) {
const method = !options.append ? 'append' : 'prepend';
options.container[method](d.container);
}
return d;
// return this.addDialog(options.peerId, options.container, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises, options.fromName, options.noIcons);
}
public addDialog(
@ -2138,7 +2298,7 @@ export class AppDialogsManager {
lastTimeSpan.classList.add('message-time');
const unreadBadge = document.createElement('div');
unreadBadge.className = 'dialog-subtitle-badge badge badge-24';
unreadBadge.className = 'dialog-subtitle-badge badge badge-' + BADGE_SIZE;
const titleP = document.createElement('p');
titleP.classList.add('dialog-title');

View File

@ -1000,6 +1000,14 @@ export class AppImManager extends EventListenerBase<{
}
private onHashChange = (saveState?: boolean) => {
try {
this.onHashChangeUnsafe(saveState);
} catch(err) {
this.log.error('hash change error', err);
}
};
private onHashChangeUnsafe = (saveState?: boolean) => {
const hash = location.hash;
if(!saveState) {
appNavigationController.replaceState();
@ -1023,6 +1031,10 @@ export class AppImManager extends EventListenerBase<{
}
case '#/im': {
if(!Object.keys(params).length) {
break;
}
const p: string = params.p;
const postId = params.post !== undefined ? generateMessageId(+params.post) : undefined;
@ -1289,7 +1301,7 @@ export class AppImManager extends EventListenerBase<{
const top = chatBubbles.scrollable.scrollTop;
const position = {
mids: getObjectKeysAndSort(chatBubbles.bubbles, 'desc').filter((mid) => !chatBubbles.skippedMids.has(mid)),
mids: getObjectKeysAndSort(chatBubbles.bubbles, 'desc').filter((mid) => mid > 0 && !chatBubbles.skippedMids.has(mid)),
top
};
@ -1704,9 +1716,7 @@ export class AppImManager extends EventListenerBase<{
this.dispatchEvent('peer_changed', chatTo.peerId);
const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);
if(searchTab) {
searchTab.close();
}
searchTab?.close();
appSidebarRight.replaceSharedMediaTab(chatTo.sharedMediaTab);
}

View File

@ -1492,6 +1492,8 @@ export class AppMessagesManager extends AppManager {
sequential: options.sequential
};
this.pendingTopMsgs[peerId] = messageId;
if(!options.isGroupedItem && message.send) {
callbacks.push(() => {
if(options.clearDraft) {

View File

@ -11,10 +11,12 @@ import parseMarkdown from '../richTextProcessor/parseMarkdown';
import {AppManager} from './manager';
import getServerMessageId from './utils/messageId/getServerMessageId';
type PollId = Poll['id'];
export class AppPollsManager extends AppManager {
public polls: {[id: string]: Poll} = {};
public results: {[id: string]: PollResults} = {};
public pollToMessages: {[id: string]: Set<string>} = {};
public polls: {[id: PollId]: Poll} = {};
public results: {[id: PollId]: PollResults} = {};
public pollToMessages: {[id: PollId]: Set<string>} = {};
private log = logger('POLLS', LogTypes.Error);
@ -78,7 +80,7 @@ export class AppPollsManager extends AppManager {
return results;
}
public getPoll(pollId: string): {poll: Poll, results: PollResults} {
public getPoll(pollId: PollId): {poll: Poll, results: PollResults} {
return {
poll: this.polls[pollId],
results: this.results[pollId]
@ -128,8 +130,8 @@ export class AppPollsManager extends AppManager {
}
}
public sendVote(message: any, optionIds: number[]): Promise<void> {
const poll: Poll = message.media.poll;
public sendVote(message: Message.message, optionIds: number[]): Promise<void> {
const poll: Poll = (message.media as MessageMedia.messageMediaPoll).poll;
const options: Uint8Array[] = optionIds.map((index) => {
return poll.answers[index].option;
@ -142,7 +144,7 @@ export class AppPollsManager extends AppManager {
if(message.pFlags.is_outgoing) {
return this.appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {
this.log('invoke sendVote callback');
return this.sendVote(message, optionIds);
return this.sendVote(message as Message.message, optionIds);
});
}
@ -156,7 +158,7 @@ export class AppPollsManager extends AppManager {
});
}
public getResults(message: any) {
public getResults(message: Message.message) {
const inputPeer = this.appPeersManager.getInputPeerById(message.peerId);
return this.apiManager.invokeApi('messages.getPollResults', {
@ -168,7 +170,7 @@ export class AppPollsManager extends AppManager {
});
}
public getVotes(message: any, option?: Uint8Array, offset?: string, limit = 20) {
public getVotes(message: Message.message, option?: Uint8Array, offset?: string, limit = 20) {
return this.apiManager.invokeApi('messages.getPollVotes', {
peer: this.appPeersManager.getInputPeerById(message.peerId),
id: getServerMessageId(message.mid),
@ -184,8 +186,8 @@ export class AppPollsManager extends AppManager {
});
}
public stopPoll(message: any) {
const poll: Poll = message.media.poll;
public stopPoll(message: Message.message) {
const poll: Poll = (message.media as MessageMedia.messageMediaPoll).poll;
if(poll.pFlags.closed) return Promise.resolve();

View File

@ -271,8 +271,11 @@ export class AppProfileManager extends AppManager {
const fullChat = this.chatsFull[id] as ChatFull.chatFull;
if(fullChat && !override && Date.now() < this.fullExpiration[peerId]) {
const chat: Chat.chat = this.appChatsManager.getChat(id);
if(chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version ||
chat.pFlags.left) {
if(
chat.pFlags.left ||
chat.pFlags.deactivated ||
chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version
) {
return fullChat as ChatFull;
}
}

View File

@ -396,10 +396,16 @@ export class AppUsersManager extends AppManager {
public getContactsPeerIds(
query?: Parameters<AppUsersManager['getContacts']>[0],
includeSaved?: Parameters<AppUsersManager['getContacts']>[1],
sortBy?: Parameters<AppUsersManager['getContacts']>[2]
sortBy?: Parameters<AppUsersManager['getContacts']>[2],
limit?: number
) {
return this.getContacts(query, includeSaved, sortBy).then((userIds) => {
return userIds.map((userId) => userId.toPeerId(false));
const peerIds = userIds.map((userId) => userId.toPeerId(false));
if(limit) {
return peerIds.slice(0, limit);
}
return peerIds;
});
}

View File

@ -10,6 +10,7 @@ import apiManagerProxy from '../mtproto/mtprotoworker';
import {AckedResult} from '../mtproto/superMessagePort';
import noop from '../../helpers/noop';
import dT from '../../helpers/dT';
import DEBUG from '../../config/debug';
// let stats: {
// [manager: string]: {
@ -58,6 +59,11 @@ import dT from '../../helpers/dT';
// sentMethods2 = {};
// }, 2000);
const DEBUG_MANAGER_REQUESTS: {[managerName: string]: Set<string>} = {};
if(DEBUG) {
(window as any).DEBUG_MANAGER_REQUESTS = DEBUG_MANAGER_REQUESTS;
}
function createProxy(/* source: T, */name: string, ack?: boolean) {
const proxy = new Proxy({}, {
get: (target, p, receiver) => {
@ -75,6 +81,12 @@ function createProxy(/* source: T, */name: string, ack?: boolean) {
args
}, ack as any);
if(DEBUG) {
if(DEBUG_MANAGER_REQUESTS[name]?.has(p as any)) {
console.warn('manager request', name, p, args);
}
}
// collectStats(name, p as string, args, promise);
return promise;
@ -93,27 +105,30 @@ type AA<T> = {
};
type T = Awaited<ReturnType<typeof createManagers>>;
export default function getProxiedManagers() {
let proxied: {
[name in keyof T]?: ModifyFunctionsToAsync<T[name]>;
} & {
acknowledged?: {
[name in keyof T]?: AA<T[name]>;
}
};
type ProxiedManagers = {
[name in keyof T]?: ModifyFunctionsToAsync<T[name]>;
} & {
acknowledged?: {
[name in keyof T]?: AA<T[name]>;
}
};
function createProxyProxy(proxied: any, ack?: boolean) {
return new Proxy(proxied, {
get: (target, p, receiver) => {
// @ts-ignore
return target[p] ??= createProxy(p as string, ack);
}
});
function createProxyProxy(proxied: any, ack?: boolean) {
return new Proxy(proxied, {
get: (target, p, receiver) => {
// @ts-ignore
return target[p] ??= createProxy(p as string, ack);
}
});
}
let proxied: ProxiedManagers;
export default function getProxiedManagers() {
if(proxied) {
return proxied;
}
proxied = createProxyProxy({}, false);
proxied.acknowledged = createProxyProxy({}, true);
return proxied;
}

View File

@ -795,14 +795,15 @@ export default class DialogsStorage extends AppManager {
const updatedDialogs: Map<PeerId, Dialog> = new Map();
(dialogsResult.dialogs as Dialog[]).forEach((dialog) => {
const peerId = this.appPeersManager.getPeerId(dialog.peer);
let topMessage = dialog.top_message;
let topMid = dialog.top_message;
const topPendingMessage = this.appMessagesManager.pendingTopMsgs[peerId];
if(topPendingMessage) {
if(!topMessage ||
(this.appMessagesManager.getMessageByPeer(peerId, topPendingMessage) as MyMessage)?.date > (this.appMessagesManager.getMessageByPeer(peerId, topMessage) as MyMessage)?.date) {
dialog.top_message = topMessage = topPendingMessage;
this.appMessagesManager.getHistoryStorage(peerId).maxId = topPendingMessage;
const topPendingMid = this.appMessagesManager.pendingTopMsgs[peerId];
if(topPendingMid) {
const topPendingMessage = this.appMessagesManager.getMessageByPeer(peerId, topPendingMid) as MyMessage;
const topMessage = this.appMessagesManager.getMessageByPeer(peerId, topMid) as MyMessage;
if(!topMid || (topPendingMessage && (!topMessage || topPendingMessage?.date > topMessage?.date))) {
dialog.top_message = topMid = topPendingMid;
this.appMessagesManager.getHistoryStorage(peerId).maxId = topPendingMid;
}
}
@ -811,7 +812,7 @@ export default class DialogsStorage extends AppManager {
this.log.error('applyConversation lun', dialog, d);
} */
if(topMessage || dialog.draft?._ === 'draftMessage') {
if(topMid || dialog.draft?._ === 'draftMessage') {
if(this.saveDialog(dialog)) {
updatedDialogs.set(peerId, dialog);
}

View File

@ -78,6 +78,7 @@ avatar-element {
} */
&.tgico-deletedaccount {
overflow: hidden;
--color-top: var(--peer-avatar-archive-top);
--color-bottom: var(--peer-avatar-archive-bottom);

View File

@ -5,11 +5,18 @@
*/
.badge {
--size: 1.375rem;
--padding: .4375rem;
border-radius: .75rem;
font-weight: var(--font-weight-bold);
color: var(--badge-text-color);
font-size: .875rem;
text-align: center;
height: var(--size);
min-width: var(--size);
line-height: var(--size) !important;
padding: 0 var(--padding);
@include animation-level(2) {
transition: background-color .2s ease-in-out;
@ -20,24 +27,18 @@
}
&-20 {
height: 1.25rem;
min-width: 1.25rem;
line-height: 1.25rem !important;
padding: 0 .375rem;
--size: 1.25rem;
--padding: .375rem;
}
&-24 {
height: 1.5rem;
min-width: 1.5rem;
line-height: 1.5rem !important;
padding: 0 .5rem;
--size: 1.5rem;
--padding: .5rem;
}
&.tgico {
// width: 1.5rem;
&:before {
font-size: 1.5rem;
}
&.tgico {
&:before {
font-size: var(--size);
}
}

View File

@ -675,7 +675,7 @@ $btn-menu-z-index: 4;
display: flex;
align-items: center;
padding: 0 1rem;
height: 3.5rem;
height: 3rem;
//width: auto;
//text-transform: capitalize;
font-weight: normal;
@ -690,7 +690,7 @@ $btn-menu-z-index: 4;
&.danger {
@include hover-background-effect(red);
}
&.primary {
@include hover-background-effect(primary);
}
@ -700,6 +700,10 @@ $btn-menu-z-index: 4;
color: var(--secondary-text-color);
font-size: 1.5rem;
margin-right: 2rem;
@include respond-to(handhelds) {
margin-right: 1.5rem;
}
}
&.btn-short:before {

View File

@ -1680,6 +1680,11 @@ $chat-input-border-radius: 1rem;
padding: 0 $chat-padding-handhelds;
}
&:after {
content: " ";
height: .125rem;
}
&.is-chat {
.is-in {
//margin-left: 45px;

View File

@ -85,6 +85,7 @@ $bubble-border-radius-big: 12px;
}
.bubble {
--line-height: var(--messages-line-height);
position: relative;
z-index: 1;
margin: 0 auto $bubble-margin;

View File

@ -180,6 +180,7 @@ body.is-right-column-shown {
max-width: calc(100% - 1.5rem);
display: flex;
align-items: center;
font-weight: var(--font-weight-bold);
span.emoji {
vertical-align: inherit;

View File

@ -129,7 +129,7 @@
.search-super {
.search-group {
margin-bottom: 0px;
padding: 4px 0 0;
padding: 0 0 .5rem;
&__name {
padding-top: 1rem;
@ -138,7 +138,6 @@
}
}
}
}
ul.chatlist {
@ -151,8 +150,6 @@ ul.chatlist {
}
.chatlist {
//--avatarSize: 54px;
//--height: 72px;
margin: 0;
display: flex;
flex-direction: column;
@ -164,40 +161,11 @@ ul.chatlist {
-webkit-user-select: none; /* disable selection/Copy of UIWebView */
-webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
/* &.chatlist-avatar-48 {
--avatarSize: 48px;
}
@include respond-to(handhelds) {
&.chatlist-handhelds-66 {
--height: 66px;
}
} */
&-chat {
--background: unset;
//height: var(--height);
height: 72px;
//max-height: var(--height);
border-radius: $border-radius-medium;
display: flex;
align-items: flex-start; // TODO: проверить разницу в производительности с align-items: center;
flex-direction: row;
position: relative;
cursor: pointer;
padding: .5625rem;
/* padding-top: calc((var(--height) - var(--avatarSize)) / 2);
padding-bottom: calc((var(--height) - var(--avatarSize)) / 2);
padding-right: 8.5px;
padding-left: 8.5px; */
overflow: hidden;
background: var(--background);
background: var(--background) !important;
-webkit-user-drag: none;
@include respond-to(handhelds) {
border-radius: 0;
}
//@include hover-background-effect();
@include hover(gray, --background, false);
@ -227,31 +195,14 @@ ul.chatlist {
}
}
p {
margin: 0;
display: flex;
flex-direction: row;
align-items: flex-start;
height: 27px;
}
a {
color: inherit;
i {
font-style: normal;
}
.text-highlight {
color: var(--primary-text-color);
}
/* img.emoji {
margin-right: .25rem;
margin-left: .25rem;
&:first-child {
margin-left: 0;
}
} */
&.menu-open {
--background: var(--light-secondary-text-color);
}
@ -261,7 +212,8 @@ ul.chatlist {
--background: var(--primary-color) !important;
//background: var(--light-secondary-text-color);
.user-caption,
.row-subtitle,
.row-title,
.tgico-chatspinned:before,
//.user-title:after,
.user-title,
@ -270,7 +222,7 @@ ul.chatlist {
.premium-icon,
.verified-icon,
.sending-status-icon {
color: #fff;
color: #fff !important;
}
.badge-fake {
@ -278,7 +230,8 @@ ul.chatlist {
border-color: #fff;
}
b {
.primary-text,
.danger {
color: #fff !important;
}
@ -316,17 +269,6 @@ ul.chatlist {
}
}
/* .user-title,
.dialog-title-details,
.user-last-message */&-chat span {
//display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
//margin: .1rem 0;
line-height: 27px;
}
.peer-typing-container {
--color: var(--secondary-text-color);
@ -347,12 +289,8 @@ ul.chatlist {
}
&-subtitle {
margin-top: -3px;
&-badge {
display: block !important;
margin-top: 4px;
margin-right: -3px;
margin-left: .5rem;
flex: 0 0 auto;
@ -368,13 +306,21 @@ ul.chatlist {
&-media {
width: 1.25rem;
height: 1.25rem;
line-height: 1.25rem;
position: relative;
flex: 0 0 auto;
border-radius: .25rem;
margin-top: -0.125rem;
margin-right: 0.375rem;
display: inline-block;
vertical-align: middle;
&:before {
content: " ";
display: inline-block;
width: inherit;
height: inherit;
min-width: inherit;
min-height: inherit;
}
&.is-round {
border-radius: 50%;
@ -400,6 +346,8 @@ ul.chatlist {
height: inherit;
object-fit: cover;
border-radius: inherit;
top: auto;
bottom: auto;
}
}
}
@ -431,15 +379,8 @@ ul.chatlist {
flex: 0 0 auto;
}
.user-caption {
overflow: hidden;
color: var(--secondary-text-color);
flex: 1 1 auto;
padding: .0625rem .4375rem .0625rem .5625rem;
}
.dialog-avatar,
.user-caption {
.dialog-avatar,
.row-row {
pointer-events: none;
position: relative; // for z-index
}
@ -454,12 +395,6 @@ ul.chatlist {
width: 18px;
height: 18px;
}
/* span.emoji {
&:first-of-type:not(:first-child) {
margin-left: .125rem;
}
} */
}
.user-last-message {
@ -481,11 +416,6 @@ ul.chatlist {
.user-last-message {
flex-grow: 1;
position: relative; // * for custom emoji
i {
font-style: normal;
//color: var(--primary-color);
}
}
.message-status {
@ -505,10 +435,6 @@ ul.chatlist {
}
}
/* .message-time {
vertical-align: middle;
} */
.tgico-chatspinned {
background: transparent;
@ -530,8 +456,7 @@ ul.chatlist {
}
}
.tgico-chatspinned/* ,
.tgico-mention */ {
.tgico-chatspinned {
position: relative;
&:before {
@ -546,12 +471,12 @@ ul.chatlist {
background-color: var(--chatlist-status-color) !important;
html.is-mac & {
line-height: 22px !important;
line-height: 1.25rem !important;
}
}
.mention-badge {
margin-right: -2px;
margin-right: -.125rem;
}
/* .tgico-mention {
@ -619,87 +544,4 @@ ul.chatlist {
// margin-top: -.5rem;
}
}
// * supernew correct layout
&-new {
.chatlist-chat {
height: 4.5rem;
padding: 0 .75rem;
align-items: center;
}
.user-caption {
padding-left: .75rem;
}
p {
height: auto !important;
}
span {
line-height: var(--line-height) !important;
}
.dialog-subtitle {
margin-top: .125rem;
}
.user-last-message {
font-size: .875rem;
}
}
}
// use together like class="chatlist-container contacts-container"
.contacts-container,
.search-group-contacts {
.chatlist-chat {
padding: .75rem;
@include respond-to(handhelds) {
height: 66px;
padding-top: 9px;
padding-bottom: 9px;
}
}
.user-caption {
padding: 1px 3.5px 1px 13px;
@include respond-to(handhelds) {
padding: 0 4px 0 14px;
}
}
.user-title,
b,
.user-last-message b {
font-weight: normal;
}
p {
height: 24px;
@include respond-to(handhelds) {
height: 26px;
}
}
span.user-last-message {
font-size: 14px;
}
}
.chatlist-new.chatlist-48 {
.chatlist-chat {
height: 3.5rem;
}
.user-caption {
padding-left: 1.125rem;
}
.dialog-subtitle {
margin-top: .0625rem;
}
}

View File

@ -95,6 +95,7 @@
}
&-input {
// --padding: calc((var(--height) - var(--border-width) * 2 - var(--line-height)) / 2);
--padding: 1rem;
--padding-horizontal: 1rem;
--border-width: 1px;

View File

@ -345,40 +345,52 @@
.chatlist {
display: flex;
flex-direction: row;
padding-left: 4px;
margin-top: -1px;
padding-bottom: 1px;
}
padding: 0 0 1px;
.chatlist-chat {
height: 98px;
border-radius: 10px;
max-width: 78px;
width: 78px;
align-items: center;
display: flex;
flex-direction: column;
padding: 12px 0 0 !important;
margin: 0 5px 0 0;
flex: 0 0 auto;
&:before,
&:after {
content: " ";
display: inline-block;
width: .3125rem;
flex: 0 0 auto;
}
@include respond-to(handhelds) {
width: 77px;
max-width: 77px;
&-chat {
width: 4.875rem;
max-width: 4.875rem;
height: 6.125rem;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
flex: 0 0 auto;
padding: 0 !important;
}
}
.dialog-title-details, .dialog-subtitle {
display: none;
}
.dialog {
&-title-details,
&-subtitle {
display: none;
}
&-title {
max-width: 65px;
padding-bottom: .75rem;
.user-caption {
max-width: 65px;
padding: 2px 0px 9px;
font-size: 12px;
.user-title {
font-size: .75rem !important;
}
@include respond-to(handhelds) {
max-width: 56px;
.peer-title {
font-weight: var(--font-weight-normal) !important;
}
}
&-avatar {
left: auto !important;
top: .75rem !important;
}
}
@ -535,7 +547,6 @@
@include respond-to(handhelds) {
width: 100%;
padding: 0 .25rem;
}
}
}
@ -550,7 +561,9 @@
}
}
.new-channel-container, .new-group-container, .edit-profile-container {
.new-channel-container,
.new-group-container,
.edit-profile-container {
.sidebar-content {
flex-direction: column;
}
@ -560,7 +573,7 @@
}
.caption {
font-size: 0.875rem;
font-size: .875rem;
margin-top: 14px;
margin-left: 23px;
color: var(--secondary-text-color);
@ -642,8 +655,8 @@
.caption {
text-align: center;
color: var(--secondary-text-color);
font-size: 14px;
line-height: var(--line-height);
font-size: var(--font-size-14);
line-height: var(--line-height-14);
max-width: 20rem;
margin: 0 auto;
}
@ -697,21 +710,6 @@
}
}
.folder-list {
.chatlist-chat {
padding: 9px 12px;
height: 50px;
}
.user-caption {
padding: 3px 28px 6px 27px;
}
p span {
font-weight: normal;
}
}
.folder-categories {
.checkbox-field {
position: absolute;
@ -719,31 +717,6 @@
}
}
.folder-category-button {
height: 50px;
}
.popup-forward, .included-chatlist-container {
.selector {
.chatlist {
&-chat {
padding: 7px .75rem !important;
height: 3.75rem;
}
.user-caption {
padding: 0px 0px 0 14px;
margin-top: -2px;
}
.user-last-message {
font-size: 15px;
margin-top: 2px;
}
}
}
}
.included-chatlist-container {
.sidebar-left-section {
padding-bottom: 0;
@ -786,27 +759,6 @@
font-size: 22px;
//}
}
@include respond-to(handhelds) {
.chatlist-chat {
height: 62px;
padding-top: 7px;
padding-bottom: 7px;
}
.user-caption {
margin-top: -2px;
}
.user-title {
font-weight: var(--font-weight-bold) !important;
}
.dialog-avatar {
--size: 46px;
--multiplier: 1.173913;
}
}
}
@include respond-to(handhelds) {
@ -913,7 +865,8 @@
}
}
.checkbox-field, .radio-field {
.checkbox-field,
.radio-field {
margin: 0;
}
@ -1081,9 +1034,9 @@
.active-sessions-container {
.row {
margin-top: 0;
padding-top: 1rem;
padding-bottom: .9375rem;
// margin-top: 0;
// padding-top: 1rem;
// padding-bottom: .9375rem;
&-title:first-child {
font-weight: var(--font-weight-bold);
@ -1113,21 +1066,6 @@
}
.blocked-users-container {
.chatlist-chat {
height: 66px;
padding-top: 9px;
padding-bottom: 9px;
}
.user-caption {
padding-left: .75rem;
}
.dialog-subtitle {
margin-top: -.375rem;
font-size: .875rem;
}
ul {
@include respond-to(not-handhelds) {
padding: 0 .6875rem;

View File

@ -79,6 +79,7 @@ poll-element {
&-avatars {
display: flex;
margin-left: 18px;
cursor: pointer;
}
&-avatar {

View File

@ -125,10 +125,6 @@
}
}
.profile-name {
margin-bottom: -1px;
}
.profile-subtitle,
.verified-icon,
.premium-icon {
@ -299,8 +295,8 @@
&-name {
text-align: center;
font-size: 1.25rem;
line-height: var(--line-height);
font-size: var(--font-size-20);
line-height: var(--line-height-20);
font-weight: var(--font-weight-bold);
overflow: hidden;
max-width: 21.25rem;

View File

@ -564,7 +564,8 @@
}
}
&-content-music, &-content-voice {
&-content-music,
&-content-voice {
.search-super-month-items {
padding: 20px 15px 0px 20px;
@ -596,19 +597,6 @@
.chatlist {
padding-top: .5rem;
padding-bottom: .5rem;
.chatlist-chat {
padding: .75rem;
}
.user-caption {
padding-left: .75rem;
}
.dialog-subtitle {
font-size: .875rem;
margin-top: -.375rem;
}
}
}
@ -692,9 +680,9 @@
}
}
}
.search-group.is-short {
li:nth-child(n + 4) {
.chatlist-chat:nth-child(n + 4) {
display: none;
}
}
@ -794,22 +782,12 @@
}
&-more {
padding-top: 13px;
padding-bottom: 13px;
cursor: pointer;
user-select: none;
position: relative;
margin: 0 .5rem;
width: auto;
@include respond-to(not-handhelds) {
padding-left: 8px;
}
.tgico-down {
float: left;
padding-right: 32px;
padding-left: 16.5px;
font-size: 24px;
color: var(--secondary-text-color);
@include respond-to(handhelds) {
margin: 0;
border-radius: 0;
}
}
@ -827,30 +805,8 @@
hr {
margin-bottom: 15px;
margin-top: 7px;
display: block !important;
}
.user-caption {
padding: 3px 28px 6px;
}
.user-title {
font-weight: normal;
}
.chatlist-chat {
height: 50px;
padding: 9px;
@include respond-to(not-handhelds) {
padding: 9px 12px;
}
}
}
}
#search-gifs-container {
.gifs-masonry {
margin-top: -2.5px;
}
}

View File

@ -16,7 +16,8 @@ $row-border-radius: $border-radius-medium;
flex-direction: column;
justify-content: center;
&.no-subtitle {
&.no-subtitle,
&.row-small {
min-height: 3rem;
padding-top: .1875rem;
padding-bottom: .1875rem;
@ -31,25 +32,43 @@ $row-border-radius: $border-radius-medium;
opacity: var(--disabled-opacity);
}
&.no-wrap {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
a {
position: relative;
z-index: 1;
}
&-title-row {
&-title-row,
& > &-title {
order: 0;
}
&-big {
min-height: 4.5rem;
padding: .5625rem .75rem .5625rem 1rem;
}
&-row {
display: flex;
justify-content: space-between;
align-items: center;
order: 0;
.row-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.row-title,
.row-subtitle {
@include text-overflow(true);
flex: 1 1 auto;
}
}
&-subtitle-row,
& > &-subtitle {
order: 1;
}
// &-title,
// &-title-row,
// &-subtitle {
@ -58,41 +77,51 @@ $row-border-radius: $border-radius-medium;
&-title {
color: var(--primary-text-color);
font-size: var(--font-size);
line-height: var(--line-height);
order: 0;
@include text-overflow(false);
&-right {
flex: 0 0 auto !important;
margin-left: 1rem;
&-secondary {
color: var(--secondary-text-color);
}
}
}
&-title-right,
&-subtitle-right {
flex: 0 0 auto !important;
margin-left: 1rem;
}
&-midtitle {
font-size: .875rem;
font-size: var(--font-size-14);
order: 1;
}
&-with-padding {
padding-left: 4.5rem;
@include respond-to(handhelds) {
padding-left: 4rem;
}
.row-title.tgico:before {
position: absolute;
left: 1rem;
font-size: 1.5rem;
color: var(--secondary-text-color);
pointer-events: none;
margin-top: -.125rem;
// margin-top: -.125rem;
top: 50%;
transform: translateY(-50%);
}
.row-subtitle:not(:empty):not(.hide) + .row-title.tgico:before {
margin-top: .25rem;
}
// .row-subtitle:not(:empty):not(.hide) + .row-title.tgico:before {
// margin-top: .25rem;
// }
}
&-clickable {
@ -144,11 +173,9 @@ $row-border-radius: $border-radius-medium;
&-subtitle {
color: var(--secondary-text-color) !important;
font-size: .875rem !important;
font-size: var(--font-size-14) !important;
line-height: var(--line-height-14);
margin-top: .125rem;
margin-bottom: .0625rem;
order: 1;
margin-top: .1875rem;
&:empty {
display: none;
@ -172,11 +199,23 @@ $row-border-radius: $border-radius-medium;
left: .75rem !important;
}
&-abitbigger {
width: 2.625rem !important;
height: 2.625rem !important;
left: .75rem !important;
}
&-big {
width: 3rem !important;
height: 3rem !important;
left: .5rem !important;
}
&-bigger {
width: 3.375rem !important;
height: 3.375rem !important;
left: .5625rem !important; // it's wrong but old chatlist has it
}
}
&.menu-open {

View File

@ -143,32 +143,6 @@
} */
}
.chatlist {
&-chat {
padding-top: .75rem;
padding-bottom: .75rem;
@include respond-to(handhelds) {
height: 66px;
padding-top: 9px;
padding-bottom: 9px;
}
}
.user-caption {
padding-left: .75rem;
padding-right: 0;
}
p {
height: 24px !important;
}
span.user-last-message {
font-size: 14px;
}
}
> hr {
margin: 0;
padding: 0;
@ -180,8 +154,11 @@
}
.checkbox-field {
margin: 0;
padding: 0;
--offset-left: 0 !important;
pointer-events: none;
position: absolute !important;
margin: 0 !important;
padding: 0 !important;
transform: translateY(-50%);
top: 50%;
z-index: 1;
@ -193,8 +170,6 @@
}
.checkbox-field-round {
pointer-events: none;
position: absolute;
right: 1.125rem;
--size: 1.25rem;
@ -206,4 +181,20 @@
--offset: 6px;
}
}
&-square {
$add: 3rem;
.checkbox-field {
left: 1.25rem !important;
}
.chatlist-chat {
padding-left: #{4.5rem + $add} !important; // 4.5 + x
}
.dialog-avatar {
margin-left: #{$add} !important;
}
}
}

View File

@ -19,21 +19,23 @@
&-header {
flex: 0 0 auto;
margin-bottom: 3px;
margin-bottom: 7px;
padding: 0 1rem;
@include respond-to(handhelds) {
padding-left: .9375rem;
padding-left: .8125rem;
}
}
&-title {
flex-grow: 1;
padding: 0;
height: 100%;
}
}
.selector, .chatlist-container {
.selector,
.chatlist-container {
height: auto;
overflow: hidden;
display: flex;
@ -44,24 +46,19 @@
.selector {
&-search-input {
font-size: 1.25rem;
font-size: var(--font-size-20);
line-height: 1;
padding: .5rem 1.5rem;
width: 100%;
line-height: var(--line-height);
height: 100%;
@include respond-to(handhelds) {
padding-left: 1.0625rem;
padding-left: 1.1875rem;
}
}
.chatlist {
margin-top: 0 !important;
&-chat {
height: 3.875rem !important;
padding-top: .5rem !important;
padding-bottom: .5rem !important;
}
}
}

View File

@ -154,7 +154,6 @@
}
&-participant {
align-items: center;
// border-radius: 0;
padding-right: .5rem;
@ -175,8 +174,14 @@
}
}
.dialog-title,
.dialog-subtitle {
padding-right: 2.5rem;
}
&-muted-icon-container {
flex: 0 0 auto;
position: absolute !important;
right: .5rem;
}
&-video {
@ -382,10 +387,6 @@
color: var(--gc-secondary-text-color);
}
.dialog-subtitle {
margin-top: -.25rem;
}
// .user-caption {
// padding-right: 1rem;
// }

View File

@ -86,6 +86,7 @@ $chat-input-inner-padding-handhelds: .25rem;
--message-highlightning-color: hsla(85.5319, 36.9171%, 40.402%, .4);//rgba(77, 142, 80, .4);
--messages-container-width: #{$messages-container-width};
--messages-text-size: 16px;
--messages-line-height: 1.3125;
--messages-secondary-text-size: calc(var(--messages-text-size) - 2px);
--messages-secondary-line-height: calc(var(--messages-secondary-text-size) + 4px);
--messages-time-text-size: calc(var(--messages-text-size) - 4px);
@ -93,15 +94,16 @@ $chat-input-inner-padding-handhelds: .25rem;
--messages-custom-emoji-size: calc(var(--messages-text-size) + 4px);
--bubble-transition-in: transform var(--transition-standard-in), opacity var(--transition-standard-in);
--bubble-transition-out: transform var(--transition-standard-out), opacity var(--transition-standard-out);
--line-height: 1.3125;
--line-height-20: 23px;
--line-height-20: 26px;
--line-height-16: 21px;
--line-height-14: 18px;
--line-height-12: 16px;
--line-height: 1.3125;
--font-size-20: 20px;
--font-size-16: 16px;
--font-size-14: 14px;
--font-size-12: 12px;
--font-size: var(--font-size-16);
--esg-sticker-size: 72px;
--esg-custom-emoji-size: 36px;
--popup-sticker-size: 80px;
@ -111,6 +113,7 @@ $chat-input-inner-padding-handhelds: .25rem;
--menu-backdrop-filter: blur(50px);
--font-monospace: 'Roboto Mono', monospace;
--font-weight-bold: 500;
--font-weight-normal: 400;
--selection-background-color: rgba(var(--primary-color-rgb), .4);
--selection-color: inherit;
@ -418,14 +421,15 @@ $chat-input-inner-padding-handhelds: .25rem;
@import "partials/pages/chats";
@import "partials/pages/password";
html, body {
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden; // + disable overscroll behavior on macOS
@include respond-to(handhelds) {
overflow: hidden;
height: calc(var(--vh, 1vh) * 100);
}
@ -619,7 +623,8 @@ input:-webkit-autofill:active {
}
}
.blue, .primary {
.blue,
.primary {
color: var(--primary-color) !important;
.c-ripple__circle {
@ -627,13 +632,19 @@ input:-webkit-autofill:active {
}
}
.primary-text {
color: var(--primary-text-color) !important;
}
.color-premium {
background: var(--premium-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.blue:before, .primary:before, .danger:before {
.blue:before,
.primary:before,
.danger:before {
color: inherit !important;
}
@ -771,16 +782,9 @@ hr {
padding-bottom: .5rem;
}
.user-title, b/* , .user-last-message b */ {
b {
color: var(--primary-text-color);
// font-weight: bolder;
font-weight: var(--font-weight-bold);
//font-weight: normal;
}
.user-last-message b {
font-weight: 400;
//margin-right: .25rem;
}
.avatar-edit {
@ -1576,13 +1580,18 @@ middle-ellipsis-element {
&-caption {
margin: -0.1875rem 0 1rem;
font-size: .875rem;
font-size: var(--font-size-14);
line-height: var(--line-height-14);
padding: 0 1.5rem;
&:first-child {
margin-top: .8125rem;
margin-bottom: .8125rem;
}
@include respond-to(handhelds) {
padding: 0 1rem;
}
}
&-container {
@ -1997,6 +2006,67 @@ hr {
}
}
.chatlist-chat {
padding-left: 4.5rem !important;
span {
@include text-overflow(true);
}
.row {
&-title {
font-size: var(--font-size-16) !important;
line-height: 1.375rem;
&-right-secondary {
margin-top: -.4375rem;
font-size: var(--font-size-12) !important;
line-height: var(--line-height-12) !important;
}
// .peer-title {
// font-weight: var(--font-weight-bold);
// }
}
&-row {
height: 1.375rem;
}
}
&.chatlist-chat-small {
}
&.chatlist-chat-abitbigger {
.row {
&-subtitle {
margin-top: 0;
}
}
}
&.chatlist-chat-bigger {
.row {
&-subtitle {
margin-top: 0;
font-size: var(--font-size-16) !important;
line-height: 1.375rem;
&-row {
margin-top: .125rem;
}
}
&-title {
.peer-title {
font-weight: var(--font-weight-bold);
}
}
}
}
}
// .contacts-container {
// .chatlist-chat {
// /* align-items: center; */