This commit is contained in:
parent
820885dbd9
commit
628fbfec26
|
@ -4,6 +4,7 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {LiteModeKey} from '../helpers/liteMode';
|
||||||
import {CustomEmojiElement, CustomEmojiRendererElement} from '../lib/richTextProcessor/wrapRichText';
|
import {CustomEmojiElement, CustomEmojiRendererElement} from '../lib/richTextProcessor/wrapRichText';
|
||||||
import rootScope from '../lib/rootScope';
|
import rootScope from '../lib/rootScope';
|
||||||
import {IS_SAFARI} from '../environment/userAgent';
|
import {IS_SAFARI} from '../environment/userAgent';
|
||||||
|
@ -25,6 +26,7 @@ export interface AnimationItem {
|
||||||
el: HTMLElement,
|
el: HTMLElement,
|
||||||
group: AnimationItemGroup,
|
group: AnimationItemGroup,
|
||||||
animation: AnimationItemWrapper,
|
animation: AnimationItemWrapper,
|
||||||
|
liteModeKey?: LiteModeKey,
|
||||||
controlled?: boolean | Middleware
|
controlled?: boolean | Middleware
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@ export interface AnimationItemWrapper {
|
||||||
pause: () => any;
|
pause: () => any;
|
||||||
play: () => any;
|
play: () => any;
|
||||||
autoplay: boolean;
|
autoplay: boolean;
|
||||||
|
loop: boolean | number;
|
||||||
// onVisibilityChange?: (visible: boolean) => boolean;
|
// onVisibilityChange?: (visible: boolean) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,12 +179,14 @@ export class AnimationIntersector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addAnimation(
|
public addAnimation(options: {
|
||||||
animation: AnimationItem['animation'],
|
animation: AnimationItem['animation'],
|
||||||
group: AnimationItemGroup = '',
|
group?: AnimationItemGroup,
|
||||||
observeElement?: HTMLElement,
|
observeElement?: HTMLElement,
|
||||||
controlled?: AnimationItem['controlled']
|
controlled?: AnimationItem['controlled'],
|
||||||
) {
|
liteModeKey?: LiteModeKey
|
||||||
|
}) {
|
||||||
|
let {animation, group = '', observeElement, controlled, liteModeKey} = options;
|
||||||
if(group === 'none' || this.byPlayer.has(animation)) {
|
if(group === 'none' || this.byPlayer.has(animation)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +207,8 @@ export class AnimationIntersector {
|
||||||
el: observeElement,
|
el: observeElement,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
group,
|
group,
|
||||||
controlled
|
controlled,
|
||||||
|
liteModeKey
|
||||||
};
|
};
|
||||||
|
|
||||||
if(controlled && typeof(controlled) !== 'boolean') {
|
if(controlled && typeof(controlled) !== 'boolean') {
|
||||||
|
|
|
@ -58,6 +58,7 @@ import clamp from '../helpers/number/clamp';
|
||||||
import debounce from '../helpers/schedulers/debounce';
|
import debounce from '../helpers/schedulers/debounce';
|
||||||
import isBetween from '../helpers/number/isBetween';
|
import isBetween from '../helpers/number/isBetween';
|
||||||
import findUpAsChild from '../helpers/dom/findUpAsChild';
|
import findUpAsChild from '../helpers/dom/findUpAsChild';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
const ZOOM_STEP = 0.5;
|
const ZOOM_STEP = 0.5;
|
||||||
const ZOOM_INITIAL_VALUE = 1;
|
const ZOOM_INITIAL_VALUE = 1;
|
||||||
|
@ -866,7 +867,7 @@ export default class AppMediaViewerBase<
|
||||||
|
|
||||||
const wasActive = fromRight !== 0;
|
const wasActive = fromRight !== 0;
|
||||||
|
|
||||||
const delay = rootScope.settings.animationsEnabled ? (wasActive ? 350 : 200) : 0;
|
const delay = liteMode.isAvailable('animations') ? (wasActive ? 350 : 200) : 0;
|
||||||
// let delay = wasActive ? 350 : 10000;
|
// let delay = wasActive ? 350 : 10000;
|
||||||
|
|
||||||
/* if(wasActive) {
|
/* if(wasActive) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import hasRights from '../lib/appManagers/utils/chats/hasRights';
|
||||||
import getDialogIndex from '../lib/appManagers/utils/dialogs/getDialogIndex';
|
import getDialogIndex from '../lib/appManagers/utils/dialogs/getDialogIndex';
|
||||||
import {generateDelimiter} from './generateDelimiter';
|
import {generateDelimiter} from './generateDelimiter';
|
||||||
import SettingSection from './settingSection';
|
import SettingSection from './settingSection';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants';
|
type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants';
|
||||||
|
|
||||||
|
@ -678,7 +679,7 @@ export default class AppSelectPeers {
|
||||||
this.onChange && this.onChange(this.selected.size);
|
this.onChange && this.onChange(this.selected.size);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
div.addEventListener('animationend', onAnimationEnd, {once: true});
|
div.addEventListener('animationend', onAnimationEnd, {once: true});
|
||||||
} else {
|
} else {
|
||||||
onAnimationEnd();
|
onAnimationEnd();
|
||||||
|
|
|
@ -12,6 +12,7 @@ import appNavigationController, {NavigationItem} from '../appNavigationControlle
|
||||||
import SetTransition from '../singleTransition';
|
import SetTransition from '../singleTransition';
|
||||||
import AutocompleteHelperController from './autocompleteHelperController';
|
import AutocompleteHelperController from './autocompleteHelperController';
|
||||||
import safeAssign from '../../helpers/object/safeAssign';
|
import safeAssign from '../../helpers/object/safeAssign';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
export default class AutocompleteHelper extends EventListenerBase<{
|
export default class AutocompleteHelper extends EventListenerBase<{
|
||||||
hidden: () => void,
|
hidden: () => void,
|
||||||
|
@ -158,7 +159,7 @@ export default class AutocompleteHelper extends EventListenerBase<{
|
||||||
element: this.container,
|
element: this.container,
|
||||||
className: 'is-visible',
|
className: 'is-visible',
|
||||||
forwards: !hide,
|
forwards: !hide,
|
||||||
duration: rootScope.settings.animationsEnabled && !skipAnimation ? 300 : 0,
|
duration: liteMode.isAvailable('animations') && !skipAnimation ? 300 : 0,
|
||||||
onTransitionEnd: () => {
|
onTransitionEnd: () => {
|
||||||
this.hidden && this.dispatchEvent('hidden');
|
this.hidden && this.dispatchEvent('hidden');
|
||||||
},
|
},
|
||||||
|
|
|
@ -132,6 +132,7 @@ import wrapPeerTitle from '../wrappers/peerTitle';
|
||||||
import {PopupPeerCheckboxOptions} from '../popups/peer';
|
import {PopupPeerCheckboxOptions} from '../popups/peer';
|
||||||
import toggleDisability from '../../helpers/dom/toggleDisability';
|
import toggleDisability from '../../helpers/dom/toggleDisability';
|
||||||
import {copyTextToClipboard} from '../../helpers/clipboard';
|
import {copyTextToClipboard} from '../../helpers/clipboard';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
export const USER_REACTIONS_INLINE = false;
|
export const USER_REACTIONS_INLINE = false;
|
||||||
const USE_MEDIA_TAILS = false;
|
const USE_MEDIA_TAILS = false;
|
||||||
|
@ -1043,7 +1044,7 @@ export default class ChatBubbles {
|
||||||
this.listenerSetter.add(rootScope)('history_append', async({storageKey, message}) => {
|
this.listenerSetter.add(rootScope)('history_append', async({storageKey, message}) => {
|
||||||
if(storageKey !== this.chat.messagesStorageKey || this.chat.type === 'scheduled') return;
|
if(storageKey !== this.chat.messagesStorageKey || this.chat.type === 'scheduled') return;
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('chat_background')) {
|
||||||
this.updateGradient = true;
|
this.updateGradient = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4458,6 +4459,7 @@ export default class ChatBubbles {
|
||||||
group: this.chat.animationGroup,
|
group: this.chat.animationGroup,
|
||||||
// play: !!message.pending || !multipleRender,
|
// play: !!message.pending || !multipleRender,
|
||||||
play: true,
|
play: true,
|
||||||
|
liteModeKey: 'stickers_chat',
|
||||||
loop: true,
|
loop: true,
|
||||||
emoji: isEmoji ? messageMessage : undefined,
|
emoji: isEmoji ? messageMessage : undefined,
|
||||||
withThumb: true,
|
withThumb: true,
|
||||||
|
@ -5529,7 +5531,8 @@ export default class ChatBubbles {
|
||||||
play: true,
|
play: true,
|
||||||
loop: true,
|
loop: true,
|
||||||
withThumb: true,
|
withThumb: true,
|
||||||
loadPromises
|
loadPromises,
|
||||||
|
liteModeKey: 'stickers_chat'
|
||||||
});
|
});
|
||||||
|
|
||||||
attachClickEvent(stickerDiv, (e) => {
|
attachClickEvent(stickerDiv, (e) => {
|
||||||
|
@ -6227,7 +6230,7 @@ export default class ChatBubbles {
|
||||||
|
|
||||||
const waitPromise = isAdditionRender ? processPromise(resultPromise) : promise;
|
const waitPromise = isAdditionRender ? processPromise(resultPromise) : promise;
|
||||||
|
|
||||||
if(isFirstMessageRender && rootScope.settings.animationsEnabled/* && false */) {
|
if(isFirstMessageRender && liteMode.isAvailable('animations')/* && false */) {
|
||||||
let times = isAdditionRender ? 2 : 1;
|
let times = isAdditionRender ? 2 : 1;
|
||||||
this.messagesQueueOnRenderAdditional = () => {
|
this.messagesQueueOnRenderAdditional = () => {
|
||||||
this.log('messagesQueueOnRenderAdditional');
|
this.log('messagesQueueOnRenderAdditional');
|
||||||
|
|
|
@ -37,6 +37,7 @@ import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
||||||
import {Message, WallPaper} from '../../layer';
|
import {Message, WallPaper} from '../../layer';
|
||||||
import animationIntersector, {AnimationItemGroup} from '../animationIntersector';
|
import animationIntersector, {AnimationItemGroup} from '../animationIntersector';
|
||||||
import {getColorsFromWallPaper} from '../../helpers/color';
|
import {getColorsFromWallPaper} from '../../helpers/color';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
export type ChatType = 'chat' | 'pinned' | 'discussion' | 'scheduled';
|
export type ChatType = 'chat' | 'pinned' | 'discussion' | 'scheduled';
|
||||||
|
|
||||||
|
@ -211,7 +212,7 @@ export default class Chat extends EventListenerBase<{
|
||||||
gradientCanvas = this.gradientCanvas = canvas;
|
gradientCanvas = this.gradientCanvas = canvas;
|
||||||
gradientCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-color-canvas');
|
gradientCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-color-canvas');
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
gradientRenderer.scrollAnimate(true);
|
gradientRenderer.scrollAnimate(true);
|
||||||
}
|
}
|
||||||
// } else {
|
// } else {
|
||||||
|
|
|
@ -307,7 +307,7 @@ export default class ChatBackgroundGradientRenderer {
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public update() {
|
private update() {
|
||||||
if(this._colors.length < 2) {
|
if(this._colors.length < 2) {
|
||||||
const color = this._colors[0];
|
const color = this._colors[0];
|
||||||
this._ctx.fillStyle = `rgb(${color.r}, ${color.g}, ${color.b})`;
|
this._ctx.fillStyle = `rgb(${color.r}, ${color.g}, ${color.b})`;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import RLottiePlayer from '../../lib/rlottie/rlottiePlayer';
|
||||||
import {fastRaf} from '../../helpers/schedulers';
|
import {fastRaf} from '../../helpers/schedulers';
|
||||||
import noop from '../../helpers/noop';
|
import noop from '../../helpers/noop';
|
||||||
import {Middleware} from '../../helpers/middleware';
|
import {Middleware} from '../../helpers/middleware';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
const CLASS_NAME = 'reaction';
|
const CLASS_NAME = 'reaction';
|
||||||
const TAG_NAME = CLASS_NAME + '-element';
|
const TAG_NAME = CLASS_NAME + '-element';
|
||||||
|
@ -186,6 +187,10 @@ export default class ReactionElement extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public fireAroundAnimation() {
|
public fireAroundAnimation() {
|
||||||
|
if(!liteMode.isAvailable('effects_reactions')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const reaction = this.reactionCount.reaction;
|
const reaction = this.reactionCount.reaction;
|
||||||
if(reaction._ !== 'reactionEmoji') return;
|
if(reaction._ !== 'reactionEmoji') return;
|
||||||
callbackify(this.managers.appReactionsManager.getReaction(reaction.emoticon), (availableReaction) => {
|
callbackify(this.managers.appReactionsManager.getReaction(reaction.emoticon), (availableReaction) => {
|
||||||
|
|
|
@ -145,7 +145,7 @@ export default class ReactionsElement extends HTMLElement {
|
||||||
const totalReactions = counts.reduce((acc, c) => acc + c.count, 0);
|
const totalReactions = counts.reduce((acc, c) => acc + c.count, 0);
|
||||||
const canRenderAvatars = reactions && (!!reactions.pFlags.can_see_list || this.message.peerId.isUser()) && totalReactions < REACTION_DISPLAY_BLOCK_COUNTER_AT;
|
const canRenderAvatars = reactions && (!!reactions.pFlags.can_see_list || this.message.peerId.isUser()) && totalReactions < REACTION_DISPLAY_BLOCK_COUNTER_AT;
|
||||||
this.sorted = counts.map((reactionCount, idx) => {
|
this.sorted = counts.map((reactionCount, idx) => {
|
||||||
let reactionElement = this.sorted.find((reactionElement) => reactionsEqual(reactionElement.reactionCount.reaction, reactionCount.reaction));
|
let reactionElement: ReactionElement = this.sorted.find((reactionElement) => reactionsEqual(reactionElement.reactionCount.reaction, reactionCount.reaction));
|
||||||
if(!reactionElement) {
|
if(!reactionElement) {
|
||||||
const middlewareHelper = this.middleware.create();
|
const middlewareHelper = this.middleware.create();
|
||||||
reactionElement = new ReactionElement();
|
reactionElement = new ReactionElement();
|
||||||
|
|
|
@ -11,6 +11,7 @@ import callbackify from '../../helpers/callbackify';
|
||||||
import {attachClickEvent} from '../../helpers/dom/clickEvent';
|
import {attachClickEvent} from '../../helpers/dom/clickEvent';
|
||||||
import findUpClassName from '../../helpers/dom/findUpClassName';
|
import findUpClassName from '../../helpers/dom/findUpClassName';
|
||||||
import getVisibleRect from '../../helpers/dom/getVisibleRect';
|
import getVisibleRect from '../../helpers/dom/getVisibleRect';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import {getMiddleware} from '../../helpers/middleware';
|
import {getMiddleware} from '../../helpers/middleware';
|
||||||
import noop from '../../helpers/noop';
|
import noop from '../../helpers/noop';
|
||||||
import {fastRaf} from '../../helpers/schedulers';
|
import {fastRaf} from '../../helpers/schedulers';
|
||||||
|
@ -136,7 +137,7 @@ export class ChatReactionsMenu {
|
||||||
};
|
};
|
||||||
|
|
||||||
private canUseAnimations() {
|
private canUseAnimations() {
|
||||||
return rootScope.settings.animationsEnabled && !IS_MOBILE;
|
return liteMode.isAvailable('animations') && liteMode.isAvailable('stickers_chat') && !IS_MOBILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderReaction(reaction: AvailableReaction) {
|
private renderReaction(reaction: AvailableReaction) {
|
||||||
|
@ -184,6 +185,7 @@ export class ChatReactionsMenu {
|
||||||
wrapSticker({
|
wrapSticker({
|
||||||
doc: reaction.static_icon,
|
doc: reaction.static_icon,
|
||||||
div: appearWrapper,
|
div: appearWrapper,
|
||||||
|
liteModeKey: false,
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -192,6 +194,7 @@ export class ChatReactionsMenu {
|
||||||
doc: reaction.appear_animation,
|
doc: reaction.appear_animation,
|
||||||
div: appearWrapper,
|
div: appearWrapper,
|
||||||
play: true,
|
play: true,
|
||||||
|
liteModeKey: false,
|
||||||
...options
|
...options
|
||||||
}).then(({render}) => render).then((player) => {
|
}).then(({render}) => render).then((player) => {
|
||||||
assumeType<RLottiePlayer>(player);
|
assumeType<RLottiePlayer>(player);
|
||||||
|
@ -217,6 +220,7 @@ export class ChatReactionsMenu {
|
||||||
const selectLoadPromise = wrapSticker({
|
const selectLoadPromise = wrapSticker({
|
||||||
doc: reaction.select_animation,
|
doc: reaction.select_animation,
|
||||||
div: selectWrapper,
|
div: selectWrapper,
|
||||||
|
liteModeKey: false,
|
||||||
...options
|
...options
|
||||||
}).then(({render}) => render).then((player) => {
|
}).then(({render}) => render).then((player) => {
|
||||||
assumeType<RLottiePlayer>(player);
|
assumeType<RLottiePlayer>(player);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
||||||
import callbackify from '../../helpers/callbackify';
|
import callbackify from '../../helpers/callbackify';
|
||||||
import ListenerSetter from '../../helpers/listenerSetter';
|
import ListenerSetter from '../../helpers/listenerSetter';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import {getMiddleware} from '../../helpers/middleware';
|
import {getMiddleware} from '../../helpers/middleware';
|
||||||
import {modifyAckedPromise} from '../../helpers/modifyAckedResult';
|
import {modifyAckedPromise} from '../../helpers/modifyAckedResult';
|
||||||
import {ChatFull} from '../../layer';
|
import {ChatFull} from '../../layer';
|
||||||
|
@ -148,7 +149,7 @@ export default class ChatSendAs {
|
||||||
this.updateButtons(peerIds);
|
this.updateButtons(peerIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
setTimeout(executeButtonsUpdate, 250);
|
setTimeout(executeButtonsUpdate, 250);
|
||||||
} else {
|
} else {
|
||||||
executeButtonsUpdate();
|
executeButtonsUpdate();
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cancelEvent from '../helpers/dom/cancelEvent';
|
||||||
|
import {attachClickEvent} from '../helpers/dom/clickEvent';
|
||||||
|
import findUpAsChild from '../helpers/dom/findUpAsChild';
|
||||||
|
import ListenerSetter from '../helpers/listenerSetter';
|
||||||
|
import safeAssign from '../helpers/object/safeAssign';
|
||||||
|
import I18n, {LangPackKey} from '../lib/langPack';
|
||||||
|
import CheckboxField from './checkboxField';
|
||||||
|
import Row from './row';
|
||||||
|
import {toast} from './toast';
|
||||||
|
|
||||||
|
export type CheckboxFieldsField = {
|
||||||
|
text: LangPackKey,
|
||||||
|
description?: LangPackKey,
|
||||||
|
restrictionText?: LangPackKey,
|
||||||
|
checkboxField?: CheckboxField,
|
||||||
|
checked?: boolean,
|
||||||
|
nested?: CheckboxFieldsField[],
|
||||||
|
nestedTo?: CheckboxFieldsField,
|
||||||
|
nestedCounter?: HTMLElement,
|
||||||
|
setNestedCounter?: (count: number) => void,
|
||||||
|
toggleWith?: {checked?: CheckboxFieldsField[], unchecked?: CheckboxFieldsField[]},
|
||||||
|
name?: string,
|
||||||
|
row?: Row
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CheckboxFields<K extends CheckboxFieldsField = CheckboxFieldsField> {
|
||||||
|
public fields: Array<K>;
|
||||||
|
protected listenerSetter: ListenerSetter;
|
||||||
|
protected asRestrictions: boolean;
|
||||||
|
|
||||||
|
constructor(options: {
|
||||||
|
fields: Array<K>,
|
||||||
|
listenerSetter: ListenerSetter,
|
||||||
|
asRestrictions?: boolean
|
||||||
|
}) {
|
||||||
|
safeAssign(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public createField(info: CheckboxFieldsField, isNested?: boolean) {
|
||||||
|
if(info.nestedTo && !isNested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = info.row = new Row({
|
||||||
|
titleLangKey: isNested ? undefined : info.text,
|
||||||
|
checkboxField: info.checkboxField = new CheckboxField({
|
||||||
|
text: isNested ? info.text : undefined,
|
||||||
|
checked: info.nested ? false : info.checked,
|
||||||
|
toggle: !isNested,
|
||||||
|
listenerSetter: this.listenerSetter,
|
||||||
|
restriction: this.asRestrictions && !isNested,
|
||||||
|
name: info.name
|
||||||
|
}),
|
||||||
|
listenerSetter: this.listenerSetter,
|
||||||
|
subtitleLangKey: info.description,
|
||||||
|
clickable: info.nested ? (e) => {
|
||||||
|
if(findUpAsChild(e.target as HTMLElement, row.checkboxField.label)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelEvent(e);
|
||||||
|
row.container.classList.toggle('accordion-toggler-expanded');
|
||||||
|
accordion.classList.toggle('is-expanded');
|
||||||
|
} : undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
if(info.restrictionText) {
|
||||||
|
info.checkboxField.input.disabled = true;
|
||||||
|
|
||||||
|
attachClickEvent(info.checkboxField.label, (e) => {
|
||||||
|
toast(I18n.format(info.restrictionText, true));
|
||||||
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodes: HTMLElement[] = [row.container];
|
||||||
|
let accordion: HTMLElement, nestedCounter: HTMLElement;
|
||||||
|
if(info.nested) {
|
||||||
|
const container = accordion = document.createElement('div');
|
||||||
|
container.classList.add('accordion');
|
||||||
|
container.style.setProperty('--max-height', info.nested.length * 48 + 'px');
|
||||||
|
const _info = info;
|
||||||
|
info.nested.forEach((info) => {
|
||||||
|
info.nestedTo ??= _info;
|
||||||
|
container.append(...this.createField(info, true).nodes);
|
||||||
|
});
|
||||||
|
nodes.push(container);
|
||||||
|
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.classList.add('tgico-down', 'accordion-icon');
|
||||||
|
|
||||||
|
nestedCounter = info.nestedCounter = document.createElement('b');
|
||||||
|
this.setNestedCounter(info);
|
||||||
|
row.title.append(' ', nestedCounter, ' ', span);
|
||||||
|
|
||||||
|
row.container.classList.add('accordion-toggler');
|
||||||
|
row.titleRow.classList.add('with-delimiter');
|
||||||
|
|
||||||
|
row.checkboxField.setValueSilently(this.getNestedCheckedLength(info) === info.nested.length);
|
||||||
|
|
||||||
|
info.toggleWith ??= {checked: info.nested, unchecked: info.nested};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info.toggleWith || info.nestedTo) {
|
||||||
|
const processToggleWith = info.toggleWith ? (info: CheckboxFieldsField) => {
|
||||||
|
const {toggleWith, nested} = info;
|
||||||
|
const value = info.checkboxField.checked;
|
||||||
|
const arr = value ? toggleWith.checked : toggleWith.unchecked;
|
||||||
|
if(!arr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const other = this.fields.filter((i) => arr.includes(i));
|
||||||
|
other.forEach((info) => {
|
||||||
|
info.checkboxField.setValueSilently(value);
|
||||||
|
if(info.nestedTo && !nested) {
|
||||||
|
this.setNestedCounter(info.nestedTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info.toggleWith) {
|
||||||
|
processToggleWith(info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(info.nested) {
|
||||||
|
this.setNestedCounter(info);
|
||||||
|
}
|
||||||
|
} : undefined;
|
||||||
|
|
||||||
|
const processNestedTo = info.nestedTo ? () => {
|
||||||
|
const length = this.getNestedCheckedLength(info.nestedTo);
|
||||||
|
info.nestedTo.checkboxField.setValueSilently(length === info.nestedTo.nested.length);
|
||||||
|
this.setNestedCounter(info.nestedTo, length);
|
||||||
|
} : undefined;
|
||||||
|
|
||||||
|
this.listenerSetter.add(info.checkboxField.input)('change', () => {
|
||||||
|
processToggleWith?.(info);
|
||||||
|
processNestedTo?.();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {row, nodes};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getNestedCheckedLength(info: CheckboxFieldsField) {
|
||||||
|
return info.nested.reduce((acc, v) => acc + +v.checkboxField.checked, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setNestedCounter(info: CheckboxFieldsField, count = this.getNestedCheckedLength(info)) {
|
||||||
|
info.nestedCounter.textContent = `${count}/${info.nested.length}`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import {IS_MOBILE} from '../environment/userAgent';
|
import {IS_MOBILE} from '../environment/userAgent';
|
||||||
import {animate} from '../helpers/animation';
|
import {animate} from '../helpers/animation';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
import {Middleware} from '../helpers/middleware';
|
import {Middleware} from '../helpers/middleware';
|
||||||
import clamp from '../helpers/number/clamp';
|
import clamp from '../helpers/number/clamp';
|
||||||
import animationIntersector, {AnimationItemGroup, AnimationItemWrapper} from './animationIntersector';
|
import animationIntersector, {AnimationItemGroup, AnimationItemWrapper} from './animationIntersector';
|
||||||
|
@ -31,6 +32,8 @@ export default class DotRenderer implements AnimationItemWrapper {
|
||||||
|
|
||||||
private dpr: number;
|
private dpr: number;
|
||||||
|
|
||||||
|
public loop: boolean = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private width: number,
|
private width: number,
|
||||||
private height: number,
|
private height: number,
|
||||||
|
@ -51,7 +54,7 @@ export default class DotRenderer implements AnimationItemWrapper {
|
||||||
private prepare() {
|
private prepare() {
|
||||||
let count = Math.round(this.width * this.height / (35 * (IS_MOBILE ? 2 : 1)));
|
let count = Math.round(this.width * this.height / (35 * (IS_MOBILE ? 2 : 1)));
|
||||||
count *= this.multiply || 1;
|
count *= this.multiply || 1;
|
||||||
count = Math.min(IS_MOBILE ? 1000 : 2200, count);
|
count = Math.min(!liteMode.isAvailable('chat_spoilers') ? 400 : IS_MOBILE ? 1000 : 2200, count);
|
||||||
count = Math.round(count);
|
count = Math.round(count);
|
||||||
const dots: DotRendererDot[] = this.dots = new Array(count);
|
const dots: DotRendererDot[] = this.dots = new Array(count);
|
||||||
|
|
||||||
|
@ -168,7 +171,12 @@ export default class DotRenderer implements AnimationItemWrapper {
|
||||||
const dotRenderer = new DotRenderer(width, height, multiply);
|
const dotRenderer = new DotRenderer(width, height, multiply);
|
||||||
dotRenderer.renderFirstFrame();
|
dotRenderer.renderFirstFrame();
|
||||||
|
|
||||||
animationIntersector.addAnimation(dotRenderer, animationGroup, dotRenderer.canvas, middleware);
|
animationIntersector.addAnimation({
|
||||||
|
animation: dotRenderer,
|
||||||
|
group: animationGroup,
|
||||||
|
observeElement: dotRenderer.canvas,
|
||||||
|
controlled: middleware
|
||||||
|
});
|
||||||
|
|
||||||
return dotRenderer;
|
return dotRenderer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import PopupStickers from '../../popups/stickers';
|
||||||
import {hideToast, toastNew} from '../../toast';
|
import {hideToast, toastNew} from '../../toast';
|
||||||
import safeAssign from '../../../helpers/object/safeAssign';
|
import safeAssign from '../../../helpers/object/safeAssign';
|
||||||
import type {AppStickersManager} from '../../../lib/appManagers/appStickersManager';
|
import type {AppStickersManager} from '../../../lib/appManagers/appStickersManager';
|
||||||
|
import liteMode from '../../../helpers/liteMode';
|
||||||
|
|
||||||
const loadedURLs: Set<string> = new Set();
|
const loadedURLs: Set<string> = new Set();
|
||||||
export function appendEmoji(emoji: string, container?: HTMLElement, prepend = false, unify = false) {
|
export function appendEmoji(emoji: string, container?: HTMLElement, prepend = false, unify = false) {
|
||||||
|
@ -81,14 +82,14 @@ export function appendEmoji(emoji: string, container?: HTMLElement, prepend = fa
|
||||||
const placeholder = document.createElement('span');
|
const placeholder = document.createElement('span');
|
||||||
placeholder.classList.add('emoji-placeholder');
|
placeholder.classList.add('emoji-placeholder');
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
image.style.opacity = '0';
|
image.style.opacity = '0';
|
||||||
placeholder.style.opacity = '1';
|
placeholder.style.opacity = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
image.addEventListener('load', () => {
|
image.addEventListener('load', () => {
|
||||||
fastRaf(() => {
|
fastRaf(() => {
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
image.style.opacity = '';
|
image.style.opacity = '';
|
||||||
placeholder.style.opacity = '';
|
placeholder.style.opacity = '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import findUpAsChild from '../helpers/dom/findUpAsChild';
|
||||||
import whichChild from '../helpers/dom/whichChild';
|
import whichChild from '../helpers/dom/whichChild';
|
||||||
import ListenerSetter from '../helpers/listenerSetter';
|
import ListenerSetter from '../helpers/listenerSetter';
|
||||||
import {attachClickEvent} from '../helpers/dom/clickEvent';
|
import {attachClickEvent} from '../helpers/dom/clickEvent';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
export function horizontalMenu(
|
export function horizontalMenu(
|
||||||
tabs: HTMLElement,
|
tabs: HTMLElement,
|
||||||
|
@ -66,7 +67,7 @@ export function horizontalMenu(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
animate = false;
|
animate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import setInnerHTML from '../helpers/dom/setInnerHTML';
|
||||||
import {AppManagers} from '../lib/appManagers/managers';
|
import {AppManagers} from '../lib/appManagers/managers';
|
||||||
import wrapEmojiText from '../lib/richTextProcessor/wrapEmojiText';
|
import wrapEmojiText from '../lib/richTextProcessor/wrapEmojiText';
|
||||||
import wrapRichText from '../lib/richTextProcessor/wrapRichText';
|
import wrapRichText from '../lib/richTextProcessor/wrapRichText';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
let lineTotalLength = 0;
|
let lineTotalLength = 0;
|
||||||
const tailLength = 9;
|
const tailLength = 9;
|
||||||
|
@ -528,7 +529,7 @@ export default class PollElement extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
performResults(results: PollResults, chosenIndexes: number[], animate = true) {
|
performResults(results: PollResults, chosenIndexes: number[], animate = true) {
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
animate = false;
|
animate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import {doubleRaf} from '../../helpers/schedulers';
|
import {doubleRaf} from '../../helpers/schedulers';
|
||||||
import appImManager from '../../lib/appManagers/appImManager';
|
import appImManager from '../../lib/appManagers/appImManager';
|
||||||
import {LangPackKey, _i18n, i18n} from '../../lib/langPack';
|
import {LangPackKey, _i18n, i18n} from '../../lib/langPack';
|
||||||
|
@ -114,7 +115,7 @@ class P extends PopupPeer {
|
||||||
hint.classList.add('active');
|
hint.classList.add('active');
|
||||||
};
|
};
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
doubleRaf().then(setHintActive);
|
doubleRaf().then(setHintActive);
|
||||||
} else {
|
} else {
|
||||||
setHintActive();
|
setHintActive();
|
||||||
|
|
|
@ -47,6 +47,7 @@ import VIDEO_MIME_TYPES_SUPPORTED from '../../environment/videoMimeTypesSupport'
|
||||||
import rootScope from '../../lib/rootScope';
|
import rootScope from '../../lib/rootScope';
|
||||||
import shake from '../../helpers/dom/shake';
|
import shake from '../../helpers/dom/shake';
|
||||||
import AUDIO_MIME_TYPES_SUPPORTED from '../../environment/audioMimeTypeSupport';
|
import AUDIO_MIME_TYPES_SUPPORTED from '../../environment/audioMimeTypeSupport';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
type SendFileParams = SendFileDetails & {
|
type SendFileParams = SendFileDetails & {
|
||||||
file?: File,
|
file?: File,
|
||||||
|
@ -559,7 +560,7 @@ export default class PopupNewMedia extends PopupElement {
|
||||||
langPackKey: key
|
langPackKey: key
|
||||||
});
|
});
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
shake(this.body);
|
shake(this.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import getPeerInitials from './wrappers/getPeerInitials';
|
||||||
import {wrapTopicIcon} from './wrappers/messageActionTextNewUnsafe';
|
import {wrapTopicIcon} from './wrappers/messageActionTextNewUnsafe';
|
||||||
import makeError from '../helpers/makeError';
|
import makeError from '../helpers/makeError';
|
||||||
import noop from '../helpers/noop';
|
import noop from '../helpers/noop';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
export async function putAvatar(
|
export async function putAvatar(
|
||||||
div: HTMLElement,
|
div: HTMLElement,
|
||||||
|
@ -46,7 +47,7 @@ export async function putAvatar(
|
||||||
div.dataset.color = '';
|
div.dataset.color = '';
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const animate = rootScope.settings.animationsEnabled;
|
const animate = liteMode.isAvailable('animations');
|
||||||
if(animate) {
|
if(animate) {
|
||||||
img.classList.add('fade-in');
|
img.classList.add('fade-in');
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import IS_TOUCH_SUPPORTED from '../environment/touchSupport';
|
||||||
import rootScope from '../lib/rootScope';
|
import rootScope from '../lib/rootScope';
|
||||||
import findUpAsChild from '../helpers/dom/findUpAsChild';
|
import findUpAsChild from '../helpers/dom/findUpAsChild';
|
||||||
import {fastRaf} from '../helpers/schedulers';
|
import {fastRaf} from '../helpers/schedulers';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
let rippleClickId = 0;
|
let rippleClickId = 0;
|
||||||
export default function ripple(
|
export default function ripple(
|
||||||
|
@ -167,7 +168,7 @@ export default function ripple(
|
||||||
};
|
};
|
||||||
|
|
||||||
attachListenerTo.addEventListener('touchstart', (e) => {
|
attachListenerTo.addEventListener('touchstart', (e) => {
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ export default function ripple(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// console.log('ripple mousedown', e, e.target, findUpClassName(e.target as HTMLElement, 'c-ripple') === r);
|
// console.log('ripple mousedown', e, e.target, findUpClassName(e.target as HTMLElement, 'c-ripple') === r);
|
||||||
|
|
|
@ -285,10 +285,15 @@ export default class Row {
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public toggleDisability(disable = !this.container.classList.contains('is-disabled')) {
|
||||||
|
this.container.classList.toggle('is-disabled', disable);
|
||||||
|
return () => this.toggleDisability(!disable);
|
||||||
|
}
|
||||||
|
|
||||||
public disableWithPromise(promise: Promise<any>) {
|
public disableWithPromise(promise: Promise<any>) {
|
||||||
this.container.classList.add('is-disabled');
|
const toggle = this.toggleDisability(true);
|
||||||
promise.finally(() => {
|
promise.finally(() => {
|
||||||
this.container.classList.remove('is-disabled');
|
toggle();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,30 +154,6 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
||||||
|
|
||||||
this.scrollable.append(section.container);
|
this.scrollable.append(section.container);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
const section = new SettingSection({name: 'AutoplayMedia'});
|
|
||||||
|
|
||||||
section.content.append(new Row({
|
|
||||||
checkboxField: new CheckboxField({
|
|
||||||
text: 'AutoplayGIF',
|
|
||||||
name: 'gifs',
|
|
||||||
stateKey: 'settings.autoPlay.gifs',
|
|
||||||
listenerSetter: this.listenerSetter
|
|
||||||
}),
|
|
||||||
listenerSetter: this.listenerSetter
|
|
||||||
}).container, new Row({
|
|
||||||
checkboxField: new CheckboxField({
|
|
||||||
text: 'AutoplayVideo',
|
|
||||||
name: 'videos',
|
|
||||||
stateKey: 'settings.autoPlay.videos',
|
|
||||||
listenerSetter: this.listenerSetter
|
|
||||||
}),
|
|
||||||
listenerSetter: this.listenerSetter
|
|
||||||
}).container);
|
|
||||||
|
|
||||||
this.scrollable.append(section.container);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setAutoDownloadSubtitle(row: Row, settings: AutoDownloadPeerTypeSettings, sizeMax?: number) {
|
private setAutoDownloadSubtitle(row: Row, settings: AutoDownloadPeerTypeSettings, sizeMax?: number) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import rootScope from '../../../lib/rootScope';
|
||||||
import {IS_APPLE, IS_SAFARI} from '../../../environment/userAgent';
|
import {IS_APPLE, IS_SAFARI} from '../../../environment/userAgent';
|
||||||
import Row, {CreateRowFromCheckboxField} from '../../row';
|
import Row, {CreateRowFromCheckboxField} from '../../row';
|
||||||
import AppBackgroundTab from './background';
|
import AppBackgroundTab from './background';
|
||||||
import {LangPackKey, _i18n} from '../../../lib/langPack';
|
import I18n, {i18n, LangPackKey, _i18n} from '../../../lib/langPack';
|
||||||
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
||||||
import assumeType from '../../../helpers/assumeType';
|
import assumeType from '../../../helpers/assumeType';
|
||||||
import {BaseTheme, MessagesAllStickers, StickerSet} from '../../../layer';
|
import {BaseTheme, MessagesAllStickers, StickerSet} from '../../../layer';
|
||||||
|
@ -33,6 +33,8 @@ import {Theme} from '../../../layer';
|
||||||
import findUpClassName from '../../../helpers/dom/findUpClassName';
|
import findUpClassName from '../../../helpers/dom/findUpClassName';
|
||||||
import RLottiePlayer from '../../../lib/rlottie/rlottiePlayer';
|
import RLottiePlayer from '../../../lib/rlottie/rlottiePlayer';
|
||||||
import themeController from '../../../helpers/themeController';
|
import themeController from '../../../helpers/themeController';
|
||||||
|
import liteMode from '../../../helpers/liteMode';
|
||||||
|
import AppPowerSavingTab from './powerSaving';
|
||||||
|
|
||||||
export class RangeSettingSelector {
|
export class RangeSettingSelector {
|
||||||
public container: HTMLDivElement;
|
public container: HTMLDivElement;
|
||||||
|
@ -123,17 +125,30 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||||
this.slider.createTab(AppBackgroundTab).open(initArgs);
|
this.slider.createTab(AppBackgroundTab).open(initArgs);
|
||||||
});
|
});
|
||||||
|
|
||||||
const animationsCheckboxField = new CheckboxField({
|
const getLiteModeStatus = (): LangPackKey => rootScope.settings.liteMode.all ? 'Checkbox.Enabled' : 'Checkbox.Disabled';
|
||||||
text: 'EnableAnimations',
|
const i = new I18n.IntlElement();
|
||||||
name: 'animations',
|
|
||||||
stateKey: 'settings.animationsEnabled',
|
const onUpdate = () => {
|
||||||
|
i.compareAndUpdate({key: getLiteModeStatus()});
|
||||||
|
};
|
||||||
|
onUpdate();
|
||||||
|
|
||||||
|
const liteModeRow = new Row({
|
||||||
|
icon: 'animations',
|
||||||
|
titleLangKey: 'LiteMode.EnableText',
|
||||||
|
titleRightSecondary: i.element,
|
||||||
|
clickable: () => {
|
||||||
|
this.slider.createTab(AppPowerSavingTab).open();
|
||||||
|
},
|
||||||
listenerSetter: this.listenerSetter
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.listenerSetter.add(rootScope)('settings_updated', onUpdate);
|
||||||
|
|
||||||
container.append(
|
container.append(
|
||||||
range.container,
|
range.container,
|
||||||
chatBackgroundButton,
|
chatBackgroundButton,
|
||||||
CreateRowFromCheckboxField(animationsCheckboxField).container
|
liteModeRow.container
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +201,7 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
||||||
|
|
||||||
lastOnFrameNo?.(-1);
|
lastOnFrameNo?.(-1);
|
||||||
|
|
||||||
if(item.player && rootScope.settings.animationsEnabled) {
|
if(item.player && liteMode.isAvailable('animations')) {
|
||||||
if(IS_SAFARI) {
|
if(IS_SAFARI) {
|
||||||
if(item.player.paused) {
|
if(item.player.paused) {
|
||||||
item.player.restart();
|
item.player.restart();
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {State} from '../../../config/state';
|
||||||
|
import flatten from '../../../helpers/array/flatten';
|
||||||
|
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
||||||
|
import {LiteModeKey} from '../../../helpers/liteMode';
|
||||||
|
import pause from '../../../helpers/schedulers/pause';
|
||||||
|
import rootScope from '../../../lib/rootScope';
|
||||||
|
import CheckboxFields, {CheckboxFieldsField} from '../../checkboxFields';
|
||||||
|
import SettingSection from '../../settingSection';
|
||||||
|
import SliderSuperTab from '../../sliderTab';
|
||||||
|
import {toastNew} from '../../toast';
|
||||||
|
|
||||||
|
type PowerSavingCheckboxFieldsField = CheckboxFieldsField & {
|
||||||
|
key: LiteModeKey
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class AppPowerSavingTab extends SliderSuperTab {
|
||||||
|
public init() {
|
||||||
|
this.container.classList.add('power-saving-container');
|
||||||
|
this.setTitle('LiteMode.Title');
|
||||||
|
|
||||||
|
const form = document.createElement('form');
|
||||||
|
|
||||||
|
let infoSection: SettingSection;
|
||||||
|
{
|
||||||
|
const section = infoSection = new SettingSection({
|
||||||
|
caption: 'LiteMode.Info'
|
||||||
|
});
|
||||||
|
|
||||||
|
form.append(section.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys: Array<LiteModeKey | [LiteModeKey, LiteModeKey[]]> = [
|
||||||
|
'all',
|
||||||
|
'video',
|
||||||
|
'gif',
|
||||||
|
['stickers', ['stickers_panel', 'stickers_chat']],
|
||||||
|
['emoji', ['emoji_panel', 'emoji_messages']],
|
||||||
|
['effects', ['effects_reactions', 'effects_premiumstickers', 'effects_emoji']],
|
||||||
|
['chat', ['chat_background', 'chat_spoilers']],
|
||||||
|
'animations'
|
||||||
|
];
|
||||||
|
|
||||||
|
let fields: PowerSavingCheckboxFieldsField[], checkboxFields: CheckboxFields<PowerSavingCheckboxFieldsField>;
|
||||||
|
{
|
||||||
|
const section = new SettingSection({});
|
||||||
|
|
||||||
|
const wrap = (key: typeof keys[0]): PowerSavingCheckboxFieldsField[] => {
|
||||||
|
const isArray = Array.isArray(key);
|
||||||
|
const mainKey = isArray ? key[0] : key;
|
||||||
|
const nested = isArray ? flatten(key[1].map(wrap)) : undefined;
|
||||||
|
const value = rootScope.settings.liteMode[mainKey];
|
||||||
|
return [{
|
||||||
|
key: mainKey,
|
||||||
|
text: mainKey === 'all' ? 'LiteMode.EnableText' : `LiteMode.Key.${mainKey}.Title`,
|
||||||
|
checked: mainKey === 'all' ? value : !value,
|
||||||
|
nested: nested,
|
||||||
|
name: 'power-saving-' + mainKey
|
||||||
|
}, ...(nested || [])];
|
||||||
|
};
|
||||||
|
|
||||||
|
fields = flatten(keys.map(wrap));
|
||||||
|
|
||||||
|
checkboxFields = new CheckboxFields({
|
||||||
|
fields: fields,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
|
});
|
||||||
|
|
||||||
|
fields.forEach((field, idx) => {
|
||||||
|
const created = checkboxFields.createField(field);
|
||||||
|
if(!created) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {row, nodes} = created;
|
||||||
|
(idx === 0 ? infoSection : section).content.append(...nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
attachClickEvent(section.content, () => {
|
||||||
|
if(rootScope.settings.liteMode.all) {
|
||||||
|
toastNew({langPackKey: 'LiteMode.DisableAlert'});
|
||||||
|
}
|
||||||
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
|
form.append(section.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAllChange = (disable: boolean) => {
|
||||||
|
fields.forEach((field) => {
|
||||||
|
if(field.key === 'all') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(field.nested) {
|
||||||
|
checkboxFields.setNestedCounter(field, disable ? 0 : undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
field.checkboxField.input.classList.toggle('is-fake-disabled', disable);
|
||||||
|
field.row.toggleDisability(disable);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.listenerSetter.add(form)('change', async() => {
|
||||||
|
const liteMode: State['settings']['liteMode'] = {} as any;
|
||||||
|
fields.forEach((field) => {
|
||||||
|
const checked = field.checkboxField.checked;
|
||||||
|
liteMode[field.key] = field.key === 'all' ? checked : !checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
const wasAll = rootScope.settings.liteMode.all;
|
||||||
|
if(wasAll !== liteMode.all) {
|
||||||
|
onAllChange(!wasAll);
|
||||||
|
|
||||||
|
if(liteMode.all) {
|
||||||
|
await pause(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.managers.appStateManager.setByKey('settings.liteMode', rootScope.settings.liteMode = liteMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
onAllChange(rootScope.settings.liteMode.all);
|
||||||
|
|
||||||
|
this.scrollable.append(form);
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,6 @@ import {AccountAuthorizations, Authorization} from '../../../layer';
|
||||||
import PopupElement from '../../popups';
|
import PopupElement from '../../popups';
|
||||||
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
||||||
import SettingSection from '../../settingSection';
|
import SettingSection from '../../settingSection';
|
||||||
// import AppMediaViewer from "../../appMediaViewerNew";
|
|
||||||
|
|
||||||
export default class AppSettingsTab extends SliderSuperTab {
|
export default class AppSettingsTab extends SliderSuperTab {
|
||||||
private buttons: {
|
private buttons: {
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {ChatRights} from '../../../lib/appManagers/appChatsManager';
|
import type {ChatRights} from '../../../lib/appManagers/appChatsManager';
|
||||||
import flatten from '../../../helpers/array/flatten';
|
|
||||||
import cancelEvent from '../../../helpers/dom/cancelEvent';
|
|
||||||
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
||||||
import findUpTag from '../../../helpers/dom/findUpTag';
|
import findUpTag from '../../../helpers/dom/findUpTag';
|
||||||
import replaceContent from '../../../helpers/dom/replaceContent';
|
import replaceContent from '../../../helpers/dom/replaceContent';
|
||||||
|
@ -19,32 +17,22 @@ import combineParticipantBannedRights from '../../../lib/appManagers/utils/chats
|
||||||
import hasRights from '../../../lib/appManagers/utils/chats/hasRights';
|
import hasRights from '../../../lib/appManagers/utils/chats/hasRights';
|
||||||
import getPeerActiveUsernames from '../../../lib/appManagers/utils/peers/getPeerActiveUsernames';
|
import getPeerActiveUsernames from '../../../lib/appManagers/utils/peers/getPeerActiveUsernames';
|
||||||
import getPeerId from '../../../lib/appManagers/utils/peers/getPeerId';
|
import getPeerId from '../../../lib/appManagers/utils/peers/getPeerId';
|
||||||
import I18n, {i18n, join, LangPackKey} from '../../../lib/langPack';
|
import {i18n, join, LangPackKey} from '../../../lib/langPack';
|
||||||
import rootScope from '../../../lib/rootScope';
|
import rootScope from '../../../lib/rootScope';
|
||||||
import CheckboxField from '../../checkboxField';
|
|
||||||
import PopupPickUser from '../../popups/pickUser';
|
import PopupPickUser from '../../popups/pickUser';
|
||||||
import Row from '../../row';
|
import Row from '../../row';
|
||||||
import SettingSection from '../../settingSection';
|
import SettingSection from '../../settingSection';
|
||||||
import {SliderSuperTabEventable} from '../../sliderTab';
|
import {SliderSuperTabEventable} from '../../sliderTab';
|
||||||
import {toast} from '../../toast';
|
import {toast} from '../../toast';
|
||||||
import AppUserPermissionsTab from './userPermissions';
|
import AppUserPermissionsTab from './userPermissions';
|
||||||
import findUpAsChild from '../../../helpers/dom/findUpAsChild';
|
import CheckboxFields, {CheckboxFieldsField} from '../../checkboxFields';
|
||||||
|
|
||||||
type T = {
|
type PermissionsCheckboxFieldsField = CheckboxFieldsField & {
|
||||||
flags: ChatRights[],
|
flags: ChatRights[],
|
||||||
text: LangPackKey,
|
exceptionText: LangPackKey
|
||||||
exceptionText: LangPackKey,
|
|
||||||
checkboxField?: CheckboxField,
|
|
||||||
nested?: T[],
|
|
||||||
nestedTo?: T,
|
|
||||||
nestedCounter?: HTMLElement,
|
|
||||||
setNestedCounter?: (count: number) => void,
|
|
||||||
toggleWith?: {checked?: ChatRights[], unchecked?: ChatRights[]}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ChatPermissions {
|
export class ChatPermissions extends CheckboxFields<PermissionsCheckboxFieldsField> {
|
||||||
public v: Array<T>;
|
|
||||||
|
|
||||||
protected chat: Chat.chat | Chat.channel;
|
protected chat: Chat.chat | Chat.channel;
|
||||||
protected rights: ChatBannedRights.chatBannedRights;
|
protected rights: ChatBannedRights.chatBannedRights;
|
||||||
protected defaultBannedRights: ChatBannedRights.chatBannedRights;
|
protected defaultBannedRights: ChatBannedRights.chatBannedRights;
|
||||||
|
@ -56,11 +44,22 @@ export class ChatPermissions {
|
||||||
appendTo: HTMLElement,
|
appendTo: HTMLElement,
|
||||||
participant?: ChannelParticipant.channelParticipantBanned
|
participant?: ChannelParticipant.channelParticipantBanned
|
||||||
}, private managers: AppManagers) {
|
}, private managers: AppManagers) {
|
||||||
|
super({
|
||||||
|
listenerSetter: options.listenerSetter,
|
||||||
|
fields: [],
|
||||||
|
asRestrictions: true
|
||||||
|
});
|
||||||
|
|
||||||
this.construct();
|
this.construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async construct() {
|
public async construct() {
|
||||||
const mediaNested: T[] = [
|
const options = this.options;
|
||||||
|
const chat = this.chat = await this.managers.appChatsManager.getChat(options.chatId) as Chat.chat | Chat.channel;
|
||||||
|
const defaultBannedRights = this.defaultBannedRights = chat.default_banned_rights;
|
||||||
|
const rights = this.rights = options.participant ? combineParticipantBannedRights(chat as Chat.channel, options.participant.banned_rights) : defaultBannedRights;
|
||||||
|
|
||||||
|
const mediaNested: PermissionsCheckboxFieldsField[] = [
|
||||||
{flags: ['send_photos'], text: 'UserRestrictionsSendPhotos', exceptionText: 'UserRestrictionsNoSendPhotos'},
|
{flags: ['send_photos'], text: 'UserRestrictionsSendPhotos', exceptionText: 'UserRestrictionsNoSendPhotos'},
|
||||||
{flags: ['send_videos'], text: 'UserRestrictionsSendVideos', exceptionText: 'UserRestrictionsNoSendVideos'},
|
{flags: ['send_videos'], text: 'UserRestrictionsSendVideos', exceptionText: 'UserRestrictionsNoSendVideos'},
|
||||||
{flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},
|
{flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},
|
||||||
|
@ -68,150 +67,57 @@ export class ChatPermissions {
|
||||||
{flags: ['send_docs'], text: 'UserRestrictionsSendFiles', exceptionText: 'UserRestrictionsNoSendDocs'},
|
{flags: ['send_docs'], text: 'UserRestrictionsSendFiles', exceptionText: 'UserRestrictionsNoSendDocs'},
|
||||||
{flags: ['send_voices'], text: 'UserRestrictionsSendVoices', exceptionText: 'UserRestrictionsNoSendVoice'},
|
{flags: ['send_voices'], text: 'UserRestrictionsSendVoices', exceptionText: 'UserRestrictionsNoSendVoice'},
|
||||||
{flags: ['send_roundvideos'], text: 'UserRestrictionsSendRound', exceptionText: 'UserRestrictionsNoSendRound'},
|
{flags: ['send_roundvideos'], text: 'UserRestrictionsSendRound', exceptionText: 'UserRestrictionsNoSendRound'},
|
||||||
{flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks', toggleWith: {checked: ['send_plain']}},
|
{flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks'},
|
||||||
{flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'}
|
{flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'}
|
||||||
];
|
];
|
||||||
|
|
||||||
const mediaToggleWith = flatten(mediaNested.map(({flags}) => flags));
|
const mediaToggleWith = mediaNested;
|
||||||
const media: T = {flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia', nested: mediaNested, toggleWith: {unchecked: mediaToggleWith, checked: mediaToggleWith}};
|
const v: PermissionsCheckboxFieldsField[] = [
|
||||||
|
{flags: ['send_plain'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend'},
|
||||||
this.v = [
|
{flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia', nested: mediaNested},
|
||||||
{flags: ['send_plain'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend', toggleWith: {unchecked: ['embed_links']}},
|
|
||||||
media,
|
|
||||||
{flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},
|
{flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},
|
||||||
{flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},
|
{flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},
|
||||||
{flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}
|
{flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}
|
||||||
];
|
];
|
||||||
|
|
||||||
mediaNested.forEach((info) => info.nestedTo = media);
|
|
||||||
|
|
||||||
const options = this.options;
|
const map: {[action in ChatRights]?: PermissionsCheckboxFieldsField} = {};
|
||||||
const chat = this.chat = await this.managers.appChatsManager.getChat(options.chatId) as Chat.chat | Chat.channel;
|
v.push(...mediaNested);
|
||||||
const defaultBannedRights = this.defaultBannedRights = chat.default_banned_rights;
|
v.forEach((info) => {
|
||||||
const rights = this.rights = options.participant ? combineParticipantBannedRights(chat as Chat.channel, options.participant.banned_rights) : defaultBannedRights;
|
const mainFlag = info.flags[0];
|
||||||
|
map[mainFlag] = info;
|
||||||
for(const info of this.v) {
|
info.checked = hasRights(chat, mainFlag, rights)
|
||||||
const {nodes} = this.createRow(info);
|
|
||||||
options.appendTo.append(...nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.v.push(...mediaNested);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected createRow(info: T, isNested?: boolean) {
|
|
||||||
const {defaultBannedRights, chat, rights, restrictionText} = this;
|
|
||||||
|
|
||||||
const mainFlag = info.flags[0];
|
|
||||||
const row = new Row({
|
|
||||||
titleLangKey: isNested ? undefined : info.text,
|
|
||||||
checkboxField: info.checkboxField = new CheckboxField({
|
|
||||||
text: isNested ? info.text : undefined,
|
|
||||||
checked: info.nested ? false : hasRights(chat, mainFlag, rights),
|
|
||||||
toggle: !isNested,
|
|
||||||
listenerSetter: this.options.listenerSetter,
|
|
||||||
restriction: !isNested
|
|
||||||
}),
|
|
||||||
listenerSetter: this.options.listenerSetter,
|
|
||||||
clickable: info.nested ? (e) => {
|
|
||||||
if(findUpAsChild(e.target as HTMLElement, row.checkboxField.label)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelEvent(e);
|
|
||||||
row.container.classList.toggle('accordion-toggler-expanded');
|
|
||||||
accordion.classList.toggle('is-expanded');
|
|
||||||
} : undefined
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if((
|
mediaNested.forEach((info) => info.nestedTo = map.send_media);
|
||||||
this.options.participant &&
|
map.send_media.toggleWith = {unchecked: mediaToggleWith, checked: mediaToggleWith};
|
||||||
defaultBannedRights.pFlags[mainFlag as keyof typeof defaultBannedRights['pFlags']]
|
map.embed_links.toggleWith = {checked: [map.send_plain]};
|
||||||
) || (
|
map.send_plain.toggleWith = {unchecked: [map.embed_links]};
|
||||||
getPeerActiveUsernames(chat as Chat.channel)[0] &&
|
|
||||||
(
|
|
||||||
info.flags.includes('pin_messages') ||
|
|
||||||
info.flags.includes('change_info')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
info.checkboxField.input.disabled = true;
|
|
||||||
|
|
||||||
attachClickEvent(info.checkboxField.label, (e) => {
|
this.fields = v;
|
||||||
toast(I18n.format(restrictionText, true));
|
|
||||||
}, {listenerSetter: this.options.listenerSetter});
|
for(const info of this.fields) {
|
||||||
|
if((
|
||||||
|
this.options.participant &&
|
||||||
|
defaultBannedRights.pFlags[info.flags[0] as keyof typeof defaultBannedRights['pFlags']]
|
||||||
|
) || (
|
||||||
|
getPeerActiveUsernames(chat as Chat.channel)[0] &&
|
||||||
|
(
|
||||||
|
info.flags.includes('pin_messages') ||
|
||||||
|
info.flags.includes('change_info')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
info.restrictionText = this.restrictionText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(info.nestedTo) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {nodes} = this.createField(info);
|
||||||
|
options.appendTo.append(...nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info.toggleWith || info.nestedTo) {
|
|
||||||
const processToggleWith = info.toggleWith ? (info: T) => {
|
|
||||||
const {toggleWith, nested} = info;
|
|
||||||
const value = info.checkboxField.checked;
|
|
||||||
const arr = value ? toggleWith.checked : toggleWith.unchecked;
|
|
||||||
if(!arr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const other = this.v.filter((i) => arr.includes(i.flags[0]));
|
|
||||||
other.forEach((info) => {
|
|
||||||
info.checkboxField.setValueSilently(value);
|
|
||||||
if(info.nestedTo && !nested) {
|
|
||||||
this.setNestedCounter(info.nestedTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(info.toggleWith) {
|
|
||||||
processToggleWith(info);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(info.nested) {
|
|
||||||
this.setNestedCounter(info);
|
|
||||||
}
|
|
||||||
} : undefined;
|
|
||||||
|
|
||||||
const processNestedTo = info.nestedTo ? () => {
|
|
||||||
const length = this.getNestedCheckedLength(info.nestedTo);
|
|
||||||
info.nestedTo.checkboxField.setValueSilently(length === info.nestedTo.nested.length);
|
|
||||||
this.setNestedCounter(info.nestedTo, length);
|
|
||||||
} : undefined;
|
|
||||||
|
|
||||||
this.options.listenerSetter.add(info.checkboxField.input)('change', () => {
|
|
||||||
processToggleWith?.(info);
|
|
||||||
processNestedTo?.();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const nodes: HTMLElement[] = [row.container];
|
|
||||||
let accordion: HTMLElement, nestedCounter: HTMLElement;
|
|
||||||
if(info.nested) {
|
|
||||||
const container = accordion = document.createElement('div');
|
|
||||||
container.classList.add('accordion');
|
|
||||||
container.style.setProperty('--max-height', info.nested.length * 48 + 'px');
|
|
||||||
info.nested.forEach((info) => {
|
|
||||||
container.append(...this.createRow(info, true).nodes);
|
|
||||||
});
|
|
||||||
nodes.push(container);
|
|
||||||
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.classList.add('tgico-down', 'accordion-icon');
|
|
||||||
|
|
||||||
nestedCounter = info.nestedCounter = document.createElement('b');
|
|
||||||
this.setNestedCounter(info);
|
|
||||||
row.title.append(' ', nestedCounter, ' ', span);
|
|
||||||
|
|
||||||
row.container.classList.add('accordion-toggler');
|
|
||||||
row.titleRow.classList.add('with-delimiter');
|
|
||||||
|
|
||||||
row.checkboxField.setValueSilently(this.getNestedCheckedLength(info) === info.nested.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {row, nodes};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getNestedCheckedLength(info: T) {
|
|
||||||
return info.nested.reduce((acc, v) => acc + +v.checkboxField.checked, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected setNestedCounter(info: T, count = this.getNestedCheckedLength(info)) {
|
|
||||||
info.nestedCounter.textContent = `${count}/${info.nested.length}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public takeOut() {
|
public takeOut() {
|
||||||
|
@ -224,7 +130,7 @@ export class ChatPermissions {
|
||||||
const IGNORE_FLAGS: Set<ChatRights> = new Set([
|
const IGNORE_FLAGS: Set<ChatRights> = new Set([
|
||||||
'send_media'
|
'send_media'
|
||||||
]);
|
]);
|
||||||
for(const info of this.v) {
|
for(const info of this.fields) {
|
||||||
const banned = !info.checkboxField.checked;
|
const banned = !info.checkboxField.checked;
|
||||||
if(!banned) {
|
if(!banned) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -341,7 +247,7 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
|
||||||
// const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);
|
// const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);
|
||||||
|
|
||||||
const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;
|
const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;
|
||||||
chatPermissions.v.forEach((info) => {
|
chatPermissions.fields.forEach((info) => {
|
||||||
const mainFlag = info.flags[0];
|
const mainFlag = info.flags[0];
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {
|
if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import PeerProfile from '../../peerProfile';
|
||||||
import {Message} from '../../../layer';
|
import {Message} from '../../../layer';
|
||||||
import getMessageThreadId from '../../../lib/appManagers/utils/messages/getMessageThreadId';
|
import getMessageThreadId from '../../../lib/appManagers/utils/messages/getMessageThreadId';
|
||||||
import AppEditTopicTab from './editTopic';
|
import AppEditTopicTab from './editTopic';
|
||||||
|
import liteMode from '../../../helpers/liteMode';
|
||||||
|
|
||||||
type SharedMediaHistoryStorage = Partial<{
|
type SharedMediaHistoryStorage = Partial<{
|
||||||
[type in SearchSuperType]: {mid: number, peerId: PeerId}[]
|
[type in SearchSuperType]: {mid: number, peerId: PeerId}[]
|
||||||
|
@ -226,7 +227,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||||
}],
|
}],
|
||||||
scrollable: this.scrollable,
|
scrollable: this.scrollable,
|
||||||
onChangeTab: (mediaTab) => {
|
onChangeTab: (mediaTab) => {
|
||||||
const timeout = mediaTab.type === 'members' && rootScope.settings.animationsEnabled ? 250 : 0;
|
const timeout = mediaTab.type === 'members' && liteMode.isAvailable('animations') ? 250 : 0;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');
|
btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
import rootScope from '../lib/rootScope';
|
import rootScope from '../lib/rootScope';
|
||||||
|
|
||||||
type SetTransitionOptions = {
|
type SetTransitionOptions = {
|
||||||
|
@ -36,7 +37,7 @@ const SetTransition = (options: SetTransitionOptions) => {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if(useRafs && rootScope.settings.animationsEnabled && duration) {
|
if(useRafs && liteMode.isAvailable('animations') && duration) {
|
||||||
element.dataset.raf = '' + window.requestAnimationFrame(() => {
|
element.dataset.raf = '' + window.requestAnimationFrame(() => {
|
||||||
delete element.dataset.raf;
|
delete element.dataset.raf;
|
||||||
SetTransition({
|
SetTransition({
|
||||||
|
@ -64,7 +65,7 @@ const SetTransition = (options: SetTransitionOptions) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onTransitionStart?.();
|
onTransitionStart?.();
|
||||||
if(!rootScope.settings.animationsEnabled || !duration) {
|
if(!liteMode.isAvailable('animations') || !duration) {
|
||||||
element.classList.remove('animating', 'backwards');
|
element.classList.remove('animating', 'backwards');
|
||||||
afterTimeout();
|
afterTimeout();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {dispatchHeavyAnimationEvent} from '../hooks/useHeavyAnimationCheck';
|
||||||
import whichChild from '../helpers/dom/whichChild';
|
import whichChild from '../helpers/dom/whichChild';
|
||||||
import cancelEvent from '../helpers/dom/cancelEvent';
|
import cancelEvent from '../helpers/dom/cancelEvent';
|
||||||
import ListenerSetter from '../helpers/listenerSetter';
|
import ListenerSetter from '../helpers/listenerSetter';
|
||||||
|
import liteMode from '../helpers/liteMode';
|
||||||
|
|
||||||
function makeTransitionFunction(options: TransitionFunction) {
|
function makeTransitionFunction(options: TransitionFunction) {
|
||||||
return options;
|
return options;
|
||||||
|
@ -216,7 +217,7 @@ const TransitionSlider = (options: TransitionSliderOptions) => {
|
||||||
|
|
||||||
const to = content.children[id] as HTMLElement;
|
const to = content.children[id] as HTMLElement;
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled || (prevId === -1 && !animateFirst)) {
|
if(!liteMode.isAvailable('animations') || (prevId === -1 && !animateFirst)) {
|
||||||
animate = false;
|
animate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {formatFullSentTime} from '../../helpers/date';
|
||||||
import {simulateClickEvent, attachClickEvent} from '../../helpers/dom/clickEvent';
|
import {simulateClickEvent, attachClickEvent} from '../../helpers/dom/clickEvent';
|
||||||
import findUpClassName from '../../helpers/dom/findUpClassName';
|
import findUpClassName from '../../helpers/dom/findUpClassName';
|
||||||
import formatBytes from '../../helpers/formatBytes';
|
import formatBytes from '../../helpers/formatBytes';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import {MediaSizeType} from '../../helpers/mediaSizes';
|
import {MediaSizeType} from '../../helpers/mediaSizes';
|
||||||
import noop from '../../helpers/noop';
|
import noop from '../../helpers/noop';
|
||||||
import {Message, MessageMedia, WebPage} from '../../layer';
|
import {Message, MessageMedia, WebPage} from '../../layer';
|
||||||
|
@ -289,7 +290,7 @@ export default async function wrapDocument({message, withTime, fontWeight, voice
|
||||||
setTimeout(async() => { // wait for preloader animation end
|
setTimeout(async() => { // wait for preloader animation end
|
||||||
const url = (await getCacheContext()).url;
|
const url = (await getCacheContext()).url;
|
||||||
window.open(url);
|
window.open(url);
|
||||||
}, rootScope.settings.animationsEnabled ? 250 : 0);
|
}, liteMode.isAvailable('animations') ? 250 : 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if(MEDIA_MIME_TYPES_SUPPORTED.has(doc.mime_type) && doc.thumbs?.length) {
|
} else if(MEDIA_MIME_TYPES_SUPPORTED.has(doc.mime_type) && doc.thumbs?.length) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import createVideo from '../../helpers/dom/createVideo';
|
||||||
import noop from '../../helpers/noop';
|
import noop from '../../helpers/noop';
|
||||||
import {THUMB_TYPE_FULL} from '../../lib/mtproto/mtproto_config';
|
import {THUMB_TYPE_FULL} from '../../lib/mtproto/mtproto_config';
|
||||||
import {Middleware} from '../../helpers/middleware';
|
import {Middleware} from '../../helpers/middleware';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
|
|
||||||
export default async function wrapPhoto({photo, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware, size, withoutPreloader, loadPromises, autoDownloadSize, noBlur, noThumb, noFadeIn, blurAfter, managers = rootScope.managers, processUrl}: {
|
export default async function wrapPhoto({photo, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware, size, withoutPreloader, loadPromises, autoDownloadSize, noBlur, noThumb, noFadeIn, blurAfter, managers = rootScope.managers, processUrl}: {
|
||||||
photo: MyPhoto | MyDocument | WebDocument,
|
photo: MyPhoto | MyDocument | WebDocument,
|
||||||
|
@ -191,7 +192,7 @@ export default async function wrapPhoto({photo, message, container, boxWidth, bo
|
||||||
|
|
||||||
// console.log('wrapPhoto downloaded:', photo, photo.downloaded, container);
|
// console.log('wrapPhoto downloaded:', photo, photo.downloaded, container);
|
||||||
|
|
||||||
const needFadeIn = (thumbImage || !cacheContext.downloaded) && rootScope.settings.animationsEnabled && !noFadeIn;
|
const needFadeIn = (thumbImage || !cacheContext.downloaded) && liteMode.isAvailable('animations') && !noFadeIn;
|
||||||
|
|
||||||
let preloader: ProgressivePreloader;
|
let preloader: ProgressivePreloader;
|
||||||
const uploadingFileName = (message as Message.message)?.uploadingFileName;
|
const uploadingFileName = (message as Message.message)?.uploadingFileName;
|
||||||
|
|
|
@ -45,6 +45,7 @@ import PopupStickers from '../popups/stickers';
|
||||||
import {hideToast, toastNew} from '../toast';
|
import {hideToast, toastNew} from '../toast';
|
||||||
import wrapStickerAnimation from './stickerAnimation';
|
import wrapStickerAnimation from './stickerAnimation';
|
||||||
import framesCache from '../../helpers/framesCache';
|
import framesCache from '../../helpers/framesCache';
|
||||||
|
import liteMode, {LiteModeKey} from '../../helpers/liteMode';
|
||||||
|
|
||||||
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp#L40
|
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp#L40
|
||||||
export const STICKER_EFFECT_MULTIPLIER = 1 + 0.245 * 2;
|
export const STICKER_EFFECT_MULTIPLIER = 1 + 0.245 * 2;
|
||||||
|
@ -64,7 +65,7 @@ const onAnimationEnd = (element: HTMLElement, onAnimationEnd: () => void, timeou
|
||||||
const _timeout = setTimeout(onEnd, timeout);
|
const _timeout = setTimeout(onEnd, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function wrapSticker({doc, div, middleware, loadStickerMiddleware, lazyLoadQueue, exportLoad, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic, managers = rootScope.managers, fullThumb, isOut, noPremium, withLock, relativeEffect, loopEffect, isCustomEmoji, syncedVideo}: {
|
export default async function wrapSticker({doc, div, middleware, loadStickerMiddleware, lazyLoadQueue, exportLoad, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic, managers = rootScope.managers, fullThumb, isOut, noPremium, withLock, relativeEffect, loopEffect, isCustomEmoji, syncedVideo, liteModeKey, isEffect}: {
|
||||||
doc: MyDocument,
|
doc: MyDocument,
|
||||||
div: HTMLElement | HTMLElement[],
|
div: HTMLElement | HTMLElement[],
|
||||||
middleware?: Middleware,
|
middleware?: Middleware,
|
||||||
|
@ -92,10 +93,14 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
relativeEffect?: boolean,
|
relativeEffect?: boolean,
|
||||||
loopEffect?: boolean,
|
loopEffect?: boolean,
|
||||||
isCustomEmoji?: boolean,
|
isCustomEmoji?: boolean,
|
||||||
syncedVideo?: boolean
|
syncedVideo?: boolean,
|
||||||
|
liteModeKey?: LiteModeKey | false,
|
||||||
|
isEffect?: boolean
|
||||||
}) {
|
}) {
|
||||||
div = Array.isArray(div) ? div : [div];
|
div = Array.isArray(div) ? div : [div];
|
||||||
|
|
||||||
|
liteModeKey ??= 'stickers_panel';
|
||||||
|
|
||||||
if(isCustomEmoji) {
|
if(isCustomEmoji) {
|
||||||
emoji = doc.stickerEmojiRaw;
|
emoji = doc.stickerEmojiRaw;
|
||||||
}
|
}
|
||||||
|
@ -118,15 +123,25 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
lottieLoader.loadLottieWorkers();
|
lottieLoader.loadLottieWorkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop = !!(!emoji || isCustomEmoji) && loop;
|
||||||
|
|
||||||
div.forEach((div) => {
|
div.forEach((div) => {
|
||||||
div.dataset.docId = '' + doc.id;
|
div.dataset.docId = '' + doc.id;
|
||||||
if(emoji) {
|
if(emoji) {
|
||||||
div.dataset.stickerEmoji = emoji;
|
div.dataset.stickerEmoji = emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.dataset.stickerPlay = '' + +play;
|
||||||
|
div.dataset.stickerLoop = '' + +loop;
|
||||||
|
|
||||||
div.classList.add('media-sticker-wrapper');
|
div.classList.add('media-sticker-wrapper');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(play && !liteMode.isAvailable(liteModeKey) && !isCustomEmoji && !isEffect) {
|
||||||
|
play = false;
|
||||||
|
loop = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* if(stickerType === 3) {
|
/* if(stickerType === 3) {
|
||||||
const videoRes = wrapVideo({
|
const videoRes = wrapVideo({
|
||||||
doc,
|
doc,
|
||||||
|
@ -277,7 +292,7 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
|
|
||||||
const path = document.createElementNS(ns, 'path');
|
const path = document.createElementNS(ns, 'path');
|
||||||
path.setAttributeNS(null, 'd', d);
|
path.setAttributeNS(null, 'd', d);
|
||||||
if(rootScope.settings.animationsEnabled && !isCustomEmoji) path.setAttributeNS(null, 'fill', 'url(#g)');
|
if(liteMode.isAvailable('animations') && !isCustomEmoji) path.setAttributeNS(null, 'fill', 'url(#g)');
|
||||||
svg.append(path);
|
svg.append(path);
|
||||||
div.forEach((div, idx) => div.append(idx > 0 ? svg.cloneNode(true) : svg));
|
div.forEach((div, idx) => div.append(idx > 0 ? svg.cloneNode(true) : svg));
|
||||||
haveThumbCached = true;
|
haveThumbCached = true;
|
||||||
|
@ -383,7 +398,7 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
|
|
||||||
const animation = await lottieLoader.loadAnimationWorker({
|
const animation = await lottieLoader.loadAnimationWorker({
|
||||||
container: (div as HTMLElement[])[0],
|
container: (div as HTMLElement[])[0],
|
||||||
loop: !!(!emoji || isCustomEmoji) && loop,
|
loop,
|
||||||
autoplay: play,
|
autoplay: play,
|
||||||
animationData: blob,
|
animationData: blob,
|
||||||
width,
|
width,
|
||||||
|
@ -394,7 +409,8 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
toneIndex,
|
toneIndex,
|
||||||
sync: isCustomEmoji,
|
sync: isCustomEmoji,
|
||||||
middleware: loadStickerMiddleware ?? middleware,
|
middleware: loadStickerMiddleware ?? middleware,
|
||||||
group
|
group,
|
||||||
|
liteModeKey: liteModeKey || undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
// const deferred = deferredPromise<void>();
|
// const deferred = deferredPromise<void>();
|
||||||
|
@ -407,7 +423,7 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
const onFirstFrame = (container: HTMLElement, canvas: HTMLCanvasElement) => {
|
const onFirstFrame = (container: HTMLElement, canvas: HTMLCanvasElement) => {
|
||||||
const element = container.firstElementChild !== canvas && container.firstElementChild as HTMLElement;
|
const element = container.firstElementChild !== canvas && container.firstElementChild as HTMLElement;
|
||||||
if(needFadeIn !== false) {
|
if(needFadeIn !== false) {
|
||||||
needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled;
|
needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && liteMode.isAvailable('animations');
|
||||||
}
|
}
|
||||||
|
|
||||||
const cb = () => {
|
const cb = () => {
|
||||||
|
@ -505,7 +521,7 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
|
|
||||||
const thumbImage = (div as HTMLElement[]).map((div, idx) => (div.firstElementChild as HTMLElement) !== media[idx] && div.firstElementChild) as HTMLElement[];
|
const thumbImage = (div as HTMLElement[]).map((div, idx) => (div.firstElementChild as HTMLElement) !== media[idx] && div.firstElementChild) as HTMLElement[];
|
||||||
if(needFadeIn !== false) {
|
if(needFadeIn !== false) {
|
||||||
needFadeIn = (needFadeIn || !downloaded || (asStatic ? thumbImage[0] : (!thumbImage[0] || thumbImage[0].tagName === 'svg'))) && rootScope.settings.animationsEnabled;
|
needFadeIn = (needFadeIn || !downloaded || (asStatic ? thumbImage[0] : (!thumbImage[0] || thumbImage[0].tagName === 'svg'))) && liteMode.isAvailable('animations');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needFadeIn) {
|
if(needFadeIn) {
|
||||||
|
@ -569,7 +585,13 @@ export default async function wrapSticker({doc, div, middleware, loadStickerMidd
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isAnimated) {
|
if(isAnimated) {
|
||||||
animationIntersector.addAnimation(media as HTMLVideoElement, group, undefined, middleware);
|
animationIntersector.addAnimation({
|
||||||
|
animation: media as HTMLVideoElement,
|
||||||
|
observeElement: div,
|
||||||
|
group,
|
||||||
|
controlled: middleware,
|
||||||
|
liteModeKey: liteModeKey || undefined
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(loaded.push(media) === mediaLength) {
|
if(loaded.push(media) === mediaLength) {
|
||||||
|
@ -666,8 +688,13 @@ function attachStickerEffectHandler({container, doc, managers, middleware, isOut
|
||||||
|
|
||||||
let playing = false;
|
let playing = false;
|
||||||
attachClickEvent(container, async(e) => {
|
attachClickEvent(container, async(e) => {
|
||||||
|
const isAvailable = liteMode.isAvailable('effects_premiumstickers') || relativeEffect;
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
if(playing) {
|
if(!e.isTrusted && !isAvailable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(playing || !isAvailable) {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.onclick = () => {
|
a.onclick = () => {
|
||||||
hideToast();
|
hideToast();
|
||||||
|
@ -749,7 +776,7 @@ export async function onEmojiStickerClick({event, container, managers, peerId, m
|
||||||
animation.restart();
|
animation.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!peerId.isUser()) {
|
if(!peerId.isUser() || !liteMode.isAvailable('effects_emoji')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,8 @@ export default function wrapStickerAnimation({
|
||||||
group: 'none',
|
group: 'none',
|
||||||
skipRatio,
|
skipRatio,
|
||||||
managers,
|
managers,
|
||||||
fullThumb
|
fullThumb,
|
||||||
|
isEffect: true
|
||||||
}).then(({render}) => render).then((_animation) => {
|
}).then(({render}) => render).then((_animation) => {
|
||||||
assumeType<RLottiePlayer>(_animation);
|
assumeType<RLottiePlayer>(_animation);
|
||||||
if(!middleware()) {
|
if(!middleware()) {
|
||||||
|
|
|
@ -69,7 +69,10 @@ export default async function wrapStickerSetThumb({set, lazyLoadQueue, container
|
||||||
container.append(media);
|
container.append(media);
|
||||||
|
|
||||||
if(set.pFlags.videos) {
|
if(set.pFlags.videos) {
|
||||||
animationIntersector.addAnimation(media as HTMLVideoElement, group);
|
animationIntersector.addAnimation({
|
||||||
|
animation: media as HTMLVideoElement,
|
||||||
|
group
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ import createVideo from '../../helpers/dom/createVideo';
|
||||||
import isInDOM from '../../helpers/dom/isInDOM';
|
import isInDOM from '../../helpers/dom/isInDOM';
|
||||||
import renderImageFromUrl from '../../helpers/dom/renderImageFromUrl';
|
import renderImageFromUrl from '../../helpers/dom/renderImageFromUrl';
|
||||||
import getStrippedThumbIfNeeded from '../../helpers/getStrippedThumbIfNeeded';
|
import getStrippedThumbIfNeeded from '../../helpers/getStrippedThumbIfNeeded';
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import makeError from '../../helpers/makeError';
|
import makeError from '../../helpers/makeError';
|
||||||
import mediaSizes, {ScreenSize} from '../../helpers/mediaSizes';
|
import mediaSizes, {ScreenSize} from '../../helpers/mediaSizes';
|
||||||
import {Middleware} from '../../helpers/middleware';
|
import {Middleware} from '../../helpers/middleware';
|
||||||
|
@ -96,7 +97,7 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
||||||
doc.size <= MAX_VIDEO_AUTOPLAY_SIZE &&
|
doc.size <= MAX_VIDEO_AUTOPLAY_SIZE &&
|
||||||
!isAlbumItem
|
!isAlbumItem
|
||||||
)
|
)
|
||||||
) && (doc.type === 'gif' ? rootScope.settings.autoPlay.gifs : rootScope.settings.autoPlay.videos)
|
) && (doc.type === 'gif' ? liteMode.isAvailable('gif') : liteMode.isAvailable('video'))
|
||||||
);
|
);
|
||||||
let spanTime: HTMLElement, spanPlay: HTMLElement;
|
let spanTime: HTMLElement, spanPlay: HTMLElement;
|
||||||
|
|
||||||
|
@ -537,7 +538,10 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
||||||
|
|
||||||
onMediaLoad(video).then(() => {
|
onMediaLoad(video).then(() => {
|
||||||
if(group) {
|
if(group) {
|
||||||
animationIntersector.addAnimation(video, group);
|
animationIntersector.addAnimation({
|
||||||
|
animation: video,
|
||||||
|
group
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(preloader && !uploadFileName) {
|
if(preloader && !uploadFileName) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ const App = {
|
||||||
version: process.env.VERSION,
|
version: process.env.VERSION,
|
||||||
versionFull: process.env.VERSION_FULL,
|
versionFull: process.env.VERSION_FULL,
|
||||||
build: +process.env.BUILD,
|
build: +process.env.BUILD,
|
||||||
langPackVersion: '0.9.3',
|
langPackVersion: '0.9.7',
|
||||||
langPack: 'webk',
|
langPack: 'webk',
|
||||||
langPackCode: 'en',
|
langPackCode: 'en',
|
||||||
domains: MAIN_DOMAINS,
|
domains: MAIN_DOMAINS,
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AppMediaPlaybackController} from '../components/appMediaPlaybackController';
|
import type {LiteModeKey} from '../helpers/liteMode';
|
||||||
|
import type {AppMediaPlaybackController} from '../components/appMediaPlaybackController';
|
||||||
|
import type {TopPeerType, MyTopPeer} from '../lib/appManagers/appUsersManager';
|
||||||
|
import type {AutoDownloadSettings, BaseTheme, NotifyPeer, PeerNotifySettings, Theme, ThemeSettings, WallPaper} from '../layer';
|
||||||
|
import type DialogsStorage from '../lib/storages/dialogs';
|
||||||
|
import type FiltersStorage from '../lib/storages/filters';
|
||||||
|
import type {AuthState, Modify} from '../types';
|
||||||
import {IS_MOBILE} from '../environment/userAgent';
|
import {IS_MOBILE} from '../environment/userAgent';
|
||||||
import getTimeFormat from '../helpers/getTimeFormat';
|
import getTimeFormat from '../helpers/getTimeFormat';
|
||||||
import {nextRandomUint} from '../helpers/random';
|
import {nextRandomUint} from '../helpers/random';
|
||||||
import {AutoDownloadSettings, BaseTheme, NotifyPeer, PeerNotifySettings, Theme, ThemeSettings, WallPaper} from '../layer';
|
|
||||||
import {TopPeerType, MyTopPeer} from '../lib/appManagers/appUsersManager';
|
|
||||||
import DialogsStorage from '../lib/storages/dialogs';
|
|
||||||
import FiltersStorage from '../lib/storages/filters';
|
|
||||||
import {AuthState, Modify} from '../types';
|
|
||||||
import App from './app';
|
import App from './app';
|
||||||
|
|
||||||
const STATE_VERSION = App.version;
|
const STATE_VERSION = App.version;
|
||||||
|
@ -74,7 +75,7 @@ export type State = {
|
||||||
messagesTextSize: number,
|
messagesTextSize: number,
|
||||||
distanceUnit: 'kilometers' | 'miles',
|
distanceUnit: 'kilometers' | 'miles',
|
||||||
sendShortcut: 'enter' | 'ctrlEnter',
|
sendShortcut: 'enter' | 'ctrlEnter',
|
||||||
animationsEnabled: boolean,
|
animationsEnabled?: boolean, // ! DEPRECATED
|
||||||
autoDownload: {
|
autoDownload: {
|
||||||
contacts?: boolean, // ! DEPRECATED
|
contacts?: boolean, // ! DEPRECATED
|
||||||
private?: boolean, // ! DEPRECATED
|
private?: boolean, // ! DEPRECATED
|
||||||
|
@ -85,7 +86,7 @@ export type State = {
|
||||||
file: AutoDownloadPeerTypeSettings
|
file: AutoDownloadPeerTypeSettings
|
||||||
},
|
},
|
||||||
autoDownloadNew: AutoDownloadSettings,
|
autoDownloadNew: AutoDownloadSettings,
|
||||||
autoPlay: {
|
autoPlay?: { // ! DEPRECATED
|
||||||
gifs: boolean,
|
gifs: boolean,
|
||||||
videos: boolean
|
videos: boolean
|
||||||
},
|
},
|
||||||
|
@ -104,7 +105,8 @@ export type State = {
|
||||||
sound: boolean
|
sound: boolean
|
||||||
},
|
},
|
||||||
nightTheme?: boolean, // ! DEPRECATED
|
nightTheme?: boolean, // ! DEPRECATED
|
||||||
timeFormat: 'h12' | 'h23'
|
timeFormat: 'h12' | 'h23',
|
||||||
|
liteMode: {[key in LiteModeKey]: boolean}
|
||||||
},
|
},
|
||||||
playbackParams: ReturnType<AppMediaPlaybackController['getPlaybackParams']>,
|
playbackParams: ReturnType<AppMediaPlaybackController['getPlaybackParams']>,
|
||||||
keepSigned: boolean,
|
keepSigned: boolean,
|
||||||
|
@ -233,7 +235,6 @@ export const STATE_INIT: State = {
|
||||||
messagesTextSize: 16,
|
messagesTextSize: 16,
|
||||||
distanceUnit: 'kilometers',
|
distanceUnit: 'kilometers',
|
||||||
sendShortcut: 'enter',
|
sendShortcut: 'enter',
|
||||||
animationsEnabled: true,
|
|
||||||
autoDownload: {
|
autoDownload: {
|
||||||
photo: {
|
photo: {
|
||||||
contacts: true,
|
contacts: true,
|
||||||
|
@ -265,10 +266,6 @@ export const STATE_INIT: State = {
|
||||||
video_size_max: 15728640,
|
video_size_max: 15728640,
|
||||||
video_upload_maxbitrate: 100
|
video_upload_maxbitrate: 100
|
||||||
},
|
},
|
||||||
autoPlay: {
|
|
||||||
gifs: true,
|
|
||||||
videos: true
|
|
||||||
},
|
|
||||||
stickers: {
|
stickers: {
|
||||||
suggest: true,
|
suggest: true,
|
||||||
loop: true
|
loop: true
|
||||||
|
@ -285,7 +282,26 @@ export const STATE_INIT: State = {
|
||||||
notifications: {
|
notifications: {
|
||||||
sound: false
|
sound: false
|
||||||
},
|
},
|
||||||
timeFormat: getTimeFormat()
|
timeFormat: getTimeFormat(),
|
||||||
|
liteMode: {
|
||||||
|
all: false,
|
||||||
|
animations: false,
|
||||||
|
chat: false,
|
||||||
|
chat_background: false,
|
||||||
|
chat_spoilers: false,
|
||||||
|
effects: false,
|
||||||
|
effects_premiumstickers: false,
|
||||||
|
effects_reactions: false,
|
||||||
|
effects_emoji: false,
|
||||||
|
emoji: false,
|
||||||
|
emoji_messages: false,
|
||||||
|
emoji_panel: false,
|
||||||
|
gif: false,
|
||||||
|
stickers: false,
|
||||||
|
stickers_chat: false,
|
||||||
|
stickers_panel: false,
|
||||||
|
video: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
playbackParams: {
|
playbackParams: {
|
||||||
volume: 1,
|
volume: 1,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import roundRect from './canvas/roundRect';
|
||||||
import Shimmer from './canvas/shimmer';
|
import Shimmer from './canvas/shimmer';
|
||||||
import customProperties from './dom/customProperties';
|
import customProperties from './dom/customProperties';
|
||||||
import easeInOutSine from './easing/easeInOutSine';
|
import easeInOutSine from './easing/easeInOutSine';
|
||||||
|
import liteMode from './liteMode';
|
||||||
import mediaSizes from './mediaSizes';
|
import mediaSizes from './mediaSizes';
|
||||||
|
|
||||||
export default class DialogsPlaceholder {
|
export default class DialogsPlaceholder {
|
||||||
|
@ -91,7 +92,7 @@ export default class DialogsPlaceholder {
|
||||||
this.availableLength = availableLength;
|
this.availableLength = availableLength;
|
||||||
this.detachTime = Date.now();
|
this.detachTime = Date.now();
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
this.remove();
|
this.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,7 @@ export default class DialogsPlaceholder {
|
||||||
|
|
||||||
if(!detachTime) {
|
if(!detachTime) {
|
||||||
return;
|
return;
|
||||||
} else if(!rootScope.settings.animationsEnabled) {
|
} else if(!liteMode.isAvailable('animations')) {
|
||||||
this.remove();
|
this.remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +220,7 @@ export default class DialogsPlaceholder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! should've removed the loop if animations are disabled
|
// ! should've removed the loop if animations are disabled
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
this.renderFrame();
|
this.renderFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import rootScope from '../../lib/rootScope';
|
import rootScope from '../../lib/rootScope';
|
||||||
|
import liteMode from '../liteMode';
|
||||||
|
|
||||||
export default function shake(element: HTMLElement) {
|
export default function shake(element: HTMLElement) {
|
||||||
if(!rootScope.settings.animationsEnabled) {
|
if(!liteMode.isAvailable('animations')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {ScrollableBase} from '../../components/scrollable';
|
||||||
import SwipeHandler from '../../components/swipeHandler';
|
import SwipeHandler from '../../components/swipeHandler';
|
||||||
import IS_TOUCH_SUPPORTED from '../../environment/touchSupport';
|
import IS_TOUCH_SUPPORTED from '../../environment/touchSupport';
|
||||||
import rootScope from '../../lib/rootScope';
|
import rootScope from '../../lib/rootScope';
|
||||||
|
import liteMode from '../liteMode';
|
||||||
import {Middleware} from '../middleware';
|
import {Middleware} from '../middleware';
|
||||||
import clamp from '../number/clamp';
|
import clamp from '../number/clamp';
|
||||||
import safeAssign from '../object/safeAssign';
|
import safeAssign from '../object/safeAssign';
|
||||||
|
@ -156,7 +157,7 @@ export default class Sortable {
|
||||||
attachClickEvent(document.body, cancelEvent, {capture: true, once: true});
|
attachClickEvent(document.body, cancelEvent, {capture: true, once: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rootScope.settings.animationsEnabled) {
|
if(liteMode.isAvailable('animations')) {
|
||||||
await pause(250);
|
await pause(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import safeAssign from './object/safeAssign';
|
||||||
import appNavigationController, {NavigationItem} from '../components/appNavigationController';
|
import appNavigationController, {NavigationItem} from '../components/appNavigationController';
|
||||||
import findUpClassName from './dom/findUpClassName';
|
import findUpClassName from './dom/findUpClassName';
|
||||||
import rootScope from '../lib/rootScope';
|
import rootScope from '../lib/rootScope';
|
||||||
|
import liteMode from './liteMode';
|
||||||
|
|
||||||
const KEEP_OPEN = false;
|
const KEEP_OPEN = false;
|
||||||
const TOGGLE_TIMEOUT = 200;
|
const TOGGLE_TIMEOUT = 200;
|
||||||
|
@ -171,7 +172,7 @@ export default class DropdownHover extends EventListenerBase<{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const delay = IS_TOUCH_SUPPORTED || !rootScope.settings.animationsEnabled ? 0 : ANIMATION_DURATION;
|
const delay = IS_TOUCH_SUPPORTED || !liteMode.isAvailable('animations') ? 0 : ANIMATION_DURATION;
|
||||||
if((this.element.style.display && enable === undefined) || enable) {
|
if((this.element.style.display && enable === undefined) || enable) {
|
||||||
const res = this.dispatchResultableEvent('open');
|
const res = this.dispatchResultableEvent('open');
|
||||||
await Promise.all(res);
|
await Promise.all(res);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {fastRafPromise} from './schedulers';
|
||||||
import {animateSingle, cancelAnimationByKey} from './animation';
|
import {animateSingle, cancelAnimationByKey} from './animation';
|
||||||
import rootScope from '../lib/rootScope';
|
import rootScope from '../lib/rootScope';
|
||||||
import isInDOM from './dom/isInDOM';
|
import isInDOM from './dom/isInDOM';
|
||||||
|
import liteMode from './liteMode';
|
||||||
|
|
||||||
const MIN_JS_DURATION = 250;
|
const MIN_JS_DURATION = 250;
|
||||||
const MAX_JS_DURATION = 600;
|
const MAX_JS_DURATION = 600;
|
||||||
|
@ -58,7 +59,7 @@ export default function fastSmoothScroll(options: ScrollOptions) {
|
||||||
options.axis ??= 'y';
|
options.axis ??= 'y';
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled || options.forceDuration === 0) {
|
if(!liteMode.isAvailable('animations') || options.forceDuration === 0) {
|
||||||
options.forceDirection = FocusDirection.Static;
|
options.forceDirection = FocusDirection.Static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {MOUNT_CLASS_TO} from '../config/debug';
|
||||||
|
import rootScope from '../lib/rootScope';
|
||||||
|
|
||||||
|
export type LiteModeKey = 'all' | 'gif' | 'video' |
|
||||||
|
'emoji' | 'emoji_panel' | 'emoji_messages' |
|
||||||
|
'effects' | 'effects_reactions' | 'effects_premiumstickers' | 'effects_emoji' |
|
||||||
|
'stickers' | 'stickers_panel' | 'stickers_chat' |
|
||||||
|
'chat' | 'chat_background' | 'chat_spoilers' | 'animations';
|
||||||
|
|
||||||
|
export class LiteMode {
|
||||||
|
public isAvailable(key: LiteModeKey) {
|
||||||
|
return !rootScope.settings.liteMode.all && !rootScope.settings.liteMode[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const liteMode = new LiteMode();
|
||||||
|
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.liteMode = liteMode);
|
||||||
|
export default liteMode;
|
25
src/lang.ts
25
src/lang.ts
|
@ -115,6 +115,17 @@ const lang = {
|
||||||
'Link.Available': 'Link is available',
|
'Link.Available': 'Link is available',
|
||||||
'Link.Taken': 'Link is already taken',
|
'Link.Taken': 'Link is already taken',
|
||||||
'Link.Invalid': 'Link is invalid',
|
'Link.Invalid': 'Link is invalid',
|
||||||
|
'LiteMode.Key.chat.Title': 'Chat Animations',
|
||||||
|
'LiteMode.Key.chat_background.Title': 'Background rotation',
|
||||||
|
'LiteMode.Key.chat_spoilers.Title': 'Animated spoiler effect',
|
||||||
|
'LiteMode.Key.stickers_panel.Title': 'Autoplay in panel',
|
||||||
|
'LiteMode.Key.stickers_chat.Title': 'Autoplay in chat',
|
||||||
|
'LiteMode.Key.emoji_panel.Title': 'Autoplay in panel',
|
||||||
|
'LiteMode.Key.emoji_messages.Title': 'Autoplay in messages',
|
||||||
|
'LiteMode.Key.effects.Title': 'Interactive Effects',
|
||||||
|
'LiteMode.Key.effects_reactions.Title': 'Reaction effect',
|
||||||
|
'LiteMode.Key.effects_premiumstickers.Title': 'Premium stickers effect',
|
||||||
|
'LiteMode.Key.effects_emoji.Title': 'Emoji effect',
|
||||||
'StickersTab.SearchPlaceholder': 'Search Stickers',
|
'StickersTab.SearchPlaceholder': 'Search Stickers',
|
||||||
'ForwardedFrom': 'Forwarded from %s',
|
'ForwardedFrom': 'Forwarded from %s',
|
||||||
'Popup.Avatar.Title': 'Drag to Reposition',
|
'Popup.Avatar.Title': 'Drag to Reposition',
|
||||||
|
@ -1178,6 +1189,20 @@ const lang = {
|
||||||
'other_value': 'last seen %d hours ago'
|
'other_value': 'last seen %d hours ago'
|
||||||
},
|
},
|
||||||
'Login.Register.LastName.Placeholder': 'Last Name',
|
'Login.Register.LastName.Placeholder': 'Last Name',
|
||||||
|
'LiteMode.Title': 'Power Saving',
|
||||||
|
'LiteMode.Key.emoji.Title': 'Emoji Animations',
|
||||||
|
'LiteMode.Key.gif.Title': 'Autoplay GIFs',
|
||||||
|
'LiteMode.Key.video.Title': 'Autoplay Videos',
|
||||||
|
'LiteMode.Key.stickers.Title': 'Sticker Animations',
|
||||||
|
'LiteMode.Key.animations.Title': 'Interface Animations',
|
||||||
|
// 'LiteMode.Key.emoji.Info': 'Loop animated emoji in messages, reactions and statuses.',
|
||||||
|
// 'LiteMode.Key.gif.Info': 'Autoplay and loop GIFs in chats and in the keyboard.',
|
||||||
|
// 'LiteMode.Key.video.Info': 'Autoplay and loop videos and video messages in chats.',
|
||||||
|
// 'LiteMode.Key.stickers.Info': 'Loop animated stickers, in chats and in the keyboard.',
|
||||||
|
// 'LiteMode.Key.animations.Info': 'Other animations that make Telegram look amazing.',
|
||||||
|
'LiteMode.Info': 'Reduce all power-intensive animations and improve performance.',
|
||||||
|
'LiteMode.EnableText': 'Power Saving Mode',
|
||||||
|
'LiteMode.DisableAlert': 'Disable Power Saving Mode',
|
||||||
'Message.Context.Select': 'Select',
|
'Message.Context.Select': 'Select',
|
||||||
'Message.Context.Pin': 'Pin',
|
'Message.Context.Pin': 'Pin',
|
||||||
'Message.Context.Unpin': 'Unpin',
|
'Message.Context.Unpin': 'Unpin',
|
||||||
|
|
|
@ -105,6 +105,8 @@ import PopupForward from '../../components/popups/forward';
|
||||||
import AppBackgroundTab from '../../components/sidebarLeft/tabs/background';
|
import AppBackgroundTab from '../../components/sidebarLeft/tabs/background';
|
||||||
import partition from '../../helpers/array/partition';
|
import partition from '../../helpers/array/partition';
|
||||||
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
import indexOfAndSplice from '../../helpers/array/indexOfAndSplice';
|
||||||
|
import liteMode, {LiteModeKey} from '../../helpers/liteMode';
|
||||||
|
import RLottiePlayer from '../rlottie/rlottiePlayer';
|
||||||
|
|
||||||
export type ChatSavedPosition = {
|
export type ChatSavedPosition = {
|
||||||
mids: number[],
|
mids: number[],
|
||||||
|
@ -458,6 +460,29 @@ export class AppImManager extends EventListenerBase<{
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', (e) => {
|
||||||
|
const mediaStickerWrapper = findUpClassName(e.target, 'media-sticker-wrapper');
|
||||||
|
if(!mediaStickerWrapper ||
|
||||||
|
mediaStickerWrapper.classList.contains('custom-emoji') ||
|
||||||
|
findUpClassName(e.target, 'emoji-big')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const animations = animationIntersector.getAnimations(mediaStickerWrapper);
|
||||||
|
animations?.forEach((animationItem) => {
|
||||||
|
const {liteModeKey, animation} = animationItem;
|
||||||
|
if(!liteModeKey || !animation?.paused || liteMode.isAvailable(liteModeKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(animation instanceof RLottiePlayer) {
|
||||||
|
animation.playOrRestart();
|
||||||
|
} else {
|
||||||
|
animation.play();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
rootScope.addEventListener('sticker_updated', ({type, faved}) => {
|
rootScope.addEventListener('sticker_updated', ({type, faved}) => {
|
||||||
if(type === 'faved') {
|
if(type === 'faved') {
|
||||||
toastNew({
|
toastNew({
|
||||||
|
@ -1006,7 +1031,7 @@ export class AppImManager extends EventListenerBase<{
|
||||||
private toggleChatGradientAnimation(activatingChat: Chat) {
|
private toggleChatGradientAnimation(activatingChat: Chat) {
|
||||||
this.chats.forEach((chat) => {
|
this.chats.forEach((chat) => {
|
||||||
if(chat.gradientRenderer) {
|
if(chat.gradientRenderer) {
|
||||||
chat.gradientRenderer.scrollAnimate(rootScope.settings.animationsEnabled && chat === activatingChat);
|
chat.gradientRenderer.scrollAnimate(liteMode.isAvailable('animations') && chat === activatingChat);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1639,18 +1664,21 @@ export class AppImManager extends EventListenerBase<{
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.classList.toggle('animation-level-0', !rootScope.settings.animationsEnabled);
|
document.body.classList.toggle('animation-level-0', !liteMode.isAvailable('animations'));
|
||||||
document.body.classList.toggle('animation-level-1', false);
|
document.body.classList.toggle('animation-level-1', false);
|
||||||
document.body.classList.toggle('animation-level-2', rootScope.settings.animationsEnabled);
|
document.body.classList.toggle('animation-level-2', liteMode.isAvailable('animations'));
|
||||||
|
|
||||||
this.chatsSelectTabDebounced = debounce(() => {
|
this.chatsSelectTabDebounced = debounce(() => {
|
||||||
const topbar = this.chat.topbar;
|
const topbar = this.chat.topbar;
|
||||||
topbar.pinnedMessage?.setCorrectIndex(0); // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации
|
topbar.pinnedMessage?.setCorrectIndex(0); // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации
|
||||||
|
|
||||||
this.managers.apiFileManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);
|
this.managers.apiFileManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);
|
||||||
}, rootScope.settings.animationsEnabled ? 250 : 0, false, true);
|
}, liteMode.isAvailable('animations') ? 250 : 0, false, true);
|
||||||
|
|
||||||
if(lottieLoader.setLoop(rootScope.settings.stickers.loop)) {
|
const c: LiteModeKey[] = ['stickers_chat', 'stickers_panel'];
|
||||||
|
const changedLoop = lottieLoader.setLoop(rootScope.settings.stickers.loop);
|
||||||
|
const changedAutoplay = !!c.filter((key) => lottieLoader.setAutoplay(liteMode.isAvailable(key), key)).length;
|
||||||
|
if(changedLoop || changedAutoplay) {
|
||||||
animationIntersector.checkAnimations2(false);
|
animationIntersector.checkAnimations2(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1679,7 +1707,7 @@ export class AppImManager extends EventListenerBase<{
|
||||||
this.chatsSelectTabDebounced();
|
this.chatsSelectTabDebounced();
|
||||||
|
|
||||||
// ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс
|
// ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс
|
||||||
if(rootScope.settings.animationsEnabled && animate !== false) {
|
if(liteMode.isAvailable('animations') && animate !== false) {
|
||||||
dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);
|
dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,11 +1955,11 @@ export class AppImManager extends EventListenerBase<{
|
||||||
|
|
||||||
this.log('selectTab', id, prevTabId);
|
this.log('selectTab', id, prevTabId);
|
||||||
|
|
||||||
let animationPromise: Promise<any> = rootScope.settings.animationsEnabled ? doubleRaf() : Promise.resolve();
|
let animationPromise: Promise<any> = liteMode.isAvailable('animations') ? doubleRaf() : Promise.resolve();
|
||||||
if(
|
if(
|
||||||
prevTabId !== undefined &&
|
prevTabId !== undefined &&
|
||||||
prevTabId !== id &&
|
prevTabId !== id &&
|
||||||
rootScope.settings.animationsEnabled &&
|
liteMode.isAvailable('animations') &&
|
||||||
animate !== false/* &&
|
animate !== false/* &&
|
||||||
mediaSizes.activeScreen !== ScreenSize.large */
|
mediaSizes.activeScreen !== ScreenSize.large */
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -87,7 +87,11 @@ export class CustomEmojiElement extends HTMLElement {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if(this.player) {
|
if(this.player) {
|
||||||
animationIntersector.addAnimation(this, this.renderer.animationGroup, undefined, true);
|
animationIntersector.addAnimation({
|
||||||
|
animation: this,
|
||||||
|
group: this.renderer.animationGroup,
|
||||||
|
controlled: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.connectedCallback = undefined;
|
// this.connectedCallback = undefined;
|
||||||
|
@ -185,7 +189,7 @@ export class CustomEmojiElement extends HTMLElement {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
|
|
||||||
if(this.player instanceof HTMLVideoElement) {
|
if(this.player instanceof HTMLVideoElement) {
|
||||||
this.player.currentTime = this.renderer.lastPausedVideo?.currentTime || this.player.currentTime;
|
this.player.currentTime = this.renderer.lastPausedVideo?.currentTime ?? this.player.currentTime;
|
||||||
this.player.play().catch(noop);
|
this.player.play().catch(noop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +210,10 @@ export class CustomEmojiElement extends HTMLElement {
|
||||||
public get autoplay() {
|
public get autoplay() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get loop() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomEmojiElements = Set<CustomEmojiElement>;
|
type CustomEmojiElements = Set<CustomEmojiElement>;
|
||||||
|
@ -648,7 +656,11 @@ export class CustomEmojiRendererElement extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element.isConnected) {
|
if(element.isConnected) {
|
||||||
animationIntersector.addAnimation(element, element.renderer.animationGroup, undefined, true);
|
animationIntersector.addAnimation({
|
||||||
|
animation: element,
|
||||||
|
group: element.renderer.animationGroup,
|
||||||
|
controlled: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {LiteModeKey} from '../../helpers/liteMode';
|
||||||
import animationIntersector, {AnimationItemGroup} from '../../components/animationIntersector';
|
import animationIntersector, {AnimationItemGroup} from '../../components/animationIntersector';
|
||||||
import {MOUNT_CLASS_TO} from '../../config/debug';
|
import {MOUNT_CLASS_TO} from '../../config/debug';
|
||||||
import pause from '../../helpers/schedulers/pause';
|
import pause from '../../helpers/schedulers/pause';
|
||||||
|
@ -45,6 +46,20 @@ export class LottieLoader {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setAutoplay(play: boolean, liteModeKey: LiteModeKey) {
|
||||||
|
let changed = false;
|
||||||
|
for(const i in this.players) {
|
||||||
|
const player = this.players[i];
|
||||||
|
if(player.liteModeKey === liteModeKey) {
|
||||||
|
changed = true;
|
||||||
|
player.autoplay = play ? !!+player.el[0].dataset.stickerPlay : false;
|
||||||
|
player.loop = play ? !!+player.el[0].dataset.stickerLoop : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
public setLoop(loop: boolean) {
|
public setLoop(loop: boolean) {
|
||||||
let changed = false;
|
let changed = false;
|
||||||
for(const i in this.players) {
|
for(const i in this.players) {
|
||||||
|
@ -196,7 +211,12 @@ export class LottieLoader {
|
||||||
|
|
||||||
const player = this.initPlayer(containers, params);
|
const player = this.initPlayer(containers, params);
|
||||||
|
|
||||||
animationIntersector.addAnimation(player, group, undefined, middleware);
|
animationIntersector.addAnimation({
|
||||||
|
animation: player,
|
||||||
|
group,
|
||||||
|
controlled: middleware,
|
||||||
|
liteModeKey: params.liteModeKey
|
||||||
|
});
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import liteMode from '../../helpers/liteMode';
|
||||||
import noop from '../../helpers/noop';
|
import noop from '../../helpers/noop';
|
||||||
import safeAssign from '../../helpers/object/safeAssign';
|
import safeAssign from '../../helpers/object/safeAssign';
|
||||||
import rootScope from '../rootScope';
|
import rootScope from '../rootScope';
|
||||||
|
@ -181,7 +182,7 @@ export default class RLottieIcon {
|
||||||
|
|
||||||
const part = item.getPart(index);
|
const part = item.getPart(index);
|
||||||
item.player.playPart({
|
item.player.playPart({
|
||||||
from: rootScope.settings.animationsEnabled && !this.skipAnimation ? part.startFrame : part.endFrame,
|
from: liteMode.isAvailable('animations') && !this.skipAnimation ? part.startFrame : part.endFrame,
|
||||||
to: part.endFrame,
|
to: part.endFrame,
|
||||||
callback
|
callback
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import type {AnimationItemGroup, AnimationItemWrapper} from '../../components/animationIntersector';
|
import type {AnimationItemGroup, AnimationItemWrapper} from '../../components/animationIntersector';
|
||||||
import type {Middleware} from '../../helpers/middleware';
|
import type {Middleware} from '../../helpers/middleware';
|
||||||
|
import type {LiteModeKey} from '../../helpers/liteMode';
|
||||||
import CAN_USE_TRANSFERABLES from '../../environment/canUseTransferables';
|
import CAN_USE_TRANSFERABLES from '../../environment/canUseTransferables';
|
||||||
import IS_APPLE_MX from '../../environment/appleMx';
|
import IS_APPLE_MX from '../../environment/appleMx';
|
||||||
import {IS_ANDROID, IS_APPLE_MOBILE, IS_APPLE, IS_SAFARI} from '../../environment/userAgent';
|
import {IS_ANDROID, IS_APPLE_MOBILE, IS_APPLE, IS_SAFARI} from '../../environment/userAgent';
|
||||||
|
@ -35,7 +36,8 @@ export type RLottieOptions = {
|
||||||
name?: string,
|
name?: string,
|
||||||
skipFirstFrameRendering?: boolean,
|
skipFirstFrameRendering?: boolean,
|
||||||
toneIndex?: number,
|
toneIndex?: number,
|
||||||
sync?: boolean
|
sync?: boolean,
|
||||||
|
liteModeKey?: LiteModeKey
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RLottieColor = [number, number, number];
|
export type RLottieColor = [number, number, number];
|
||||||
|
@ -92,6 +94,7 @@ export default class RLottiePlayer extends EventListenerBase<{
|
||||||
public loop: number | boolean = true;
|
public loop: number | boolean = true;
|
||||||
public _loop: RLottiePlayer['loop']; // ! will be used to store original value for settings.stickers.loop
|
public _loop: RLottiePlayer['loop']; // ! will be used to store original value for settings.stickers.loop
|
||||||
public group: AnimationItemGroup = '';
|
public group: AnimationItemGroup = '';
|
||||||
|
public liteModeKey: LiteModeKey;
|
||||||
|
|
||||||
private frInterval: number;
|
private frInterval: number;
|
||||||
private frThen: number;
|
private frThen: number;
|
||||||
|
@ -153,6 +156,7 @@ export default class RLottiePlayer extends EventListenerBase<{
|
||||||
this.skipFirstFrameRendering = options.skipFirstFrameRendering;
|
this.skipFirstFrameRendering = options.skipFirstFrameRendering;
|
||||||
this.toneIndex = options.toneIndex;
|
this.toneIndex = options.toneIndex;
|
||||||
this.raw = this.color !== undefined;
|
this.raw = this.color !== undefined;
|
||||||
|
this.liteModeKey = options.liteModeKey;
|
||||||
|
|
||||||
if(this.name) {
|
if(this.name) {
|
||||||
this.cacheName = RLottiePlayer.CACHE.generateName(this.name, this.width, this.height, this.color, this.toneIndex);
|
this.cacheName = RLottiePlayer.CACHE.generateName(this.name, this.width, this.height, this.color, this.toneIndex);
|
||||||
|
@ -284,6 +288,18 @@ export default class RLottiePlayer extends EventListenerBase<{
|
||||||
this.play();
|
this.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public playOrRestart() {
|
||||||
|
if(!this.paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.curFrame === this.maxFrame) {
|
||||||
|
this.restart();
|
||||||
|
} else {
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public setSpeed(speed: number) {
|
public setSpeed(speed: number) {
|
||||||
if(this.speed === speed) {
|
if(this.speed === speed) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -66,9 +66,9 @@
|
||||||
left: -15%;
|
left: -15%;
|
||||||
|
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
transform: scale(1);
|
transform: scale(0);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transition: transform .2s 0s ease-in-out;
|
transition: transform .2s .05s ease-in-out;
|
||||||
|
|
||||||
@include animation-level(0) {
|
@include animation-level(0) {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
|
@ -87,10 +87,10 @@
|
||||||
stroke: #fff;
|
stroke: #fff;
|
||||||
stroke-width: 3.75;
|
stroke-width: 3.75;
|
||||||
stroke-linecap: round;
|
stroke-linecap: round;
|
||||||
stroke-dasharray: 24.19, 24.19;
|
stroke-dasharray: 0, 24.19;
|
||||||
stroke-dashoffset: 0;
|
stroke-dashoffset: 0;
|
||||||
transition: stroke-dasharray .1s .15s ease-in-out, visibility 0s .15s;
|
transition: stroke-dasharray .1s ease-in-out, visibility 0s .1s;
|
||||||
visibility: visible; // fix blinking on parent's transform
|
visibility: hidden; // fix blinking on parent's transform
|
||||||
|
|
||||||
@include animation-level(0) {
|
@include animation-level(0) {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
|
@ -287,18 +287,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-field .checkbox-field-input {
|
.checkbox-field .checkbox-field-input {
|
||||||
&:not(:checked) + .checkbox-box {
|
&:checked:not(.is-fake-disabled) + .checkbox-box {
|
||||||
.checkbox-box-check {
|
.checkbox-box-check {
|
||||||
use {
|
use {
|
||||||
stroke-dasharray: 0, 24.19;
|
stroke-dasharray: 24.19, 24.19;
|
||||||
visibility: hidden;
|
visibility: visible;
|
||||||
transition: stroke-dasharray .1s ease-in-out, visibility 0s .1s;
|
transition: stroke-dasharray .1s .15s ease-in-out, visibility 0s .15s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-box-background {
|
.checkbox-box-background {
|
||||||
transition: transform .2s .05s ease-in-out;
|
transition: transform .2s 0s ease-in-out;
|
||||||
transform: scale(0);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[type="checkbox"]:checked + .checkbox-toggle {
|
[type="checkbox"]:checked:not(.is-fake-disabled) + .checkbox-toggle {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
|
|
|
@ -1204,6 +1204,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.power-saving-container {
|
||||||
|
.row.is-disabled {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.empty-placeholder {
|
.empty-placeholder {
|
||||||
// left: 50%;
|
// left: 50%;
|
||||||
// transform: translate(-50%, -50%);
|
// transform: translate(-50%, -50%);
|
||||||
|
|
Loading…
Reference in New Issue