From f64abd9ea22cc1144f95b2fd6b266e86efe42595 Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Mon, 1 Mar 2021 00:14:01 +0400 Subject: [PATCH] Privacy Fix network once again Fix event listener --- src/components/appSelectPeers.ts | 4 +- src/components/chat/bubbles.ts | 2 +- src/components/privacySection.ts | 235 ++++++++++++++++++ src/components/radioField.ts | 2 +- src/components/sidebarLeft/tabs/2fa/email.ts | 6 +- .../sidebarLeft/tabs/2fa/emailConfirmation.ts | 6 +- .../sidebarLeft/tabs/2fa/enterPassword.ts | 7 +- src/components/sidebarLeft/tabs/2fa/hint.ts | 6 +- src/components/sidebarLeft/tabs/2fa/index.ts | 6 +- .../sidebarLeft/tabs/2fa/passwordSet.ts | 4 - .../sidebarLeft/tabs/2fa/reEnterPassword.ts | 6 +- src/components/sidebarLeft/tabs/addMembers.ts | 11 +- .../sidebarLeft/tabs/archivedTab.ts | 8 +- src/components/sidebarLeft/tabs/background.ts | 6 +- .../sidebarLeft/tabs/chatFolders.ts | 6 +- src/components/sidebarLeft/tabs/contacts.ts | 6 +- src/components/sidebarLeft/tabs/editFolder.ts | 8 +- .../sidebarLeft/tabs/editProfile.ts | 6 +- .../sidebarLeft/tabs/generalSettings.ts | 7 +- .../sidebarLeft/tabs/includedChats.ts | 13 +- src/components/sidebarLeft/tabs/newChannel.ts | 6 +- src/components/sidebarLeft/tabs/newGroup.ts | 6 +- .../sidebarLeft/tabs/privacy/addToGroups.ts | 19 ++ .../sidebarLeft/tabs/privacy/calls.ts | 31 +++ .../tabs/privacy/forwardMessages.ts | 19 ++ .../sidebarLeft/tabs/privacy/lastSeen.ts | 19 ++ .../sidebarLeft/tabs/privacy/profilePhoto.ts | 21 ++ .../sidebarLeft/tabs/privacyAndSecurity.ts | 45 ++-- src/components/sidebarLeft/tabs/settings.ts | 7 +- src/components/sliderTab.ts | 50 +++- src/helpers/applyMixins.ts | 37 +++ src/helpers/eventListenerBase.ts | 58 ++++- src/lib/appManagers/appPrivacyManager.ts | 41 ++- src/lib/mtproto/networker.ts | 8 +- 34 files changed, 564 insertions(+), 158 deletions(-) create mode 100644 src/components/privacySection.ts create mode 100644 src/components/sidebarLeft/tabs/privacy/addToGroups.ts create mode 100644 src/components/sidebarLeft/tabs/privacy/calls.ts create mode 100644 src/components/sidebarLeft/tabs/privacy/forwardMessages.ts create mode 100644 src/components/sidebarLeft/tabs/privacy/lastSeen.ts create mode 100644 src/components/sidebarLeft/tabs/privacy/profilePhoto.ts create mode 100644 src/helpers/applyMixins.ts diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts index f68157c2..eac63887 100644 --- a/src/components/appSelectPeers.ts +++ b/src/components/appSelectPeers.ts @@ -445,6 +445,8 @@ export default class AppSelectPeers { this.add(value, undefined, false); }); - this.selectedScrollable.scrollIntoViewNew(this.input, 'center', undefined, undefined, FocusDirection.Static); + window.requestAnimationFrame(() => { // ! not the best place for this raf though it works + this.selectedScrollable.scrollIntoViewNew(this.input, 'center', undefined, undefined, FocusDirection.Static); + }); } } \ No newline at end of file diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 218979c6..c42ccf5f 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -380,7 +380,7 @@ export default class ChatBubbles { }); } - if(false) this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => { + /* if(false) */this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => { for(const timestamp in this.dateMessages) { const dateMessage = this.dateMessages[timestamp]; if(dateMessage.container === target) { diff --git a/src/components/privacySection.ts b/src/components/privacySection.ts new file mode 100644 index 00000000..6f87838d --- /dev/null +++ b/src/components/privacySection.ts @@ -0,0 +1,235 @@ +import { randomLong } from "../helpers/random"; +import { InputPrivacyKey, InputPrivacyRule } from "../layer"; +import appPrivacyManager, { PrivacyType } from "../lib/appManagers/appPrivacyManager"; +import appUsersManager from "../lib/appManagers/appUsersManager"; +import RadioField from "./radioField"; +import Row, { RadioFormFromRows } from "./row"; +import Scrollable from "./scrollable"; +import { SettingSection, generateSection } from "./sidebarLeft"; +import AppAddMembersTab from "./sidebarLeft/tabs/addMembers"; +import { SliderSuperTabEventable } from "./sliderTab"; + +export default class PrivacySection { + public radioRows: Map; + public radioSection: SettingSection; + public exceptions: Map; + public peerIds: { + disallow?: number[], + allow?: number[] + }; + public type: PrivacyType; + + constructor(public options: { + tab: SliderSuperTabEventable, + title: string, + inputKey: InputPrivacyKey['_'], + captions?: [string, string, string], + appendTo?: Scrollable, + noExceptions?: boolean, + onRadioChange?: (value: number) => any, + skipTypes?: PrivacyType[], + exceptionTexts?: [string, string] + }) { + if(options.captions) { + options.captions.reverse(); + } + + this.radioSection = new SettingSection({name: options.title, caption: ' '}); + + this.radioRows = new Map(); + + let r = [{ + type: PrivacyType.Everybody, + text: 'Everybody' + }, { + type: PrivacyType.Contacts, + text: 'My Contacts' + }, { + type: PrivacyType.Nobody, + text: 'Nobody' + }]; + + if(options.skipTypes) { + r = r.filter(r => !options.skipTypes.includes(r.type)); + } + + const random = randomLong(); + r.forEach(({type, text}) => { + this.radioRows.set(type, new Row({radioField: RadioField(text, random, '' + type)})); + }); + + const form = RadioFormFromRows([...this.radioRows.values()], this.onRadioChange); + + this.radioSection.content.append(form); + if(options.appendTo) { + options.appendTo.append(this.radioSection.container); + } + + if(!options.noExceptions) { + const container = generateSection(options.appendTo, 'Exceptions', 'You can add users or entire groups as exceptions that will override settings above.'); + + this.exceptions = new Map([[ + 'disallow', + { + title: options.exceptionTexts[0], + key: 'disallow', + row: null, + icon: 'deleteuser', + subtitle: 'Add Users', + clickable: true + } + ], [ + 'allow', + { + title: options.exceptionTexts[1], + key: 'allow', + row: null, + icon: 'adduser', + subtitle: 'Add Users', + clickable: true + } + ]]); + + this.exceptions.forEach((exception) => { + exception.row = new Row(exception); + + exception.row.container.addEventListener('click', () => { + promise.then(() => { + const _peerIds = this.peerIds[exception.key]; + new AppAddMembersTab(options.tab.slider).open({ + type: 'privacy', + skippable: true, + title: exception.title, + placeholder: 'Add Users or Groups...', + takeOut: (newPeerIds) => { + _peerIds.length = 0; + _peerIds.push(...newPeerIds); + exception.row.subtitle.innerHTML = this.generateStr(this.splitPeersByType(newPeerIds)); + }, + selectedPeerIds: _peerIds + }); + }); + }); + + container.append(exception.row.container); + }); + } + + setTimeout(() => { + this.setRadio(PrivacyType.Contacts); + }, 0); + + const promise = appPrivacyManager.getPrivacy(options.inputKey).then(rules => { + const details = appPrivacyManager.getPrivacyRulesDetails(rules); + this.setRadio(details.type); + + if(this.exceptions) { + this.peerIds = {}; + (['allow', 'disallow'] as ('allow' | 'disallow')[]).forEach(k => { + const arr = []; + const from = k === 'allow' ? details.allowPeers : details.disallowPeers; + arr.push(...from.users); + arr.push(...from.chats.map(id => -id)); + this.peerIds[k] = arr; + this.exceptions.get(k).row.subtitle.innerHTML = this.generateStr(from); + }); + } + + options.tab.eventListener.addListener('destroy', () => { + const rules: InputPrivacyRule[] = []; + + switch(this.type) { + case PrivacyType.Everybody: + rules.push({_: 'inputPrivacyValueAllowAll'}); + break; + case PrivacyType.Contacts: + rules.push({_: 'inputPrivacyValueAllowContacts'}); + break; + case PrivacyType.Nobody: + rules.push({_: 'inputPrivacyValueDisallowAll'}); + break; + } + + if(this.exceptions) { + ([ + ['allow', 'inputPrivacyValueAllowChatParticipants', 'inputPrivacyValueAllowUsers'], + ['disallow', 'inputPrivacyValueDisallowChatParticipants', 'inputPrivacyValueDisallowUsers'] + ] as Array<[ + 'allow' | 'disallow', + 'inputPrivacyValueAllowChatParticipants' | 'inputPrivacyValueDisallowChatParticipants', + 'inputPrivacyValueAllowUsers' | 'inputPrivacyValueDisallowUsers' + ]>).forEach(([k, chatKey, usersKey], idx) => { + if(this.exceptions.get(k).row.container.classList.contains('hide')) { + return; + } + + const _peerIds: number[] = this.peerIds[k]; + + if(_peerIds) { + const splitted = this.splitPeersByType(_peerIds); + if(splitted.chats.length) { + rules.push({_: chatKey, chats: splitted.chats.map(peerId => -peerId)}); + } + + if(splitted.users.length) { + rules.push({_: usersKey, users: splitted.users.map(id => appUsersManager.getUserInput(id))}); + } + } + }); + } + + appPrivacyManager.setPrivacy(options.inputKey, rules); + }, true); + }); + } + + private onRadioChange = (value: string | PrivacySection['type']) => { + value = +value as PrivacySection['type']; + this.type = value; + + const caption = this.options.captions[this.type]; + const captionElement = this.radioSection.caption; + captionElement.innerHTML = caption; + captionElement.classList.toggle('hide', !caption); + + if(this.exceptions) { + this.exceptions.get('allow').row.container.classList.toggle('hide', this.type === PrivacyType.Everybody); + this.exceptions.get('disallow').row.container.classList.toggle('hide', this.type === PrivacyType.Nobody); + } + + this.options.onRadioChange && this.options.onRadioChange(value); + }; + + public setRadio(type: PrivacySection['type']) { + const row = this.radioRows.get(type); + this.onRadioChange(type); + row.radioField.input.checked = true; + } + + private splitPeersByType(peerIds: number[]) { + const peers = {users: [] as number[], chats: [] as number[]}; + peerIds.forEach(peerId => { + peers[peerId < 0 ? 'chats' : 'users'].push(peerId < 0 ? -peerId : peerId); + }); + + return peers; + } + + private generateStr(peers: {users: number[], chats: number[]}) { + if(!peers.users.length && !peers.chats.length) { + return 'Add Users'; + } + + return [ + peers.users.length ? peers.users.length + ' ' + (peers.users.length === 1 ? 'user' : 'users') : '', + peers.chats.length ? peers.chats.length + ' ' + (peers.chats.length === 1 ? 'chat' : 'chats') : '' + ].filter(Boolean).join(', '); + } +} \ No newline at end of file diff --git a/src/components/radioField.ts b/src/components/radioField.ts index f9efd666..a1d0c147 100644 --- a/src/components/radioField.ts +++ b/src/components/radioField.ts @@ -7,7 +7,7 @@ const RadioField = (text: string, name: string, value?: string, stateKey?: strin const input = document.createElement('input'); input.type = 'radio'; - input.id = input.name = 'input-radio-' + name; + /* input.id = */input.name = 'input-radio-' + name; if(value) { input.value = value; diff --git a/src/components/sidebarLeft/tabs/2fa/email.ts b/src/components/sidebarLeft/tabs/2fa/email.ts index 2d8f8e39..91977828 100644 --- a/src/components/sidebarLeft/tabs/2fa/email.ts +++ b/src/components/sidebarLeft/tabs/2fa/email.ts @@ -2,7 +2,7 @@ import { SettingSection } from "../.."; import { AccountPassword } from "../../../../layer"; import appStickersManager from "../../../../lib/appManagers/appStickersManager"; import Button from "../../../button"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import { wrapSticker } from "../../../wrappers"; import InputField from "../../../inputField"; import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom"; @@ -21,10 +21,6 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { public hint: string; public isFirst = false; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-email'); this.title.innerHTML = 'Recovery Email'; diff --git a/src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts b/src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts index 668ff5bd..816f6b8e 100644 --- a/src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts +++ b/src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts @@ -2,7 +2,7 @@ import { SettingSection } from "../.."; import { AccountPassword } from "../../../../layer"; import appStickersManager from "../../../../lib/appManagers/appStickersManager"; import Button from "../../../button"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import { wrapSticker } from "../../../wrappers"; import { attachClickEvent, canFocus, toggleDisability } from "../../../../helpers/dom"; import passwordManager from "../../../../lib/mtproto/passwordManager"; @@ -18,10 +18,6 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu public length: number; public isFirst = false; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-email-confirmation'); this.title.innerHTML = 'Recovery Email'; diff --git a/src/components/sidebarLeft/tabs/2fa/enterPassword.ts b/src/components/sidebarLeft/tabs/2fa/enterPassword.ts index 0a23255e..8e2f50f5 100644 --- a/src/components/sidebarLeft/tabs/2fa/enterPassword.ts +++ b/src/components/sidebarLeft/tabs/2fa/enterPassword.ts @@ -1,7 +1,6 @@ import AppTwoStepVerificationTab from "."; import { SettingSection } from "../.."; import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom"; -import { isMobileSafari } from "../../../../helpers/userAgent"; import { AccountPassword } from "../../../../layer"; import passwordManager from "../../../../lib/mtproto/passwordManager"; import RichTextProcessor from "../../../../lib/richtextprocessor"; @@ -10,7 +9,7 @@ import { putPreloader } from "../../../misc"; import PasswordMonkey from "../../../monkeys/password"; import PasswordInputField from "../../../passwordInputField"; import { ripple } from "../../../ripple"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import AppTwoStepVerificationReEnterPasswordTab from "./reEnterPassword"; export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperTab { @@ -19,10 +18,6 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT public plainPassword: string; public isFirst = true; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { const isNew = !this.state.pFlags.has_password || this.plainPassword; this.container.classList.add('two-step-verification', 'two-step-verification-enter-password'); diff --git a/src/components/sidebarLeft/tabs/2fa/hint.ts b/src/components/sidebarLeft/tabs/2fa/hint.ts index 2f04a082..c5dfdda7 100644 --- a/src/components/sidebarLeft/tabs/2fa/hint.ts +++ b/src/components/sidebarLeft/tabs/2fa/hint.ts @@ -2,7 +2,7 @@ import { SettingSection } from "../.."; import { AccountPassword } from "../../../../layer"; import appStickersManager from "../../../../lib/appManagers/appStickersManager"; import Button from "../../../button"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import { wrapSticker } from "../../../wrappers"; import InputField from "../../../inputField"; import AppTwoStepVerificationEmailTab from "./email"; @@ -15,10 +15,6 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { public plainPassword: string; public newPassword: string; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-hint'); this.title.innerHTML = 'Password Hint'; diff --git a/src/components/sidebarLeft/tabs/2fa/index.ts b/src/components/sidebarLeft/tabs/2fa/index.ts index 2ea1286c..90b6fe7f 100644 --- a/src/components/sidebarLeft/tabs/2fa/index.ts +++ b/src/components/sidebarLeft/tabs/2fa/index.ts @@ -5,7 +5,7 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager"; import passwordManager from "../../../../lib/mtproto/passwordManager"; import Button from "../../../button"; import PopupConfirmAction from "../../../popups/confirmAction"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import { wrapSticker } from "../../../wrappers"; import AppSettingsTab from "../settings"; import AppTwoStepVerificationEmailTab from "./email"; @@ -15,10 +15,6 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { public state: AccountPassword; public plainPassword: string; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-main'); this.title.innerHTML = 'Two-Step Verification'; diff --git a/src/components/sidebarLeft/tabs/2fa/passwordSet.ts b/src/components/sidebarLeft/tabs/2fa/passwordSet.ts index ce4b0fd7..6df9f5f3 100644 --- a/src/components/sidebarLeft/tabs/2fa/passwordSet.ts +++ b/src/components/sidebarLeft/tabs/2fa/passwordSet.ts @@ -7,10 +7,6 @@ import { wrapSticker } from "../../../wrappers"; import AppSettingsTab from "../settings"; export default class AppTwoStepVerificationSetTab extends SliderSuperTab { - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-set'); this.title.innerHTML = 'Password Set!'; diff --git a/src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts b/src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts index 89df6200..289dd70d 100644 --- a/src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts +++ b/src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts @@ -4,7 +4,7 @@ import { AccountPassword } from "../../../../layer"; import Button from "../../../button"; import PasswordInputField from "../../../passwordInputField"; import { ripple } from "../../../ripple"; -import SidebarSlider, { SliderSuperTab } from "../../../slider"; +import { SliderSuperTab } from "../../../slider"; import TrackingMonkey from "../../../monkeys/tracking"; import AppTwoStepVerificationHintTab from "./hint"; @@ -13,10 +13,6 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe public passwordInputField: PasswordInputField; public plainPassword: string; public newPassword: string; - - constructor(slider: SidebarSlider) { - super(slider, true); - } protected init() { this.container.classList.add('two-step-verification', 'two-step-verification-enter-password', 'two-step-verification-re-enter-password'); diff --git a/src/components/sidebarLeft/tabs/addMembers.ts b/src/components/sidebarLeft/tabs/addMembers.ts index f86d7f89..b436c402 100644 --- a/src/components/sidebarLeft/tabs/addMembers.ts +++ b/src/components/sidebarLeft/tabs/addMembers.ts @@ -1,8 +1,7 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import AppSelectPeers from "../../appSelectPeers"; import { putPreloader } from "../../misc"; import Button from "../../button"; -import { fastRaf } from "../../../helpers/schedulers"; export default class AppAddMembersTab extends SliderSuperTab { private nextBtn: HTMLButtonElement; @@ -11,10 +10,6 @@ export default class AppAddMembersTab extends SliderSuperTab { private takeOut: (peerIds: number[]) => Promise | any; private skippable: boolean; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.nextBtn = Button('btn-corner btn-circle', {icon: 'arrow_next'}); this.content.append(this.nextBtn); @@ -70,9 +65,7 @@ export default class AppAddMembersTab extends SliderSuperTab { this.selector.input.placeholder = options.placeholder; if(options.selectedPeerIds) { - fastRaf(() => { - this.selector.addInitial(options.selectedPeerIds); - }); + this.selector.addInitial(options.selectedPeerIds); } this.nextBtn.classList.add('tgico-arrow_next'); diff --git a/src/components/sidebarLeft/tabs/archivedTab.ts b/src/components/sidebarLeft/tabs/archivedTab.ts index b201f44d..c0049c8f 100644 --- a/src/components/sidebarLeft/tabs/archivedTab.ts +++ b/src/components/sidebarLeft/tabs/archivedTab.ts @@ -1,15 +1,11 @@ import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; export default class AppArchivedTab extends SliderSuperTab { public loadedAll: boolean; public loadDialogsPromise: Promise; public wasFilterId: number; - constructor(slider: SidebarSlider) { - super(slider, true); - } - init() { this.container.id = 'chats-archived-container'; this.title.innerHTML = 'Archived Chats'; @@ -38,8 +34,6 @@ export default class AppArchivedTab extends SliderSuperTab { appDialogsManager.scroll = this.scrollable; appDialogsManager.filterId = 1; appDialogsManager.onTabChange(); - - return super.onOpen(); } // вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд... diff --git a/src/components/sidebarLeft/tabs/background.ts b/src/components/sidebarLeft/tabs/background.ts index 1b00cfff..b658e559 100644 --- a/src/components/sidebarLeft/tabs/background.ts +++ b/src/components/sidebarLeft/tabs/background.ts @@ -14,14 +14,10 @@ import rootScope from "../../../lib/rootScope"; import Button from "../../button"; import CheckboxField from "../../checkbox"; import ProgressivePreloader from "../../preloader"; -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import { wrapPhoto } from "../../wrappers"; export default class AppBackgroundTab extends SliderSuperTab { - constructor(slider: SidebarSlider) { - super(slider, true); - } - init() { this.container.classList.add('background-container'); this.title.innerText = 'Chat Background'; diff --git a/src/components/sidebarLeft/tabs/chatFolders.ts b/src/components/sidebarLeft/tabs/chatFolders.ts index 5c61fbb4..f67a9831 100644 --- a/src/components/sidebarLeft/tabs/chatFolders.ts +++ b/src/components/sidebarLeft/tabs/chatFolders.ts @@ -1,4 +1,4 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader"; import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { cancelEvent, positionElementByIndex } from "../../../helpers/dom"; @@ -23,10 +23,6 @@ export default class AppChatFoldersTab extends SliderSuperTab { private filtersRendered: {[filterId: number]: HTMLElement} = {}; - constructor(slider: SidebarSlider) { - super(slider, true); - } - private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, div: HTMLElement = document.createElement('div')) { let filter: DialogFilter | MyDialogFilter; let description = ''; diff --git a/src/components/sidebarLeft/tabs/contacts.ts b/src/components/sidebarLeft/tabs/contacts.ts index fce289e9..853ed32e 100644 --- a/src/components/sidebarLeft/tabs/contacts.ts +++ b/src/components/sidebarLeft/tabs/contacts.ts @@ -1,4 +1,4 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appUsersManager from "../../../lib/appManagers/appUsersManager"; import appPhotosManager from "../../../lib/appManagers/appPhotosManager"; @@ -14,10 +14,6 @@ export default class AppContactsTab extends SliderSuperTab { private inputSearch: InputSearch; private alive = true; - constructor(slider: SidebarSlider) { - super(slider, true); - } - init() { this.container.id = 'contacts-container'; diff --git a/src/components/sidebarLeft/tabs/editFolder.ts b/src/components/sidebarLeft/tabs/editFolder.ts index e693ea46..0e622f18 100644 --- a/src/components/sidebarLeft/tabs/editFolder.ts +++ b/src/components/sidebarLeft/tabs/editFolder.ts @@ -3,7 +3,7 @@ import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import { MyDialogFilter as DialogFilter } from "../../../lib/storages/filters"; import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader"; import { ripple } from "../../ripple"; -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import { toast } from "../../toast"; import appMessagesManager from "../../../lib/appManagers/appMessagesManager"; import InputField from "../../inputField"; @@ -34,10 +34,6 @@ export default class AppEditFolderTab extends SliderSuperTab { private type: 'edit' | 'create'; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('edit-folder-container'); this.caption = document.createElement('div'); @@ -226,8 +222,6 @@ export default class AppEditFolderTab extends SliderSuperTab { if(this.animation) { this.animation.restart(); } - - return super.onOpen(); } private onCreateOpen() { diff --git a/src/components/sidebarLeft/tabs/editProfile.ts b/src/components/sidebarLeft/tabs/editProfile.ts index 524982cf..86b64f48 100644 --- a/src/components/sidebarLeft/tabs/editProfile.ts +++ b/src/components/sidebarLeft/tabs/editProfile.ts @@ -6,7 +6,7 @@ import RichTextProcessor from "../../../lib/richtextprocessor"; import rootScope from "../../../lib/rootScope"; import AvatarElement from "../../avatar"; import InputField from "../../inputField"; -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import AvatarEdit from "../../avatarEdit"; import Button from "../../button"; @@ -39,10 +39,6 @@ export default class AppEditProfileTab extends SliderSuperTab { bio: '' }; - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('edit-profile-container'); this.title.innerText = 'Edit Profile'; diff --git a/src/components/sidebarLeft/tabs/generalSettings.ts b/src/components/sidebarLeft/tabs/generalSettings.ts index ac865c0b..3ae5d8e4 100644 --- a/src/components/sidebarLeft/tabs/generalSettings.ts +++ b/src/components/sidebarLeft/tabs/generalSettings.ts @@ -1,7 +1,6 @@ import { SliderSuperTab } from "../../slider" -import { AppSidebarLeft, generateSection } from ".."; +import { generateSection } from ".."; import RangeSelector from "../../rangeSelector"; -import { clamp } from "../../../helpers/number"; import Button from "../../button"; import CheckboxField from "../../checkbox"; import RadioField from "../../radioField"; @@ -54,10 +53,6 @@ export class RangeSettingSelector { } export default class AppGeneralSettingsTab extends SliderSuperTab { - constructor(appSidebarLeft: AppSidebarLeft) { - super(appSidebarLeft, true); - } - init() { this.container.classList.add('general-settings-container'); this.title.innerText = 'General'; diff --git a/src/components/sidebarLeft/tabs/includedChats.ts b/src/components/sidebarLeft/tabs/includedChats.ts index de85c3a4..9d5ada0b 100644 --- a/src/components/sidebarLeft/tabs/includedChats.ts +++ b/src/components/sidebarLeft/tabs/includedChats.ts @@ -1,4 +1,4 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import AppSelectPeers from "../../appSelectPeers"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appPeersManager from "../../../lib/appManagers/appPeersManager"; @@ -7,7 +7,6 @@ import { MyDialogFilter as DialogFilter } from "../../../lib/storages/filters"; import rootScope from "../../../lib/rootScope"; import { copy } from "../../../helpers/object"; import ButtonIcon from "../../buttonIcon"; -import { fastRaf } from "../../../helpers/schedulers"; import CheckboxField from "../../checkbox"; import Button from "../../button"; import AppEditFolderTab from "./editFolder"; @@ -21,10 +20,6 @@ export default class AppIncludedChatsTab extends SliderSuperTab { private filter: DialogFilter; private originalFilter: DialogFilter; - constructor(slider: SidebarSlider) { - super(slider, true); - } - init() { this.content.remove(); this.container.classList.add('included-chatlist-container'); @@ -224,9 +219,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab { this.selector.list.parentElement.insertBefore(fragment, this.selector.list); - fastRaf(() => { - this.selector.addInitial(selectedPeers); - }); + this.selector.addInitial(selectedPeers); for(const flag in filter.pFlags) { // @ts-ignore @@ -234,8 +227,6 @@ export default class AppIncludedChatsTab extends SliderSuperTab { (categories.querySelector(`[data-peer-id="${flag}"]`) as HTMLElement).click(); } } - - return super.onOpen(); } onSelectChange = (length: number) => { diff --git a/src/components/sidebarLeft/tabs/newChannel.ts b/src/components/sidebarLeft/tabs/newChannel.ts index 9295c342..e347665c 100644 --- a/src/components/sidebarLeft/tabs/newChannel.ts +++ b/src/components/sidebarLeft/tabs/newChannel.ts @@ -1,4 +1,4 @@ -import appSidebarLeft, { AppSidebarLeft } from ".."; +import appSidebarLeft from ".."; import { InputFile } from "../../../layer"; import appChatsManager from "../../../lib/appManagers/appChatsManager"; import Button from "../../button"; @@ -15,10 +15,6 @@ export default class AppNewChannelTab extends SliderSuperTab { private nextBtn: HTMLButtonElement; private avatarEdit: AvatarEdit; - constructor(appSidebarLeft: AppSidebarLeft) { - super(appSidebarLeft, true); - } - protected init() { this.container.classList.add('new-channel-container'); this.title.innerText = 'New Channel'; diff --git a/src/components/sidebarLeft/tabs/newGroup.ts b/src/components/sidebarLeft/tabs/newGroup.ts index 762f2745..d20bab9b 100644 --- a/src/components/sidebarLeft/tabs/newGroup.ts +++ b/src/components/sidebarLeft/tabs/newGroup.ts @@ -1,4 +1,4 @@ -import appSidebarLeft, { AppSidebarLeft } from ".."; +import appSidebarLeft from ".."; import { InputFile } from "../../../layer"; import appChatsManager from "../../../lib/appManagers/appChatsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; @@ -16,10 +16,6 @@ export default class AppNewGroupTab extends SliderSuperTab { private userIds: number[]; private nextBtn: HTMLButtonElement; private groupNameInputField: InputField; - - constructor(appSidebarLeft: AppSidebarLeft) { - super(appSidebarLeft, true); - } protected init() { this.container.classList.add('new-group-container'); diff --git a/src/components/sidebarLeft/tabs/privacy/addToGroups.ts b/src/components/sidebarLeft/tabs/privacy/addToGroups.ts new file mode 100644 index 00000000..e421fc55 --- /dev/null +++ b/src/components/sidebarLeft/tabs/privacy/addToGroups.ts @@ -0,0 +1,19 @@ +import { SliderSuperTabEventable } from "../../../sliderTab"; +import PrivacySection from "../../../privacySection"; + +export default class AppPrivacyAddToGroupsTab extends SliderSuperTabEventable { + protected init() { + this.container.classList.add('privacy-tab', 'privacy-add-to-groups'); + this.title.innerHTML = 'Groups and Channels'; + + const caption = 'You can restrict who can add you to groups and channels with granular precision.'; + new PrivacySection({ + tab: this, + title: 'Who can add me to group chats?', + inputKey: 'inputPrivacyKeyForwards', + captions: [caption, caption, caption], + exceptionTexts: ['Never Allow', 'Always Allow'], + appendTo: this.scrollable + }); + } +} diff --git a/src/components/sidebarLeft/tabs/privacy/calls.ts b/src/components/sidebarLeft/tabs/privacy/calls.ts new file mode 100644 index 00000000..f6b387a8 --- /dev/null +++ b/src/components/sidebarLeft/tabs/privacy/calls.ts @@ -0,0 +1,31 @@ +import { SliderSuperTabEventable } from "../../../sliderTab"; +import PrivacySection from "../../../privacySection"; + +export default class AppPrivacyCallsTab extends SliderSuperTabEventable { + protected init() { + this.container.classList.add('privacy-tab', 'privacy-calls'); + this.title.innerHTML = 'Calls'; + + const caption = 'You can restrict who can call you with granular precision.'; + new PrivacySection({ + tab: this, + title: 'Who can call me?', + inputKey: 'inputPrivacyKeyPhoneCall', + captions: [caption, caption, caption], + exceptionTexts: ['Never Allow', 'Always Allow'], + appendTo: this.scrollable + }); + + { + const caption = 'Disabling peer-to-peer will relay all calls through Telegram servers to avoid revealing your IP address, but will slightly decrease audio quality.'; + new PrivacySection({ + tab: this, + title: 'Peer to peer?', + inputKey: 'inputPrivacyKeyPhoneP2P', + captions: [caption, caption, caption], + exceptionTexts: ['Never Allow', 'Always Allow'], + appendTo: this.scrollable + }); + } + } +} diff --git a/src/components/sidebarLeft/tabs/privacy/forwardMessages.ts b/src/components/sidebarLeft/tabs/privacy/forwardMessages.ts new file mode 100644 index 00000000..d974daa7 --- /dev/null +++ b/src/components/sidebarLeft/tabs/privacy/forwardMessages.ts @@ -0,0 +1,19 @@ +import { SliderSuperTabEventable } from "../../../sliderTab"; +import PrivacySection from "../../../privacySection"; + +export default class AppPrivacyForwardMessagesTab extends SliderSuperTabEventable { + protected init() { + this.container.classList.add('privacy-tab', 'privacy-forward-messages'); + this.title.innerHTML = 'Forward Messages'; + + const caption = 'You can restrict who can add a link to your account when forwarding your messages.'; + new PrivacySection({ + tab: this, + title: 'Who can add a link to my account when forwarding my messages?', + inputKey: 'inputPrivacyKeyForwards', + captions: [caption, caption, caption], + exceptionTexts: ['Never Allow', 'Always Allow'], + appendTo: this.scrollable + }); + } +} diff --git a/src/components/sidebarLeft/tabs/privacy/lastSeen.ts b/src/components/sidebarLeft/tabs/privacy/lastSeen.ts new file mode 100644 index 00000000..e5a600ca --- /dev/null +++ b/src/components/sidebarLeft/tabs/privacy/lastSeen.ts @@ -0,0 +1,19 @@ +import { SliderSuperTabEventable } from "../../../sliderTab"; +import PrivacySection from "../../../privacySection"; + +export default class AppPrivacyLastSeenTab extends SliderSuperTabEventable { + protected init() { + this.container.classList.add('privacy-tab', 'privacy-last-seen'); + this.title.innerHTML = 'Last Seen & Online'; + + const caption = 'You won\'t see Last Seen and online statuses for people with whom you don\'t share yours.
Approximate last seen will be shown instead (recently, within a week, within a month).'; + new PrivacySection({ + tab: this, + title: 'Who can see your Last Seen time?', + inputKey: 'inputPrivacyKeyStatusTimestamp', + captions: [caption, caption, caption], + exceptionTexts: ['Never Share With', 'Always Share With'], + appendTo: this.scrollable + }); + } +} diff --git a/src/components/sidebarLeft/tabs/privacy/profilePhoto.ts b/src/components/sidebarLeft/tabs/privacy/profilePhoto.ts new file mode 100644 index 00000000..1df97680 --- /dev/null +++ b/src/components/sidebarLeft/tabs/privacy/profilePhoto.ts @@ -0,0 +1,21 @@ +import { SliderSuperTabEventable } from "../../../sliderTab"; +import PrivacySection from "../../../privacySection"; +import { PrivacyType } from "../../../../lib/appManagers/appPrivacyManager"; + +export default class AppPrivacyProfilePhotoTab extends SliderSuperTabEventable { + protected init() { + this.container.classList.add('privacy-tab', 'privacy-profile-photo'); + this.title.innerHTML = 'Profile Photo'; + + const caption = 'You can restrict who can see your profile photo with granular precision.'; + new PrivacySection({ + tab: this, + title: 'Who can see your profile photo?', + inputKey: 'inputPrivacyKeyChatInvite', + captions: [caption, caption, caption], + exceptionTexts: ['Never Share With', 'Always Share With'], + appendTo: this.scrollable, + skipTypes: [PrivacyType.Nobody] + }); + } +} diff --git a/src/components/sidebarLeft/tabs/privacyAndSecurity.ts b/src/components/sidebarLeft/tabs/privacyAndSecurity.ts index 2903707e..4036ca8e 100644 --- a/src/components/sidebarLeft/tabs/privacyAndSecurity.ts +++ b/src/components/sidebarLeft/tabs/privacyAndSecurity.ts @@ -1,19 +1,20 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import { generateSection, SettingSection } from ".."; import Row from "../../row"; import { AccountPassword, InputPrivacyKey, PrivacyRule } from "../../../layer"; -import appPrivacyManager from "../../../lib/appManagers/appPrivacyManager"; +import appPrivacyManager, { PrivacyType } from "../../../lib/appManagers/appPrivacyManager"; import AppPrivacyPhoneNumberTab from "./privacy/phoneNumber"; import AppTwoStepVerificationTab from "./2fa"; import passwordManager from "../../../lib/mtproto/passwordManager"; import AppTwoStepVerificationEnterPasswordTab from "./2fa/enterPassword"; import AppTwoStepVerificationEmailConfirmationTab from "./2fa/emailConfirmation"; +import AppPrivacyLastSeenTab from "./privacy/lastSeen"; +import AppPrivacyProfilePhotoTab from "./privacy/profilePhoto"; +import AppPrivacyForwardMessagesTab from "./privacy/forwardMessages"; +import AppPrivacyAddToGroupsTab from "./privacy/addToGroups"; +import AppPrivacyCallsTab from "./privacy/calls"; export default class AppPrivacyAndSecurityTab extends SliderSuperTab { - constructor(slider: SidebarSlider) { - super(slider, true); - } - protected init() { this.container.classList.add('privacy-container'); this.title.innerText = 'Privacy and Security'; @@ -94,40 +95,56 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab { const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({ title: 'Who can see your Last Seen time?', subtitle: 'Everybody', - clickable: true + clickable: () => { + new AppPrivacyLastSeenTab(this.slider).open() + } }); const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({ title: 'Who can see my profile photo?', subtitle: 'Everybody', - clickable: true + clickable: () => { + new AppPrivacyProfilePhotoTab(this.slider).open(); + } + }); + + const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({ + title: 'Who can call me?', + subtitle: 'Everybody', + clickable: () => { + new AppPrivacyCallsTab(this.slider).open(); + } }); const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({ title: 'Who can add a link to my account when forwarding my messages?', subtitle: 'Everybody', - clickable: true + clickable: () => { + new AppPrivacyForwardMessagesTab(this.slider).open(); + } }); const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({ title: 'Who can add me to group chats?', subtitle: 'Everybody', - clickable: true + clickable: () => { + new AppPrivacyAddToGroupsTab(this.slider).open(); + } }); for(const key in rowsByKeys) { const row = rowsByKeys[key as keyof typeof rowsByKeys]; appPrivacyManager.getPrivacy(key as keyof typeof rowsByKeys).then(rules => { const details = appPrivacyManager.getPrivacyRulesDetails(rules); - const type = details.type === 2 ? 'Everybody' : (details.type === 1 ? 'My Contacts' : 'Nobody'); - const disallowLength = details.disallowLengths.users + details.disallowLengths.chats; - const allowLength = details.allowLengths.users + details.allowLengths.chats; + const type = details.type === PrivacyType.Everybody ? 'Everybody' : (details.type === PrivacyType.Contacts ? 'My Contacts' : 'Nobody'); + const disallowLength = details.disallowPeers.users.length + details.disallowPeers.chats.length; + const allowLength = details.allowPeers.users.length + details.allowPeers.chats.length; const str = type + (disallowLength || allowLength ? ` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})` : ''); row.subtitle.innerHTML = str; }); } - container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, linkAccountRow.container, groupChatsAddRow.container); + container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, callRow.container, linkAccountRow.container, groupChatsAddRow.container); } } } diff --git a/src/components/sidebarLeft/tabs/settings.ts b/src/components/sidebarLeft/tabs/settings.ts index 4c403e23..bd74a408 100644 --- a/src/components/sidebarLeft/tabs/settings.ts +++ b/src/components/sidebarLeft/tabs/settings.ts @@ -1,4 +1,4 @@ -import SidebarSlider, { SliderSuperTab } from "../../slider"; +import { SliderSuperTab } from "../../slider"; import AvatarElement from "../../avatar"; import apiManager from "../../../lib/mtproto/mtprotoworker"; import appUsersManager from "../../../lib/appManagers/appUsersManager"; @@ -24,10 +24,6 @@ export default class AppSettingsTab extends SliderSuperTab { language: HTMLButtonElement } = {} as any; - constructor(slider: SidebarSlider) { - super(slider, true); - } - init() { this.container.classList.add('settings-container'); this.title.innerText = 'Settings'; @@ -146,6 +142,5 @@ export default class AppSettingsTab extends SliderSuperTab { } this.fillElements(); - return super.onOpen(); } } diff --git a/src/components/sliderTab.ts b/src/components/sliderTab.ts index e481ec60..91c8e9e8 100644 --- a/src/components/sliderTab.ts +++ b/src/components/sliderTab.ts @@ -1,3 +1,4 @@ +import EventListenerBase from "../helpers/eventListenerBase"; import ButtonIcon from "./buttonIcon"; import Scrollable from "./scrollable"; import SidebarSlider from "./slider"; @@ -23,7 +24,17 @@ export default class SliderSuperTab implements SliderTab { public content: HTMLElement; public scrollable: Scrollable; - constructor(protected slider: SidebarSlider, protected destroyable = false) { + public slider: SidebarSlider; + public destroyable: boolean; + + constructor(slider: SidebarSlider, destroyable?: boolean) { + this._constructor(slider, destroyable); + } + + public _constructor(slider: SidebarSlider, destroyable = true): any { + this.slider = slider; + this.destroyable = destroyable; + this.container = document.createElement('div'); this.container.classList.add('sidebar-slider-item'); @@ -67,11 +78,6 @@ export default class SliderSuperTab implements SliderTab { } - // * fix incompability - public onOpen() { - - } - public onCloseAfterTimeout() { if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой ! this.slider.tabs.delete(this); @@ -79,3 +85,35 @@ export default class SliderSuperTab implements SliderTab { } } } + +export class SliderSuperTabEventable extends SliderSuperTab { + public eventListener: EventListenerBase<{ + destroy: () => void + }>; + + constructor(slider: SidebarSlider) { + super(slider); + this.eventListener = new EventListenerBase(); + } + + onCloseAfterTimeout() { + this.eventListener.setListenerResult('destroy'); + this.eventListener.cleanup(); + return super.onCloseAfterTimeout(); + } +} + +/* // @ts-ignore +interface SliderSuperEventsTab extends SliderSuperTab, EventListenerBase<{}> { + superConstructor: (...args: any[]) => any; +} +class SliderSuperEventsTab implements SliderSuperEventsTab { + constructor(slider: SidebarSlider) { + this.superConstructor([slider, true]); + } +} +applyMixins(SliderSuperEventsTab, [SliderSuperTab, EventListenerBase]); + +(window as any).lol = SliderSuperEventsTab + +export {SliderSuperEventsTab}; */ diff --git a/src/helpers/applyMixins.ts b/src/helpers/applyMixins.ts new file mode 100644 index 00000000..759280ae --- /dev/null +++ b/src/helpers/applyMixins.ts @@ -0,0 +1,37 @@ +export default function applyMixins(derivedCtor: any, constructors: any[]) { + const callbacks: Array<(...args: any[]) => any> = []; + + constructors.forEach((baseCtor) => { + Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => { + const value: PropertyDescriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name) || Object.create(null); + if(name === '_constructor') { + callbacks.push(value.value); + return; + } else if(name === 'constructor') { + return; + } + + Object.defineProperty( + derivedCtor.prototype, + name, + value + ); + }); + }); + + if(callbacks.length) { + function c(...args: any[]): any { + callbacks.forEach((cb, idx) => { + // @ts-ignore + cb.apply(this, args[idx] || []); + }); + }; + + Object.defineProperty(derivedCtor.prototype, 'superConstructor', { + configurable: true, + enumerable: true, + value: c, + writable: true + }); + } +} diff --git a/src/helpers/eventListenerBase.ts b/src/helpers/eventListenerBase.ts index 15255bb7..ff4344b4 100644 --- a/src/helpers/eventListenerBase.ts +++ b/src/helpers/eventListenerBase.ts @@ -1,27 +1,39 @@ import type { ArgumentTypes, SuperReturnType } from "../types"; +/** + * Better not to remove listeners during setting + * Should add listener callback only once + */ export default class EventListenerBase { protected listeners: Partial<{ - [k in keyof Listeners]: Array<{callback: Listeners[k], once?: true}> - }> = {}; + [k in keyof Listeners]: Array<{callback: Listeners[k], once?: boolean}> + }>; protected listenerResults: Partial<{ [k in keyof Listeners]: ArgumentTypes - }> = {}; + }>; - constructor(private reuseResults?: true) { + private reuseResults: boolean; + constructor(reuseResults?: boolean) { + this._constructor(reuseResults); } - public addListener(name: keyof Listeners, callback: Listeners[typeof name], once?: true) { - (this.listeners[name] ?? (this.listeners[name] = [])).push({callback, once}); + public _constructor(reuseResults = false): any { + this.reuseResults = reuseResults; + this.listeners = {}; + this.listenerResults = {}; + } + public addListener(name: keyof Listeners, callback: Listeners[typeof name], once?: boolean) { if(this.listenerResults.hasOwnProperty(name)) { callback(...this.listenerResults[name]); - + if(once) { - this.removeListener(name, callback); + return; } } + + (this.listeners[name] ?? (this.listeners[name] = [])).push({callback, once}); } public removeListener(name: keyof Listeners, callback: Listeners[typeof name]) { @@ -37,16 +49,40 @@ export default class EventListenerBase> = []; - if(this.listeners[name]) { - this.listeners[name].forEach(listener => { + const listeners = this.listeners[name]; + if(listeners) { + // ! this one will guarantee execution even if delete another listener during setting + const left = listeners.slice(); + left.forEach(listener => { + const index = listeners.findIndex(l => l.callback === listener.callback); + if(index === -1) { + return; + } + arr.push(listener.callback(...args)); if(listener.once) { this.removeListener(name, listener.callback); } }); + + /* for(let i = 0, length = listeners.length; i < length; ++i) { + const listener = listeners[i]; + arr.push(listener.callback(...args)); + + if(listener.once) { + listeners.splice(i, 1); + --i; + --length; + } + } */ } return arr; } -} \ No newline at end of file + + public cleanup() { + this.listeners = {}; + this.listenerResults = {}; + } +} diff --git a/src/lib/appManagers/appPrivacyManager.ts b/src/lib/appManagers/appPrivacyManager.ts index 52e61efc..4082f821 100644 --- a/src/lib/appManagers/appPrivacyManager.ts +++ b/src/lib/appManagers/appPrivacyManager.ts @@ -1,14 +1,36 @@ import { MOUNT_CLASS_TO } from "../../config/debug"; -import { InputPrivacyKey, PrivacyRule } from "../../layer"; +import { InputPrivacyKey, InputPrivacyRule, PrivacyRule } from "../../layer"; import apiManager from "../mtproto/mtprotoworker"; import appChatsManager from "./appChatsManager"; import appUsersManager from "./appUsersManager"; +export enum PrivacyType { + Everybody = 2, + Contacts = 1, + Nobody = 0 +} + export class AppPrivacyManager { constructor() { } + public setPrivacy(inputKey: InputPrivacyKey['_'], rules: InputPrivacyRule[]) { + return apiManager.invokeApi('account.setPrivacy', { + key: { + _: inputKey + }, + rules + }).then(privacyRules => { + /* appUsersManager.saveApiUsers(privacyRules.users); + appChatsManager.saveApiChats(privacyRules.chats); + + console.log('privacy rules', inputKey, privacyRules, privacyRules.rules); */ + + return privacyRules.rules; + }); + } + public getPrivacy(inputKey: InputPrivacyKey['_']) { return apiManager.invokeApi('account.getPrivacy', { key: { @@ -18,16 +40,17 @@ export class AppPrivacyManager { appUsersManager.saveApiUsers(privacyRules.users); appChatsManager.saveApiChats(privacyRules.chats); - console.log('privacy rules', inputKey, privacyRules, privacyRules.rules); + //console.log('privacy rules', inputKey, privacyRules, privacyRules.rules); return privacyRules.rules; }); } public getPrivacyRulesDetails(rules: PrivacyRule[]) { - const types: number[] = []; + const types: PrivacyType[] = []; - let allowLengths = {users: 0, chats: 0}, disallowLengths = {users: 0, chats: 0}; + type peers = {users: number[], chats: number[]}; + let allowPeers: peers = {users: [], chats: []}, disallowPeers: peers = {users: [], chats: []}; rules.forEach(rule => { switch(rule._) { case 'privacyValueAllowAll': @@ -43,21 +66,21 @@ export class AppPrivacyManager { types.push('Except My Contacts'); break; */ case 'privacyValueAllowChatParticipants': - allowLengths.chats += rule.chats.length; + allowPeers.chats.push(...rule.chats); break; case 'privacyValueAllowUsers': - allowLengths.users += rule.users.length; + allowPeers.users.push(...rule.users); break; case 'privacyValueDisallowChatParticipants': - disallowLengths.chats += rule.chats.length; + disallowPeers.chats.push(...rule.chats); break; case 'privacyValueDisallowUsers': - disallowLengths.users += rule.users.length; + disallowPeers.users.push(...rule.users); break; } }); - return {type: types[0], disallowLengths, allowLengths}; + return {type: types[0], disallowPeers, allowPeers}; } } diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index e5193d64..560e60e8 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -1214,9 +1214,9 @@ export default class MTPNetworker { // ! таймаут очень сильно тормозит скорость работы сокета (даже нулевой) public scheduleRequest(delay?: number) { - if(!this.isOnline) { + /* if(!this.isOnline) { return; - } + } */ /// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD if(!(this.transport instanceof HTTP)) { @@ -1256,9 +1256,9 @@ export default class MTPNetworker { return; } /// #else - if(!this.isOnline) { + /* if(!this.isOnline) { return; - } + } */ this.performScheduledRequest(); /// #endif