Browse Source

Misc folder management fixes

master
Eduard Kuzmenko 2 years ago
parent
commit
b148a60c8c
  1. 73
      src/components/sidebarLeft/tabs/chatFolders.ts
  2. 31
      src/components/sidebarLeft/tabs/includedChats.ts
  3. 1
      src/lib/appManagers/appUsersManager.ts
  4. 1
      src/lib/mtproto/api_methods.ts
  5. 3
      src/lib/mtproto/mtproto_config.ts
  6. 15
      src/lib/rootScope.ts
  7. 3
      src/lib/storages/filters.ts

73
src/components/sidebarLeft/tabs/chatFolders.ts

@ -4,12 +4,12 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
import type { MyDialogFilter } from "../../../lib/storages/filters";
import type { DialogFilterSuggested } from "../../../layer";
import type _rootScope from "../../../lib/rootScope";
import { SliderSuperTab } from "../../slider"; import { SliderSuperTab } from "../../slider";
import lottieLoader, { LottieLoader } from "../../../lib/rlottie/lottieLoader"; import lottieLoader, { LottieLoader } from "../../../lib/rlottie/lottieLoader";
import { toast } from "../../toast"; import { toast } from "../../toast";
import type { MyDialogFilter } from "../../../lib/storages/filters";
import type { DialogFilterSuggested, DialogFilter } from "../../../layer";
import type _rootScope from "../../../lib/rootScope";
import Button from "../../button"; import Button from "../../button";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import AppEditFolderTab from "./editFolder"; import AppEditFolderTab from "./editFolder";
@ -22,6 +22,7 @@ import positionElementByIndex from "../../../helpers/dom/positionElementByIndex"
import RLottiePlayer from "../../../lib/rlottie/rlottiePlayer"; import RLottiePlayer from "../../../lib/rlottie/rlottiePlayer";
import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText"; import wrapEmojiText from "../../../lib/richTextProcessor/wrapEmojiText";
import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, REAL_FOLDERS } from "../../../lib/mtproto/mtproto_config"; import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, REAL_FOLDERS } from "../../../lib/mtproto/mtproto_config";
import replaceContent from "../../../helpers/dom/replaceContent";
export default class AppChatFoldersTab extends SliderSuperTab { export default class AppChatFoldersTab extends SliderSuperTab {
private createFolderBtn: HTMLElement; private createFolderBtn: HTMLElement;
@ -33,7 +34,12 @@ export default class AppChatFoldersTab extends SliderSuperTab {
private filtersRendered: {[filterId: number]: Row} = {}; private filtersRendered: {[filterId: number]: Row} = {};
private loadAnimationPromise: ReturnType<LottieLoader['waitForFirstFrame']>; private loadAnimationPromise: ReturnType<LottieLoader['waitForFirstFrame']>;
private async renderFolder(dialogFilter: DialogFilterSuggested | MyDialogFilter, container?: HTMLElement, row?: Row) { private async renderFolder(
dialogFilter: DialogFilterSuggested | MyDialogFilter,
container?: HTMLElement,
row?: Row,
append?: boolean
) {
let filter: MyDialogFilter; let filter: MyDialogFilter;
let description = ''; let description = '';
let d: HTMLElement[] = []; let d: HTMLElement[] = [];
@ -86,14 +92,12 @@ export default class AppChatFoldersTab extends SliderSuperTab {
}); });
if(d.length) { if(d.length) {
join(d).forEach((el) => { row.subtitle.append(...join(d));
row.subtitle.append(el);
});
} }
if(dialogFilter._ === 'dialogFilter') { if(dialogFilter._ === 'dialogFilter') {
const filterId = filter.id; const filterId = filter.id;
if(!this.filtersRendered.hasOwnProperty(filter.id) && filter.id !== FOLDER_ID_ALL) { if(!this.filtersRendered[filter.id] && filter.id !== FOLDER_ID_ALL) {
attachClickEvent(row.container, async() => { attachClickEvent(row.container, async() => {
this.slider.createTab(AppEditFolderTab).open(await this.managers.filtersStorage.getFilter(filterId)); this.slider.createTab(AppEditFolderTab).open(await this.managers.filtersStorage.getFilter(filterId));
}, {listenerSetter: this.listenerSetter}); }, {listenerSetter: this.listenerSetter});
@ -102,18 +106,25 @@ export default class AppChatFoldersTab extends SliderSuperTab {
this.filtersRendered[filter.id] = row; this.filtersRendered[filter.id] = row;
} }
} else { } else {
if(filter.id !== FOLDER_ID_ALL) {
replaceContent(row.title, wrapEmojiText(filter.title));
}
row.subtitle.textContent = ''; row.subtitle.textContent = '';
join(d).forEach((el) => { row.subtitle.append(...join(d));
row.subtitle.append(el);
});
} }
div = row.container; div = row.container;
if((filter as MyDialogFilter).localId !== undefined) { if(append) {
// ! header will be at 0 index const localId = (filter as MyDialogFilter).localId;
positionElementByIndex(div, div.parentElement || container, (filter as MyDialogFilter).localId); if(localId !== undefined) {
} else if(container) container.append(div); // ! header will be at 0 index
positionElementByIndex(div, div.parentElement || container, localId);
} else if(container) {
container.append(div);
}
}
return div; return div;
} }
@ -166,17 +177,20 @@ export default class AppChatFoldersTab extends SliderSuperTab {
continue; continue;
} }
await this.renderFolder(filter, this.foldersSection.content); await this.renderFolder(filter, this.foldersSection.content, undefined, true);
} }
this.toggleAllChats();
onFiltersContainerUpdate(); onFiltersContainerUpdate();
}); });
this.listenerSetter.add(rootScope)('filter_update', async(filter) => { this.listenerSetter.add(rootScope)('filter_update', async(filter) => {
if(this.filtersRendered.hasOwnProperty(filter.id)) { const filterRendered = this.filtersRendered[filter.id];
await this.renderFolder(filter, null, this.filtersRendered[filter.id]); if(filterRendered) {
} else { await this.renderFolder(filter, null, filterRendered);
await this.renderFolder(filter, this.foldersSection.content); } else if(filter.id !== FOLDER_ID_ARCHIVE) {
await this.renderFolder(filter, this.foldersSection.content, undefined, true);
} }
onFiltersContainerUpdate(); onFiltersContainerUpdate();
@ -185,7 +199,8 @@ export default class AppChatFoldersTab extends SliderSuperTab {
}); });
this.listenerSetter.add(rootScope)('filter_delete', (filter) => { this.listenerSetter.add(rootScope)('filter_delete', (filter) => {
if(this.filtersRendered.hasOwnProperty(filter.id)) { const filterRendered = this.filtersRendered[filter.id];
if(filterRendered) {
/* for(const suggested of this.suggestedFilters) { /* for(const suggested of this.suggestedFilters) {
if(deepEqual(suggested.filter, filter)) { if(deepEqual(suggested.filter, filter)) {
@ -193,7 +208,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
} */ } */
this.getSuggestedFilters(); this.getSuggestedFilters();
this.filtersRendered[filter.id].container.remove(); filterRendered.container.remove();
delete this.filtersRendered[filter.id]; delete this.filtersRendered[filter.id];
} }
@ -201,12 +216,17 @@ export default class AppChatFoldersTab extends SliderSuperTab {
}); });
this.listenerSetter.add(rootScope)('filter_order', (order) => { this.listenerSetter.add(rootScope)('filter_order', (order) => {
order.forEach((filterId, idx) => { order.filter((filterId) => !!this.filtersRendered[filterId]).forEach((filterId, idx) => {
const container = this.filtersRendered[filterId].container; const filterRendered = this.filtersRendered[filterId];
const container = filterRendered.container;
positionElementByIndex(container, container.parentElement, idx + 1); // ! + 1 due to header positionElementByIndex(container, container.parentElement, idx + 1); // ! + 1 due to header
}); });
}); });
this.listenerSetter.add(rootScope)('premium_toggle', () => {
this.toggleAllChats();
});
this.loadAnimationPromise = lottieLoader.loadAnimationAsAsset({ this.loadAnimationPromise = lottieLoader.loadAnimationAsAsset({
container: this.stickerContainer, container: this.stickerContainer,
loop: false, loop: false,
@ -234,6 +254,11 @@ export default class AppChatFoldersTab extends SliderSuperTab {
}); });
} }
private toggleAllChats() {
const filterRendered = this.filtersRendered[FOLDER_ID_ALL];
filterRendered.container.classList.toggle('hide', !rootScope.premium);
}
private async canCreateFolder() { private async canCreateFolder() {
const [appConfig, filters] = await Promise.all([ const [appConfig, filters] = await Promise.all([
this.managers.apiManager.getAppConfig(), this.managers.apiManager.getAppConfig(),

31
src/components/sidebarLeft/tabs/includedChats.ts

@ -20,6 +20,8 @@ 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 { REAL_FOLDERS } from "../../../lib/mtproto/mtproto_config"; import { REAL_FOLDERS } from "../../../lib/mtproto/mtproto_config";
import rootScope from "../../../lib/rootScope";
import { MTAppConfig } from "../../../lib/mtproto/appConfig";
export default class AppIncludedChatsTab extends SliderSuperTab { export default class AppIncludedChatsTab extends SliderSuperTab {
private editFolderTab: AppEditFolderTab; private editFolderTab: AppEditFolderTab;
@ -31,6 +33,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
private originalFilter: DialogFilter; private originalFilter: DialogFilter;
private dialogsByFilters: Map<DialogFilter, Set<PeerId>>; private dialogsByFilters: Map<DialogFilter, Set<PeerId>>;
private limit: number;
protected init() { protected init() {
this.content.remove(); this.content.remove();
@ -106,14 +109,26 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
this.close(); this.close();
}); });
const onAppConfig = (appConfig: MTAppConfig) => {
this.limit = rootScope.premium ? appConfig.dialog_filters_chats_limit_premium : appConfig.dialog_filters_chats_limit_default;
};
this.listenerSetter.add(rootScope)('app_config', onAppConfig);
this.dialogsByFilters = new Map(); this.dialogsByFilters = new Map();
return this.managers.filtersStorage.getDialogFilters().then(async(filters) => { return Promise.all([
await Promise.all(filters.filter((filter) => !REAL_FOLDERS.has(filter.id)).map(async(filter) => { this.managers.filtersStorage.getDialogFilters().then(async(filters) => {
const dialogs = await this.managers.dialogsStorage.getFolderDialogs(filter.id); await Promise.all(filters.filter((filter) => !REAL_FOLDERS.has(filter.id)).map(async(filter) => {
const peerIds = dialogs.map((d) => d.peerId); const dialogs = await this.managers.dialogsStorage.getFolderDialogs(filter.id);
this.dialogsByFilters.set(filter, new Set(peerIds)); const peerIds = dialogs.map((d) => d.peerId);
})); this.dialogsByFilters.set(filter, new Set(peerIds));
}); }));
}),
this.managers.apiManager.getAppConfig().then((appConfig) => {
onAppConfig(appConfig);
})
]);
} }
checkbox(selected?: boolean) { checkbox(selected?: boolean) {
@ -223,7 +238,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
let addedInitial = false; let addedInitial = false;
const _add = this.selector.add.bind(this.selector); const _add = this.selector.add.bind(this.selector);
this.selector.add = (peerId, title, scroll) => { this.selector.add = (peerId, title, scroll) => {
if(this.selector.selected.size >= 100 && addedInitial && !details[peerId]) { if(this.selector.selected.size >= this.limit && addedInitial && !details[peerId]) {
const el: HTMLInputElement = this.selector.list.querySelector(`[data-peer-id="${peerId}"] [type="checkbox"]`); const el: HTMLInputElement = this.selector.list.querySelector(`[data-peer-id="${peerId}"] [type="checkbox"]`);
if(el) { if(el) {
setTimeout(() => { setTimeout(() => {

1
src/lib/appManagers/appUsersManager.ts

@ -550,7 +550,6 @@ export class AppUsersManager extends AppManager {
if(user.pFlags.self) { if(user.pFlags.self) {
const isPremium = !!user.pFlags.premium; const isPremium = !!user.pFlags.premium;
if(this.rootScope.premium !== isPremium) { if(this.rootScope.premium !== isPremium) {
this.rootScope.premium = isPremium;
this.rootScope.dispatchEvent('premium_toggle', isPremium); this.rootScope.dispatchEvent('premium_toggle', isPremium);
} }
} }

1
src/lib/mtproto/api_methods.ts

@ -241,6 +241,7 @@ export default abstract class ApiManagerMethods extends AppManager {
this.appConfig = config; this.appConfig = config;
ignoreRestrictionReasons(config.ignore_restriction_reasons ?? []); ignoreRestrictionReasons(config.ignore_restriction_reasons ?? []);
this.rootScope.dispatchEvent('app_config', config);
return config; return config;
}); });

3
src/lib/mtproto/mtproto_config.ts

@ -4,6 +4,8 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE * https://github.com/morethanwords/tweb/blob/master/LICENSE
*/ */
import type { MyDialogFilter } from "../storages/filters";
/** /**
* Legacy Webogram's format, don't change dcID to camelCase. date is timestamp * Legacy Webogram's format, don't change dcID to camelCase. date is timestamp
*/ */
@ -20,3 +22,4 @@ export const BOT_START_PARAM = '';
export const FOLDER_ID_ALL: REAL_FOLDER_ID = 0; export const FOLDER_ID_ALL: REAL_FOLDER_ID = 0;
export const FOLDER_ID_ARCHIVE: REAL_FOLDER_ID = 1; export const FOLDER_ID_ARCHIVE: REAL_FOLDER_ID = 1;
export const REAL_FOLDERS: Set<number> = new Set([FOLDER_ID_ALL, FOLDER_ID_ARCHIVE]); export const REAL_FOLDERS: Set<number> = new Set([FOLDER_ID_ALL, FOLDER_ID_ARCHIVE]);
export const START_LOCAL_ID = Math.max(...Array.from(REAL_FOLDERS)) + 1 as MyDialogFilter['localId'];

15
src/lib/rootScope.ts

@ -21,6 +21,7 @@ import EventListenerBase from "../helpers/eventListenerBase";
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
import MTProtoMessagePort from "./mtproto/mtprotoMessagePort"; import MTProtoMessagePort from "./mtproto/mtprotoMessagePort";
import { IS_WORKER } from "../helpers/context"; import { IS_WORKER } from "../helpers/context";
import { MTAppConfig } from "./mtproto/appConfig";
export type BroadcastEvents = { export type BroadcastEvents = {
'chat_full_update': ChatId, 'chat_full_update': ChatId,
@ -140,7 +141,9 @@ export type BroadcastEvents = {
'payment_sent': {peerId: PeerId, mid: number}, 'payment_sent': {peerId: PeerId, mid: number},
'premium_toggle': boolean 'premium_toggle': boolean,
'app_config': MTAppConfig
}; };
export type BroadcastEventsListeners = { export type BroadcastEventsListeners = {
@ -148,8 +151,8 @@ export type BroadcastEventsListeners = {
}; };
export class RootScope extends EventListenerBase<BroadcastEventsListeners> { export class RootScope extends EventListenerBase<BroadcastEventsListeners> {
public myId: PeerId = NULL_PEER_ID; public myId: PeerId;
private connectionStatus: {[name: string]: ConnectionStatusChange} = {}; private connectionStatus: {[name: string]: ConnectionStatusChange};
public settings: State['settings']; public settings: State['settings'];
public managers: AppManagers; public managers: AppManagers;
public premium: boolean; public premium: boolean;
@ -157,12 +160,18 @@ export class RootScope extends EventListenerBase<BroadcastEventsListeners> {
constructor() { constructor() {
super(); super();
this.myId = NULL_PEER_ID;
this.connectionStatus = {};
this.premium = false; this.premium = false;
this.addEventListener('user_auth', ({id}) => { this.addEventListener('user_auth', ({id}) => {
this.myId = id.toPeerId(); this.myId = id.toPeerId();
}); });
this.addEventListener('premium_toggle', (isPremium) => {
this.premium = isPremium;
});
this.addEventListener('connection_status_change', (status) => { this.addEventListener('connection_status_change', (status) => {
this.connectionStatus[status.name] = status; this.connectionStatus[status.name] = status;
}); });

3
src/lib/storages/filters.ts

@ -11,7 +11,7 @@ import copy from "../../helpers/object/copy";
import { AppManager } from "../appManagers/manager"; import { AppManager } from "../appManagers/manager";
import findAndSplice from "../../helpers/array/findAndSplice"; import findAndSplice from "../../helpers/array/findAndSplice";
import assumeType from "../../helpers/assumeType"; import assumeType from "../../helpers/assumeType";
import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, REAL_FOLDERS, REAL_FOLDER_ID } from "../mtproto/mtproto_config"; import { FOLDER_ID_ALL, FOLDER_ID_ARCHIVE, REAL_FOLDERS, REAL_FOLDER_ID, START_LOCAL_ID } from "../mtproto/mtproto_config";
export type MyDialogFilter = DialogFilter.dialogFilter; export type MyDialogFilter = DialogFilter.dialogFilter;
@ -21,7 +21,6 @@ const convertment = [
['include_peers', 'includePeerIds'] ['include_peers', 'includePeerIds']
] as ['pinned_peers' | 'exclude_peers' | 'include_peers', 'pinnedPeerIds' | 'excludePeerIds' | 'includePeerIds'][]; ] as ['pinned_peers' | 'exclude_peers' | 'include_peers', 'pinnedPeerIds' | 'excludePeerIds' | 'includePeerIds'][];
const START_LOCAL_ID = Math.max(...Array.from(REAL_FOLDERS)) + 1 as MyDialogFilter['localId'];
const PREPENDED_FILTERS = REAL_FOLDERS.size; const PREPENDED_FILTERS = REAL_FOLDERS.size;
const LOCAL_FILTER: MyDialogFilter = { const LOCAL_FILTER: MyDialogFilter = {

Loading…
Cancel
Save