Fix memory leaks
This commit is contained in:
parent
25ecb89f2b
commit
d2d184d242
@ -69,6 +69,8 @@ import { attachContextMenuListener } from "../helpers/dom/attachContextMenuListe
|
|||||||
import contextMenuController from "../helpers/contextMenuController";
|
import contextMenuController from "../helpers/contextMenuController";
|
||||||
import positionMenu from "../helpers/positionMenu";
|
import positionMenu from "../helpers/positionMenu";
|
||||||
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
||||||
|
import ListenerSetter from "../helpers/listenerSetter";
|
||||||
|
import SwipeHandler from "./swipeHandler";
|
||||||
|
|
||||||
//const testScroll = false;
|
//const testScroll = false;
|
||||||
|
|
||||||
@ -107,7 +109,8 @@ class SearchContextMenu {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private attachTo: HTMLElement,
|
private attachTo: HTMLElement,
|
||||||
private searchSuper: AppSearchSuper
|
private searchSuper: AppSearchSuper,
|
||||||
|
private listenerSetter: ListenerSetter
|
||||||
) {
|
) {
|
||||||
this.managers = searchSuper.managers;
|
this.managers = searchSuper.managers;
|
||||||
|
|
||||||
@ -162,7 +165,7 @@ class SearchContextMenu {
|
|||||||
if(IS_TOUCH_SUPPORTED) {
|
if(IS_TOUCH_SUPPORTED) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
attachContextMenuListener(attachTo, onContextMenu as any);
|
attachContextMenuListener(attachTo, onContextMenu as any, listenerSetter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,14 +326,18 @@ export default class AppSearchSuper {
|
|||||||
public managers: AppManagers;
|
public managers: AppManagers;
|
||||||
private loadFirstTimePromise: Promise<void>;
|
private loadFirstTimePromise: Promise<void>;
|
||||||
|
|
||||||
|
private listenerSetter: ListenerSetter;
|
||||||
|
private swipeHandler: SwipeHandler;
|
||||||
|
|
||||||
constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender' | 'managers'>) {
|
constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender' | 'managers'>) {
|
||||||
safeAssign(this, options);
|
safeAssign(this, options);
|
||||||
|
|
||||||
this.container = document.createElement('div');
|
this.container = document.createElement('div');
|
||||||
this.container.classList.add('search-super');
|
this.container.classList.add('search-super');
|
||||||
|
|
||||||
this.searchContextMenu = new SearchContextMenu(this.container, this);
|
this.listenerSetter = new ListenerSetter();
|
||||||
this.selection = new SearchSelection(this, this.managers);
|
this.searchContextMenu = new SearchContextMenu(this.container, this, this.listenerSetter);
|
||||||
|
this.selection = new SearchSelection(this, this.managers, this.listenerSetter);
|
||||||
|
|
||||||
const navScrollableContainer = this.navScrollableContainer = document.createElement('div');
|
const navScrollableContainer = this.navScrollableContainer = document.createElement('div');
|
||||||
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');
|
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');
|
||||||
@ -369,7 +376,7 @@ export default class AppSearchSuper {
|
|||||||
|
|
||||||
let unlockScroll: ReturnType<typeof lockTouchScroll>;
|
let unlockScroll: ReturnType<typeof lockTouchScroll>;
|
||||||
if(IS_TOUCH_SUPPORTED) {
|
if(IS_TOUCH_SUPPORTED) {
|
||||||
handleTabSwipe({
|
this.swipeHandler = handleTabSwipe({
|
||||||
element: this.tabsContainer,
|
element: this.tabsContainer,
|
||||||
onSwipe: (xDiff, yDiff, e) => {
|
onSwipe: (xDiff, yDiff, e) => {
|
||||||
const prevId = this.selectTab.prevId();
|
const prevId = this.selectTab.prevId();
|
||||||
@ -521,14 +528,14 @@ export default class AppSearchSuper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.onTransitionEnd();
|
this.onTransitionEnd();
|
||||||
}, undefined, navScrollable);
|
}, undefined, navScrollable, this.listenerSetter);
|
||||||
|
|
||||||
attachClickEvent(this.tabsContainer, (e) => {
|
attachClickEvent(this.tabsContainer, (e) => {
|
||||||
if(this.selection.isSelecting) {
|
if(this.selection.isSelecting) {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));
|
this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));
|
||||||
}
|
}
|
||||||
}, {capture: true, passive: false});
|
}, {capture: true, passive: false, listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
const onMediaClick = async(className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {
|
const onMediaClick = async(className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {
|
||||||
const target = findUpClassName(e.target as HTMLDivElement, className);
|
const target = findUpClassName(e.target as HTMLDivElement, className);
|
||||||
@ -560,8 +567,8 @@ export default class AppSearchSuper {
|
|||||||
.openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
.openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));
|
attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'), {listenerSetter: this.listenerSetter});
|
||||||
attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));
|
attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'), {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
/* attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {
|
/* attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
@ -581,7 +588,7 @@ export default class AppSearchSuper {
|
|||||||
this.lazyLoadQueue.lock();
|
this.lazyLoadQueue.lock();
|
||||||
}, () => {
|
}, () => {
|
||||||
this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient
|
this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient
|
||||||
});
|
}, this.listenerSetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTransitionStart = () => {
|
private onTransitionStart = () => {
|
||||||
@ -920,7 +927,7 @@ export default class AppSearchSuper {
|
|||||||
element.dataset.peerId = '' + message.peerId;
|
element.dataset.peerId = '' + message.peerId;
|
||||||
monthContainer.items[method](element);
|
monthContainer.items[method](element);
|
||||||
|
|
||||||
if(this.selection.isSelecting) {
|
if(this.selection?.isSelecting) {
|
||||||
this.selection.toggleElementCheckbox(element, true);
|
this.selection.toggleElementCheckbox(element, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1524,7 +1531,7 @@ export default class AppSearchSuper {
|
|||||||
this.usedFromHistory[mediaTab.inputFilter] = -1;
|
this.usedFromHistory[mediaTab.inputFilter] = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this.selection.isSelecting) {
|
if(this.selection?.isSelecting) {
|
||||||
this.selection.cancelSelection();
|
this.selection.cancelSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1641,4 +1648,18 @@ export default class AppSearchSuper {
|
|||||||
|
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.listenerSetter.removeAll();
|
||||||
|
this.scrollable.destroy();
|
||||||
|
this.swipeHandler?.removeListeners();
|
||||||
|
this.selection?.cleanup();
|
||||||
|
|
||||||
|
this.scrollStartCallback = undefined;
|
||||||
|
this.onChangeTab = undefined;
|
||||||
|
this.selectTab = undefined;
|
||||||
|
this.searchContextMenu = undefined;
|
||||||
|
this.swipeHandler = undefined;
|
||||||
|
this.selection = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ export default function callVideoCanvasBlur(video: HTMLVideoElement) {
|
|||||||
canvas.width = size;
|
canvas.width = size;
|
||||||
canvas.height = size;
|
canvas.height = size;
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d', {alpha: false});
|
||||||
ctx.filter = 'blur(2px)';
|
ctx.filter = 'blur(2px)';
|
||||||
const renderFrame = () => {
|
const renderFrame = () => {
|
||||||
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height);
|
||||||
|
@ -1937,7 +1937,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onScroll = (ignoreHeavyAnimation?: boolean, scrollDimensions?: ScrollStartCallbackDimensions) => {
|
public onScroll = (ignoreHeavyAnimation?: boolean, scrollDimensions?: ScrollStartCallbackDimensions) => {
|
||||||
//return;
|
// return;
|
||||||
|
|
||||||
if(this.isHeavyAnimationInProgress) {
|
if(this.isHeavyAnimationInProgress) {
|
||||||
if(this.sliceViewportDebounced) {
|
if(this.sliceViewportDebounced) {
|
||||||
@ -2470,8 +2470,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private destroyScrollable() {
|
private destroyScrollable() {
|
||||||
this.scrollable.removeListeners();
|
this.scrollable.destroy();
|
||||||
this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
@ -2517,6 +2516,7 @@ export default class ChatBubbles {
|
|||||||
// clear messages
|
// clear messages
|
||||||
if(bubblesToo) {
|
if(bubblesToo) {
|
||||||
this.scrollable.container.textContent = '';
|
this.scrollable.container.textContent = '';
|
||||||
|
this.chatInner.textContent = '';
|
||||||
this.cleanupPlaceholders();
|
this.cleanupPlaceholders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2805,7 +2805,7 @@ export default class ChatBubbles {
|
|||||||
this.attachPlaceholderOnRender();
|
this.attachPlaceholderOnRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isTarget && this.chat.type === 'chat') {
|
if(!isTarget && this.chat.type === 'chat' && this.chat.topbar.pinnedMessage) {
|
||||||
this.chat.topbar.pinnedMessage.setCorrectIndex(0);
|
this.chat.topbar.pinnedMessage.setCorrectIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +458,11 @@ export default class Chat extends EventListenerBase<{
|
|||||||
this.cleanup(true);
|
this.cleanup(true);
|
||||||
this.bubbles.setPeer(false, peerId);
|
this.bubbles.setPeer(false, peerId);
|
||||||
this.appImManager.dispatchEvent('peer_changed', peerId);
|
this.appImManager.dispatchEvent('peer_changed', peerId);
|
||||||
|
|
||||||
|
appSidebarRight.replaceSharedMediaTab();
|
||||||
|
this.destroySharedMediaTab();
|
||||||
|
this.sharedMediaTab = undefined;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,11 +283,11 @@ export default class ChatBackgroundGradientRenderer {
|
|||||||
this._hc = document.createElement('canvas');
|
this._hc = document.createElement('canvas');
|
||||||
this._hc.width = this._width;
|
this._hc.width = this._width;
|
||||||
this._hc.height = this._height;
|
this._hc.height = this._height;
|
||||||
this._hctx = this._hc.getContext('2d');
|
this._hctx = this._hc.getContext('2d', {alpha: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._canvas = el;
|
this._canvas = el;
|
||||||
this._ctx = this._canvas.getContext('2d');
|
this._ctx = this._canvas.getContext('2d', {alpha: false});
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import safeAssign from "../../helpers/object/safeAssign";
|
|||||||
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
import setInnerHTML from "../../helpers/dom/setInnerHTML";
|
||||||
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
||||||
import { AppManagers } from "../../lib/appManagers/managers";
|
import { AppManagers } from "../../lib/appManagers/managers";
|
||||||
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class ReplyKeyboard extends DropdownHover {
|
export default class ReplyKeyboard extends DropdownHover {
|
||||||
private static BASE_CLASS = 'reply-keyboard';
|
private static BASE_CLASS = 'reply-keyboard';
|
||||||
@ -74,7 +75,7 @@ export default class ReplyKeyboard extends DropdownHover {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenerSetter.add(this.element)('click', (e) => {
|
attachClickEvent(this.element, (e) => {
|
||||||
const target = findUpClassName(e.target, 'btn');
|
const target = findUpClassName(e.target, 'btn');
|
||||||
if(!target) {
|
if(!target) {
|
||||||
return;
|
return;
|
||||||
@ -103,7 +104,7 @@ export default class ReplyKeyboard extends DropdownHover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.toggle(false);
|
this.toggle(false);
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
return super.init();
|
return super.init();
|
||||||
}
|
}
|
||||||
|
@ -533,7 +533,7 @@ export class SearchSelection extends AppSelection {
|
|||||||
|
|
||||||
private isPrivate: boolean;
|
private isPrivate: boolean;
|
||||||
|
|
||||||
constructor(private searchSuper: AppSearchSuper, managers: AppManagers) {
|
constructor(private searchSuper: AppSearchSuper, managers: AppManagers, listenerSetter: ListenerSetter) {
|
||||||
super({
|
super({
|
||||||
managers,
|
managers,
|
||||||
verifyTarget: (e, target) => !!target && this.isSelecting,
|
verifyTarget: (e, target) => !!target && this.isSelecting,
|
||||||
@ -544,7 +544,7 @@ export class SearchSelection extends AppSelection {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.isPrivate = !searchSuper.showSender;
|
this.isPrivate = !searchSuper.showSender;
|
||||||
this.attachListeners(searchSuper.container, new ListenerSetter());
|
this.attachListeners(searchSuper.container, listenerSetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {
|
/* public appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {
|
||||||
@ -615,7 +615,7 @@ export class SearchSelection extends AppSelection {
|
|||||||
this.selectionContainer.classList.add(BASE_CLASS + '-container');
|
this.selectionContainer.classList.add(BASE_CLASS + '-container');
|
||||||
|
|
||||||
const btnCancel = ButtonIcon(`close ${BASE_CLASS}-cancel`, {noRipple: true});
|
const btnCancel = ButtonIcon(`close ${BASE_CLASS}-cancel`, {noRipple: true});
|
||||||
this.listenerSetter.add(btnCancel)('click', () => this.cancelSelection(), {once: true});
|
attachClickEvent(btnCancel, () => this.cancelSelection(), {listenerSetter: this.listenerSetter, once: true});
|
||||||
|
|
||||||
this.selectionCountEl = document.createElement('div');
|
this.selectionCountEl = document.createElement('div');
|
||||||
this.selectionCountEl.classList.add(BASE_CLASS + '-count');
|
this.selectionCountEl.classList.add(BASE_CLASS + '-count');
|
||||||
|
@ -9,6 +9,7 @@ import { LangPackKey, _i18n } from "../lib/langPack";
|
|||||||
import getDeepProperty from "../helpers/object/getDeepProperty";
|
import getDeepProperty from "../helpers/object/getDeepProperty";
|
||||||
import rootScope from "../lib/rootScope";
|
import rootScope from "../lib/rootScope";
|
||||||
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
import apiManagerProxy from "../lib/mtproto/mtprotoworker";
|
||||||
|
import ListenerSetter from "../helpers/listenerSetter";
|
||||||
|
|
||||||
export type CheckboxFieldOptions = {
|
export type CheckboxFieldOptions = {
|
||||||
text?: LangPackKey,
|
text?: LangPackKey,
|
||||||
@ -23,6 +24,7 @@ export type CheckboxFieldOptions = {
|
|||||||
restriction?: boolean,
|
restriction?: boolean,
|
||||||
withRipple?: boolean,
|
withRipple?: boolean,
|
||||||
withHover?: boolean,
|
withHover?: boolean,
|
||||||
|
listenerSetter?: ListenerSetter
|
||||||
};
|
};
|
||||||
export default class CheckboxField {
|
export default class CheckboxField {
|
||||||
public input: HTMLInputElement;
|
public input: HTMLInputElement;
|
||||||
@ -57,7 +59,24 @@ export default class CheckboxField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(options.stateKey) {
|
if(options.stateKey) {
|
||||||
|
let loaded = false;
|
||||||
|
const onChange = () => {
|
||||||
|
if(!loaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: any;
|
||||||
|
if(options.stateValues) {
|
||||||
|
value = options.stateValues[input.checked ? 1 : 0];
|
||||||
|
} else {
|
||||||
|
value = input.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
rootScope.managers.appStateManager.setByKey(options.stateKey, value);
|
||||||
|
};
|
||||||
|
|
||||||
apiManagerProxy.getState().then((state) => {
|
apiManagerProxy.getState().then((state) => {
|
||||||
|
loaded = true;
|
||||||
const stateValue = getDeepProperty(state, options.stateKey);
|
const stateValue = getDeepProperty(state, options.stateKey);
|
||||||
let checked: boolean;
|
let checked: boolean;
|
||||||
if(options.stateValues) {
|
if(options.stateValues) {
|
||||||
@ -67,18 +86,10 @@ export default class CheckboxField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setValueSilently(checked);
|
this.setValueSilently(checked);
|
||||||
|
|
||||||
input.addEventListener('change', () => {
|
|
||||||
let value: any;
|
|
||||||
if(options.stateValues) {
|
|
||||||
value = options.stateValues[input.checked ? 1 : 0];
|
|
||||||
} else {
|
|
||||||
value = input.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
rootScope.managers.appStateManager.setByKey(options.stateKey, value);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(options.listenerSetter) options.listenerSetter.add(input)('change', onChange);
|
||||||
|
else input.addEventListener('change', onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
let span: HTMLSpanElement;
|
let span: HTMLSpanElement;
|
||||||
|
@ -24,6 +24,7 @@ import { AppManagers } from "../../../lib/appManagers/managers";
|
|||||||
import fixEmoji from "../../../lib/richTextProcessor/fixEmoji";
|
import fixEmoji from "../../../lib/richTextProcessor/fixEmoji";
|
||||||
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
||||||
import wrapSingleEmoji from "../../../lib/richTextProcessor/wrapSingleEmoji";
|
import wrapSingleEmoji from "../../../lib/richTextProcessor/wrapSingleEmoji";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
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) {
|
||||||
@ -258,7 +259,7 @@ export default class EmojiTab implements EmoticonsTab {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.content.addEventListener('click', this.onContentClick);
|
attachClickEvent(this.content, this.onContentClick);
|
||||||
this.init = null;
|
this.init = null;
|
||||||
|
|
||||||
rootScope.addEventListener('emoji_recent', (emoji) => {
|
rootScope.addEventListener('emoji_recent', (emoji) => {
|
||||||
|
@ -9,6 +9,7 @@ import GifsMasonry from "../../gifsMasonry";
|
|||||||
import Scrollable from "../../scrollable";
|
import Scrollable from "../../scrollable";
|
||||||
import { putPreloader } from "../../putPreloader";
|
import { putPreloader } from "../../putPreloader";
|
||||||
import { AppManagers } from "../../../lib/appManagers/managers";
|
import { AppManagers } from "../../../lib/appManagers/managers";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class GifsTab implements EmoticonsTab {
|
export default class GifsTab implements EmoticonsTab {
|
||||||
private content: HTMLElement;
|
private content: HTMLElement;
|
||||||
@ -20,7 +21,7 @@ export default class GifsTab implements EmoticonsTab {
|
|||||||
init() {
|
init() {
|
||||||
this.content = document.getElementById('content-gifs');
|
this.content = document.getElementById('content-gifs');
|
||||||
const gifsContainer = this.content.firstElementChild as HTMLDivElement;
|
const gifsContainer = this.content.firstElementChild as HTMLDivElement;
|
||||||
gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);
|
attachClickEvent(gifsContainer, EmoticonsDropdown.onMediaClick);
|
||||||
|
|
||||||
const scroll = new Scrollable(this.content, 'GIFS');
|
const scroll = new Scrollable(this.content, 'GIFS');
|
||||||
const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);
|
const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);
|
||||||
|
@ -11,6 +11,8 @@ import { fastRaf } from "../helpers/schedulers";
|
|||||||
import { FocusDirection } from "../helpers/fastSmoothScroll";
|
import { FocusDirection } from "../helpers/fastSmoothScroll";
|
||||||
import findUpAsChild from "../helpers/dom/findUpAsChild";
|
import findUpAsChild from "../helpers/dom/findUpAsChild";
|
||||||
import whichChild from "../helpers/dom/whichChild";
|
import whichChild from "../helpers/dom/whichChild";
|
||||||
|
import ListenerSetter from "../helpers/listenerSetter";
|
||||||
|
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export function horizontalMenu(
|
export function horizontalMenu(
|
||||||
tabs: HTMLElement,
|
tabs: HTMLElement,
|
||||||
@ -18,9 +20,10 @@ export function horizontalMenu(
|
|||||||
onClick?: (id: number, tabContent: HTMLDivElement, animate: boolean) => void | boolean | Promise<void | boolean>,
|
onClick?: (id: number, tabContent: HTMLDivElement, animate: boolean) => void | boolean | Promise<void | boolean>,
|
||||||
onTransitionEnd?: () => void,
|
onTransitionEnd?: () => void,
|
||||||
transitionTime = 250,
|
transitionTime = 250,
|
||||||
scrollableX?: ScrollableX
|
scrollableX?: ScrollableX,
|
||||||
|
listenerSetter?: ListenerSetter
|
||||||
) {
|
) {
|
||||||
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd);
|
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd, undefined, listenerSetter);
|
||||||
|
|
||||||
if(!tabs) {
|
if(!tabs) {
|
||||||
return selectTab;
|
return selectTab;
|
||||||
@ -109,7 +112,7 @@ export function horizontalMenu(
|
|||||||
|
|
||||||
//const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';
|
//const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';
|
||||||
const tagName = tabs.firstElementChild.tagName;
|
const tagName = tabs.firstElementChild.tagName;
|
||||||
tabs.addEventListener('click', function(e) {
|
attachClickEvent(tabs, (e) => {
|
||||||
let target = e.target as HTMLElement;
|
let target = e.target as HTMLElement;
|
||||||
|
|
||||||
target = findUpAsChild(target, tabs);
|
target = findUpAsChild(target, tabs);
|
||||||
@ -129,7 +132,7 @@ export function horizontalMenu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectTarget(target, id);
|
selectTarget(target, id);
|
||||||
});
|
}, {listenerSetter});
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,8 @@ export default class PeerProfile {
|
|||||||
const full = await this.managers.appProfileManager.getProfileByPeerId(this.peerId);
|
const full = await this.managers.appProfileManager.getProfileByPeerId(this.peerId);
|
||||||
copyTextToClipboard(full.about);
|
copyTextToClipboard(full.about);
|
||||||
toast(I18n.format('BioCopied', true));
|
toast(I18n.format('BioCopied', true));
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
this.bio.title.classList.add('pre-wrap');
|
this.bio.title.classList.add('pre-wrap');
|
||||||
@ -118,7 +119,8 @@ export default class PeerProfile {
|
|||||||
const peer: Channel | User.user = await this.managers.appPeersManager.getPeer(this.peerId);
|
const peer: Channel | User.user = await this.managers.appPeersManager.getPeer(this.peerId);
|
||||||
copyTextToClipboard('@' + peer.username);
|
copyTextToClipboard('@' + peer.username);
|
||||||
toast(I18n.format('UsernameCopied', true));
|
toast(I18n.format('UsernameCopied', true));
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
this.phone = new Row({
|
this.phone = new Row({
|
||||||
@ -129,7 +131,8 @@ export default class PeerProfile {
|
|||||||
const peer: User = await this.managers.appUsersManager.getUser(this.peerId);
|
const peer: User = await this.managers.appUsersManager.getUser(this.peerId);
|
||||||
copyTextToClipboard('+' + peer.phone);
|
copyTextToClipboard('+' + peer.phone);
|
||||||
toast(I18n.format('PhoneCopied', true));
|
toast(I18n.format('PhoneCopied', true));
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
this.link = new Row({
|
this.link = new Row({
|
||||||
@ -142,7 +145,8 @@ export default class PeerProfile {
|
|||||||
// copyTextToClipboard(chatFull.exported_invite.link);
|
// copyTextToClipboard(chatFull.exported_invite.link);
|
||||||
toast(I18n.format('LinkCopied', true));
|
toast(I18n.format('LinkCopied', true));
|
||||||
// });
|
// });
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
this.location = new Row({
|
this.location = new Row({
|
||||||
@ -164,7 +168,8 @@ export default class PeerProfile {
|
|||||||
this.notifications = new Row({
|
this.notifications = new Row({
|
||||||
checkboxField: new CheckboxField({toggle: true}),
|
checkboxField: new CheckboxField({toggle: true}),
|
||||||
titleLangKey: 'Notifications',
|
titleLangKey: 'Notifications',
|
||||||
icon: 'unmute'
|
icon: 'unmute',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
listenerSetter.add(this.notifications.checkboxField.input)('change', (e) => {
|
listenerSetter.add(this.notifications.checkboxField.input)('change', (e) => {
|
||||||
@ -457,5 +462,6 @@ export default class PeerProfile {
|
|||||||
public destroy() {
|
public destroy() {
|
||||||
this.clearSetMoreDetailsTimeout();
|
this.clearSetMoreDetailsTimeout();
|
||||||
clearInterval(this.setPeerStatusInterval);
|
clearInterval(this.setPeerStatusInterval);
|
||||||
|
this.avatars?.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,5 +409,6 @@ export default class PeerProfileAvatars {
|
|||||||
public cleanup() {
|
public cleanup() {
|
||||||
this.listenerSetter.removeAll();
|
this.listenerSetter.removeAll();
|
||||||
this.swipeHandler.removeListeners();
|
this.swipeHandler.removeListeners();
|
||||||
|
this.intersectionObserver?.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ export default class PopupReactedList extends PopupElement {
|
|||||||
|
|
||||||
const loader = loaders.get(tabContent);
|
const loader = loaders.get(tabContent);
|
||||||
loader.load();
|
loader.load();
|
||||||
});
|
}, undefined, undefined, undefined, this.listenerSetter);
|
||||||
|
|
||||||
// selectTab(hasAllReactions && hasReadParticipants ? 1 : 0, false);
|
// selectTab(hasAllReactions && hasReadParticipants ? 1 : 0, false);
|
||||||
selectTab(0, false);
|
selectTab(0, false);
|
||||||
|
@ -12,6 +12,8 @@ import RadioForm from "./radioForm";
|
|||||||
import { i18n, LangPackKey } from "../lib/langPack";
|
import { i18n, LangPackKey } from "../lib/langPack";
|
||||||
import replaceContent from "../helpers/dom/replaceContent";
|
import replaceContent from "../helpers/dom/replaceContent";
|
||||||
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
import ListenerSetter from "../helpers/listenerSetter";
|
||||||
|
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class Row {
|
export default class Row {
|
||||||
public container: HTMLElement;
|
public container: HTMLElement;
|
||||||
@ -41,7 +43,8 @@ export default class Row {
|
|||||||
navigationTab: SliderSuperTab,
|
navigationTab: SliderSuperTab,
|
||||||
havePadding: boolean,
|
havePadding: boolean,
|
||||||
noRipple: boolean,
|
noRipple: boolean,
|
||||||
noWrap: boolean
|
noWrap: boolean,
|
||||||
|
listenerSetter: ListenerSetter
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
|
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
|
||||||
this.container.classList.add('row');
|
this.container.classList.add('row');
|
||||||
@ -81,9 +84,12 @@ export default class Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!options.noCheckboxSubtitle && !isToggle) {
|
if(!options.noCheckboxSubtitle && !isToggle) {
|
||||||
this.checkboxField.input.addEventListener('change', () => {
|
const onChange = () => {
|
||||||
replaceContent(this.subtitle, i18n(this.checkboxField.input.checked ? 'Checkbox.Enabled' : 'Checkbox.Disabled'));
|
replaceContent(this.subtitle, i18n(this.checkboxField.input.checked ? 'Checkbox.Enabled' : 'Checkbox.Disabled'));
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if(options.listenerSetter) options.listenerSetter.add(this.checkboxField.input)('change', onChange);
|
||||||
|
else this.checkboxField.input.addEventListener('change', onChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,10 +157,10 @@ export default class Row {
|
|||||||
|
|
||||||
if(options.clickable || options.radioField || options.checkboxField) {
|
if(options.clickable || options.radioField || options.checkboxField) {
|
||||||
if(typeof(options.clickable) === 'function') {
|
if(typeof(options.clickable) === 'function') {
|
||||||
this.container.addEventListener('click', (e) => {
|
attachClickEvent(this.container, (e) => {
|
||||||
if(this.freezed) return;
|
if(this.freezed) return;
|
||||||
(options.clickable as any)(e);
|
(options.clickable as any)(e);
|
||||||
});
|
}, {listenerSetter: options.listenerSetter});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.container.classList.add('row-clickable', 'hover-effect');
|
this.container.classList.add('row-clickable', 'hover-effect');
|
||||||
|
@ -143,6 +143,13 @@ export class ScrollableBase {
|
|||||||
this.removeHeavyAnimationListener = undefined;
|
this.removeHeavyAnimationListener = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.removeListeners();
|
||||||
|
this.onAdditionalScroll = undefined;
|
||||||
|
this.onScrolledTop = undefined;
|
||||||
|
this.onScrolledBottom = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public append(element: HTMLElement) {
|
public append(element: HTMLElement) {
|
||||||
this.container.append(element);
|
this.container.append(element);
|
||||||
}
|
}
|
||||||
@ -160,7 +167,7 @@ export class ScrollableBase {
|
|||||||
//this.log('onScroll call', this.onScrollMeasure);
|
//this.log('onScroll call', this.onScrollMeasure);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//return;
|
// return;
|
||||||
|
|
||||||
if(this.isHeavyAnimationInProgress) {
|
if(this.isHeavyAnimationInProgress) {
|
||||||
this.cancelMeasure();
|
this.cancelMeasure();
|
||||||
@ -172,7 +179,8 @@ export class ScrollableBase {
|
|||||||
if((!this.onScrolledTop && !this.onScrolledBottom) && !this.splitUp && !this.onAdditionalScroll) return;
|
if((!this.onScrolledTop && !this.onScrolledBottom) && !this.splitUp && !this.onAdditionalScroll) return;
|
||||||
if(this.onScrollMeasure) return;
|
if(this.onScrollMeasure) return;
|
||||||
// if(this.onScrollMeasure) window.cancelAnimationFrame(this.onScrollMeasure);
|
// if(this.onScrollMeasure) window.cancelAnimationFrame(this.onScrollMeasure);
|
||||||
this.onScrollMeasure = window.requestAnimationFrame(() => {
|
// this.onScrollMeasure = window.requestAnimationFrame(() => {
|
||||||
|
this.onScrollMeasure = window.setTimeout(() => {
|
||||||
this.onScrollMeasure = 0;
|
this.onScrollMeasure = 0;
|
||||||
|
|
||||||
const scrollPosition = this.container[this.scrollProperty];
|
const scrollPosition = this.container[this.scrollProperty];
|
||||||
@ -187,12 +195,14 @@ export class ScrollableBase {
|
|||||||
if(this.checkForTriggers) {
|
if(this.checkForTriggers) {
|
||||||
this.checkForTriggers();
|
this.checkForTriggers();
|
||||||
}
|
}
|
||||||
});
|
// });
|
||||||
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
public cancelMeasure() {
|
public cancelMeasure() {
|
||||||
if(this.onScrollMeasure) {
|
if(this.onScrollMeasure) {
|
||||||
window.cancelAnimationFrame(this.onScrollMeasure);
|
// window.cancelAnimationFrame(this.onScrollMeasure);
|
||||||
|
clearTimeout(this.onScrollMeasure);
|
||||||
this.onScrollMeasure = 0;
|
this.onScrollMeasure = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ export default class AppAutoDownloadFileTab extends SliderSuperTabEventable {
|
|||||||
this.managers.appStateManager.setByKey('settings.autoDownloadNew.file_size_max', sizeMax);
|
this.managers.appStateManager.setByKey('settings.autoDownloadNew.file_size_max', sizeMax);
|
||||||
}, 200, false, true);
|
}, 200, false, true);
|
||||||
|
|
||||||
const section = autoDownloadPeerTypeSection('file', 'AutoDownloadFilesTitle');
|
const section = autoDownloadPeerTypeSection('file', 'AutoDownloadFilesTitle', this.listenerSetter);
|
||||||
|
|
||||||
const MIN = 512 * 1024;
|
const MIN = 512 * 1024;
|
||||||
// const MAX = 2 * 1024 * 1024 * 1024;
|
// const MAX = 2 * 1024 * 1024 * 1024;
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { SettingSection } from "../..";
|
import { SettingSection } from "../..";
|
||||||
|
import ListenerSetter from "../../../../helpers/listenerSetter";
|
||||||
import { LangPackKey } from "../../../../lib/langPack";
|
import { LangPackKey } from "../../../../lib/langPack";
|
||||||
import CheckboxField from "../../../checkboxField";
|
import CheckboxField from "../../../checkboxField";
|
||||||
import { SliderSuperTabEventable } from "../../../sliderTab";
|
import { SliderSuperTabEventable } from "../../../sliderTab";
|
||||||
|
|
||||||
export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', title: LangPackKey) {
|
export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', title: LangPackKey, listenerSetter: ListenerSetter) {
|
||||||
const section = new SettingSection({name: title});
|
const section = new SettingSection({name: title});
|
||||||
|
|
||||||
const key = 'settings.autoDownload.' + type + '.';
|
const key = 'settings.autoDownload.' + type + '.';
|
||||||
@ -17,25 +18,29 @@ export function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', ti
|
|||||||
text: 'AutodownloadContacts',
|
text: 'AutodownloadContacts',
|
||||||
name: 'contacts',
|
name: 'contacts',
|
||||||
stateKey: key + 'contacts',
|
stateKey: key + 'contacts',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter
|
||||||
});
|
});
|
||||||
const privateCheckboxField = new CheckboxField({
|
const privateCheckboxField = new CheckboxField({
|
||||||
text: 'AutodownloadPrivateChats',
|
text: 'AutodownloadPrivateChats',
|
||||||
name: 'private',
|
name: 'private',
|
||||||
stateKey: key + 'private',
|
stateKey: key + 'private',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter
|
||||||
});
|
});
|
||||||
const groupsCheckboxField = new CheckboxField({
|
const groupsCheckboxField = new CheckboxField({
|
||||||
text: 'AutodownloadGroupChats',
|
text: 'AutodownloadGroupChats',
|
||||||
name: 'groups',
|
name: 'groups',
|
||||||
stateKey: key + 'groups',
|
stateKey: key + 'groups',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter
|
||||||
});
|
});
|
||||||
const channelsCheckboxField = new CheckboxField({
|
const channelsCheckboxField = new CheckboxField({
|
||||||
text: 'AutodownloadChannels',
|
text: 'AutodownloadChannels',
|
||||||
name: 'channels',
|
name: 'channels',
|
||||||
stateKey: key + 'channels',
|
stateKey: key + 'channels',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
section.content.append(
|
section.content.append(
|
||||||
@ -53,7 +58,7 @@ export default class AppAutoDownloadPhotoTab extends SliderSuperTabEventable {
|
|||||||
this.header.classList.add('with-border');
|
this.header.classList.add('with-border');
|
||||||
this.setTitle('AutoDownloadPhotos');
|
this.setTitle('AutoDownloadPhotos');
|
||||||
|
|
||||||
const section = autoDownloadPeerTypeSection('photo', 'AutoDownloadPhotosTitle');
|
const section = autoDownloadPeerTypeSection('photo', 'AutoDownloadPhotosTitle', this.listenerSetter);
|
||||||
this.scrollable.append(section.container);
|
this.scrollable.append(section.container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ export default class AppAutoDownloadVideoTab extends SliderSuperTabEventable {
|
|||||||
this.header.classList.add('with-border');
|
this.header.classList.add('with-border');
|
||||||
this.setTitle('AutoDownloadVideos');
|
this.setTitle('AutoDownloadVideos');
|
||||||
|
|
||||||
const section = autoDownloadPeerTypeSection('video', 'AutoDownloadVideosTitle');
|
const section = autoDownloadPeerTypeSection('video', 'AutoDownloadVideosTitle', this.listenerSetter);
|
||||||
this.scrollable.append(section.container);
|
this.scrollable.append(section.container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
|||||||
subtitle: '',
|
subtitle: '',
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
openTab(AppAutoDownloadPhotoTab);
|
openTab(AppAutoDownloadPhotoTab);
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const videoRow = new Row({
|
const videoRow = new Row({
|
||||||
@ -83,7 +84,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
|||||||
subtitle: '',
|
subtitle: '',
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
openTab(AppAutoDownloadVideoTab);
|
openTab(AppAutoDownloadVideoTab);
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileRow = new Row({
|
const fileRow = new Row({
|
||||||
@ -91,7 +93,8 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
|||||||
subtitle: '',
|
subtitle: '',
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
openTab(AppAutoDownloadFileTab);
|
openTab(AppAutoDownloadFileTab);
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const resetButton = Button('btn-primary btn-transparent primary', {icon: 'delete', text: 'ResetAutomaticMediaDownload'});
|
const resetButton = Button('btn-primary btn-transparent primary', {icon: 'delete', text: 'ResetAutomaticMediaDownload'});
|
||||||
@ -154,13 +157,15 @@ export default class AppDataAndStorageTab extends SliderSuperTabEventable {
|
|||||||
text: 'AutoplayGIF',
|
text: 'AutoplayGIF',
|
||||||
name: 'gifs',
|
name: 'gifs',
|
||||||
stateKey: 'settings.autoPlay.gifs',
|
stateKey: 'settings.autoPlay.gifs',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
const videosCheckboxField = new CheckboxField({
|
const videosCheckboxField = new CheckboxField({
|
||||||
text: 'AutoplayVideo',
|
text: 'AutoplayVideo',
|
||||||
name: 'videos',
|
name: 'videos',
|
||||||
stateKey: 'settings.autoPlay.videos',
|
stateKey: 'settings.autoPlay.videos',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
section.content.append(gifsCheckboxField.label, videosCheckboxField.label);
|
section.content.append(gifsCheckboxField.label, videosCheckboxField.label);
|
||||||
|
@ -24,6 +24,7 @@ import deepEqual from "../../../helpers/object/deepEqual";
|
|||||||
import documentFragmentToHTML from "../../../helpers/dom/documentFragmentToHTML";
|
import documentFragmentToHTML from "../../../helpers/dom/documentFragmentToHTML";
|
||||||
import wrapDraftText from "../../../lib/richTextProcessor/wrapDraftText";
|
import wrapDraftText from "../../../lib/richTextProcessor/wrapDraftText";
|
||||||
import filterAsync from "../../../helpers/array/filterAsync";
|
import filterAsync from "../../../helpers/array/filterAsync";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
const MAX_FOLDER_NAME_LENGTH = 12;
|
const MAX_FOLDER_NAME_LENGTH = 12;
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
|||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.menuBtn = ButtonMenuToggle({}, 'bottom-left', [deleteFolderButton]);
|
this.menuBtn = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', [deleteFolderButton]);
|
||||||
this.menuBtn.classList.add('hide');
|
this.menuBtn.classList.add('hide');
|
||||||
|
|
||||||
this.header.append(this.confirmBtn, this.menuBtn);
|
this.header.append(this.confirmBtn, this.menuBtn);
|
||||||
@ -174,15 +175,15 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
|||||||
const includedFlagsContainer = this.includePeerIds.container.querySelector('.folder-categories');
|
const includedFlagsContainer = this.includePeerIds.container.querySelector('.folder-categories');
|
||||||
const excludedFlagsContainer = this.excludePeerIds.container.querySelector('.folder-categories');
|
const excludedFlagsContainer = this.excludePeerIds.container.querySelector('.folder-categories');
|
||||||
|
|
||||||
includedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
attachClickEvent(includedFlagsContainer.querySelector('.btn') as HTMLElement, () => {
|
||||||
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'included', this);
|
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'included', this);
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
excludedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
attachClickEvent(excludedFlagsContainer.querySelector('.btn') as HTMLElement, () => {
|
||||||
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'excluded', this);
|
this.slider.createTab(AppIncludedChatsTab).open(this.filter, 'excluded', this);
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
this.confirmBtn.addEventListener('click', () => {
|
attachClickEvent(this.confirmBtn, () => {
|
||||||
if(this.nameInputField.input.classList.contains('error')) {
|
if(this.nameInputField.input.classList.contains('error')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -222,9 +223,9 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
|||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.confirmBtn.removeAttribute('disabled');
|
this.confirmBtn.removeAttribute('disabled');
|
||||||
});
|
});
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
this.nameInputField.input.addEventListener('input', () => {
|
this.listenerSetter.add(this.nameInputField.input)('input', () => {
|
||||||
this.filter.title = this.nameInputField.value;
|
this.filter.title = this.nameInputField.value;
|
||||||
this.editCheckForChange();
|
this.editCheckForChange();
|
||||||
});
|
});
|
||||||
@ -336,7 +337,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
|||||||
const content = section.generateContentElement();
|
const content = section.generateContentElement();
|
||||||
showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});
|
showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});
|
||||||
showMore.classList.add('load-more', 'rp-overflow');
|
showMore.classList.add('load-more', 'rp-overflow');
|
||||||
showMore.addEventListener('click', () => renderMore(20));
|
attachClickEvent(showMore, () => renderMore(20), {listenerSetter: this.listenerSetter});
|
||||||
showMore.append(i18n('FilterShowMoreChats', [peers.length]));
|
showMore.append(i18n('FilterShowMoreChats', [peers.length]));
|
||||||
|
|
||||||
content.append(showMore);
|
content.append(showMore);
|
||||||
|
@ -111,7 +111,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
|||||||
text: 'EnableAnimations',
|
text: 'EnableAnimations',
|
||||||
name: 'animations',
|
name: 'animations',
|
||||||
stateKey: 'settings.animationsEnabled',
|
stateKey: 'settings.animationsEnabled',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
container.append(range.container, chatBackgroundButton, animationsCheckboxField.label);
|
container.append(range.container, chatBackgroundButton, animationsCheckboxField.label);
|
||||||
@ -231,13 +232,15 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
|||||||
text: 'GeneralSettings.EmojiPrediction',
|
text: 'GeneralSettings.EmojiPrediction',
|
||||||
name: 'suggest-emoji',
|
name: 'suggest-emoji',
|
||||||
stateKey: 'settings.emoji.suggest',
|
stateKey: 'settings.emoji.suggest',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
const bigCheckboxField = new CheckboxField({
|
const bigCheckboxField = new CheckboxField({
|
||||||
text: 'GeneralSettings.BigEmoji',
|
text: 'GeneralSettings.BigEmoji',
|
||||||
name: 'emoji-big',
|
name: 'emoji-big',
|
||||||
stateKey: 'settings.emoji.big',
|
stateKey: 'settings.emoji.big',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
container.append(suggestCheckboxField.label, bigCheckboxField.label);
|
container.append(suggestCheckboxField.label, bigCheckboxField.label);
|
||||||
@ -251,7 +254,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
|||||||
havePadding: true,
|
havePadding: true,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppQuickReactionTab).open();
|
this.slider.createTab(AppQuickReactionTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderQuickReaction = () => {
|
const renderQuickReaction = () => {
|
||||||
@ -272,13 +276,15 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
|||||||
text: 'Stickers.SuggestStickers',
|
text: 'Stickers.SuggestStickers',
|
||||||
name: 'suggest',
|
name: 'suggest',
|
||||||
stateKey: 'settings.stickers.suggest',
|
stateKey: 'settings.stickers.suggest',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
const loopCheckboxField = new CheckboxField({
|
const loopCheckboxField = new CheckboxField({
|
||||||
text: 'InstalledStickers.LoopAnimated',
|
text: 'InstalledStickers.LoopAnimated',
|
||||||
name: 'loop',
|
name: 'loop',
|
||||||
stateKey: 'settings.stickers.loop',
|
stateKey: 'settings.stickers.loop',
|
||||||
withRipple: true
|
withRipple: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const stickerSets: {[id: string]: Row} = {};
|
const stickerSets: {[id: string]: Row} = {};
|
||||||
@ -294,7 +300,8 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
|
|||||||
havePadding: true,
|
havePadding: true,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
new PopupStickers({id: stickerSet.id, access_hash: stickerSet.access_hash}).show();
|
new PopupStickers({id: stickerSet.id, access_hash: stickerSet.access_hash}).show();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
stickerSets[stickerSet.id] = row;
|
stickerSets[stickerSet.id] = row;
|
||||||
|
@ -19,6 +19,7 @@ import copy from "../../../helpers/object/copy";
|
|||||||
import forEachReverse from "../../../helpers/array/forEachReverse";
|
import forEachReverse from "../../../helpers/array/forEachReverse";
|
||||||
import setInnerHTML from "../../../helpers/dom/setInnerHTML";
|
import setInnerHTML from "../../../helpers/dom/setInnerHTML";
|
||||||
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class AppIncludedChatsTab extends SliderSuperTab {
|
export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||||
private editFolderTab: AppEditFolderTab;
|
private editFolderTab: AppEditFolderTab;
|
||||||
@ -39,7 +40,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.header.append(this.confirmBtn);
|
this.header.append(this.confirmBtn);
|
||||||
|
|
||||||
this.confirmBtn.addEventListener('click', async() => {
|
attachClickEvent(this.confirmBtn, async() => {
|
||||||
const selected = this.selector.getSelected();
|
const selected = this.selector.getSelected();
|
||||||
|
|
||||||
//this.filter.pFlags = {};
|
//this.filter.pFlags = {};
|
||||||
@ -103,7 +104,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.editFolderTab.setFilter(this.filter, false);
|
this.editFolderTab.setFilter(this.filter, false);
|
||||||
this.close();
|
this.close();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
this.dialogsByFilters = new Map();
|
this.dialogsByFilters = new Map();
|
||||||
return this.managers.filtersStorage.getDialogFilters().then(async(filters) => {
|
return this.managers.filtersStorage.getDialogFilters().then(async(filters) => {
|
||||||
|
@ -13,6 +13,7 @@ import AppAddMembersTab from "./addMembers";
|
|||||||
import { _i18n } from "../../../lib/langPack";
|
import { _i18n } from "../../../lib/langPack";
|
||||||
import ButtonCorner from "../../buttonCorner";
|
import ButtonCorner from "../../buttonCorner";
|
||||||
import appImManager from "../../../lib/appManagers/appImManager";
|
import appImManager from "../../../lib/appManagers/appImManager";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class AppNewChannelTab extends SliderSuperTab {
|
export default class AppNewChannelTab extends SliderSuperTab {
|
||||||
private uploadAvatar: () => Promise<InputFile> = null;
|
private uploadAvatar: () => Promise<InputFile> = null;
|
||||||
@ -60,7 +61,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
||||||
|
|
||||||
this.nextBtn.addEventListener('click', () => {
|
attachClickEvent(this.nextBtn, () => {
|
||||||
const title = this.channelNameInputField.value;
|
const title = this.channelNameInputField.value;
|
||||||
const about = this.channelDescriptionInputField.value;
|
const about = this.channelDescriptionInputField.value;
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
this.content.append(this.nextBtn);
|
this.content.append(this.nextBtn);
|
||||||
section.content.append(this.avatarEdit.container, inputWrapper);
|
section.content.append(this.avatarEdit.container, inputWrapper);
|
||||||
|
@ -14,6 +14,7 @@ import I18n from "../../../lib/langPack";
|
|||||||
import ButtonCorner from "../../buttonCorner";
|
import ButtonCorner from "../../buttonCorner";
|
||||||
import getUserStatusString from "../../wrappers/getUserStatusString";
|
import getUserStatusString from "../../wrappers/getUserStatusString";
|
||||||
import appImManager from "../../../lib/appManagers/appImManager";
|
import appImManager from "../../../lib/appManagers/appImManager";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
|
|
||||||
interface OpenStreetMapInterface {
|
interface OpenStreetMapInterface {
|
||||||
place_id?: number;
|
place_id?: number;
|
||||||
@ -68,7 +69,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
|||||||
this.groupLocationInputField.container
|
this.groupLocationInputField.container
|
||||||
);
|
);
|
||||||
|
|
||||||
this.groupNameInputField.input.addEventListener('input', () => {
|
this.listenerSetter.add(this.groupNameInputField.input)('input', () => {
|
||||||
const value = this.groupNameInputField.value;
|
const value = this.groupNameInputField.value;
|
||||||
let valueCheck = !!value.length && !this.groupNameInputField.input.classList.contains('error');
|
let valueCheck = !!value.length && !this.groupNameInputField.input.classList.contains('error');
|
||||||
if(this.isGeoChat) valueCheck = valueCheck && !!this.userLocationCoords && !!this.userLocationAddress;
|
if(this.isGeoChat) valueCheck = valueCheck && !!this.userLocationCoords && !!this.userLocationAddress;
|
||||||
@ -77,7 +78,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
|
||||||
|
|
||||||
this.nextBtn.addEventListener('click', () => {
|
attachClickEvent(this.nextBtn, () => {
|
||||||
const title = this.groupNameInputField.value;
|
const title = this.groupNameInputField.value;
|
||||||
|
|
||||||
let promise: Promise<ChatId>;
|
let promise: Promise<ChatId>;
|
||||||
@ -128,7 +129,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
|||||||
|
|
||||||
appImManager.setInnerPeer({peerId: chatId.toPeerId(true)});
|
appImManager.setInnerPeer({peerId: chatId.toPeerId(true)});
|
||||||
});
|
});
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
const chatsSection = new SettingSection({
|
const chatsSection = new SettingSection({
|
||||||
name: 'Members',
|
name: 'Members',
|
||||||
|
@ -36,11 +36,13 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
|
|||||||
const enabledRow = new Row({
|
const enabledRow = new Row({
|
||||||
checkboxField: new CheckboxField({text: options.typeText, checked: true}),
|
checkboxField: new CheckboxField({text: options.typeText, checked: true}),
|
||||||
subtitleLangKey: 'Loading',
|
subtitleLangKey: 'Loading',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const previewEnabledRow = new Row({
|
const previewEnabledRow = new Row({
|
||||||
checkboxField: new CheckboxField({text: 'MessagePreview', checked: true}),
|
checkboxField: new CheckboxField({text: 'MessagePreview', checked: true}),
|
||||||
subtitleLangKey: 'Loading',
|
subtitleLangKey: 'Loading',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
section.content.append(enabledRow.container, previewEnabledRow.container);
|
section.content.append(enabledRow.container, previewEnabledRow.container);
|
||||||
@ -112,11 +114,13 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
|
|||||||
const contactsSignUpRow = new Row({
|
const contactsSignUpRow = new Row({
|
||||||
checkboxField: new CheckboxField({text: 'ContactJoined', checked: true}),
|
checkboxField: new CheckboxField({text: 'ContactJoined', checked: true}),
|
||||||
subtitleLangKey: 'Loading',
|
subtitleLangKey: 'Loading',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const soundRow = new Row({
|
const soundRow = new Row({
|
||||||
checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound'}),
|
checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound', listenerSetter: this.listenerSetter}),
|
||||||
subtitleLangKey: 'Loading',
|
subtitleLangKey: 'Loading',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
apiManagerProxy.getState().then((state) => {
|
apiManagerProxy.getState().then((state) => {
|
||||||
|
@ -56,7 +56,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
const tab = this.slider.createTab(AppBlockedUsersTab);
|
const tab = this.slider.createTab(AppBlockedUsersTab);
|
||||||
tab.peerIds = blockedPeerIds;
|
tab.peerIds = blockedPeerIds;
|
||||||
tab.open();
|
tab.open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
blockedUsersRow.freezed = true;
|
blockedUsersRow.freezed = true;
|
||||||
|
|
||||||
@ -81,7 +82,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
|
|
||||||
tab.state = passwordState;
|
tab.state = passwordState;
|
||||||
tab.open();
|
tab.open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
};
|
};
|
||||||
|
|
||||||
const twoFactorRow = new Row(twoFactorRowOptions);
|
const twoFactorRow = new Row(twoFactorRowOptions);
|
||||||
@ -98,7 +100,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
this.updateActiveSessions();
|
this.updateActiveSessions();
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
tab.open();
|
tab.open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
activeSessionsRow.freezed = true;
|
activeSessionsRow.freezed = true;
|
||||||
|
|
||||||
@ -157,7 +160,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyPhoneNumberTab).open();
|
this.slider.createTab(AppPrivacyPhoneNumberTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({
|
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({
|
||||||
@ -165,7 +169,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyLastSeenTab).open();
|
this.slider.createTab(AppPrivacyLastSeenTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({
|
const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({
|
||||||
@ -173,7 +178,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyProfilePhotoTab).open();
|
this.slider.createTab(AppPrivacyProfilePhotoTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({
|
const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({
|
||||||
@ -181,7 +187,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyCallsTab).open();
|
this.slider.createTab(AppPrivacyCallsTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({
|
const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({
|
||||||
@ -189,7 +196,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyForwardMessagesTab).open();
|
this.slider.createTab(AppPrivacyForwardMessagesTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({
|
const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({
|
||||||
@ -197,7 +205,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||||||
subtitleLangKey: SUBTITLE,
|
subtitleLangKey: SUBTITLE,
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppPrivacyAddToGroupsTab).open();
|
this.slider.createTab(AppPrivacyAddToGroupsTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatePrivacyRow = (key: InputPrivacyKey['_']) => {
|
const updatePrivacyRow = (key: InputPrivacyKey['_']) => {
|
||||||
|
@ -27,6 +27,7 @@ import { SliderSuperTabConstructable } from "../../sliderTab";
|
|||||||
import PopupAvatar from "../../popups/avatar";
|
import PopupAvatar from "../../popups/avatar";
|
||||||
import { AccountAuthorizations, Authorization } from "../../../layer";
|
import { AccountAuthorizations, Authorization } from "../../../layer";
|
||||||
import PopupElement from "../../popups";
|
import PopupElement from "../../popups";
|
||||||
|
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||||
//import AppMediaViewer from "../../appMediaViewerNew";
|
//import AppMediaViewer from "../../appMediaViewerNew";
|
||||||
|
|
||||||
export default class AppSettingsTab extends SliderSuperTab {
|
export default class AppSettingsTab extends SliderSuperTab {
|
||||||
@ -50,7 +51,7 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
this.container.classList.add('settings-container');
|
this.container.classList.add('settings-container');
|
||||||
this.setTitle('Settings');
|
this.setTitle('Settings');
|
||||||
|
|
||||||
const btnMenu = ButtonMenuToggle({}, 'bottom-left', [{
|
const btnMenu = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', [{
|
||||||
icon: 'logout',
|
icon: 'logout',
|
||||||
text: 'EditAccount.Logout',
|
text: 'EditAccount.Logout',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@ -78,14 +79,14 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
const fillPromise = this.profile.fillProfileElements();
|
const fillPromise = this.profile.fillProfileElements();
|
||||||
|
|
||||||
const changeAvatarBtn = Button('btn-circle btn-corner z-depth-1 profile-change-avatar', {icon: 'cameraadd'});
|
const changeAvatarBtn = Button('btn-circle btn-corner z-depth-1 profile-change-avatar', {icon: 'cameraadd'});
|
||||||
changeAvatarBtn.addEventListener('click', () => {
|
attachClickEvent(changeAvatarBtn, () => {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
PopupElement.createPopup(PopupAvatar).open(canvas, (upload) => {
|
PopupElement.createPopup(PopupAvatar).open(canvas, (upload) => {
|
||||||
upload().then((inputFile) => {
|
upload().then((inputFile) => {
|
||||||
return this.managers.appProfileManager.uploadProfilePhoto(inputFile);
|
return this.managers.appProfileManager.uploadProfilePhoto(inputFile);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
this.profile.element.lastElementChild.firstElementChild.append(changeAvatarBtn);
|
this.profile.element.lastElementChild.firstElementChild.append(changeAvatarBtn);
|
||||||
|
|
||||||
const updateChangeAvatarBtn = async() => {
|
const updateChangeAvatarBtn = async() => {
|
||||||
@ -160,7 +161,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(tabConstructor).open();
|
this.slider.createTab(tabConstructor).open();
|
||||||
// new tabConstructor(this.slider, true).open();
|
// new tabConstructor(this.slider, true).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -181,7 +183,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
this.updateActiveSessions(true);
|
this.updateActiveSessions(true);
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
tab.open();
|
tab.open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
}),
|
}),
|
||||||
|
|
||||||
this.languageRow = new Row({
|
this.languageRow = new Row({
|
||||||
@ -190,7 +193,8 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
icon: 'language',
|
icon: 'language',
|
||||||
clickable: () => {
|
clickable: () => {
|
||||||
this.slider.createTab(AppLanguageTab).open();
|
this.slider.createTab(AppLanguageTab).open();
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -204,10 +208,10 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.scrollable.append(this.profile.element/* profileSection.container */, buttonsSection.container);
|
this.scrollable.append(this.profile.element/* profileSection.container */, buttonsSection.container);
|
||||||
|
|
||||||
this.buttons.edit.addEventListener('click', () => {
|
attachClickEvent(this.buttons.edit, () => {
|
||||||
const tab = this.slider.createTab(AppEditProfileTab);
|
const tab = this.slider.createTab(AppEditProfileTab);
|
||||||
tab.open();
|
tab.open();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
lottieLoader.loadLottieWorkers();
|
lottieLoader.loadLottieWorkers();
|
||||||
|
|
||||||
@ -235,4 +239,9 @@ export default class AppSettingsTab extends SliderSuperTab {
|
|||||||
this.devicesRow.titleRight.textContent = '' + this.authorizations.length;
|
this.devicesRow.titleRight.textContent = '' + this.authorizations.length;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onCloseAfterTimeout() {
|
||||||
|
this.profile.destroy();
|
||||||
|
return super.onCloseAfterTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,19 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
public replaceSharedMediaTab(tab: AppSharedMediaTab) {
|
public replaceSharedMediaTab(tab?: AppSharedMediaTab) {
|
||||||
let previousTab = this.sharedMediaTab;
|
let previousTab = this.sharedMediaTab;
|
||||||
if(previousTab) {
|
if(previousTab) {
|
||||||
const wasActive = previousTab.container.classList.contains('active');
|
if(tab) {
|
||||||
if(wasActive) {
|
const wasActive = previousTab.container.classList.contains('active');
|
||||||
tab.container.classList.add('active');
|
if(wasActive) {
|
||||||
|
tab.container.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
previousTab.container.replaceWith(tab.container);
|
||||||
|
} else {
|
||||||
|
previousTab.container.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
previousTab.container.replaceWith(tab.container);
|
|
||||||
} else {
|
} else {
|
||||||
this.tabsContainer.prepend(tab.container);
|
this.tabsContainer.prepend(tab.container);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ export default class AppChatReactionsTab extends SliderSuperTabEventable {
|
|||||||
const toggleCheckboxField = new CheckboxField({toggle: true, checked: !!enabledReactions.size});
|
const toggleCheckboxField = new CheckboxField({toggle: true, checked: !!enabledReactions.size});
|
||||||
const toggleRow = new Row({
|
const toggleRow = new Row({
|
||||||
checkboxField: toggleCheckboxField,
|
checkboxField: toggleCheckboxField,
|
||||||
titleLangKey: 'EnableReactions'
|
titleLangKey: 'EnableReactions',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
toggleSection.content.append(toggleRow.container);
|
toggleSection.content.append(toggleRow.container);
|
||||||
@ -65,7 +66,8 @@ export default class AppChatReactionsTab extends SliderSuperTabEventable {
|
|||||||
const row = new Row({
|
const row = new Row({
|
||||||
checkboxField,
|
checkboxField,
|
||||||
title: availableReaction.title,
|
title: availableReaction.title,
|
||||||
havePadding: true
|
havePadding: true,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapStickerToRow({
|
wrapStickerToRow({
|
||||||
|
@ -78,7 +78,8 @@ export default class AppChatTypeTab extends SliderSuperTabEventable {
|
|||||||
clickable: () => {
|
clickable: () => {
|
||||||
copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);
|
copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);
|
||||||
toast(I18n.format('LinkCopied', true));
|
toast(I18n.format('LinkCopied', true));
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});
|
const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});
|
||||||
|
@ -113,7 +113,8 @@ export default class AppEditChatTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.listenerSetter.add(tab.eventListener)('destroy', setChatTypeSubtitle);
|
this.listenerSetter.add(tab.eventListener)('destroy', setChatTypeSubtitle);
|
||||||
},
|
},
|
||||||
icon: 'lock'
|
icon: 'lock',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const setChatTypeSubtitle = () => {
|
const setChatTypeSubtitle = () => {
|
||||||
@ -147,7 +148,8 @@ export default class AppEditChatTab extends SliderSuperTab {
|
|||||||
|
|
||||||
this.listenerSetter.add(tab.eventListener)('destroy', setReactionsLength);
|
this.listenerSetter.add(tab.eventListener)('destroy', setReactionsLength);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableReactions = await this.managers.appReactionsManager.getAvailableReactions();
|
const availableReactions = await this.managers.appReactionsManager.getAvailableReactions();
|
||||||
@ -182,6 +184,7 @@ export default class AppEditChatTab extends SliderSuperTab {
|
|||||||
tab.open();
|
tab.open();
|
||||||
},
|
},
|
||||||
icon: 'permissions',
|
icon: 'permissions',
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const setPermissionsLength = async() => {
|
const setPermissionsLength = async() => {
|
||||||
|
@ -117,7 +117,8 @@ export default class AppEditContactTab extends SliderSuperTab {
|
|||||||
|
|
||||||
if(!isNew) {
|
if(!isNew) {
|
||||||
const notificationsRow = new Row({
|
const notificationsRow = new Row({
|
||||||
checkboxField: notificationsCheckboxField
|
checkboxField: notificationsCheckboxField,
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const enabled = !(await this.managers.appNotificationsManager.isPeerLocalMuted(this.peerId, false));
|
const enabled = !(await this.managers.appNotificationsManager.isPeerLocalMuted(this.peerId, false));
|
||||||
|
@ -185,7 +185,8 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
|
|||||||
placeholder: 'ExceptionModal.Search.Placeholder',
|
placeholder: 'ExceptionModal.Search.Placeholder',
|
||||||
peerId: -this.chatId,
|
peerId: -this.chatId,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
listenerSetter: this.listenerSetter
|
||||||
});
|
});
|
||||||
|
|
||||||
const openPermissions = async(peerId: PeerId) => {
|
const openPermissions = async(peerId: PeerId) => {
|
||||||
|
@ -85,7 +85,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
|
|
||||||
// * body
|
// * body
|
||||||
|
|
||||||
this.profile = new PeerProfile(this.managers, this.scrollable);
|
this.profile = new PeerProfile(this.managers, this.scrollable, this.listenerSetter);
|
||||||
this.profile.init();
|
this.profile.init();
|
||||||
|
|
||||||
this.scrollable.append(this.profile.element);
|
this.scrollable.append(this.profile.element);
|
||||||
@ -124,7 +124,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
} else if(!this.scrollable.isHeavyAnimationInProgress) {
|
} else if(!this.scrollable.isHeavyAnimationInProgress) {
|
||||||
this.slider.onCloseBtnClick();
|
this.slider.onCloseBtnClick();
|
||||||
}
|
}
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
attachClickEvent(this.editBtn, (e) => {
|
attachClickEvent(this.editBtn, (e) => {
|
||||||
let tab: AppEditChatTab | AppEditContactTab;
|
let tab: AppEditChatTab | AppEditContactTab;
|
||||||
@ -143,7 +143,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
|
|
||||||
tab.open();
|
tab.open();
|
||||||
}
|
}
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
this.listenerSetter.add(rootScope)('contacts_update', (userId) => {
|
this.listenerSetter.add(rootScope)('contacts_update', (userId) => {
|
||||||
if(this.peerId === userId) {
|
if(this.peerId === userId) {
|
||||||
@ -217,7 +217,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});
|
const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});
|
||||||
this.content.append(btnAddMembers);
|
this.content.append(btnAddMembers);
|
||||||
|
|
||||||
btnAddMembers.addEventListener('click', async() => {
|
attachClickEvent(btnAddMembers, async() => {
|
||||||
const peerId = this.peerId;
|
const peerId = this.peerId;
|
||||||
const id = this.peerId.toChatId();
|
const id = this.peerId.toChatId();
|
||||||
const isChannel = await this.managers.appChatsManager.isChannel(id);
|
const isChannel = await this.managers.appChatsManager.isChannel(id);
|
||||||
@ -315,7 +315,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
//console.log('construct shared media time:', performance.now() - perf);
|
//console.log('construct shared media time:', performance.now() - perf);
|
||||||
}
|
}
|
||||||
@ -458,5 +458,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
this.destroyable = true;
|
this.destroyable = true;
|
||||||
this.onCloseAfterTimeout();
|
this.onCloseAfterTimeout();
|
||||||
this.profile.destroy();
|
this.profile.destroy();
|
||||||
|
this.searchSuper.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ const SetTransition = (
|
|||||||
clearTimeout(+timeout);
|
clearTimeout(+timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// useRafs = undefined;
|
||||||
|
// duration = 0;
|
||||||
|
|
||||||
if(raf !== undefined) {
|
if(raf !== undefined) {
|
||||||
window.cancelAnimationFrame(+raf);
|
window.cancelAnimationFrame(+raf);
|
||||||
if(!useRafs) {
|
if(!useRafs) {
|
||||||
|
@ -152,7 +152,7 @@ export default class SidebarSlider {
|
|||||||
if(tab.onCloseAfterTimeout) {
|
if(tab.onCloseAfterTimeout) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
tab.onCloseAfterTimeout();
|
tab.onCloseAfterTimeout();
|
||||||
}, TRANSITION_TIME);
|
}, TRANSITION_TIME + 30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ export default class SliderSuperTab implements SliderTab {
|
|||||||
if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !
|
if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !
|
||||||
this.slider.tabs.delete(this);
|
this.slider.tabs.delete(this);
|
||||||
this.container.remove();
|
this.container.remove();
|
||||||
|
this.scrollable.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.listenerSetter) {
|
if(this.listenerSetter) {
|
||||||
|
@ -9,6 +9,7 @@ import deferredPromise, { CancellablePromise } from "../helpers/cancellablePromi
|
|||||||
import { dispatchHeavyAnimationEvent } from "../hooks/useHeavyAnimationCheck";
|
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";
|
||||||
|
|
||||||
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
|
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
|
||||||
const width = prevTabContent.getBoundingClientRect().width;
|
const width = prevTabContent.getBoundingClientRect().width;
|
||||||
@ -84,7 +85,8 @@ export const TransitionSlider = (
|
|||||||
type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */,
|
type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */,
|
||||||
transitionTime: number,
|
transitionTime: number,
|
||||||
onTransitionEnd?: (id: number) => void,
|
onTransitionEnd?: (id: number) => void,
|
||||||
isHeavy = true
|
isHeavy = true,
|
||||||
|
listenerSetter?: ListenerSetter
|
||||||
) => {
|
) => {
|
||||||
let animationFunction: TransitionFunction = null;
|
let animationFunction: TransitionFunction = null;
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ export const TransitionSlider = (
|
|||||||
|
|
||||||
content.dataset.animation = type;
|
content.dataset.animation = type;
|
||||||
|
|
||||||
return Transition(content, animationFunction, transitionTime, onTransitionEnd, isHeavy);
|
return Transition(content, animationFunction, transitionTime, onTransitionEnd, isHeavy, undefined, undefined, listenerSetter);
|
||||||
};
|
};
|
||||||
|
|
||||||
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
||||||
@ -113,7 +115,8 @@ const Transition = (
|
|||||||
onTransitionEnd?: (id: number) => void,
|
onTransitionEnd?: (id: number) => void,
|
||||||
isHeavy = true,
|
isHeavy = true,
|
||||||
once = false,
|
once = false,
|
||||||
withAnimationListener = true
|
withAnimationListener = true,
|
||||||
|
listenerSetter?: ListenerSetter
|
||||||
) => {
|
) => {
|
||||||
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
||||||
let animationDeferred: CancellablePromise<void>;
|
let animationDeferred: CancellablePromise<void>;
|
||||||
@ -133,7 +136,7 @@ const Transition = (
|
|||||||
//console.log('Transition: transitionend', /* content, */ e, selectTab.prevId, performance.now() - animationStarted);
|
//console.log('Transition: transitionend', /* content, */ e, selectTab.prevId, performance.now() - animationStarted);
|
||||||
|
|
||||||
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
||||||
if(callback) callback();
|
callback?.();
|
||||||
|
|
||||||
if(e.target !== from) {
|
if(e.target !== from) {
|
||||||
return;
|
return;
|
||||||
@ -153,14 +156,16 @@ const Transition = (
|
|||||||
content.classList.remove('animating', 'backwards', 'disable-hover');
|
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||||
|
|
||||||
if(once) {
|
if(once) {
|
||||||
content.removeEventListener(listenerName, onEndEvent/* , {capture: false} */);
|
if(listenerSetter) listenerSetter.removeManual(content, listenerName, onEndEvent);
|
||||||
|
else content.removeEventListener(listenerName, onEndEvent/* , {capture: false} */);
|
||||||
from = animationDeferred = undefined;
|
from = animationDeferred = undefined;
|
||||||
onTransitionEndCallbacks.clear();
|
onTransitionEndCallbacks.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: check for transition type (transform, etc) using by animationFunction
|
// TODO: check for transition type (transform, etc) using by animationFunction
|
||||||
content.addEventListener(listenerName, onEndEvent/* , {passive: true, capture: false} */);
|
if(listenerSetter) listenerSetter.add(content)(listenerName, onEndEvent);
|
||||||
|
else content.addEventListener(listenerName, onEndEvent/* , {passive: true, capture: false} */);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectTab(id: number | HTMLElement, animate = true, overrideFrom?: typeof from) {
|
function selectTab(id: number | HTMLElement, animate = true, overrideFrom?: typeof from) {
|
||||||
@ -196,9 +201,7 @@ const Transition = (
|
|||||||
if(from) from.classList.remove('active', 'to', 'from');
|
if(from) from.classList.remove('active', 'to', 'from');
|
||||||
else if(to) { // fix instant opening back from closed slider (e.g. instant closening and opening right sidebar)
|
else if(to) { // fix instant opening back from closed slider (e.g. instant closening and opening right sidebar)
|
||||||
const callback = onTransitionEndCallbacks.get(to);
|
const callback = onTransitionEndCallbacks.get(to);
|
||||||
if(callback) {
|
callback?.();
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(to) {
|
if(to) {
|
||||||
@ -254,21 +257,24 @@ const Transition = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(from/* && false */) {
|
if(from/* && false */) {
|
||||||
|
let timeout: number;
|
||||||
const _from = from;
|
const _from = from;
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
_from.classList.remove('active', 'from');
|
_from.classList.remove('active', 'from');
|
||||||
|
|
||||||
if(onTransitionEndCallback) {
|
if(onTransitionEndCallback) {
|
||||||
onTransitionEndCallback();
|
onTransitionEndCallback?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTransitionEndCallbacks.delete(_from);
|
onTransitionEndCallbacks.delete(_from);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(to) {
|
if(to) {
|
||||||
|
timeout = window.setTimeout(callback, transitionTime + 100); // something happened to container
|
||||||
onTransitionEndCallbacks.set(_from, callback);
|
onTransitionEndCallbacks.set(_from, callback);
|
||||||
} else {
|
} else {
|
||||||
const timeout = window.setTimeout(callback, transitionTime);
|
timeout = window.setTimeout(callback, transitionTime);
|
||||||
onTransitionEndCallbacks.set(_from, () => {
|
onTransitionEndCallbacks.set(_from, () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
onTransitionEndCallbacks.delete(_from);
|
onTransitionEndCallbacks.delete(_from);
|
||||||
@ -290,7 +296,7 @@ const Transition = (
|
|||||||
|
|
||||||
//selectTab.prevId = -1;
|
//selectTab.prevId = -1;
|
||||||
selectTab.prevId = () => from ? whichChild(from) : -1;
|
selectTab.prevId = () => from ? whichChild(from) : -1;
|
||||||
|
|
||||||
return selectTab;
|
return selectTab;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ import isInDOM from "../../helpers/dom/isInDOM";
|
|||||||
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
|
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
|
||||||
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
|
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
|
||||||
import onMediaLoad from "../../helpers/onMediaLoad";
|
import onMediaLoad from "../../helpers/onMediaLoad";
|
||||||
import throttleWithRaf from "../../helpers/schedulers/throttleWithRaf";
|
import { fastRaf } from "../../helpers/schedulers";
|
||||||
|
import throttle from "../../helpers/schedulers/throttle";
|
||||||
import sequentialDom from "../../helpers/sequentialDom";
|
import sequentialDom from "../../helpers/sequentialDom";
|
||||||
import toHHMMSS from "../../helpers/string/toHHMMSS";
|
import toHHMMSS from "../../helpers/string/toHHMMSS";
|
||||||
import { Message, PhotoSize } from "../../layer";
|
import { Message, PhotoSize } from "../../layer";
|
||||||
@ -245,7 +246,9 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
|||||||
spanTime.innerText = toHHMMSS(globalVideo.duration - globalVideo.currentTime, false);
|
spanTime.innerText = toHHMMSS(globalVideo.duration - globalVideo.currentTime, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);
|
const throttledTimeUpdate = throttle(() => {
|
||||||
|
fastRaf(onTimeUpdate);
|
||||||
|
}, 1000, false);
|
||||||
|
|
||||||
const onPlay = () => {
|
const onPlay = () => {
|
||||||
video.classList.add('hide');
|
video.classList.add('hide');
|
||||||
@ -437,14 +440,16 @@ export default async function wrapVideo({doc, container, message, boxWidth, boxH
|
|||||||
|
|
||||||
if(doc.type === 'video') {
|
if(doc.type === 'video') {
|
||||||
const onTimeUpdate = () => {
|
const onTimeUpdate = () => {
|
||||||
if(!video.videoWidth) {
|
if(!video.duration) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spanTime.innerText = toHHMMSS(video.duration - video.currentTime, false);
|
spanTime.innerText = toHHMMSS(video.duration - video.currentTime, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);
|
const throttledTimeUpdate = throttle(() => {
|
||||||
|
fastRaf(onTimeUpdate);
|
||||||
|
}, 1e3, false);
|
||||||
|
|
||||||
video.addEventListener('timeupdate', throttledTimeUpdate);
|
video.addEventListener('timeupdate', throttledTimeUpdate);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export default function getTextWidth(text: string, font: string) {
|
|||||||
// const perf = performance.now();
|
// const perf = performance.now();
|
||||||
if(!context) {
|
if(!context) {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
context = canvas.getContext('2d');
|
context = canvas.getContext('2d', {alpha: false});
|
||||||
context.font = font;
|
context.font = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,12 +38,11 @@ export default function renderImageWithFadeIn(
|
|||||||
image.addEventListener('animationend', () => {
|
image.addEventListener('animationend', () => {
|
||||||
sequentialDom.mutate(() => {
|
sequentialDom.mutate(() => {
|
||||||
image.classList.remove('fade-in');
|
image.classList.remove('fade-in');
|
||||||
|
thumbImage?.remove();
|
||||||
if(thumbImage) {
|
|
||||||
thumbImage.remove();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
|
} else {
|
||||||
|
thumbImage?.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1516,7 +1516,7 @@ export class AppDialogsManager {
|
|||||||
}, {capture: true});
|
}, {capture: true});
|
||||||
|
|
||||||
// cancel link click
|
// cancel link click
|
||||||
list.addEventListener('click', (e) => {
|
attachClickEvent(list, (e) => {
|
||||||
if(e.button === 0) {
|
if(e.button === 0) {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ import apiManagerProxy from '../mtproto/mtprotoworker';
|
|||||||
import appRuntimeManager from './appRuntimeManager';
|
import appRuntimeManager from './appRuntimeManager';
|
||||||
import paymentsWrapCurrencyAmount from '../../helpers/paymentsWrapCurrencyAmount';
|
import paymentsWrapCurrencyAmount from '../../helpers/paymentsWrapCurrencyAmount';
|
||||||
import findUpClassName from '../../helpers/dom/findUpClassName';
|
import findUpClassName from '../../helpers/dom/findUpClassName';
|
||||||
|
import { CLICK_EVENT_NAME } from '../../helpers/dom/clickEvent';
|
||||||
|
|
||||||
export const CHAT_ANIMATION_GROUP = 'chat';
|
export const CHAT_ANIMATION_GROUP = 'chat';
|
||||||
|
|
||||||
@ -368,6 +369,10 @@ export class AppImManager extends EventListenerBase<{
|
|||||||
const isVisible = parentElement.classList.contains(className);
|
const isVisible = parentElement.classList.contains(className);
|
||||||
if(!isVisible) {
|
if(!isVisible) {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
|
|
||||||
|
if(CLICK_EVENT_NAME !== 'click') {
|
||||||
|
window.addEventListener('click', cancelEvent, {capture: true, once: true});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = 400 / 2;
|
const duration = 400 / 2;
|
||||||
|
@ -11,7 +11,6 @@ import cancelEvent from "../helpers/dom/cancelEvent";
|
|||||||
import ListenerSetter, { Listener } from "../helpers/listenerSetter";
|
import ListenerSetter, { Listener } from "../helpers/listenerSetter";
|
||||||
import ButtonMenu from "../components/buttonMenu";
|
import ButtonMenu from "../components/buttonMenu";
|
||||||
import { ButtonMenuToggleHandler } from "../components/buttonMenuToggle";
|
import { ButtonMenuToggleHandler } from "../components/buttonMenuToggle";
|
||||||
import rootScope from "./rootScope";
|
|
||||||
import ControlsHover from "../helpers/dom/controlsHover";
|
import ControlsHover from "../helpers/dom/controlsHover";
|
||||||
import { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from "../helpers/dom/fullScreen";
|
import { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from "../helpers/dom/fullScreen";
|
||||||
import toHHMMSS from "../helpers/string/toHHMMSS";
|
import toHHMMSS from "../helpers/string/toHHMMSS";
|
||||||
@ -20,6 +19,7 @@ import VolumeSelector from "../components/volumeSelector";
|
|||||||
import debounce from "../helpers/schedulers/debounce";
|
import debounce from "../helpers/schedulers/debounce";
|
||||||
import overlayCounter from "../helpers/overlayCounter";
|
import overlayCounter from "../helpers/overlayCounter";
|
||||||
import onMediaLoad from "../helpers/onMediaLoad";
|
import onMediaLoad from "../helpers/onMediaLoad";
|
||||||
|
import { attachClickEvent } from "../helpers/dom/clickEvent";
|
||||||
|
|
||||||
export default class VideoPlayer extends ControlsHover {
|
export default class VideoPlayer extends ControlsHover {
|
||||||
private static PLAYBACK_RATES = [0.5, 1, 1.5, 2];
|
private static PLAYBACK_RATES = [0.5, 1, 1.5, 2];
|
||||||
@ -127,15 +127,15 @@ export default class VideoPlayer extends ControlsHover {
|
|||||||
leftControls.insertBefore(volumeSelector.btn, timeElapsed.parentElement);
|
leftControls.insertBefore(volumeSelector.btn, timeElapsed.parentElement);
|
||||||
|
|
||||||
Array.from(toggle).forEach((button) => {
|
Array.from(toggle).forEach((button) => {
|
||||||
listenerSetter.add(button)('click', () => {
|
attachClickEvent(button, () => {
|
||||||
this.togglePlay();
|
this.togglePlay();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this.pipButton) {
|
if(this.pipButton) {
|
||||||
listenerSetter.add(this.pipButton)('click', () => {
|
attachClickEvent(this.pipButton, () => {
|
||||||
this.video.requestPictureInPicture();
|
this.video.requestPictureInPicture();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
const onPip = (pip: boolean) => {
|
const onPip = (pip: boolean) => {
|
||||||
this.wrapper.style.visibility = pip ? 'hidden': '';
|
this.wrapper.style.visibility = pip ? 'hidden': '';
|
||||||
@ -170,9 +170,9 @@ export default class VideoPlayer extends ControlsHover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!IS_TOUCH_SUPPORTED) {
|
if(!IS_TOUCH_SUPPORTED) {
|
||||||
listenerSetter.add(video)('click', () => {
|
attachClickEvent(video, () => {
|
||||||
this.togglePlay();
|
this.togglePlay();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {
|
listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {
|
||||||
if(overlayCounter.overlaysActive > 1 || document.pictureInPictureElement === video) { // forward popup is active, etc
|
if(overlayCounter.overlaysActive > 1 || document.pictureInPictureElement === video) { // forward popup is active, etc
|
||||||
@ -216,9 +216,9 @@ export default class VideoPlayer extends ControlsHover {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
listenerSetter.add(fullScreenButton)('click', () => {
|
attachClickEvent(fullScreenButton, () => {
|
||||||
this.toggleFullScreen();
|
this.toggleFullScreen();
|
||||||
});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
addFullScreenListener(wrapper, this.onFullScreen.bind(this, fullScreenButton), listenerSetter);
|
addFullScreenListener(wrapper, this.onFullScreen.bind(this, fullScreenButton), listenerSetter);
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ export default class QueryableWorker extends EventListenerBase<{
|
|||||||
queryMethodArguments: args
|
queryMethodArguments: args
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const transfer: (ArrayBuffer | OffscreenCanvas)[] = [];
|
const transfer: Transferable[] = [];
|
||||||
args.forEach((arg) => {
|
args.forEach((arg) => {
|
||||||
if(arg instanceof ArrayBuffer) {
|
if(arg instanceof ArrayBuffer) {
|
||||||
transfer.push(arg);
|
transfer.push(arg);
|
||||||
@ -62,7 +62,7 @@ export default class QueryableWorker extends EventListenerBase<{
|
|||||||
this.worker.postMessage({
|
this.worker.postMessage({
|
||||||
queryMethod: queryMethod,
|
queryMethod: queryMethod,
|
||||||
queryMethodArguments: args
|
queryMethodArguments: args
|
||||||
}, transfer as Transferable[]);
|
}, transfer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,8 @@ module.exports = {
|
|||||||
// directory: path.join(__dirname, 'public')
|
// directory: path.join(__dirname, 'public')
|
||||||
// },
|
// },
|
||||||
compress: true,
|
compress: true,
|
||||||
http2: useLocalNotLocal ? true : (useLocal ? undefined : true),
|
// http2: useLocalNotLocal ? true : (useLocal ? undefined : true),
|
||||||
|
http2: true,
|
||||||
https: useLocal ? undefined : {
|
https: useLocal ? undefined : {
|
||||||
key: fs.readFileSync(__dirname + '/certs/server-key.pem', 'utf8'),
|
key: fs.readFileSync(__dirname + '/certs/server-key.pem', 'utf8'),
|
||||||
cert: fs.readFileSync(__dirname + '/certs/server-cert.pem', 'utf8')
|
cert: fs.readFileSync(__dirname + '/certs/server-cert.pem', 'utf8')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user