358 lines
11 KiB
TypeScript
358 lines
11 KiB
TypeScript
/*
|
|
* https://github.com/morethanwords/tweb
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
*/
|
|
|
|
import { deepEqual, copy } from "../../../helpers/object";
|
|
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
|
import { MyDialogFilter as DialogFilter } from "../../../lib/storages/filters";
|
|
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
|
|
import { SliderSuperTab } from "../../slider";
|
|
import { toast } from "../../toast";
|
|
import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
|
|
import InputField from "../../inputField";
|
|
import RichTextProcessor from "../../../lib/richtextprocessor";
|
|
import ButtonIcon from "../../buttonIcon";
|
|
import ButtonMenuToggle from "../../buttonMenuToggle";
|
|
import { ButtonMenuItemOptions } from "../../buttonMenu";
|
|
import Button from "../../button";
|
|
import AppIncludedChatsTab from "./includedChats";
|
|
import { i18n, i18n_, LangPackKey } from "../../../lib/langPack";
|
|
import { SettingSection } from "..";
|
|
|
|
const MAX_FOLDER_NAME_LENGTH = 12;
|
|
|
|
export default class AppEditFolderTab extends SliderSuperTab {
|
|
private caption: HTMLElement;
|
|
private stickerContainer: HTMLElement;
|
|
|
|
private confirmBtn: HTMLElement;
|
|
private menuBtn: HTMLElement;
|
|
private nameInputField: InputField;
|
|
|
|
private includePeerIds: SettingSection;
|
|
private excludePeerIds: SettingSection;
|
|
private flags: {[k in 'contacts' | 'non_contacts' | 'groups' | 'broadcasts' | 'bots' | 'exclude_muted' | 'exclude_archived' | 'exclude_read']: HTMLElement} = {} as any;
|
|
|
|
private animation: RLottiePlayer;
|
|
private filter: DialogFilter;
|
|
private originalFilter: DialogFilter;
|
|
|
|
private type: 'edit' | 'create';
|
|
private loadAnimationPromise: Promise<void>;
|
|
|
|
protected init() {
|
|
this.container.classList.add('edit-folder-container');
|
|
this.caption = document.createElement('div');
|
|
this.caption.classList.add('caption');
|
|
this.caption.append(i18n('FilterIncludeExcludeInfo'));
|
|
this.stickerContainer = document.createElement('div');
|
|
this.stickerContainer.classList.add('sticker-container');
|
|
|
|
this.confirmBtn = ButtonIcon('check btn-confirm hide blue');
|
|
const deleteFolderButton: ButtonMenuItemOptions = {
|
|
icon: 'delete danger',
|
|
text: 'FilterMenuDelete',
|
|
onClick: () => {
|
|
deleteFolderButton.element.setAttribute('disabled', 'true');
|
|
appMessagesManager.filtersStorage.updateDialogFilter(this.filter, true).then(bool => {
|
|
if(bool) {
|
|
this.close();
|
|
}
|
|
}).finally(() => {
|
|
deleteFolderButton.element.removeAttribute('disabled');
|
|
});
|
|
}
|
|
};
|
|
this.menuBtn = ButtonMenuToggle({}, 'bottom-left', [deleteFolderButton]);
|
|
this.menuBtn.classList.add('hide');
|
|
|
|
this.header.append(this.confirmBtn, this.menuBtn);
|
|
|
|
const inputWrapper = document.createElement('div');
|
|
inputWrapper.classList.add('input-wrapper');
|
|
|
|
this.nameInputField = new InputField({
|
|
label: 'FilterNameInputLabel',
|
|
maxLength: MAX_FOLDER_NAME_LENGTH
|
|
});
|
|
|
|
inputWrapper.append(this.nameInputField.container);
|
|
|
|
const generateList = (className: string, h2Text: LangPackKey, buttons: {icon: string, name?: string, withRipple?: true, text: LangPackKey}[], to: any) => {
|
|
const section = new SettingSection({
|
|
name: h2Text,
|
|
noDelimiter: true
|
|
});
|
|
|
|
section.container.classList.add('folder-list', className);
|
|
|
|
const categories = section.generateContentElement();
|
|
categories.classList.add('folder-categories');
|
|
|
|
buttons.forEach(o => {
|
|
const button = Button('folder-category-button btn btn-primary btn-transparent', {
|
|
icon: o.icon,
|
|
text: o.text,
|
|
noRipple: o.withRipple ? undefined : true
|
|
});
|
|
|
|
if(o.name) {
|
|
to[o.name] = button;
|
|
}
|
|
|
|
categories.append(button);
|
|
});
|
|
|
|
return section;
|
|
};
|
|
|
|
this.includePeerIds = generateList('folder-list-included', 'FilterInclude', [{
|
|
icon: 'add primary',
|
|
text: 'ChatList.Filter.Include.AddChat',
|
|
withRipple: true
|
|
}, {
|
|
text: 'ChatList.Filter.Contacts',
|
|
icon: 'newprivate',
|
|
name: 'contacts'
|
|
}, {
|
|
text: 'ChatList.Filter.NonContacts',
|
|
icon: 'noncontacts',
|
|
name: 'non_contacts'
|
|
}, {
|
|
text: 'ChatList.Filter.Groups',
|
|
icon: 'group',
|
|
name: 'groups'
|
|
}, {
|
|
text: 'ChatList.Filter.Channels',
|
|
icon: 'channel',
|
|
name: 'broadcasts'
|
|
}, {
|
|
text: 'ChatList.Filter.Bots',
|
|
icon: 'bots',
|
|
name: 'bots'
|
|
}], this.flags);
|
|
|
|
this.excludePeerIds = generateList('folder-list-excluded', 'FilterExclude', [{
|
|
icon: 'minus primary',
|
|
text: 'ChatList.Filter.Exclude.AddChat',
|
|
withRipple: true
|
|
}, {
|
|
text: 'ChatList.Filter.MutedChats',
|
|
icon: 'mute',
|
|
name: 'exclude_muted'
|
|
}, {
|
|
text: 'ChatList.Filter.Archive',
|
|
icon: 'archive',
|
|
name: 'exclude_archived'
|
|
}, {
|
|
text: 'ChatList.Filter.ReadChats',
|
|
icon: 'readchats',
|
|
name: 'exclude_read'
|
|
}], this.flags);
|
|
|
|
this.scrollable.append(this.stickerContainer, this.caption, inputWrapper, this.includePeerIds.container, this.excludePeerIds.container);
|
|
|
|
const includedFlagsContainer = this.includePeerIds.container.querySelector('.folder-categories');
|
|
const excludedFlagsContainer = this.excludePeerIds.container.querySelector('.folder-categories');
|
|
|
|
includedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
|
new AppIncludedChatsTab(this.slider).open(this.filter, 'included', this);
|
|
});
|
|
|
|
excludedFlagsContainer.querySelector('.btn').addEventListener('click', () => {
|
|
new AppIncludedChatsTab(this.slider).open(this.filter, 'excluded', this);
|
|
});
|
|
|
|
this.confirmBtn.addEventListener('click', () => {
|
|
if(this.nameInputField.input.classList.contains('error')) {
|
|
return;
|
|
}
|
|
|
|
if(!this.nameInputField.value.trim()) {
|
|
this.nameInputField.input.classList.add('error');
|
|
return;
|
|
}
|
|
|
|
let include = (Array.from(includedFlagsContainer.children) as HTMLElement[]).slice(1).reduce((acc, el) => acc + +!el.style.display, 0);
|
|
include += this.filter.include_peers.length;
|
|
|
|
if(!include) {
|
|
toast('Please choose at least one chat for this folder.');
|
|
return;
|
|
}
|
|
|
|
this.confirmBtn.setAttribute('disabled', 'true');
|
|
|
|
let promise: Promise<boolean>;
|
|
if(!this.filter.id) {
|
|
promise = appMessagesManager.filtersStorage.createDialogFilter(this.filter);
|
|
} else {
|
|
promise = appMessagesManager.filtersStorage.updateDialogFilter(this.filter);
|
|
}
|
|
|
|
promise.then(bool => {
|
|
if(bool) {
|
|
this.close();
|
|
}
|
|
}).catch(err => {
|
|
if(err.type === 'DIALOG_FILTERS_TOO_MUCH') {
|
|
toast('Sorry, you can\'t create more folders.');
|
|
} else {
|
|
console.error('updateDialogFilter error:', err);
|
|
}
|
|
}).finally(() => {
|
|
this.confirmBtn.removeAttribute('disabled');
|
|
});
|
|
});
|
|
|
|
this.nameInputField.input.addEventListener('input', () => {
|
|
this.filter.title = this.nameInputField.value;
|
|
this.editCheckForChange();
|
|
});
|
|
|
|
return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({
|
|
container: this.stickerContainer,
|
|
loop: false,
|
|
autoplay: false,
|
|
width: 86,
|
|
height: 86
|
|
}, 'assets/img/Folders_2.tgs').then(player => {
|
|
this.animation = player;
|
|
|
|
return lottieLoader.waitForFirstFrame(player);
|
|
});
|
|
}
|
|
|
|
onOpenAfterTimeout() {
|
|
this.loadAnimationPromise.then(() => {
|
|
this.animation.autoplay = true;
|
|
this.animation.play();
|
|
});
|
|
}
|
|
|
|
private onCreateOpen() {
|
|
this.caption.style.display = '';
|
|
this.setTitle('FilterNew');
|
|
this.menuBtn.classList.add('hide');
|
|
this.confirmBtn.classList.remove('hide');
|
|
this.nameInputField.value = '';
|
|
|
|
for(const flag in this.flags) {
|
|
// @ts-ignore
|
|
this.flags[flag].style.display = 'none';
|
|
}
|
|
}
|
|
|
|
private onEditOpen() {
|
|
this.caption.style.display = 'none';
|
|
this.setTitle(this.type === 'create' ? 'FilterNew' : 'FilterHeaderEdit');
|
|
|
|
if(this.type === 'edit') {
|
|
this.menuBtn.classList.remove('hide');
|
|
this.confirmBtn.classList.add('hide');
|
|
}
|
|
|
|
const filter = this.filter;
|
|
this.nameInputField.value = RichTextProcessor.wrapDraftText(filter.title);
|
|
|
|
for(const flag in this.flags) {
|
|
this.flags[flag as keyof AppEditFolderTab['flags']].style.display = !!filter.pFlags[flag as keyof AppEditFolderTab['flags']] ? '' : 'none';
|
|
}
|
|
|
|
(['includePeerIds' as const, 'excludePeerIds' as const]).forEach(key => {
|
|
const section = this[key];
|
|
const ul = appDialogsManager.createChatList();
|
|
|
|
const peers = filter[key].slice();
|
|
|
|
const renderMore = (_length: number) => {
|
|
for(let i = 0, length = Math.min(peers.length, _length); i < length; ++i) {
|
|
const peerId = peers.shift();
|
|
|
|
const {dom} = appDialogsManager.addDialogNew({
|
|
dialog: peerId,
|
|
container: ul,
|
|
drawStatus: false,
|
|
rippleEnabled: false,
|
|
meAsSaved: true,
|
|
avatarSize: 32
|
|
});
|
|
dom.lastMessageSpan.parentElement.remove();
|
|
}
|
|
|
|
if(peers.length) {
|
|
showMore.lastElementChild.replaceWith(i18n('FilterShowMoreChats', [peers.length]));
|
|
} else if(showMore) {
|
|
showMore.remove();
|
|
}
|
|
};
|
|
|
|
section.generateContentElement().append(ul);
|
|
|
|
let showMore: HTMLElement;
|
|
if(peers.length) {
|
|
const content = section.generateContentElement();
|
|
showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});
|
|
showMore.classList.add('load-more', 'rp-overflow');
|
|
showMore.addEventListener('click', () => renderMore(20));
|
|
showMore.append(i18n('FilterShowMoreChats', [peers.length]));
|
|
|
|
content.append(showMore);
|
|
}
|
|
|
|
renderMore(4);
|
|
});
|
|
}
|
|
|
|
editCheckForChange() {
|
|
if(this.type === 'edit') {
|
|
const changed = !deepEqual(this.originalFilter, this.filter);
|
|
this.confirmBtn.classList.toggle('hide', !changed);
|
|
this.menuBtn.classList.toggle('hide', changed);
|
|
}
|
|
};
|
|
|
|
setFilter(filter: DialogFilter, firstTime: boolean) {
|
|
// cleanup
|
|
Array.from(this.container.querySelectorAll('ul, .load-more')).forEach(el => el.remove());
|
|
|
|
if(firstTime) {
|
|
this.originalFilter = filter;
|
|
this.filter = copy(filter);
|
|
} else {
|
|
this.filter = filter;
|
|
this.onEditOpen();
|
|
this.editCheckForChange();
|
|
}
|
|
}
|
|
|
|
public open(filter?: DialogFilter) {
|
|
const ret = super.open();
|
|
|
|
if(filter === undefined) {
|
|
this.setFilter({
|
|
_: 'dialogFilter',
|
|
id: 0,
|
|
title: '',
|
|
pFlags: {},
|
|
pinned_peers: [],
|
|
include_peers: [],
|
|
exclude_peers: [],
|
|
pinnedPeerIds: [],
|
|
includePeerIds: [],
|
|
excludePeerIds: []
|
|
}, true);
|
|
this.type = 'create';
|
|
this.onCreateOpen();
|
|
} else {
|
|
this.setFilter(filter, true);
|
|
this.type = 'edit';
|
|
this.onEditOpen();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
}
|