Some fixes
This commit is contained in:
parent
274f611bdd
commit
6a3a923310
|
@ -282,7 +282,7 @@ export default class BubbleGroups {
|
|||
}
|
||||
|
||||
removeItem(item: GroupItem) {
|
||||
item.group.removeItem(item);
|
||||
item.group?.removeItem(item);
|
||||
this.removeItemFromCache(item);
|
||||
}
|
||||
|
||||
|
@ -298,10 +298,12 @@ export default class BubbleGroups {
|
|||
|
||||
const group = item.group;
|
||||
this.removeItem(item);
|
||||
group.unmountItem(item);
|
||||
|
||||
const modifiedGroups: Set<BubbleGroup> = new Set();
|
||||
modifiedGroups.add(group);
|
||||
if(group) {
|
||||
group.unmountItem(item);
|
||||
modifiedGroups.add(group);
|
||||
}
|
||||
|
||||
const [previousSibling, nextSibling] = siblings;
|
||||
if(
|
||||
|
|
|
@ -1214,7 +1214,7 @@ export default class ChatBubbles {
|
|||
|
||||
private onBubblesMouseMove = async(e: MouseEvent) => {
|
||||
const content = findUpClassName(e.target, 'bubble-content');
|
||||
if(content && !this.chat.selection.isSelecting) {
|
||||
if(content && !this.chat.selection.isSelecting && !findUpClassName(e.target, 'service')) {
|
||||
const bubble = findUpClassName(content, 'bubble');
|
||||
if(!this.chat.selection.canSelectBubble(bubble)) {
|
||||
this.unhoverPrevious();
|
||||
|
@ -1241,7 +1241,12 @@ export default class ChatBubbles {
|
|||
|
||||
content.append(hoverReaction);
|
||||
|
||||
let message = (await this.chat.getMessage(+bubble.dataset.mid)) as Message.message;
|
||||
let message = await this.chat.getMessage(+bubble.dataset.mid);
|
||||
if(message?._ !== 'message') {
|
||||
this.unhoverPrevious();
|
||||
return;
|
||||
}
|
||||
|
||||
message = await this.managers.appMessagesManager.getGroupsFirstMessage(message);
|
||||
|
||||
const middleware = this.getMiddleware(() => this.hoverReaction === hoverReaction);
|
||||
|
@ -1281,7 +1286,7 @@ export default class ChatBubbles {
|
|||
attachClickEvent(hoverReaction, (e) => {
|
||||
cancelEvent(e); // cancel triggering selection
|
||||
|
||||
this.managers.appReactionsManager.sendReaction(message, availableReaction);
|
||||
this.managers.appReactionsManager.sendReaction(message as Message.message, availableReaction);
|
||||
this.unhoverPrevious();
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
}, noop);
|
||||
|
@ -4407,6 +4412,7 @@ export default class ChatBubbles {
|
|||
bubble.classList.add('must-have-name');
|
||||
}
|
||||
|
||||
const isForward = fwdFromId || fwdFrom;
|
||||
if(isHidden) {
|
||||
// /////this.log('message to render hidden', message);
|
||||
title = document.createElement('span');
|
||||
|
@ -4415,7 +4421,7 @@ export default class ChatBubbles {
|
|||
// title = fwdFrom.from_name;
|
||||
bubble.classList.add('hidden-profile');
|
||||
} else {
|
||||
title = new PeerTitle({peerId: fwdFromId || message.fromId, withPremiumIcon: true}).element;
|
||||
title = new PeerTitle({peerId: fwdFromId || message.fromId, withPremiumIcon: !isForward}).element;
|
||||
}
|
||||
|
||||
if(message.reply_to_mid && message.reply_to_mid !== this.chat.threadId && isMessage) {
|
||||
|
@ -4430,7 +4436,7 @@ export default class ChatBubbles {
|
|||
// this.log(title);
|
||||
|
||||
let nameDiv: HTMLElement;
|
||||
if((fwdFromId || fwdFrom)) {
|
||||
if(isForward) {
|
||||
if(this.peerId !== rootScope.myId && !isForwardFromChannel) {
|
||||
bubble.classList.add('forwarded');
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ import type {Dialog} from '../lib/appManagers/appMessagesManager';
|
|||
import rootScope from '../lib/rootScope';
|
||||
import ButtonMenu, {ButtonMenuItemOptions} from './buttonMenu';
|
||||
import PopupDeleteDialog from './popups/deleteDialog';
|
||||
import {i18n} from '../lib/langPack';
|
||||
import {i18n, LangPackKey, _i18n} from '../lib/langPack';
|
||||
import findUpTag from '../helpers/dom/findUpTag';
|
||||
import PopupPeer from './popups/peer';
|
||||
import PopupPeer, {PopupPeerButton} from './popups/peer';
|
||||
import AppChatFoldersTab from './sidebarLeft/tabs/chatFolders';
|
||||
import appSidebarLeft from './sidebarLeft';
|
||||
import {toastNew} from './toast';
|
||||
|
@ -19,6 +19,7 @@ import PopupMute from './popups/mute';
|
|||
import {AppManagers} from '../lib/appManagers/managers';
|
||||
import positionMenu from '../helpers/positionMenu';
|
||||
import contextMenuController from '../helpers/contextMenuController';
|
||||
import type {ApiLimitType} from '../lib/mtproto/api_methods';
|
||||
|
||||
export default class DialogsContextMenu {
|
||||
private element: HTMLElement;
|
||||
|
@ -113,6 +114,107 @@ export default class DialogsContextMenu {
|
|||
if(this.filterId >= 1) {
|
||||
toastNew({langPackKey: 'PinFolderLimitReached'});
|
||||
} else {
|
||||
// const a: {[type in ApiLimitType]?: {
|
||||
// title: LangPackKey,
|
||||
// description: LangPackKey,
|
||||
// descriptionPremium: LangPackKey,
|
||||
// descriptionLocked: LangPackKey,
|
||||
// icon: string
|
||||
// }} = {
|
||||
// pin: {
|
||||
// title: 'LimitReached',
|
||||
// description: 'LimitReachedPinDialogs',
|
||||
// descriptionPremium: 'LimitReachedPinDialogsPremium',
|
||||
// descriptionLocked: 'LimitReachedPinDialogsLocked',
|
||||
// icon: 'limit_pin'
|
||||
// }
|
||||
// };
|
||||
|
||||
// class P extends PopupPeer {
|
||||
// constructor(options: {
|
||||
// isPremium: boolean,
|
||||
// limit: number,
|
||||
// limitPremium: number
|
||||
// }, _a: typeof a[keyof typeof a]) {
|
||||
// super('popup-limit', {
|
||||
// buttons: options.isPremium === undefined ? [{
|
||||
// langKey: 'LimitReached.Ok',
|
||||
// isCancel: true
|
||||
// }] : (options.isPremium ? [{
|
||||
// langKey: 'OK',
|
||||
// isCancel: true
|
||||
// }] : [{
|
||||
// langKey: 'IncreaseLimit',
|
||||
// callback: () => {
|
||||
|
||||
// }
|
||||
// }, {
|
||||
// langKey: 'Cancel',
|
||||
// isCancel: true
|
||||
// }]),
|
||||
// descriptionLangKey: options.isPremium === undefined ? _a.descriptionLocked : (options.isPremium ? _a.descriptionPremium : _a.description),
|
||||
// descriptionLangArgs: options.isPremium ? [options.limitPremium] : [options.limit, options.limitPremium],
|
||||
// titleLangKey: _a.title
|
||||
// });
|
||||
|
||||
// const isLocked = options.isPremium === undefined;
|
||||
// if(isLocked) {
|
||||
// this.element.classList.add('is-locked');
|
||||
// }
|
||||
|
||||
// const limitContainer = document.createElement('div');
|
||||
// limitContainer.classList.add('popup-limit-line');
|
||||
|
||||
// const hint = document.createElement('div');
|
||||
// hint.classList.add('popup-limit-hint');
|
||||
// const i = document.createElement('span');
|
||||
// i.classList.add('popup-limit-hint-icon', 'tgico-' + _a.icon);
|
||||
// hint.append(i, '' + (options.isPremium ? options.limitPremium : options.limit));
|
||||
|
||||
// limitContainer.append(hint);
|
||||
|
||||
// if(!isLocked) {
|
||||
// const limit = document.createElement('div');
|
||||
// limit.classList.add('limit-line');
|
||||
|
||||
// const free = document.createElement('div');
|
||||
// free.classList.add('limit-line-free');
|
||||
|
||||
// const premium = document.createElement('div');
|
||||
// premium.classList.add('limit-line-premium');
|
||||
|
||||
// limit.append(free, premium);
|
||||
|
||||
// _i18n(free, 'LimitFree');
|
||||
// premium.append(i18n('LimitPremium'), '' + options.limitPremium);
|
||||
|
||||
// limitContainer.append(limit);
|
||||
// }
|
||||
|
||||
// this.container.insertBefore(limitContainer, this.description);
|
||||
|
||||
// if(options.isPremium === false) {
|
||||
// this.buttons.pop().element.remove();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// async function showLimitPopup(type: keyof typeof a) {
|
||||
// const _a = a[type];
|
||||
// const [appConfig, limit, limitPremium] = await Promise.all([
|
||||
// rootScope.managers.apiManager.getAppConfig(),
|
||||
// ...[false, true].map((v) => rootScope.managers.apiManager.getLimit(type, v))
|
||||
// ]);
|
||||
// const isLocked = appConfig.premium_purchase_blocked;
|
||||
// new P({
|
||||
// isPremium: isLocked ? undefined : rootScope.premium,
|
||||
// limit,
|
||||
// limitPremium
|
||||
// }, _a).show();
|
||||
// }
|
||||
|
||||
// showLimitPopup('pin');
|
||||
|
||||
const config = await this.managers.apiManager.getConfig();
|
||||
new PopupPeer('pinned-dialogs-too-much', {
|
||||
buttons: [{
|
||||
|
|
|
@ -298,8 +298,7 @@ class EmoticonsTabC {
|
|||
export default class StickersTab extends EmoticonsTabC implements EmoticonsTab {
|
||||
private superStickerRenderer: SuperStickerRenderer;
|
||||
|
||||
private setFavedLimit(appConfig: MTAppConfig) {
|
||||
const limit = rootScope.premium ? appConfig.stickers_faved_limit_premium : appConfig.stickers_faved_limit_default;
|
||||
private setFavedLimit(limit: number) {
|
||||
const category = this.categories['faved'];
|
||||
category.limit = limit;
|
||||
}
|
||||
|
@ -494,10 +493,10 @@ export default class StickersTab extends EmoticonsTabC implements EmoticonsTab {
|
|||
|
||||
const promises = [
|
||||
Promise.all([
|
||||
this.managers.apiManager.getAppConfig(),
|
||||
this.managers.apiManager.getLimit('favedStickers'),
|
||||
this.managers.appStickersManager.getFavedStickersStickers()
|
||||
]).then(([appConfig, stickers]) => {
|
||||
this.setFavedLimit(appConfig);
|
||||
]).then(([limit, stickers]) => {
|
||||
this.setFavedLimit(limit);
|
||||
onCategoryStickers(favedCategory, stickers);
|
||||
}),
|
||||
|
||||
|
@ -604,7 +603,9 @@ export default class StickersTab extends EmoticonsTabC implements EmoticonsTab {
|
|||
});
|
||||
|
||||
rootScope.addEventListener('app_config', (appConfig) => {
|
||||
this.setFavedLimit(appConfig);
|
||||
this.managers.apiManager.getLimit('favedStickers').then((limit) => {
|
||||
this.setFavedLimit(limit);
|
||||
});
|
||||
});
|
||||
|
||||
const resizeCategories = () => {
|
||||
|
|
|
@ -209,6 +209,7 @@ export const RadioFormFromRows = (rows: Row[], onChange: (value: string) => void
|
|||
|
||||
export const RadioFormFromValues = (values: {langPackKey: LangPackKey, value: number | string, checked?: boolean}[], onChange: Parameters<typeof RadioFormFromRows>[1]) => {
|
||||
const name = 'name-' + (Math.random() * 0x7FFFFF | 0);
|
||||
let checkedRadioField: RadioField;
|
||||
const rows = values.map(({langPackKey, value, checked}) => {
|
||||
const row = new Row({
|
||||
radioField: new RadioField({
|
||||
|
@ -219,11 +220,15 @@ export const RadioFormFromValues = (values: {langPackKey: LangPackKey, value: nu
|
|||
});
|
||||
|
||||
if(checked) {
|
||||
row.radioField.checked = checked;
|
||||
checkedRadioField = row.radioField;
|
||||
}
|
||||
|
||||
return row;
|
||||
});
|
||||
|
||||
return RadioFormFromRows(rows, onChange);
|
||||
const form = RadioFormFromRows(rows, onChange);
|
||||
if(checkedRadioField) {
|
||||
checkedRadioField.checked = true;
|
||||
}
|
||||
return form;
|
||||
};
|
||||
|
|
|
@ -260,13 +260,13 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
|||
}
|
||||
|
||||
private async canCreateFolder() {
|
||||
const [appConfig, filters] = await Promise.all([
|
||||
this.managers.apiManager.getAppConfig(),
|
||||
const [limit, filters] = await Promise.all([
|
||||
this.managers.apiManager.getLimit('folders'),
|
||||
this.managers.filtersStorage.getDialogFilters()
|
||||
]);
|
||||
|
||||
const filtersLength = filters.filter((filter) => !REAL_FOLDERS.has(filter.id)).length;
|
||||
return filtersLength < (rootScope.premium ? appConfig.dialog_filters_limit_premium : appConfig.dialog_filters_limit_default);
|
||||
return filtersLength < limit;
|
||||
}
|
||||
|
||||
private getSuggestedFilters() {
|
||||
|
|
|
@ -37,7 +37,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
|||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
const appConfig = await this.managers.apiManager.getAppConfig();
|
||||
const bioMaxLength = await this.managers.apiManager.getLimit('bio');
|
||||
this.firstNameInputField = new InputField({
|
||||
label: 'EditProfile.FirstNameLabel',
|
||||
name: 'first-name',
|
||||
|
@ -51,7 +51,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
|||
this.bioInputField = new InputField({
|
||||
label: 'EditProfile.BioLabel',
|
||||
name: 'bio',
|
||||
maxLength: rootScope.premium ? appConfig.about_length_limit_premium : appConfig.about_length_limit_default
|
||||
maxLength: bioMaxLength
|
||||
});
|
||||
|
||||
inputWrapper.append(this.firstNameInputField.container, this.lastNameInputField.container, this.bioInputField.container);
|
||||
|
|
|
@ -19,7 +19,7 @@ const App = {
|
|||
version: process.env.VERSION,
|
||||
versionFull: process.env.VERSION_FULL,
|
||||
build: +process.env.BUILD,
|
||||
langPackVersion: '0.4.8',
|
||||
langPackVersion: '0.4.9',
|
||||
langPack: 'macos',
|
||||
langPackCode: 'en',
|
||||
domains: [MAIN_DOMAIN] as string[],
|
||||
|
|
|
@ -142,6 +142,7 @@ const lang = {
|
|||
'PaymentInfo.Done': 'PROCEED TO CHECKOUT',
|
||||
'PaymentCard.Error.Invalid': 'Invalid card number',
|
||||
'PaymentCard.Error.Incomplete': 'Incomplete card number',
|
||||
'LimitReached.Ok': 'OK, GOT IT',
|
||||
|
||||
// * android
|
||||
'AccDescrEditing': 'Editing',
|
||||
|
@ -783,6 +784,13 @@ const lang = {
|
|||
'AllReactions': 'All reactions',
|
||||
'SomeReactions': 'Some reactions',
|
||||
'NoReactions': 'No reactions',
|
||||
'LimitReached': 'Limit Reached',
|
||||
'LimitReachedPinDialogs': 'You can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned – or subscribe to **Telegram Premium** to double the limit to **%2$d** chats.',
|
||||
'LimitReachedPinDialogsPremium': 'Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned.',
|
||||
'LimitReachedPinDialogsLocked': 'Sorry, you can\'t pin more than %1$d chats to the top. Unpin some that are currently pinned. We are working to let you increase this limit in the future.',
|
||||
'IncreaseLimit': 'Increase Limit',
|
||||
'LimitFree': 'Free',
|
||||
'LimitPremium': 'Premium',
|
||||
|
||||
// * macos
|
||||
'AccountSettings.Filters': 'Chat Folders',
|
||||
|
|
|
@ -3085,10 +3085,7 @@ export class AppMessagesManager extends AppManager {
|
|||
const pinned = dialog.pFlags?.pinned ? undefined : true;
|
||||
|
||||
if(pinned) {
|
||||
const appConfig = await this.apiManager.getAppConfig();
|
||||
const max = filterId === 1 ?
|
||||
(this.rootScope.premium ? appConfig.dialogs_folder_pinned_limit_premium : appConfig.dialogs_folder_pinned_limit_default) :
|
||||
(this.rootScope.premium ? appConfig.dialogs_pinned_limit_premium : appConfig.dialogs_pinned_limit_default);
|
||||
const max = await this.apiManager.getLimit(filterId === 1 ? 'folderPin' : 'pin');
|
||||
if(this.dialogsStorage.getPinnedOrders(filterId).length >= max) {
|
||||
return Promise.reject(makeError('PINNED_DIALOGS_TOO_MUCH'));
|
||||
}
|
||||
|
@ -4329,8 +4326,11 @@ export class AppMessagesManager extends AppManager {
|
|||
message
|
||||
});
|
||||
|
||||
if(isTopMessage || (message as Message.message).grouped_id) {
|
||||
if(isTopMessage) {
|
||||
this.dialogsStorage.setDialogToState(dialog);
|
||||
}
|
||||
|
||||
if((isTopMessage || (message as Message.message).grouped_id) && dialog) {
|
||||
this.rootScope.dispatchEvent('dialogs_multiupdate', new Map([[peerId, dialog]]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,13 @@ import {ReferenceContext} from '../mtproto/referenceDatabase';
|
|||
|
||||
export type UserTyping = Partial<{userId: UserId, action: SendMessageAction, timeout: number}>;
|
||||
|
||||
const PEER_FULL_TTL = 3 * 60e3;
|
||||
|
||||
export class AppProfileManager extends AppManager {
|
||||
// private botInfos: any = {};
|
||||
private usersFull: {[id: UserId]: UserFull.userFull} = {};
|
||||
private chatsFull: {[id: ChatId]: ChatFull} = {};
|
||||
private fullExpiration: {[peerId: PeerId]: number} = {};
|
||||
private typingsInPeer: {[peerId: PeerId]: UserTyping[]};
|
||||
|
||||
protected after() {
|
||||
|
@ -161,7 +164,7 @@ export class AppProfileManager extends AppManager {
|
|||
} */
|
||||
|
||||
public getProfile(id: UserId, override?: true) {
|
||||
if(this.usersFull[id] && !override) {
|
||||
if(this.usersFull[id] && !override && Date.now() < this.fullExpiration[id.toPeerId()]) {
|
||||
return this.usersFull[id];
|
||||
}
|
||||
|
||||
|
@ -193,6 +196,7 @@ export class AppProfileManager extends AppManager {
|
|||
});
|
||||
|
||||
this.usersFull[id] = userFull;
|
||||
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
||||
|
||||
/* if(userFull.bot_info) {
|
||||
userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any;
|
||||
|
@ -263,9 +267,10 @@ export class AppProfileManager extends AppManager {
|
|||
return this.getChannelFull(id, override);
|
||||
}
|
||||
|
||||
const peerId = id.toPeerId(true);
|
||||
const fullChat = this.chatsFull[id] as ChatFull.chatFull;
|
||||
if(fullChat && !override) {
|
||||
const chat = this.appChatsManager.getChat(id);
|
||||
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) {
|
||||
return fullChat as ChatFull;
|
||||
|
@ -281,7 +286,6 @@ export class AppProfileManager extends AppManager {
|
|||
this.appChatsManager.saveApiChats(result.chats, true);
|
||||
this.appUsersManager.saveApiUsers(result.users);
|
||||
const chatFull = result.full_chat as ChatFull.chatFull;
|
||||
const peerId = id.toPeerId(true);
|
||||
if(chatFull && chatFull.chat_photo && chatFull.chat_photo.id) {
|
||||
chatFull.chat_photo = this.appPhotosManager.savePhoto(chatFull.chat_photo, {type: 'profilePhoto', peerId});
|
||||
}
|
||||
|
@ -297,6 +301,7 @@ export class AppProfileManager extends AppManager {
|
|||
});
|
||||
|
||||
this.chatsFull[id] = chatFull;
|
||||
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
||||
this.rootScope.dispatchEvent('chat_full_update', id);
|
||||
|
||||
return chatFull;
|
||||
|
@ -383,7 +388,8 @@ export class AppProfileManager extends AppManager {
|
|||
}
|
||||
|
||||
public getChannelFull(id: ChatId, override?: true) {
|
||||
if(this.chatsFull[id] !== undefined && !override) {
|
||||
const peerId = id.toPeerId(true);
|
||||
if(this.chatsFull[id] !== undefined && !override && Date.now() < this.fullExpiration[peerId]) {
|
||||
return this.chatsFull[id] as ChatFull.channelFull;
|
||||
}
|
||||
|
||||
|
@ -393,7 +399,6 @@ export class AppProfileManager extends AppManager {
|
|||
channel: this.appChatsManager.getChannelInput(id)
|
||||
},
|
||||
processResult: (result) => {
|
||||
const peerId = id.toPeerId(true);
|
||||
this.appChatsManager.saveApiChats(result.chats, true);
|
||||
this.appUsersManager.saveApiUsers(result.users);
|
||||
const fullChannel = result.full_chat as ChatFull.channelFull;
|
||||
|
@ -412,6 +417,7 @@ export class AppProfileManager extends AppManager {
|
|||
});
|
||||
|
||||
this.chatsFull[id] = fullChannel;
|
||||
this.fullExpiration[peerId] = Date.now() + PEER_FULL_TTL;
|
||||
this.rootScope.dispatchEvent('chat_full_update', id);
|
||||
|
||||
return fullChannel;
|
||||
|
@ -533,7 +539,7 @@ export class AppProfileManager extends AppManager {
|
|||
this.rootScope.dispatchEvent('peer_bio_edit', peerId);
|
||||
}
|
||||
|
||||
return this.getProfile(this.appPeersManager.peerId, true);
|
||||
return this.getProfile(user.id, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -231,8 +231,7 @@ export class AppReactionsManager extends AppManager {
|
|||
};
|
||||
}
|
||||
|
||||
const appConfig = await this.apiManager.getAppConfig();
|
||||
const limit = this.rootScope.premium ? appConfig.reactions_user_max_premium : appConfig.reactions_user_max_default;
|
||||
const limit = await this.apiManager.getLimit('reactions');
|
||||
|
||||
const lastSendingTimeKey = message.peerId + '_' + message.mid;
|
||||
const lastSendingTime = this.lastSendingTimes.get(lastSendingTimeKey);
|
||||
|
|
|
@ -521,9 +521,8 @@ export class AppStickersManager extends AppManager {
|
|||
return this.getFavedStickers().then(() => this.favedStickers);
|
||||
}
|
||||
|
||||
public async getFavedStickersLimit() {
|
||||
const appConfig = await this.apiManager.getAppConfig();
|
||||
return this.rootScope.premium ? appConfig.stickers_faved_limit_premium : appConfig.stickers_faved_limit_default;
|
||||
public getFavedStickersLimit() {
|
||||
return this.apiManager.getLimit('favedStickers');
|
||||
}
|
||||
|
||||
public async faveSticker(docId: DocId, unfave?: boolean) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import ctx from '../../environment/ctx';
|
||||
import callbackify from '../../helpers/callbackify';
|
||||
import {ignoreRestrictionReasons} from '../../helpers/restrictions';
|
||||
import {Config, MethodDeclMap, User} from '../../layer';
|
||||
import {InvokeApiOptions} from '../../types';
|
||||
|
@ -22,6 +23,8 @@ type HashOptions = {
|
|||
[queryJSON: string]: HashResult
|
||||
};
|
||||
|
||||
export type ApiLimitType = 'pin' | 'folderPin' | 'folders' | 'favedStickers' | 'reactions' | 'bio';
|
||||
|
||||
export default abstract class ApiManagerMethods extends AppManager {
|
||||
private afterMessageIdTemp: number;
|
||||
private hashes: {[method: string]: HashOptions} = {};
|
||||
|
@ -282,4 +285,22 @@ export default abstract class ApiManagerMethods extends AppManager {
|
|||
options: {overwrite}
|
||||
});
|
||||
}
|
||||
|
||||
public getLimit(type: ApiLimitType, isPremium?: boolean) {
|
||||
return callbackify(this.getAppConfig(), (appConfig) => {
|
||||
const map: {[type in ApiLimitType]: [keyof MTAppConfig, keyof MTAppConfig]} = {
|
||||
pin: ['dialogs_pinned_limit_default', 'dialogs_pinned_limit_premium'],
|
||||
folderPin: ['dialogs_folder_pinned_limit_default', 'dialogs_folder_pinned_limit_premium'],
|
||||
folders: ['dialog_filters_limit_default', 'dialog_filters_limit_premium'],
|
||||
favedStickers: ['stickers_faved_limit_default', 'stickers_faved_limit_premium'],
|
||||
reactions: ['reactions_user_max_default', 'reactions_user_max_premium'],
|
||||
bio: ['about_length_limit_default', 'about_length_limit_premium']
|
||||
};
|
||||
|
||||
isPremium ??= this.rootScope.premium;
|
||||
|
||||
const key = map[type][isPremium ? 1 : 0];
|
||||
return appConfig[key] as number;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ export interface MTAppConfig {
|
|||
message_animated_emoji_max?: number;
|
||||
premium_promo_order?: string[];
|
||||
premium_bot_username?: string;
|
||||
premium_purchase_blocked?: boolean;
|
||||
}
|
||||
|
||||
export interface EmojiesSendDiceSuccess {
|
||||
|
|
|
@ -34,10 +34,10 @@ export class RLottieItem {
|
|||
constructor(
|
||||
private reqId: number,
|
||||
private width: number,
|
||||
private height: number/* ,
|
||||
private height: number,
|
||||
private raw?: boolean/* ,
|
||||
private canvas: OffscreenCanvas */
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public init(json: string, fps: number) {
|
||||
|
@ -67,7 +67,7 @@ export class RLottieItem {
|
|||
|
||||
reply(['loaded', this.reqId, this.frameCount, this.fps]);
|
||||
|
||||
if(IS_IMAGE_BITMAP_SUPPORTED) {
|
||||
if(!this.raw && IS_IMAGE_BITMAP_SUPPORTED) {
|
||||
this.imageData = new ImageData(this.width, this.height);
|
||||
}
|
||||
} catch(e) {
|
||||
|
@ -105,7 +105,7 @@ export class RLottieItem {
|
|||
|
||||
// this.context.putImageData(new ImageData(clamped, this.width, this.height), 0, 0);
|
||||
|
||||
reply(['frame', this.reqId, frameNo, clamped], [clamped]);
|
||||
reply(['frame', this.reqId, frameNo, clamped], [clamped.buffer]);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Render error:', e);
|
||||
|
@ -158,8 +158,8 @@ _Module.onRuntimeInitialized = function() {
|
|||
|
||||
const items: {[reqId: string]: RLottieItem} = {};
|
||||
const queryableFunctions = {
|
||||
loadFromData: function(reqId: number, blob: Blob, width: number, height: number, toneIndex: number/* , canvas: OffscreenCanvas */) {
|
||||
const item = items[reqId] = new RLottieItem(reqId, width, height/* , canvas */);
|
||||
loadFromData: function(reqId: number, blob: Blob, width: number, height: number, toneIndex: number, raw: boolean/* , canvas: OffscreenCanvas */) {
|
||||
const item = items[reqId] = new RLottieItem(reqId, width, height, raw/* , canvas */);
|
||||
readBlobAsText(blob).then((json) => {
|
||||
try {
|
||||
if(typeof(toneIndex) === 'number' && toneIndex >= 1 && toneIndex <= 5) {
|
||||
|
|
|
@ -120,6 +120,8 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||
public overrideRender: (frame: ImageData | HTMLCanvasElement | ImageBitmap) => void;
|
||||
private renderedFirstFrame: boolean;
|
||||
|
||||
private raw: boolean;
|
||||
|
||||
constructor({el, worker, options}: {
|
||||
el: RLottiePlayer['el'],
|
||||
worker: QueryableWorker,
|
||||
|
@ -148,6 +150,7 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||
this.name = options.name;
|
||||
this.skipFirstFrameRendering = options.skipFirstFrameRendering;
|
||||
this.toneIndex = options.toneIndex;
|
||||
this.raw = this.color !== undefined;
|
||||
|
||||
if(this.name) {
|
||||
this.cacheName = RLottiePlayer.CACHE.generateName(this.name, this.width, this.height, this.color, this.toneIndex);
|
||||
|
@ -203,7 +206,7 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||
|
||||
this.contexts = this.canvas.map((canvas) => canvas.getContext('2d'));
|
||||
|
||||
if(!IS_IMAGE_BITMAP_SUPPORTED) {
|
||||
if(!IS_IMAGE_BITMAP_SUPPORTED || this.raw) {
|
||||
this.imageData = new ImageData(this.width, this.height);
|
||||
|
||||
if(CAN_USE_TRANSFERABLES) {
|
||||
|
@ -230,12 +233,12 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||
this.cache.clearCache();
|
||||
}
|
||||
|
||||
public sendQuery(args: any[]) {
|
||||
this.worker.sendQuery([args.shift(), this.reqId, ...args]);
|
||||
public sendQuery(args: any[], transfer?: Transferable[]) {
|
||||
this.worker.sendQuery([args.shift(), this.reqId, ...args], transfer);
|
||||
}
|
||||
|
||||
public loadFromData(data: RLottieOptions['animationData']) {
|
||||
this.sendQuery(['loadFromData', data, this.width, this.height, this.toneIndex/* , this.canvas.transferControlToOffscreen() */]);
|
||||
this.sendQuery(['loadFromData', data, this.width, this.height, this.toneIndex, this.color !== undefined/* , this.canvas.transferControlToOffscreen() */]);
|
||||
}
|
||||
|
||||
public play() {
|
||||
|
@ -442,7 +445,7 @@ export default class RLottiePlayer extends EventListenerBase<{
|
|||
this.clamped = new Uint8ClampedArray(this.width * this.height * 4);
|
||||
}
|
||||
|
||||
this.sendQuery(['renderFrame', frameNo, this.clamped]);
|
||||
this.sendQuery(['renderFrame', frameNo], this.clamped ? [this.clamped.buffer] : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -545,13 +545,8 @@ export default class FiltersStorage extends AppManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
const isPremium = this.rootScope.premium;
|
||||
let isFolderAvailable = isPremium;
|
||||
if(!isPremium) {
|
||||
const config = await this.apiManager.getAppConfig();
|
||||
const limit = config.dialog_filters_limit_default;
|
||||
isFolderAvailable = this.filtersArr.filter((filter) => !REAL_FOLDERS.has(filter.id)).slice(0, limit).some((filter) => filter.id === filterId);
|
||||
}
|
||||
const limit = await this.apiManager.getLimit('folders');
|
||||
const isFolderAvailable = this.filtersArr.filter((filter) => !REAL_FOLDERS.has(filter.id)).slice(0, limit).some((filter) => filter.id === filterId);
|
||||
|
||||
return isFolderAvailable;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
@use "sass:math";
|
||||
|
||||
$bubble-margin: .25rem;
|
||||
$bubble-margin: .125rem;
|
||||
$bubble-margin-big: .5rem;
|
||||
$bubble-overflow: math.div($bubble-margin-big, 8);
|
||||
$bubble-overflow-big: math.div($bubble-margin-big, 2);
|
||||
$bubble-beside-button-width: 38px;
|
||||
|
||||
@keyframes bubbleSelected {
|
||||
|
@ -36,7 +39,7 @@ $bubble-beside-button-width: 38px;
|
|||
e.g. make the height bigger and adjust the top so observeHeaders()'s
|
||||
IntersectionObserver fires as soon as the bottom of the sentinel crosses the
|
||||
top of the intersection container. */
|
||||
height: $bubble-margin;
|
||||
height: $bubble-overflow-big;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
|
@ -136,8 +139,8 @@ $bubble-beside-button-width: 38px;
|
|||
left: -50%;
|
||||
/* top: 0;
|
||||
bottom: 0; */
|
||||
top: -#{math.div($bubble-margin, 2)};
|
||||
bottom: -#{math.div($bubble-margin, 2)};
|
||||
top: -#{$bubble-overflow};
|
||||
bottom: -#{$bubble-overflow};
|
||||
content: " ";
|
||||
z-index: -1;
|
||||
}
|
||||
|
@ -145,13 +148,13 @@ $bubble-beside-button-width: 38px;
|
|||
|
||||
/* &.is-highlighted, &.is-selected {
|
||||
&:not(.is-group-last):after {
|
||||
height: calc(100% + #{math.div($bubble-margin, 2)}) !important;
|
||||
height: calc(100% + #{$bubble-overflow}) !important;
|
||||
}
|
||||
|
||||
& + &:not(.is-group-last) {
|
||||
&:after {
|
||||
top: .125rem !important;
|
||||
height: calc(100% - #{math.div($bubble-margin, 2)}) !important;
|
||||
height: calc(100% - #{$bubble-overflow}) !important;
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
@ -159,7 +162,7 @@ $bubble-beside-button-width: 38px;
|
|||
// ! if turn this on, there will be an empty space
|
||||
/* &.is-highlighted, &.is-selected {
|
||||
&.is-group-last:after {
|
||||
bottom: #{math.div($bubble-margin, 2)} !important;
|
||||
bottom: #{$bubble-overflow} !important;
|
||||
}
|
||||
} */
|
||||
|
||||
|
@ -180,7 +183,7 @@ $bubble-beside-button-width: 38px;
|
|||
&:before {
|
||||
content: "Unread messages";
|
||||
height: 30px;
|
||||
margin-bottom: $bubble-margin;
|
||||
margin-bottom: $bubble-overflow-big;
|
||||
margin-left: -50%;
|
||||
margin-right: -50%;
|
||||
text-align: center;
|
||||
|
@ -193,9 +196,10 @@ $bubble-beside-button-width: 38px;
|
|||
position: relative;
|
||||
}
|
||||
|
||||
&.is-highlighted, &.is-selected {
|
||||
&.is-highlighted,
|
||||
&.is-selected {
|
||||
&:after {
|
||||
top: calc(#{math.div($bubble-margin, 2)} + 30px);
|
||||
top: calc(#{$bubble-overflow} + 30px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,8 +395,8 @@ $bubble-beside-button-width: 38px;
|
|||
|
||||
&.is-date {
|
||||
position: sticky;
|
||||
top: $bubble-margin;
|
||||
padding-bottom: $bubble-margin;
|
||||
top: $bubble-overflow-big;
|
||||
padding-bottom: #{$bubble-overflow-big + $bubble-margin};
|
||||
//z-index: 3;
|
||||
z-index: 2;
|
||||
transition: opacity .3s ease;
|
||||
|
@ -500,10 +504,10 @@ $bubble-beside-button-width: 38px;
|
|||
} */
|
||||
|
||||
&.is-group-last {
|
||||
margin-bottom: #{$bubble-margin * 2};
|
||||
margin-bottom: #{$bubble-margin-big};
|
||||
|
||||
&:after {
|
||||
bottom: -#{$bubble-margin};
|
||||
bottom: -#{$bubble-overflow-big};
|
||||
}
|
||||
|
||||
/* > .bubble-select-checkbox {
|
||||
|
@ -519,7 +523,7 @@ $bubble-beside-button-width: 38px;
|
|||
|
||||
&.is-group-first {
|
||||
&:after {
|
||||
top: -#{$bubble-margin};
|
||||
top: -#{$bubble-overflow-big};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1618,7 +1622,7 @@ $bubble-beside-button-width: 38px;
|
|||
|
||||
&:first-of-type {
|
||||
.document-selection {
|
||||
top: -#{math.div($bubble-margin, 2)}; // * padding inner + half padding outer
|
||||
top: -#{$bubble-overflow}; // * padding inner + half padding outer
|
||||
}
|
||||
|
||||
.document-wrapper {
|
||||
|
@ -1630,7 +1634,7 @@ $bubble-beside-button-width: 38px;
|
|||
|
||||
&:last-of-type {
|
||||
.document-selection {
|
||||
bottom: -#{math.div($bubble-margin, 2)};
|
||||
bottom: -#{$bubble-overflow};
|
||||
}
|
||||
|
||||
.document-wrapper {
|
||||
|
@ -1644,7 +1648,7 @@ $bubble-beside-button-width: 38px;
|
|||
&.is-group-first .document-container {
|
||||
&:first-of-type {
|
||||
.document-selection {
|
||||
top: -$bubble-margin;
|
||||
top: -$bubble-overflow-big;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1652,7 +1656,7 @@ $bubble-beside-button-width: 38px;
|
|||
&.is-group-last .document-container {
|
||||
&:last-of-type {
|
||||
.document-selection {
|
||||
bottom: -$bubble-margin;
|
||||
bottom: -$bubble-overflow-big;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
.popup-limit {
|
||||
.popup-container {
|
||||
min-width: 22.5rem;
|
||||
}
|
||||
|
||||
&-line {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: .75rem 0;
|
||||
}
|
||||
|
||||
&-hint {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
&-icon {
|
||||
font-size: 1.25rem;
|
||||
margin-right: .25rem;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.limit-line {
|
||||
align-self: stretch;
|
||||
margin: 1rem .5rem 0;
|
||||
}
|
||||
|
||||
&:not(.is-locked) &-hint {
|
||||
height: 2rem;
|
||||
border-radius: 1rem;
|
||||
padding: 0 .75rem;
|
||||
position: relative;
|
||||
background: linear-gradient(73.4deg, #6C93FF -7.21%, #976FFF 114.57%, #DF69D1 241.52%);
|
||||
background-size: 200px 2rem;
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
content: " ";
|
||||
width: 100%; // 26
|
||||
height: 9px;
|
||||
position: absolute;
|
||||
bottom: -9px;
|
||||
clip-path: path("M0 0H26H24.4853C22.894 0 21.3679 0.632141 20.2426 1.75736L14.4142 7.58579C13.6332 8.36684 12.3668 8.36683 11.5858 7.58579L5.75736 1.75736C4.63214 0.632139 3.10602 0 1.51472 0H0Z");
|
||||
background: inherit;
|
||||
background-size: inherit;
|
||||
background-position-x: calc(-50% + -86px);
|
||||
background-repeat: no-repeat;
|
||||
left: 50%;
|
||||
margin-left: -13px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-locked &-hint {
|
||||
height: 2.75rem;
|
||||
border-radius: 1.375rem;
|
||||
padding: 0 1.25rem 0 1rem;
|
||||
margin-right: -.25rem;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
}
|
|
@ -390,6 +390,7 @@ $chat-input-inner-padding-handhelds: .25rem;
|
|||
@import "partials/popups/paymentShippingMethods";
|
||||
@import "partials/popups/paymentVerification";
|
||||
@import "partials/popups/paymentCardConfirmation";
|
||||
@import "partials/popups/limit";
|
||||
|
||||
@import "partials/pages/pages";
|
||||
@import "partials/pages/authCode";
|
||||
|
@ -1717,6 +1718,43 @@ hr {
|
|||
}
|
||||
}
|
||||
|
||||
.limit-line {
|
||||
height: 2rem;
|
||||
// border-radius: $border-radius-medium;
|
||||
font-weight: var(--font-weight-bold);
|
||||
display: flex;
|
||||
// background: linear-gradient(84.4deg, #6C93FF -4.85%, #976FFF 51.72%, #DF69D1 110.7%), #F1F3F5;
|
||||
|
||||
&-free {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&-premium {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&-free {
|
||||
border-top-left-radius: $border-radius-medium;
|
||||
border-bottom-left-radius: $border-radius-medium;
|
||||
background-color: #F1F3F5;
|
||||
}
|
||||
|
||||
&-premium {
|
||||
border-top-right-radius: $border-radius-medium;
|
||||
border-bottom-right-radius: $border-radius-medium;
|
||||
background: linear-gradient(84.4deg, #6C93FF -4.85%, #976FFF 51.72%, #DF69D1 110.7%);
|
||||
}
|
||||
|
||||
&-free,
|
||||
&-premium {
|
||||
flex: 1 1 0;
|
||||
padding: 0 .75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.movable-element {
|
||||
--size: .5rem;
|
||||
position: relative;
|
||||
|
|
Loading…
Reference in New Issue