Some fixes

This commit is contained in:
Eduard Kuzmenko 2022-09-25 21:49:33 +04:00
parent 274f611bdd
commit 6a3a923310
21 changed files with 338 additions and 78 deletions

View File

@ -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(

View File

@ -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');
}

View File

@ -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: [{

View File

@ -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 = () => {

View File

@ -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;
};

View File

@ -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() {

View File

@ -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);

View File

@ -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[],

View File

@ -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',

View File

@ -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]]));
}
}

View File

@ -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);
});
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;
});
}
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;