diff --git a/public/assets/img/pattern_newbroken.svg b/public/assets/img/pattern_newbroken.svg
new file mode 100644
index 000000000..05984b97a
--- /dev/null
+++ b/public/assets/img/pattern_newbroken.svg
@@ -0,0 +1,4649 @@
+
+
+
diff --git a/src/components/appSearch.ts b/src/components/appSearch.ts
index 149608bb5..88be9721e 100644
--- a/src/components/appSearch.ts
+++ b/src/components/appSearch.ts
@@ -204,7 +204,7 @@ export default class AppSearch {
appDialogsManager.addDialogAndSetLastMessage({
peerId,
container: this.scrollable/* searchGroup.list */,
- avatarSize: 54,
+ avatarSize: 'bigger',
meAsSaved: false,
message,
query,
diff --git a/src/components/appSearchSuper..ts b/src/components/appSearchSuper..ts
index 2a86ffa53..54b7474f5 100644
--- a/src/components/appSearchSuper..ts
+++ b/src/components/appSearchSuper..ts
@@ -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', `
-
${title}${titleAdditionHTML}
- ${subtitle}
- ${url}
- ${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 = '' + username + '';
+ 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();
});
}
diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts
index c43fe9cbf..386db8102 100644
--- a/src/components/appSelectPeers.ts
+++ b/src/components/appSelectPeers.ts
@@ -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);
// }
diff --git a/src/components/chat/bubbleGroups.ts b/src/components/chat/bubbleGroups.ts
index 09c3ac96e..8de8c206d 100644
--- a/src/components/chat/bubbleGroups.ts
+++ b/src/components/chat/bubbleGroups.ts
@@ -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[]) {
diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts
index af20197b3..67ac46736 100644
--- a/src/components/chat/bubbles.ts
+++ b/src/components/chat/bubbles.ts
@@ -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[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()
diff --git a/src/components/chat/chat.ts b/src/components/chat/chat.ts
index 05eb2f890..3c06df60e 100644
--- a/src/components/chat/chat.ts
+++ b/src/components/chat/chat.ts
@@ -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();
}
diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts
index 7618e8f14..028606dc3 100644
--- a/src/components/chat/contextMenu.ts
+++ b/src/components/chat/contextMenu.ts
@@ -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() => {
diff --git a/src/components/groupCall/participantsList.ts b/src/components/groupCall/participantsList.ts
index 5118be7f7..3234df7f3 100644
--- a/src/components/groupCall/participantsList.ts
+++ b/src/components/groupCall/participantsList.ts
@@ -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[0] = {/* new: true, */dialogSize: 72};
diff --git a/src/components/peerProfile.ts b/src/components/peerProfile.ts
index c7ae55ca8..fdc4adb68 100644
--- a/src/components/peerProfile.ts
+++ b/src/components/peerProfile.ts
@@ -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();
diff --git a/src/components/popups/forward.ts b/src/components/popups/forward.ts
index 14970d658..a412b1211 100644
--- a/src/components/popups/forward.ts
+++ b/src/components/popups/forward.ts
@@ -30,5 +30,8 @@ export default class PopupForward extends PopupPickUser {
chatRightsAction: 'send_messages',
selfPresence: 'ChatYourSelf'
});
+
+ this.scrollable = this.selector.scrollable;
+ this.attachScrollableListeners(this.scrollable);
}
}
diff --git a/src/components/popups/index.ts b/src/components/popups/index.ts
index 1347c19f0..5e31572e4 100644
--- a/src/components/popups/index.ts
+++ b/src/components/popups/index.ts
@@ -159,12 +159,7 @@ export default class PopupElement 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 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 extends
this.element.remove();
this.dispatchEvent('closeAfterTimeout');
this.cleanup();
+ this.scrollable?.destroy();
if(!this.withoutOverlay) {
animationIntersector.checkAnimations2(false);
diff --git a/src/components/popups/pickUser.ts b/src/components/popups/pickUser.ts
index 51d507486..a620fff22 100644
--- a/src/components/popups/pickUser.ts
+++ b/src/components/popups/pickUser.ts
@@ -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,
diff --git a/src/components/popups/reactedList.ts b/src/components/popups/reactedList.ts
index 1659547ce..8957a4cfa 100644
--- a/src/components/popups/reactedList.ts
+++ b/src/components/popups/reactedList.ts
@@ -144,7 +144,7 @@ export default class PopupReactedList extends PopupElement {
peerId: peerId,
autonomous: true,
container: chatlist,
- avatarSize: 54,
+ avatarSize: 'abitbigger',
rippleEnabled: false,
meAsSaved: false
});
diff --git a/src/components/row.ts b/src/components/row.ts
index 2b376fcaa..6034f4ffc 100644
--- a/src/components/row.ts
+++ b/src/components/row.ts
@@ -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) {
diff --git a/src/components/sidebarLeft/tabs/addMembers.ts b/src/components/sidebarLeft/tabs/addMembers.ts
index f74ade178..9436439e1 100644
--- a/src/components/sidebarLeft/tabs/addMembers.ts
+++ b/src/components/sidebarLeft/tabs/addMembers.ts
@@ -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) {
diff --git a/src/components/sidebarLeft/tabs/blockedUsers.ts b/src/components/sidebarLeft/tabs/blockedUsers.ts
index 44768e017..d496035a1 100644
--- a/src/components/sidebarLeft/tabs/blockedUsers.ts
+++ b/src/components/sidebarLeft/tabs/blockedUsers.ts
@@ -59,7 +59,7 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
peerId: peerId,
container: list,
rippleEnabled: true,
- avatarSize: 48,
+ avatarSize: 'abitbigger',
append
});
diff --git a/src/components/sidebarLeft/tabs/contacts.ts b/src/components/sidebarLeft/tabs/contacts.ts
index 90cd9bc74..6bc5f2e85 100644
--- a/src/components/sidebarLeft/tabs/contacts.ts
+++ b/src/components/sidebarLeft/tabs/contacts.ts
@@ -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) => {
diff --git a/src/components/sidebarLeft/tabs/editFolder.ts b/src/components/sidebarLeft/tabs/editFolder.ts
index d771521a5..172ffb36e 100644
--- a/src/components/sidebarLeft/tabs/editFolder.ts
+++ b/src/components/sidebarLeft/tabs/editFolder.ts
@@ -317,7 +317,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
container: ul,
rippleEnabled: false,
meAsSaved: true,
- avatarSize: 32
+ avatarSize: 'small'
});
dom.lastMessageSpan.parentElement.remove();
}
diff --git a/src/components/sidebarLeft/tabs/editProfile.ts b/src/components/sidebarLeft/tabs/editProfile.ts
index 8e7192775..4c3e4eeaf 100644
--- a/src/components/sidebarLeft/tabs/editProfile.ts
+++ b/src/components/sidebarLeft/tabs/editProfile.ts
@@ -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}));
}
}
}
diff --git a/src/components/sidebarLeft/tabs/includedChats.ts b/src/components/sidebarLeft/tabs/includedChats.ts
index ad49e68ce..965e7c65d 100644
--- a/src/components/sidebarLeft/tabs/includedChats.ts
+++ b/src/components/sidebarLeft/tabs/includedChats.ts
@@ -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);
diff --git a/src/components/sidebarLeft/tabs/newGroup.ts b/src/components/sidebarLeft/tabs/newGroup.ts
index f9c971dd5..abc0e312c 100644
--- a/src/components/sidebarLeft/tabs/newGroup.ts
+++ b/src/components/sidebarLeft/tabs/newGroup.ts
@@ -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)));
diff --git a/src/components/sidebarRight/index.ts b/src/components/sidebarRight/index.ts
index 592ff03c5..30d0ee020 100644
--- a/src/components/sidebarRight/index.ts
+++ b/src/components/sidebarRight/index.ts
@@ -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) {
diff --git a/src/components/sidebarRight/tabs/groupPermissions.ts b/src/components/sidebarRight/tabs/groupPermissions.ts
index 1ee57b343..7d7d69fae 100644
--- a/src/components/sidebarRight/tabs/groupPermissions.ts
+++ b/src/components/sidebarRight/tabs/groupPermissions.ts
@@ -264,7 +264,7 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
peerId: getPeerId(participant.peer),
container: list,
rippleEnabled: true,
- avatarSize: 48,
+ avatarSize: 'abitbigger',
append
});
diff --git a/src/components/sidebarRight/tabs/pollResults.ts b/src/components/sidebarRight/tabs/pollResults.ts
index 2772bfbb2..3e9b0b033 100644
--- a/src/components/sidebarRight/tabs/pollResults.ts
+++ b/src/components/sidebarRight/tabs/pollResults.ts
@@ -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);
diff --git a/src/components/sidebarRight/tabs/userPermissions.ts b/src/components/sidebarRight/tabs/userPermissions.ts
index 4b5eb6b6a..ed5adfe79 100644
--- a/src/components/sidebarRight/tabs/userPermissions.ts
+++ b/src/components/sidebarRight/tabs/userPermissions.ts
@@ -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)));
diff --git a/src/components/sortedUserList.ts b/src/components/sortedUserList.ts
index 776c7c96f..b2822bda6 100644
--- a/src/components/sortedUserList.ts
+++ b/src/components/sortedUserList.ts
@@ -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 {
public list: HTMLUListElement;
protected lazyLoadQueue: LazyLoadQueue;
- protected avatarSize = 48;
+ protected avatarSize: DialogElementSize = 'abitbigger';
protected rippleEnabled = true;
protected autonomous = true;
protected createChatListOptions: Parameters[0];
diff --git a/src/components/wrappers/messageActionTextNewUnsafe.ts b/src/components/wrappers/messageActionTextNewUnsafe.ts
index 768bbaadd..1eca561cb 100644
--- a/src/components/wrappers/messageActionTextNewUnsafe.ts
+++ b/src/components/wrappers/messageActionTextNewUnsafe.ts
@@ -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;
+ 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;
diff --git a/src/components/wrappers/messageForReply.ts b/src/components/wrappers/messageForReply.ts
index 16a30c9e5..dc0d157a9 100644
--- a/src/components/wrappers/messageForReply.ts
+++ b/src/components/wrappers/messageForReply.ts
@@ -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);
diff --git a/src/components/wrappers/sticker.ts b/src/components/wrappers/sticker.ts
index 8c075b16b..20852e3f0 100644
--- a/src/components/wrappers/sticker.ts
+++ b/src/components/wrappers/sticker.ts
@@ -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,
diff --git a/src/helpers/dom/superIntersectionObserver.ts b/src/helpers/dom/superIntersectionObserver.ts
index f82d2e0ed..f099d387c 100644
--- a/src/helpers/dom/superIntersectionObserver.ts
+++ b/src/helpers/dom/superIntersectionObserver.ts
@@ -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) {
diff --git a/src/helpers/formatCallDuration.ts b/src/helpers/formatCallDuration.ts
index 58872b53f..1ac17547a 100644
--- a/src/helpers/formatCallDuration.ts
+++ b/src/helpers/formatCallDuration.ts
@@ -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);
diff --git a/src/helpers/formatDuration.ts b/src/helpers/formatDuration.ts
index bcb4a194b..017072e31 100644
--- a/src/helpers/formatDuration.ts
+++ b/src/helpers/formatDuration.ts
@@ -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;
diff --git a/src/lang.ts b/src/lang.ts
index 5a0a61047..7f89ddfab 100644
--- a/src/lang.ts
+++ b/src/lang.ts
@@ -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',
diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts
index 237d97ff7..9f974bafc 100644
--- a/src/lib/appManagers/appChatsManager.ts
+++ b/src/lib/appManagers/appChatsManager.ts
@@ -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);
diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts
index a20769dc6..b25d24712 100644
--- a/src/lib/appManagers/appDialogsManager.ts
+++ b/src/lib/appManagers/appDialogsManager.ts
@@ -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 {
constructor(
public managers: AppManagers,
@@ -170,6 +173,151 @@ class SortedDialogList extends SortedList {
}
}
+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[],
+ 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[] = [];
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((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[],
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');
diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts
index e10d0305f..4584a644d 100644
--- a/src/lib/appManagers/appImManager.ts
+++ b/src/lib/appManagers/appImManager.ts
@@ -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);
}
diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts
index 8328260b4..5fd1911c2 100644
--- a/src/lib/appManagers/appMessagesManager.ts
+++ b/src/lib/appManagers/appMessagesManager.ts
@@ -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) {
diff --git a/src/lib/appManagers/appPollsManager.ts b/src/lib/appManagers/appPollsManager.ts
index 0432722ba..5896786d1 100644
--- a/src/lib/appManagers/appPollsManager.ts
+++ b/src/lib/appManagers/appPollsManager.ts
@@ -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} = {};
+ public polls: {[id: PollId]: Poll} = {};
+ public results: {[id: PollId]: PollResults} = {};
+ public pollToMessages: {[id: PollId]: Set} = {};
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 {
- const poll: Poll = message.media.poll;
+ public sendVote(message: Message.message, optionIds: number[]): Promise {
+ 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();
diff --git a/src/lib/appManagers/appProfileManager.ts b/src/lib/appManagers/appProfileManager.ts
index 67a0f6764..6fa353fa1 100644
--- a/src/lib/appManagers/appProfileManager.ts
+++ b/src/lib/appManagers/appProfileManager.ts
@@ -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;
}
}
diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts
index c63c81489..7f86d36b9 100644
--- a/src/lib/appManagers/appUsersManager.ts
+++ b/src/lib/appManagers/appUsersManager.ts
@@ -396,10 +396,16 @@ export class AppUsersManager extends AppManager {
public getContactsPeerIds(
query?: Parameters[0],
includeSaved?: Parameters[1],
- sortBy?: Parameters[2]
+ sortBy?: Parameters[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;
});
}
diff --git a/src/lib/appManagers/getProxiedManagers.ts b/src/lib/appManagers/getProxiedManagers.ts
index b4b31ffdd..85f0e5283 100644
--- a/src/lib/appManagers/getProxiedManagers.ts
+++ b/src/lib/appManagers/getProxiedManagers.ts
@@ -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} = {};
+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 = {
};
type T = Awaited>;
-export default function getProxiedManagers() {
- let proxied: {
- [name in keyof T]?: ModifyFunctionsToAsync;
- } & {
- acknowledged?: {
- [name in keyof T]?: AA;
- }
- };
+type ProxiedManagers = {
+ [name in keyof T]?: ModifyFunctionsToAsync;
+} & {
+ acknowledged?: {
+ [name in keyof T]?: AA;
+ }
+};
- 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;
}
diff --git a/src/lib/storages/dialogs.ts b/src/lib/storages/dialogs.ts
index fcef7c819..947e654ce 100644
--- a/src/lib/storages/dialogs.ts
+++ b/src/lib/storages/dialogs.ts
@@ -795,14 +795,15 @@ export default class DialogsStorage extends AppManager {
const updatedDialogs: Map = 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);
}
diff --git a/src/scss/partials/_avatar.scss b/src/scss/partials/_avatar.scss
index dbc0f82d9..4937f8f5c 100644
--- a/src/scss/partials/_avatar.scss
+++ b/src/scss/partials/_avatar.scss
@@ -78,6 +78,7 @@ avatar-element {
} */
&.tgico-deletedaccount {
+ overflow: hidden;
--color-top: var(--peer-avatar-archive-top);
--color-bottom: var(--peer-avatar-archive-bottom);
diff --git a/src/scss/partials/_badge.scss b/src/scss/partials/_badge.scss
index 277481614..484dc2e76 100644
--- a/src/scss/partials/_badge.scss
+++ b/src/scss/partials/_badge.scss
@@ -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);
}
}
diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss
index 92bdc2de3..bac285e92 100644
--- a/src/scss/partials/_button.scss
+++ b/src/scss/partials/_button.scss
@@ -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 {
diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss
index 0212d48d8..4448271a0 100644
--- a/src/scss/partials/_chat.scss
+++ b/src/scss/partials/_chat.scss
@@ -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;
diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss
index 641d0169e..077925223 100644
--- a/src/scss/partials/_chatBubble.scss
+++ b/src/scss/partials/_chatBubble.scss
@@ -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;
diff --git a/src/scss/partials/_chatTopbar.scss b/src/scss/partials/_chatTopbar.scss
index 22b5e5818..9868c261b 100644
--- a/src/scss/partials/_chatTopbar.scss
+++ b/src/scss/partials/_chatTopbar.scss
@@ -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;
diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss
index 3f172f27b..d78a289f7 100644
--- a/src/scss/partials/_chatlist.scss
+++ b/src/scss/partials/_chatlist.scss
@@ -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;
- }
}
diff --git a/src/scss/partials/_input.scss b/src/scss/partials/_input.scss
index f50e464d7..73d618038 100644
--- a/src/scss/partials/_input.scss
+++ b/src/scss/partials/_input.scss
@@ -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;
diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss
index d6539013a..31ed69936 100644
--- a/src/scss/partials/_leftSidebar.scss
+++ b/src/scss/partials/_leftSidebar.scss
@@ -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;
diff --git a/src/scss/partials/_poll.scss b/src/scss/partials/_poll.scss
index 767b18688..070f926a0 100644
--- a/src/scss/partials/_poll.scss
+++ b/src/scss/partials/_poll.scss
@@ -79,6 +79,7 @@ poll-element {
&-avatars {
display: flex;
margin-left: 18px;
+ cursor: pointer;
}
&-avatar {
diff --git a/src/scss/partials/_profile.scss b/src/scss/partials/_profile.scss
index ba601cf06..829cb9f99 100644
--- a/src/scss/partials/_profile.scss
+++ b/src/scss/partials/_profile.scss
@@ -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;
diff --git a/src/scss/partials/_rightSidebar.scss b/src/scss/partials/_rightSidebar.scss
index ff3c7a89f..efb1c8926 100644
--- a/src/scss/partials/_rightSidebar.scss
+++ b/src/scss/partials/_rightSidebar.scss
@@ -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;
}
}
diff --git a/src/scss/partials/_row.scss b/src/scss/partials/_row.scss
index f90b148a7..96c3c44d9 100644
--- a/src/scss/partials/_row.scss
+++ b/src/scss/partials/_row.scss
@@ -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 {
diff --git a/src/scss/partials/_selector.scss b/src/scss/partials/_selector.scss
index ed51b4452..6d56f9d41 100644
--- a/src/scss/partials/_selector.scss
+++ b/src/scss/partials/_selector.scss
@@ -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;
+ }
+ }
}
diff --git a/src/scss/partials/popups/_forward.scss b/src/scss/partials/popups/_forward.scss
index 1d21f26dc..cedb23c6f 100644
--- a/src/scss/partials/popups/_forward.scss
+++ b/src/scss/partials/popups/_forward.scss
@@ -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;
- }
}
}
diff --git a/src/scss/partials/popups/_groupCall.scss b/src/scss/partials/popups/_groupCall.scss
index f6c6b66ae..476ef69dd 100644
--- a/src/scss/partials/popups/_groupCall.scss
+++ b/src/scss/partials/popups/_groupCall.scss
@@ -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;
// }
diff --git a/src/scss/style.scss b/src/scss/style.scss
index cdf32b733..af0bffc74 100644
--- a/src/scss/style.scss
+++ b/src/scss/style.scss
@@ -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; */