Two-Step Verification layout
This commit is contained in:
parent
3e514c1caa
commit
23fd0376ba
@ -218,7 +218,7 @@ export default class ChatTopbar {
|
||||
|
||||
this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);
|
||||
|
||||
this.btnJoin = Button('btn-primary chat-join hide');
|
||||
this.btnJoin = Button('btn-primary btn-color-primary chat-join hide');
|
||||
this.btnJoin.append('SUBSCRIBE');
|
||||
|
||||
this.btnPinned = ButtonIcon('pinlist');
|
||||
|
@ -32,7 +32,8 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
animate = false;
|
||||
}
|
||||
|
||||
if(target.classList.contains('active') || id === selectTab.prevId) {
|
||||
const prevId = selectTab.prevId();
|
||||
if(target.classList.contains('active') || id === prevId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -42,7 +43,6 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
|
||||
prev && prev.classList.remove('active');
|
||||
});
|
||||
|
||||
const prevId = selectTab.prevId;
|
||||
// stripe from ZINCHUK
|
||||
if(useStripe && prevId !== -1 && animate) {
|
||||
fastRaf(() => {
|
||||
|
@ -66,7 +66,7 @@ export default class PopupAvatar extends PopupElement {
|
||||
}, false);
|
||||
|
||||
this.btnSubmit = document.createElement('button');
|
||||
this.btnSubmit.className = 'btn-primary btn-circle btn-crop btn-icon tgico-check z-depth-1';
|
||||
this.btnSubmit.className = 'btn-primary btn-color-primary btn-circle btn-crop btn-icon tgico-check z-depth-1';
|
||||
ripple(this.btnSubmit);
|
||||
this.btnSubmit.addEventListener('click', () => {
|
||||
this.cropper.crop();
|
||||
|
@ -64,7 +64,7 @@ export default class PopupElement {
|
||||
|
||||
if(options.withConfirm) {
|
||||
this.btnConfirm = document.createElement('button');
|
||||
this.btnConfirm.classList.add('btn-primary');
|
||||
this.btnConfirm.classList.add('btn-primary', 'btn-color-primary');
|
||||
this.btnConfirm.innerText = options.withConfirm;
|
||||
this.header.append(this.btnConfirm);
|
||||
ripple(this.btnConfirm);
|
||||
|
@ -97,7 +97,7 @@ export default class PopupStickers extends PopupElement {
|
||||
|
||||
this.h6.innerHTML = RichTextProcessor.wrapEmojiText(set.set.title);
|
||||
!set.set.installed_date ? this.stickersFooter.classList.add('add') : this.stickersFooter.classList.remove('add');
|
||||
this.stickersFooter.innerHTML = set.set.hasOwnProperty('installed_date') ? '<div style="cursor: pointer; margin: 0 auto; width: 150px;">Remove stickers</div>' : `<button class="btn-primary">ADD ${set.set.count} STICKERS</button>`;
|
||||
this.stickersFooter.innerHTML = set.set.hasOwnProperty('installed_date') ? '<div style="cursor: pointer; margin: 0 auto; width: 150px;">Remove stickers</div>' : `<button class="btn-primary btn-color-primary">ADD ${set.set.count} STICKERS</button>`;
|
||||
|
||||
this.stickersFooter.addEventListener('click', this.onFooterClick);
|
||||
|
||||
|
@ -13,33 +13,18 @@ import Scrollable, { ScrollableX } from "../scrollable";
|
||||
import InputSearch from "../inputSearch";
|
||||
import SidebarSlider from "../slider";
|
||||
import { TransitionSlider } from "../transition";
|
||||
import AppAddMembersTab from "./tabs/addMembers";
|
||||
import AppArchivedTab from "./tabs/archivedTab";
|
||||
import AppChatFoldersTab from "./tabs/chatFolders";
|
||||
import AppContactsTab from "./tabs/contacts";
|
||||
import AppEditFolderTab from "./tabs/editFolder";
|
||||
import AppEditProfileTab from "./tabs/editProfile";
|
||||
import AppIncludedChatsTab from "./tabs/includedChats";
|
||||
import AppNewChannelTab from "./tabs/newChannel";
|
||||
import AppNewGroupTab from "./tabs/newGroup";
|
||||
import AppSettingsTab from "./tabs/settings";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import apiManagerProxy from "../../lib/mtproto/mtprotoworker";
|
||||
import AppSearchSuper from "../appSearchSuper.";
|
||||
import { DateData, fillTipDates } from "../../helpers/date";
|
||||
import AppGeneralSettingsTab from "./tabs/generalSettings";
|
||||
import AppPrivacyAndSecurityTab from "./tabs/privacyAndSecurity";
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
|
||||
const contactsTab = new AppContactsTab();
|
||||
const archivedTab = new AppArchivedTab();
|
||||
import AppSettingsTab from "./tabs/settings";
|
||||
import AppNewChannelTab from "./tabs/newChannel";
|
||||
import AppContactsTab from "./tabs/contacts";
|
||||
import AppArchivedTab from "./tabs/archivedTab";
|
||||
import AppAddMembersTab from "./tabs/addMembers";
|
||||
|
||||
export class AppSidebarLeft extends SidebarSlider {
|
||||
public static SLIDERITEMSIDS = {
|
||||
archived: 1,
|
||||
contacts: 2
|
||||
};
|
||||
|
||||
private toolsBtn: HTMLButtonElement;
|
||||
private backBtn: HTMLButtonElement;
|
||||
//private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||
@ -63,19 +48,6 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
privateChat: HTMLButtonElement,
|
||||
} = {} as any;
|
||||
|
||||
public archivedTab: AppArchivedTab;
|
||||
public newChannelTab: AppNewChannelTab;
|
||||
public addMembersTab: AppAddMembersTab;
|
||||
public contactsTab: AppContactsTab;
|
||||
public newGroupTab: AppNewGroupTab;
|
||||
public settingsTab: AppSettingsTab;
|
||||
public editProfileTab: AppEditProfileTab;
|
||||
public chatFoldersTab: AppChatFoldersTab;
|
||||
public editFolderTab: AppEditFolderTab;
|
||||
public includedChatsTab: AppIncludedChatsTab;
|
||||
public generalSettingsTab: AppGeneralSettingsTab;
|
||||
public privacyAndSecurityTab: AppPrivacyAndSecurityTab;
|
||||
|
||||
//private log = logger('SL');
|
||||
|
||||
private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;
|
||||
@ -87,11 +59,6 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
navigationType: 'left'
|
||||
});
|
||||
|
||||
Object.assign(this.tabs, {
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.archived]: archivedTab,
|
||||
[AppSidebarLeft.SLIDERITEMSIDS.contacts]: contactsTab
|
||||
});
|
||||
|
||||
//this._selectTab(0); // make first tab as default
|
||||
|
||||
this.inputSearch = new InputSearch('Telegram Search');
|
||||
@ -101,19 +68,6 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
|
||||
this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
||||
|
||||
this.archivedTab = archivedTab;
|
||||
this.newChannelTab = new AppNewChannelTab(this);
|
||||
this.contactsTab = contactsTab;
|
||||
this.newGroupTab = new AppNewGroupTab(this);
|
||||
this.settingsTab = new AppSettingsTab(this);
|
||||
this.chatFoldersTab = new AppChatFoldersTab(appMessagesManager, appPeersManager, this, apiManagerProxy, rootScope);
|
||||
this.editFolderTab = new AppEditFolderTab(this);
|
||||
this.includedChatsTab = new AppIncludedChatsTab(this);
|
||||
this.editProfileTab = new AppEditProfileTab(this);
|
||||
this.generalSettingsTab = new AppGeneralSettingsTab(this);
|
||||
this.privacyAndSecurityTab = new AppPrivacyAndSecurityTab(this);
|
||||
this.addMembersTab = new AppAddMembersTab(this);
|
||||
|
||||
this.menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||
this.newBtnMenu = this.sidebarEl.querySelector('#new-menu');
|
||||
|
||||
@ -132,29 +86,29 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
});
|
||||
|
||||
attachClickEvent(this.buttons.archived, (e) => {
|
||||
this.selectTab(AppSidebarLeft.SLIDERITEMSIDS.archived);
|
||||
new AppArchivedTab(this).open();
|
||||
});
|
||||
|
||||
attachClickEvent(this.buttons.contacts, (e) => {
|
||||
this.contactsTab.openContacts();
|
||||
new AppContactsTab(this).open();
|
||||
});
|
||||
|
||||
attachClickEvent(this.buttons.settings, (e) => {
|
||||
this.settingsTab.open();
|
||||
new AppSettingsTab(this).open();
|
||||
});
|
||||
|
||||
attachClickEvent(this.newButtons.channel, (e) => {
|
||||
this.newChannelTab.open();
|
||||
new AppNewChannelTab(this).open();
|
||||
});
|
||||
|
||||
[this.newButtons.group, this.buttons.newGroup].forEach(btn => {
|
||||
attachClickEvent(btn, (e) => {
|
||||
this.addMembersTab.open({
|
||||
new AppAddMembersTab(this).open({
|
||||
peerId: 0,
|
||||
type: 'chat',
|
||||
skippable: false,
|
||||
takeOut: (peerIds) => {
|
||||
this.newGroupTab.open(peerIds);
|
||||
new AppNewGroupTab(this).open(peerIds);
|
||||
},
|
||||
title: 'Add Members',
|
||||
placeholder: 'Add People...'
|
||||
|
@ -9,6 +9,7 @@ import { attachClickEvent } from "../../../../helpers/dom";
|
||||
import PopupConfirmAction from "../../../popups/confirmAction";
|
||||
import { putPreloader } from "../../../misc";
|
||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||
import AppTwoStepVerificationSetTab from "./passwordSet";
|
||||
|
||||
export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
||||
public inputField: InputField;
|
||||
@ -22,7 +23,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('two-step-verification-email');
|
||||
this.container.classList.add('two-step-verification', 'two-step-verification-email');
|
||||
this.title.innerHTML = 'Recovery Email';
|
||||
|
||||
const section = new SettingSection({
|
||||
@ -34,17 +35,21 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
||||
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
||||
const stickerContainer = document.createElement('div');
|
||||
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 168,
|
||||
height: 168,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
if(doc) {
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 160,
|
||||
height: 160,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
} else {
|
||||
stickerContainer.classList.add('media-sticker-wrapper');
|
||||
}
|
||||
|
||||
section.content.append(stickerContainer);
|
||||
|
||||
@ -58,9 +63,13 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
||||
label: 'Recovery Email'
|
||||
});
|
||||
|
||||
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
|
||||
|
||||
const goNext = () => {
|
||||
new AppTwoStepVerificationSetTab(this.slider).open();
|
||||
};
|
||||
|
||||
attachClickEvent(btnSkip, (e) => {
|
||||
const popup = new PopupConfirmAction('popup-skip-email', [{
|
||||
text: 'CANCEL',
|
||||
@ -68,20 +77,25 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
|
||||
}, {
|
||||
text: 'SKIP',
|
||||
callback: () => {
|
||||
inputContent.classList.add('sidebar-left-section-disabled');
|
||||
//inputContent.classList.add('sidebar-left-section-disabled');
|
||||
btnContinue.setAttribute('disabled', 'true');
|
||||
btnSkip.setAttribute('disabled', 'true');
|
||||
putPreloader(btnSkip);
|
||||
passwordManager.updateSettings({
|
||||
hint: this.hint,
|
||||
currentPassword: this.plainPassword,
|
||||
newPassword: this.newPassword
|
||||
}).then(() => {
|
||||
|
||||
goNext();
|
||||
}, (err) => {
|
||||
btnContinue.removeAttribute('disabled');
|
||||
btnSkip.removeAttribute('disabled');
|
||||
});
|
||||
},
|
||||
isDanger: true,
|
||||
}], {
|
||||
title: 'Warning',
|
||||
text: 'No, seriously.<br/><br/>If you forget your password, you will<br/>lose access to your Telegram account.<br/>There will be no way to restore it.'
|
||||
text: 'No, seriously.<br/><br/>If you forget your password, you will lose access to your Telegram account. There will be no way to restore it.'
|
||||
});
|
||||
|
||||
popup.show();
|
||||
|
@ -3,6 +3,7 @@ import { SettingSection } from "../..";
|
||||
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
|
||||
import { AccountPassword } from "../../../../layer";
|
||||
import passwordManager from "../../../../lib/mtproto/passwordManager";
|
||||
import RichTextProcessor from "../../../../lib/richtextprocessor";
|
||||
import Button from "../../../button";
|
||||
import { putPreloader } from "../../../misc";
|
||||
import PasswordMonkey from "../../../monkeys/password";
|
||||
@ -22,7 +23,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
||||
|
||||
protected init() {
|
||||
const isNew = !this.state.pFlags.has_password || this.plainPassword;
|
||||
this.container.classList.add('two-step-verification-enter-password');
|
||||
this.container.classList.add('two-step-verification', 'two-step-verification-enter-password');
|
||||
this.title.innerHTML = isNew ? 'Enter a Password' : 'Enter your Password';
|
||||
|
||||
const section = new SettingSection({
|
||||
@ -40,7 +41,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
||||
const monkey = new PasswordMonkey(passwordInputField, 157);
|
||||
monkey.load();
|
||||
|
||||
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||
|
||||
inputWrapper.append(passwordInputField.container, btnContinue);
|
||||
section.content.append(monkey.container, inputWrapper);
|
||||
@ -80,7 +81,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
||||
return passwordManager.getState().then(_state => {
|
||||
this.state = _state;
|
||||
|
||||
passwordInputField.label.innerText = this.state.hint ?? 'Password';
|
||||
passwordInputField.label.innerHTML = this.state.hint ? RichTextProcessor.wrapEmojiText(this.state.hint) : 'Password';
|
||||
});
|
||||
};
|
||||
|
||||
@ -105,6 +106,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
|
||||
tab.state = this.state;
|
||||
tab.plainPassword = plainPassword;
|
||||
tab.open();
|
||||
this.slider.removeTabFromHistory(this);
|
||||
}
|
||||
}, (err) => {
|
||||
btnContinue.removeAttribute('disabled');
|
||||
|
@ -19,7 +19,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('two-step-verification-hint');
|
||||
this.container.classList.add('two-step-verification', 'two-step-verification-hint');
|
||||
this.title.innerHTML = 'Password Hint';
|
||||
|
||||
const section = new SettingSection({
|
||||
@ -31,17 +31,21 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
||||
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
||||
const stickerContainer = document.createElement('div');
|
||||
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 168,
|
||||
height: 168,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
if(doc) {
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 160,
|
||||
height: 160,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
} else {
|
||||
stickerContainer.classList.add('media-sticker-wrapper');
|
||||
}
|
||||
|
||||
section.content.append(stickerContainer);
|
||||
|
||||
@ -72,7 +76,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
|
||||
tab.open();
|
||||
};
|
||||
|
||||
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||
const btnSkip = Button('btn-primary btn-primary-transparent primary', {text: 'SKIP'});
|
||||
|
||||
attachClickEvent(btnContinue, (e) => goNext(e, true));
|
||||
|
@ -30,23 +30,27 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
||||
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
||||
const stickerContainer = document.createElement('div');
|
||||
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 168,
|
||||
height: 168,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
if(doc) {
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 168,
|
||||
height: 168,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
} else {
|
||||
stickerContainer.classList.add('media-sticker-wrapper');
|
||||
}
|
||||
|
||||
section.content.append(stickerContainer);
|
||||
|
||||
const c = section.generateContentElement();
|
||||
if(this.state.pFlags.has_password) {
|
||||
section.caption.innerHTML = 'You have enabled Two-Step verification.<br/>You\'ll need the password you set up here to log in to your Telegram account';
|
||||
section.caption.innerHTML = 'You have enabled Two-Step verification.<br/>You\'ll need the password you set up here to log in to your Telegram account.';
|
||||
|
||||
const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'Change Password'});
|
||||
const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'Turn Password Off'});
|
||||
@ -78,8 +82,13 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
|
||||
} else {
|
||||
section.caption.innerHTML = 'You can set a password that will be required when you log in on a new device in addition to the code you get in the SMS.';
|
||||
|
||||
const btnSetPassword = Button('btn-primary', {text: 'SET PASSWORD'});
|
||||
c.append(btnSetPassword);
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
const btnSetPassword = Button('btn-primary btn-color-primary', {text: 'SET PASSWORD'});
|
||||
|
||||
inputWrapper.append(btnSetPassword);
|
||||
c.append(inputWrapper);
|
||||
|
||||
attachClickEvent(btnSetPassword, (e) => {
|
||||
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
|
||||
|
61
src/components/sidebarLeft/tabs/2fa/passwordSet.ts
Normal file
61
src/components/sidebarLeft/tabs/2fa/passwordSet.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { SettingSection } from "../..";
|
||||
import { attachClickEvent } from "../../../../helpers/dom";
|
||||
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
|
||||
import Button from "../../../button";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../../slider";
|
||||
import { wrapSticker } from "../../../wrappers";
|
||||
|
||||
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!';
|
||||
|
||||
const section = new SettingSection({
|
||||
caption: 'This password will be required when you log in on a new device in addition to the code you get via SMS.',
|
||||
noDelimiter: true
|
||||
});
|
||||
|
||||
const emoji = '🥳';
|
||||
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
|
||||
const stickerContainer = document.createElement('div');
|
||||
|
||||
if(doc) {
|
||||
wrapSticker({
|
||||
doc,
|
||||
div: stickerContainer,
|
||||
loop: false,
|
||||
play: true,
|
||||
width: 160,
|
||||
height: 160,
|
||||
emoji
|
||||
}).then(() => {
|
||||
// this.animation = player;
|
||||
});
|
||||
} else {
|
||||
stickerContainer.classList.add('media-sticker-wrapper');
|
||||
}
|
||||
|
||||
section.content.append(stickerContainer);
|
||||
|
||||
const inputContent = section.generateContentElement();
|
||||
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
const btnReturn = Button('btn-primary btn-color-primary', {text: 'RETURN TO SETTINGS'});
|
||||
|
||||
attachClickEvent(btnReturn, (e) => {
|
||||
|
||||
});
|
||||
|
||||
inputWrapper.append(btnReturn);
|
||||
|
||||
inputContent.append(inputWrapper);
|
||||
|
||||
this.scrollable.container.append(section.container);
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('two-step-verification-enter-password', 'two-step-verification-re-enter-password');
|
||||
this.container.classList.add('two-step-verification', 'two-step-verification-enter-password', 'two-step-verification-re-enter-password');
|
||||
this.title.innerHTML = 'Re-Enter your Password';
|
||||
|
||||
const section = new SettingSection({
|
||||
@ -37,7 +37,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
|
||||
const monkey = new TrackingMonkey(passwordInputField, 157);
|
||||
monkey.load();
|
||||
|
||||
const btnContinue = Button('btn-primary', {text: 'CONTINUE'});
|
||||
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
|
||||
|
||||
inputWrapper.append(passwordInputField.container, btnContinue);
|
||||
section.content.append(monkey.container, inputWrapper);
|
||||
|
@ -12,7 +12,7 @@ export default class AppAddMembersTab extends SliderSuperTab {
|
||||
private skippable: boolean;
|
||||
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider);
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -44,13 +44,6 @@ export default class AppAddMembersTab extends SliderSuperTab {
|
||||
});
|
||||
}
|
||||
|
||||
public onCloseAfterTimeout() {
|
||||
if(this.selector) {
|
||||
this.selector.container.remove();
|
||||
this.selector = null;
|
||||
}
|
||||
}
|
||||
|
||||
public open(options: {
|
||||
title: string,
|
||||
placeholder: string,
|
||||
@ -67,7 +60,6 @@ export default class AppAddMembersTab extends SliderSuperTab {
|
||||
this.takeOut = options.takeOut;
|
||||
this.skippable = options.skippable;
|
||||
|
||||
this.onCloseAfterTimeout();
|
||||
this.selector = new AppSelectPeers({
|
||||
appendTo: this.content,
|
||||
onChange: this.skippable ? null : (length) => {
|
||||
|
@ -1,23 +1,27 @@
|
||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||
import Scrollable from "../../scrollable";
|
||||
import { SliderTab } from "../../slider";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
|
||||
export default class AppArchivedTab implements SliderTab {
|
||||
public container = document.getElementById('chats-archived-container') as HTMLDivElement;
|
||||
public chatList = document.getElementById('dialogs-archived') as HTMLUListElement;
|
||||
public scroll: Scrollable = null;
|
||||
export default class AppArchivedTab extends SliderSuperTab {
|
||||
public loadedAll: boolean;
|
||||
public loadDialogsPromise: Promise<any>;
|
||||
public wasFilterId: number;
|
||||
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.scroll = new Scrollable(this.container, 'CLA', 500);
|
||||
this.scroll.container.addEventListener('scroll', appDialogsManager.onChatsRegularScroll);
|
||||
this.scroll.setVirtualContainer(this.chatList);
|
||||
this.scroll.onScrolledBottom = appDialogsManager.onChatsScroll;
|
||||
this.container.id = 'chats-archived-container';
|
||||
this.title.innerHTML = 'Archived Chats';
|
||||
|
||||
//this.scrollable = new Scrollable(this.container, 'CLA', 500);
|
||||
this.scrollable.append(appDialogsManager.chatListArchived);
|
||||
this.scrollable.container.addEventListener('scroll', appDialogsManager.onChatsRegularScroll);
|
||||
this.scrollable.setVirtualContainer(appDialogsManager.chatListArchived);
|
||||
this.scrollable.onScrolledBottom = appDialogsManager.onChatsScroll;
|
||||
///this.scroll.attachSentinels();
|
||||
|
||||
appDialogsManager.setListClickListener(this.chatList, null, true);
|
||||
appDialogsManager.setListClickListener(appDialogsManager.chatListArchived, null, true);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
setTimeout(appDialogsManager.scroll.checkForTriggers, 0);
|
||||
@ -31,9 +35,11 @@ export default class AppArchivedTab implements SliderTab {
|
||||
}
|
||||
|
||||
this.wasFilterId = appDialogsManager.filterId;
|
||||
appDialogsManager.scroll = this.scroll;
|
||||
appDialogsManager.scroll = this.scrollable;
|
||||
appDialogsManager.filterId = 1;
|
||||
appDialogsManager.onTabChange();
|
||||
|
||||
return super.onOpen();
|
||||
}
|
||||
|
||||
// вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...
|
||||
@ -48,6 +54,7 @@ export default class AppArchivedTab implements SliderTab {
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
this.chatList.innerHTML = '';
|
||||
appDialogsManager.chatListArchived.innerHTML = '';
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
import { SliderTab, SliderSuperTab } from "../../slider";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
|
||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import { cancelEvent, positionElementByIndex } from "../../../helpers/dom";
|
||||
import { ripple } from "../../ripple";
|
||||
import { toast } from "../../toast";
|
||||
import type { ApiManagerProxy } from "../../../lib/mtproto/mtprotoworker";
|
||||
import type { AppMessagesManager } from "../../../lib/appManagers/appMessagesManager";
|
||||
import type { MyDialogFilter } from "../../../lib/storages/filters";
|
||||
import type { AppPeersManager } from "../../../lib/appManagers/appPeersManager";
|
||||
import type { AppSidebarLeft } from "..";
|
||||
import type { DialogFilterSuggested, DialogFilter } from "../../../layer";
|
||||
import type _rootScope from "../../../lib/rootScope";
|
||||
import Button from "../../button";
|
||||
import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../../../lib/appManagers/appPeersManager";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import AppEditFolderTab from "./editFolder";
|
||||
|
||||
export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
public createFolderBtn: HTMLElement;
|
||||
@ -22,8 +23,8 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
|
||||
private filtersRendered: {[filterId: number]: HTMLElement} = {};
|
||||
|
||||
constructor(private appMessagesManager: AppMessagesManager, private appPeersManager: AppPeersManager, private appSidebarLeft: AppSidebarLeft, private apiManager: ApiManagerProxy, private rootScope: typeof _rootScope) {
|
||||
super(appSidebarLeft);
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, div: HTMLElement = document.createElement('div')) {
|
||||
@ -40,7 +41,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
const filterId = filter.id;
|
||||
if(!this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
div.addEventListener('click', () => {
|
||||
this.appSidebarLeft.editFolderTab.open(this.appMessagesManager.filtersStorage.filters[filterId]);
|
||||
new AppEditFolderTab(this.slider).open(appMessagesManager.filtersStorage.filters[filterId]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -65,11 +66,11 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
else if(pFlags.exclude_archived) description += 'Unarchived';
|
||||
d.push(description);
|
||||
} else {
|
||||
const folder = this.appMessagesManager.dialogsStorage.getFolder(filter.id);
|
||||
const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);
|
||||
let chats = 0, channels = 0, groups = 0;
|
||||
for(const dialog of folder) {
|
||||
if(this.appPeersManager.isAnyGroup(dialog.peerId)) groups++;
|
||||
else if(this.appPeersManager.isBroadcast(dialog.peerId)) channels++;
|
||||
if(appPeersManager.isAnyGroup(dialog.peerId)) groups++;
|
||||
else if(appPeersManager.isBroadcast(dialog.peerId)) channels++;
|
||||
else chats++;
|
||||
}
|
||||
|
||||
@ -109,7 +110,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
caption.classList.add('caption');
|
||||
caption.innerHTML = `Create folders for different groups of chats<br>and quickly switch between them.`;
|
||||
|
||||
this.createFolderBtn = Button('btn-primary btn-create-folder', {
|
||||
this.createFolderBtn = Button('btn-primary btn-color-primary btn-create-folder', {
|
||||
text: 'Create Folder',
|
||||
icon: 'add'
|
||||
});
|
||||
@ -139,7 +140,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
if(Object.keys(this.filtersRendered).length >= 10) {
|
||||
toast('Sorry, you can\'t create more folders.');
|
||||
} else {
|
||||
this.appSidebarLeft.editFolderTab.open();
|
||||
new AppEditFolderTab(this.slider).open();
|
||||
}
|
||||
});
|
||||
|
||||
@ -153,13 +154,13 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
this.animation = player;
|
||||
});
|
||||
|
||||
this.appMessagesManager.filtersStorage.getDialogFilters().then(filters => {
|
||||
appMessagesManager.filtersStorage.getDialogFilters().then(filters => {
|
||||
for(const filter of filters) {
|
||||
this.renderFolder(filter, this.foldersContainer);
|
||||
}
|
||||
});
|
||||
|
||||
this.rootScope.on('filter_update', (e) => {
|
||||
rootScope.on('filter_update', (e) => {
|
||||
const filter = e;
|
||||
if(this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
this.renderFolder(filter, null, this.filtersRendered[filter.id]);
|
||||
@ -170,7 +171,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
this.getSuggestedFilters();
|
||||
});
|
||||
|
||||
this.rootScope.on('filter_delete', (e) => {
|
||||
rootScope.on('filter_delete', (e) => {
|
||||
const filter = e;
|
||||
if(this.filtersRendered.hasOwnProperty(filter.id)) {
|
||||
/* for(const suggested of this.suggestedFilters) {
|
||||
@ -185,7 +186,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
}
|
||||
});
|
||||
|
||||
this.rootScope.on('filter_order', (e) => {
|
||||
rootScope.on('filter_order', (e) => {
|
||||
const order = e;
|
||||
order.forEach((filterId, idx) => {
|
||||
const div = this.filtersRendered[filterId];
|
||||
@ -197,14 +198,14 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
}
|
||||
|
||||
private getSuggestedFilters() {
|
||||
this.apiManager.invokeApi('messages.getSuggestedDialogFilters').then(suggestedFilters => {
|
||||
apiManager.invokeApi('messages.getSuggestedDialogFilters').then(suggestedFilters => {
|
||||
this.suggestedContainer.style.display = suggestedFilters.length ? '' : 'none';
|
||||
Array.from(this.suggestedContainer.children).slice(1).forEach(el => el.remove());
|
||||
|
||||
suggestedFilters.forEach(filter => {
|
||||
const div = this.renderFolder(filter);
|
||||
const button = document.createElement('button');
|
||||
button.classList.add('btn-primary');
|
||||
button.classList.add('btn-primary', 'btn-color-primary');
|
||||
button.innerText = 'Add';
|
||||
div.append(button);
|
||||
this.suggestedContainer.append(div);
|
||||
@ -219,7 +220,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
|
||||
button.setAttribute('disabled', 'true');
|
||||
|
||||
this.appMessagesManager.filtersStorage.createDialogFilter(filter.filter as any).then(bool => {
|
||||
appMessagesManager.filtersStorage.createDialogFilter(filter.filter as any).then(bool => {
|
||||
if(bool) {
|
||||
div.remove();
|
||||
}
|
||||
|
@ -1,52 +1,52 @@
|
||||
import { SliderTab } from "../../slider";
|
||||
import Scrollable from "../../scrollable";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
|
||||
import appSidebarLeft, { AppSidebarLeft } from "..";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import InputSearch from "../../inputSearch";
|
||||
|
||||
// TODO: поиск по людям глобальный, если не нашло в контактах никого
|
||||
|
||||
export default class AppContactsTab implements SliderTab {
|
||||
private container: HTMLElement;
|
||||
export default class AppContactsTab extends SliderSuperTab {
|
||||
private list: HTMLUListElement;
|
||||
private scrollable: Scrollable;
|
||||
private promise: Promise<void>;
|
||||
|
||||
private inputSearch: InputSearch;
|
||||
private alive = true;
|
||||
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.container = document.getElementById('contacts-container');
|
||||
this.list = this.container.querySelector('#contacts');
|
||||
this.container.id = 'contacts-container';
|
||||
|
||||
this.list = document.createElement('ul');
|
||||
this.list.id = 'contacts';
|
||||
this.list.classList.add('contacts-container');
|
||||
|
||||
appDialogsManager.setListClickListener(this.list, () => {
|
||||
(this.container.querySelector('.sidebar-close-button') as HTMLElement).click();
|
||||
}, undefined, true);
|
||||
|
||||
this.scrollable = new Scrollable(this.list.parentElement);
|
||||
|
||||
this.inputSearch = new InputSearch('Search', (value) => {
|
||||
this.list.innerHTML = '';
|
||||
this.openContacts(value);
|
||||
});
|
||||
|
||||
this.container.firstElementChild.append(this.inputSearch.container);
|
||||
this.title.replaceWith(this.inputSearch.container);
|
||||
|
||||
this.scrollable.append(this.list);
|
||||
|
||||
// preload contacts
|
||||
// appUsersManager.getContacts();
|
||||
}
|
||||
|
||||
// need to clear, and left 1 page for smooth slide
|
||||
public onClose() {
|
||||
onClose() {
|
||||
this.alive = false;
|
||||
/* // need to clear, and left 1 page for smooth slide
|
||||
let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
|
||||
(Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove());
|
||||
}
|
||||
|
||||
public onCloseAfterTimeout() {
|
||||
this.list.innerHTML = '';
|
||||
this.inputSearch.value = '';
|
||||
(Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove()); */
|
||||
}
|
||||
|
||||
public openContacts(query?: string) {
|
||||
@ -55,18 +55,14 @@ export default class AppContactsTab implements SliderTab {
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
if(appSidebarLeft.historyTabIds.indexOf(AppSidebarLeft.SLIDERITEMSIDS.contacts) === -1) {
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.contacts);
|
||||
}
|
||||
|
||||
if(this.promise) return this.promise;
|
||||
this.scrollable.onScrolledBottom = null;
|
||||
|
||||
this.promise = appUsersManager.getContacts(query).then(_contacts => {
|
||||
this.promise = null;
|
||||
|
||||
if(appSidebarLeft.historyTabIds[appSidebarLeft.historyTabIds.length - 1] !== AppSidebarLeft.SLIDERITEMSIDS.contacts) {
|
||||
console.warn('user closed contacts before it\'s loaded');
|
||||
if(!this.alive) {
|
||||
//console.warn('user closed contacts before it\'s loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -118,4 +114,9 @@ export default class AppContactsTab implements SliderTab {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public open() {
|
||||
this.openContacts();
|
||||
return super.open();
|
||||
}
|
||||
}
|
@ -1,20 +1,18 @@
|
||||
import appSidebarLeft, { AppSidebarLeft } from "..";
|
||||
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 { parseMenuButtonsTo } from "../../misc";
|
||||
import { ripple } from "../../ripple";
|
||||
import { SliderTab, SliderSuperTab } from "../../slider";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
import { toast } from "../../toast";
|
||||
import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
|
||||
import { attachClickEvent } from "../../../helpers/dom";
|
||||
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";
|
||||
|
||||
const MAX_FOLDER_NAME_LENGTH = 12;
|
||||
|
||||
@ -36,8 +34,8 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
|
||||
private type: 'edit' | 'create';
|
||||
|
||||
constructor(appSidebarLeft: AppSidebarLeft) {
|
||||
super(appSidebarLeft);
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -159,11 +157,11 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
const excludedFlagsContainer = this.exclude_peers.querySelector('.folder-categories');
|
||||
|
||||
includedFlagsContainer.firstElementChild.addEventListener('click', () => {
|
||||
appSidebarLeft.includedChatsTab.open(this.filter, 'included');
|
||||
new AppIncludedChatsTab(this.slider).open(this.filter, 'included', this);
|
||||
});
|
||||
|
||||
excludedFlagsContainer.firstElementChild.addEventListener('click', () => {
|
||||
appSidebarLeft.includedChatsTab.open(this.filter, 'excluded');
|
||||
new AppIncludedChatsTab(this.slider).open(this.filter, 'excluded', this);
|
||||
});
|
||||
|
||||
lottieLoader.loadAnimationFromURL({
|
||||
@ -228,10 +226,8 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
if(this.animation) {
|
||||
this.animation.restart();
|
||||
}
|
||||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
Array.from(this.container.querySelectorAll('ul, .show-more')).forEach(el => el.remove());
|
||||
return super.onOpen();
|
||||
}
|
||||
|
||||
private onCreateOpen() {
|
||||
@ -318,7 +314,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
|
||||
|
||||
setFilter(filter: DialogFilter, firstTime: boolean) {
|
||||
// cleanup
|
||||
this.onCloseAfterTimeout();
|
||||
Array.from(this.container.querySelectorAll('ul, .show-more')).forEach(el => el.remove());
|
||||
|
||||
if(firstTime) {
|
||||
this.originalFilter = filter;
|
||||
|
@ -40,7 +40,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
};
|
||||
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider);
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -282,7 +282,6 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
};
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
this.nextBtn.classList.remove('is-visible');
|
||||
this.firstNameInputField.value = this.lastNameInputField.value = this.bioInputField.value = '';
|
||||
super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ export class RangeSettingSelector {
|
||||
|
||||
export default class AppGeneralSettingsTab extends SliderSuperTab {
|
||||
constructor(appSidebarLeft: AppSidebarLeft) {
|
||||
super(appSidebarLeft);
|
||||
super(appSidebarLeft, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { SliderTab, SliderSuperTab } from "../../slider";
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
import AppSelectPeers from "../../appSelectPeers";
|
||||
import appSidebarLeft, { AppSidebarLeft } from "..";
|
||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||
import appPeersManager from "../../../lib/appManagers/appPeersManager";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
@ -11,8 +10,10 @@ import ButtonIcon from "../../buttonIcon";
|
||||
import { fastRaf } from "../../../helpers/schedulers";
|
||||
import CheckboxField from "../../checkbox";
|
||||
import Button from "../../button";
|
||||
import AppEditFolderTab from "./editFolder";
|
||||
|
||||
export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
private editFolderTab: AppEditFolderTab;
|
||||
private confirmBtn: HTMLElement;
|
||||
|
||||
private selector: AppSelectPeers;
|
||||
@ -20,8 +21,8 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
private filter: DialogFilter;
|
||||
private originalFilter: DialogFilter;
|
||||
|
||||
constructor(appSidebarLeft: AppSidebarLeft) {
|
||||
super(appSidebarLeft);
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -92,7 +93,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
this.filter[this.type === 'included' ? 'include_peers' : 'exclude_peers'] = peers;
|
||||
//this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => this.filter.include_peers.includes(peerId));
|
||||
|
||||
appSidebarLeft.editFolderTab.setFilter(this.filter, false);
|
||||
this.editFolderTab.setFilter(this.filter, false);
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
@ -233,6 +234,8 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
(categories.querySelector(`[data-peer-id="${flag}"]`) as HTMLElement).click();
|
||||
}
|
||||
}
|
||||
|
||||
return super.onOpen();
|
||||
}
|
||||
|
||||
onSelectChange = (length: number) => {
|
||||
@ -247,15 +250,18 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
|
||||
this.selector.container.remove();
|
||||
this.selector = null;
|
||||
}
|
||||
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not ignore arguments!
|
||||
*/
|
||||
public open(filter?: DialogFilter, type?: 'included' | 'excluded') {
|
||||
public open(filter?: DialogFilter, type?: 'included' | 'excluded', editFolderTab?: AppIncludedChatsTab['editFolderTab']) {
|
||||
this.originalFilter = filter;
|
||||
this.filter = copy(this.originalFilter);
|
||||
this.type = type;
|
||||
this.editFolderTab = editFolderTab;
|
||||
|
||||
return super.open();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import Button from "../../button";
|
||||
import InputField from "../../inputField";
|
||||
import { SliderSuperTab } from "../../slider";
|
||||
import AvatarEdit from "../../avatarEdit";
|
||||
import AppAddMembersTab from "./addMembers";
|
||||
|
||||
export default class AppNewChannelTab extends SliderSuperTab {
|
||||
private uploadAvatar: () => Promise<InputFile> = null;
|
||||
@ -15,7 +16,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
||||
private avatarEdit: AvatarEdit;
|
||||
|
||||
constructor(appSidebarLeft: AppSidebarLeft) {
|
||||
super(appSidebarLeft);
|
||||
super(appSidebarLeft, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -68,8 +69,8 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
||||
});
|
||||
}
|
||||
|
||||
appSidebarLeft.removeTabFromHistory(this.id);
|
||||
appSidebarLeft.addMembersTab.open({
|
||||
appSidebarLeft.removeTabFromHistory(this);
|
||||
new AppAddMembersTab(this.slider).open({
|
||||
peerId: channelId,
|
||||
type: 'channel',
|
||||
skippable: true,
|
||||
@ -92,5 +93,6 @@ export default class AppNewChannelTab extends SliderSuperTab {
|
||||
this.channelNameInputField.value = '';
|
||||
this.channelDescriptionInputField.value = '';
|
||||
this.nextBtn.disabled = false;
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
||||
private groupNameInputField: InputField;
|
||||
|
||||
constructor(appSidebarLeft: AppSidebarLeft) {
|
||||
super(appSidebarLeft);
|
||||
super(appSidebarLeft, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -57,7 +57,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
|
||||
});
|
||||
}
|
||||
|
||||
appSidebarLeft.removeTabFromHistory(this.id);
|
||||
appSidebarLeft.removeTabFromHistory(this);
|
||||
appSidebarLeft.selectTab(0);
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import AppTwoStepVerificationEnterPasswordTab from "./2fa/enterPassword";
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider);
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
@ -79,7 +79,9 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
const numberVisibilityRow = rowsByKeys['inputPrivacyKeyPhoneNumber'] = new Row({
|
||||
title: 'Who can see my phone number?',
|
||||
subtitle: 'My Contacts',
|
||||
navigationTab: new AppPrivacyPhoneNumberTab(this.slider)
|
||||
clickable: () => {
|
||||
new AppPrivacyPhoneNumberTab(this.slider).open()
|
||||
}
|
||||
});
|
||||
|
||||
const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({
|
||||
@ -121,4 +123,4 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
|
||||
container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, linkAccountRow.container, groupChatsAddRow.container);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import SidebarSlider, { SliderSuperTab } from "../../slider";
|
||||
import AvatarElement from "../../avatar";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import appSidebarLeft, { AppSidebarLeft } from "..";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import ButtonMenuToggle from "../../buttonMenuToggle";
|
||||
import Button from "../../button";
|
||||
import AppPrivacyAndSecurityTab from "./privacyAndSecurity";
|
||||
import AppGeneralSettingsTab from "./generalSettings";
|
||||
import AppEditProfileTab from "./editProfile";
|
||||
import AppChatFoldersTab from "./chatFolders";
|
||||
//import AppMediaViewer from "../../appMediaViewerNew";
|
||||
|
||||
export default class AppSettingsTab extends SliderSuperTab {
|
||||
@ -22,7 +25,7 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
} = {} as any;
|
||||
|
||||
constructor(slider: SidebarSlider) {
|
||||
super(slider);
|
||||
super(slider, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -110,20 +113,21 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
}); */
|
||||
|
||||
this.buttons.edit.addEventListener('click', () => {
|
||||
appSidebarLeft.editProfileTab.fillElements();
|
||||
appSidebarLeft.editProfileTab.open();
|
||||
const tab = new AppEditProfileTab(this.slider);
|
||||
tab.fillElements();
|
||||
tab.open();
|
||||
});
|
||||
|
||||
this.buttons.folders.addEventListener('click', () => {
|
||||
appSidebarLeft.chatFoldersTab.open();
|
||||
new AppChatFoldersTab(this.slider).open();
|
||||
});
|
||||
|
||||
this.buttons.general.addEventListener('click', () => {
|
||||
appSidebarLeft.generalSettingsTab.open();
|
||||
new AppGeneralSettingsTab(this.slider as any).open();
|
||||
});
|
||||
|
||||
this.buttons.privacy.addEventListener('click', () => {
|
||||
appSidebarLeft.privacyAndSecurityTab.open();
|
||||
new AppPrivacyAndSecurityTab(this.slider).open();
|
||||
});
|
||||
}
|
||||
|
||||
@ -142,9 +146,6 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
}
|
||||
|
||||
this.fillElements();
|
||||
return super.onOpen();
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,13 +34,13 @@ export class AppSidebarRight extends SidebarSlider {
|
||||
constructor() {
|
||||
super({
|
||||
sidebarEl: document.getElementById('column-right') as HTMLElement,
|
||||
tabs: {
|
||||
[AppSidebarRight.SLIDERITEMSIDS.sharedMedia]: sharedMediaTab,
|
||||
[AppSidebarRight.SLIDERITEMSIDS.search]: searchTab,
|
||||
[AppSidebarRight.SLIDERITEMSIDS.stickers]: stickersTab,
|
||||
[AppSidebarRight.SLIDERITEMSIDS.pollResults]: pollResultsTab,
|
||||
[AppSidebarRight.SLIDERITEMSIDS.gifs]: gifsTab
|
||||
},
|
||||
tabs: new Map([
|
||||
[AppSidebarRight.SLIDERITEMSIDS.sharedMedia, sharedMediaTab],
|
||||
[AppSidebarRight.SLIDERITEMSIDS.search, searchTab],
|
||||
[AppSidebarRight.SLIDERITEMSIDS.stickers, stickersTab],
|
||||
[AppSidebarRight.SLIDERITEMSIDS.pollResults, pollResultsTab],
|
||||
[AppSidebarRight.SLIDERITEMSIDS.gifs, gifsTab]
|
||||
] as any[]),
|
||||
canHideFirst: true,
|
||||
navigationType: 'right'
|
||||
});
|
||||
|
@ -95,7 +95,7 @@ export default class AppStickersTab implements SliderTab {
|
||||
`;
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.classList.add('btn-primary', 'sticker-set-button');
|
||||
button.classList.add('btn-primary', 'btn-color-primary', 'sticker-set-button');
|
||||
button.innerText = set.installed_date ? 'Added' : 'Add';
|
||||
// button.style.width = set.installed_date ? '68px' : '52px';
|
||||
|
||||
|
@ -1,93 +1,20 @@
|
||||
import { attachClickEvent } from "../helpers/dom";
|
||||
import { horizontalMenu } from "./horizontalMenu";
|
||||
import ButtonIcon from "./buttonIcon";
|
||||
import Scrollable from "./scrollable";
|
||||
import { TransitionSlider } from "./transition";
|
||||
import appNavigationController, { NavigationItem } from "./appNavigationController";
|
||||
import { isSafari } from "../helpers/userAgent";
|
||||
|
||||
export interface SliderTab {
|
||||
onOpen?: () => void,
|
||||
onOpenAfterTimeout?: () => void,
|
||||
onClose?: () => void,
|
||||
onCloseAfterTimeout?: () => void
|
||||
}
|
||||
|
||||
export class SliderSuperTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
|
||||
public header: HTMLElement;
|
||||
public closeBtn: HTMLElement;
|
||||
public title: HTMLElement;
|
||||
|
||||
public content: HTMLElement;
|
||||
public scrollable: Scrollable;
|
||||
|
||||
public id: number;
|
||||
|
||||
constructor(protected slider: SidebarSlider, protected destroyable = false) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('sidebar-slider-item');
|
||||
|
||||
// * Header
|
||||
this.header = document.createElement('div');
|
||||
this.header.classList.add('sidebar-header');
|
||||
|
||||
this.closeBtn = ButtonIcon('arrow_back sidebar-close-button', {noRipple: true});
|
||||
this.title = document.createElement('div');
|
||||
this.title.classList.add('sidebar-header__title');
|
||||
this.header.append(this.closeBtn, this.title);
|
||||
|
||||
// * Content
|
||||
this.content = document.createElement('div');
|
||||
this.content.classList.add('sidebar-content');
|
||||
|
||||
this.scrollable = new Scrollable(this.content, undefined, undefined, true);
|
||||
|
||||
this.container.append(this.header, this.content);
|
||||
|
||||
this.id = this.slider.addTab(this);
|
||||
}
|
||||
|
||||
public close() {
|
||||
return this.slider.closeTab(this.id);
|
||||
}
|
||||
|
||||
public async open(...args: any[]) {
|
||||
if(this.init) {
|
||||
const result = this.init();
|
||||
this.init = null;
|
||||
await (result instanceof Promise ? result : Promise.resolve());
|
||||
}
|
||||
|
||||
return this.slider.selectTab(this);
|
||||
}
|
||||
|
||||
protected init(): Promise<any> | any {
|
||||
|
||||
}
|
||||
|
||||
// * fix incompability
|
||||
public onOpen() {
|
||||
|
||||
}
|
||||
|
||||
public onCloseAfterTimeout() {
|
||||
if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !
|
||||
delete this.slider.tabs[this.id];
|
||||
this.container.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
import SliderSuperTab, { SliderTab } from "./sliderTab";
|
||||
|
||||
const TRANSITION_TIME = 250;
|
||||
|
||||
export type {SliderTab};
|
||||
export {SliderSuperTab};
|
||||
|
||||
export default class SidebarSlider {
|
||||
protected _selectTab: ReturnType<typeof horizontalMenu>;
|
||||
public historyTabIds: number[] = [];
|
||||
public historyTabIds: (number | SliderSuperTab)[] = []; // * key is any, since right sidebar is ugly nowz
|
||||
public tabsContainer: HTMLElement;
|
||||
public sidebarEl: HTMLElement;
|
||||
public tabs: {[id: number]: SliderTab} = {};
|
||||
public tabs: Map<any, SliderTab>; // * key is any, since right sidebar is ugly now
|
||||
private canHideFirst = false;
|
||||
private navigationType: NavigationItem['type']
|
||||
|
||||
@ -102,6 +29,10 @@ export default class SidebarSlider {
|
||||
this[i] = options[i];
|
||||
}
|
||||
|
||||
if(!this.tabs) {
|
||||
this.tabs = new Map();
|
||||
}
|
||||
|
||||
this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider');
|
||||
this._selectTab = TransitionSlider(this.tabsContainer, 'navigation', TRANSITION_TIME);
|
||||
if(!this.canHideFirst) {
|
||||
@ -118,28 +49,30 @@ export default class SidebarSlider {
|
||||
// this.closeTab();
|
||||
};
|
||||
|
||||
public closeTab = (tabId?: number, animate?: boolean) => {
|
||||
if(tabId !== undefined && this.historyTabIds[this.historyTabIds.length - 1] !== tabId) {
|
||||
public closeTab = (id?: number | SliderSuperTab, animate?: boolean) => {
|
||||
if(id !== undefined && this.historyTabIds[this.historyTabIds.length - 1] !== id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//console.log('sidebar-close-button click:', this.historyTabIDs);
|
||||
const closingId = this.historyTabIds.pop(); // pop current
|
||||
this.onCloseTab(closingId, animate);
|
||||
this._selectTab(this.historyTabIds[this.historyTabIds.length - 1] ?? (this.canHideFirst ? -1 : 0), animate);
|
||||
|
||||
const tab = this.historyTabIds[this.historyTabIds.length - 1];
|
||||
this._selectTab(tab !== undefined ? (tab instanceof SliderSuperTab ? tab.container : tab) : (this.canHideFirst ? -1 : 0), animate);
|
||||
return true;
|
||||
};
|
||||
|
||||
public selectTab(id: number | SliderSuperTab): boolean {
|
||||
if(id instanceof SliderSuperTab) {
|
||||
/* if(id instanceof SliderSuperTab) {
|
||||
id = id.id;
|
||||
}
|
||||
} */
|
||||
|
||||
if(this.historyTabIds[this.historyTabIds.length - 1] === id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const tab = this.tabs[id];
|
||||
const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);
|
||||
if(tab) {
|
||||
if(tab.onOpen) {
|
||||
tab.onOpen();
|
||||
@ -163,17 +96,17 @@ export default class SidebarSlider {
|
||||
//}
|
||||
|
||||
this.historyTabIds.push(id);
|
||||
this._selectTab(id);
|
||||
this._selectTab(id instanceof SliderSuperTab ? id.container : id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public removeTabFromHistory(id: number) {
|
||||
public removeTabFromHistory(id: number | SliderSuperTab) {
|
||||
this.historyTabIds.findAndSplice(i => i === id);
|
||||
this.onCloseTab(id, undefined);
|
||||
}
|
||||
|
||||
public onCloseTab(id: number, animate: boolean) {
|
||||
let tab = this.tabs[id];
|
||||
public onCloseTab(id: number | SliderSuperTab, animate: boolean) {
|
||||
const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);
|
||||
if(tab) {
|
||||
if(tab.onClose) {
|
||||
tab.onClose();
|
||||
@ -188,20 +121,12 @@ export default class SidebarSlider {
|
||||
}
|
||||
|
||||
public addTab(tab: SliderSuperTab) {
|
||||
let id: number;
|
||||
if(tab.container.parentElement) {
|
||||
id = Array.from(this.tabsContainer.children).findIndex(el => el === tab.container);
|
||||
} else {
|
||||
id = this.tabsContainer.childElementCount;
|
||||
if(!tab.container.parentElement) {
|
||||
this.tabsContainer.append(tab.container);
|
||||
|
||||
if(tab.closeBtn) {
|
||||
tab.closeBtn.addEventListener('click', this.onCloseBtnClick);
|
||||
}
|
||||
}
|
||||
|
||||
this.tabs[id] = tab;
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
77
src/components/sliderTab.ts
Normal file
77
src/components/sliderTab.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import ButtonIcon from "./buttonIcon";
|
||||
import Scrollable from "./scrollable";
|
||||
import SidebarSlider from "./slider";
|
||||
|
||||
export interface SliderTab {
|
||||
onOpen?: () => void,
|
||||
onOpenAfterTimeout?: () => void,
|
||||
onClose?: () => void,
|
||||
onCloseAfterTimeout?: () => void
|
||||
}
|
||||
|
||||
export default class SliderSuperTab implements SliderTab {
|
||||
public container: HTMLElement;
|
||||
|
||||
public header: HTMLElement;
|
||||
public closeBtn: HTMLElement;
|
||||
public title: HTMLElement;
|
||||
|
||||
public content: HTMLElement;
|
||||
public scrollable: Scrollable;
|
||||
|
||||
constructor(protected slider: SidebarSlider, protected destroyable = false) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('sidebar-slider-item');
|
||||
|
||||
// * Header
|
||||
this.header = document.createElement('div');
|
||||
this.header.classList.add('sidebar-header');
|
||||
|
||||
this.closeBtn = ButtonIcon('arrow_back sidebar-close-button', {noRipple: true});
|
||||
this.title = document.createElement('div');
|
||||
this.title.classList.add('sidebar-header__title');
|
||||
this.header.append(this.closeBtn, this.title);
|
||||
|
||||
// * Content
|
||||
this.content = document.createElement('div');
|
||||
this.content.classList.add('sidebar-content');
|
||||
|
||||
this.scrollable = new Scrollable(this.content, undefined, undefined, true);
|
||||
|
||||
this.container.append(this.header, this.content);
|
||||
|
||||
this.slider.addTab(this);
|
||||
}
|
||||
|
||||
public close() {
|
||||
return this.slider.closeTab(this);
|
||||
}
|
||||
|
||||
public async open(...args: any[]) {
|
||||
if(this.init) {
|
||||
const result = this.init();
|
||||
this.init = null;
|
||||
if(result instanceof Promise) {
|
||||
await result;
|
||||
}
|
||||
}
|
||||
|
||||
return this.slider.selectTab(this);
|
||||
}
|
||||
|
||||
protected init(): Promise<any> | any {
|
||||
|
||||
}
|
||||
|
||||
// * fix incompability
|
||||
public onOpen() {
|
||||
|
||||
}
|
||||
|
||||
public onCloseAfterTimeout() {
|
||||
if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !
|
||||
this.slider.tabs.delete(this);
|
||||
this.container.remove();
|
||||
}
|
||||
}
|
||||
}
|
@ -96,7 +96,7 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
}
|
||||
|
||||
if(onTransitionEnd) {
|
||||
onTransitionEnd(selectTab.prevId);
|
||||
onTransitionEnd(selectTab.prevId());
|
||||
}
|
||||
|
||||
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||
@ -109,14 +109,15 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
id = whichChild(id);
|
||||
}
|
||||
|
||||
if(id === self.prevId) return false;
|
||||
const prevId = self.prevId();
|
||||
if(id === prevId) return false;
|
||||
|
||||
//console.log('selectTab id:', id);
|
||||
|
||||
const _from = from;
|
||||
const to = content.children[id] as HTMLElement;
|
||||
|
||||
if(!rootScope.settings.animationsEnabled || self.prevId === -1) {
|
||||
if(!rootScope.settings.animationsEnabled || prevId === -1) {
|
||||
animate = false;
|
||||
}
|
||||
|
||||
@ -129,10 +130,9 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
|
||||
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||
|
||||
self.prevId = id;
|
||||
from = to;
|
||||
|
||||
if(onTransitionEnd) onTransitionEnd(self.prevId);
|
||||
if(onTransitionEnd) onTransitionEnd(id);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
}
|
||||
|
||||
content.classList.add('animating', 'disable-hover');
|
||||
const toRight = self.prevId < id;
|
||||
const toRight = prevId < id;
|
||||
content.classList.toggle('backwards', !toRight);
|
||||
|
||||
let onTransitionEndCallback: ReturnType<TransitionFunction>;
|
||||
@ -196,11 +196,11 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
||||
}
|
||||
}
|
||||
|
||||
self.prevId = id;
|
||||
from = to;
|
||||
}
|
||||
|
||||
selectTab.prevId = -1;
|
||||
//selectTab.prevId = -1;
|
||||
selectTab.prevId = () => from ? whichChild(from) : -1;
|
||||
|
||||
return selectTab;
|
||||
};
|
||||
|
@ -1,24 +1,23 @@
|
||||
export function bytesToHex(bytes: ArrayLike<number>) {
|
||||
bytes = bytes || [];
|
||||
var arr = [];
|
||||
for(var i = 0; i < bytes.length; i++) {
|
||||
let arr: string[] = [];
|
||||
for(let i = 0; i < bytes.length; ++i) {
|
||||
arr.push((bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16));
|
||||
}
|
||||
return arr.join('');
|
||||
}
|
||||
|
||||
export function bytesFromHex(hexString: string) {
|
||||
var len = hexString.length,
|
||||
i;
|
||||
var start = 0;
|
||||
var bytes = [];
|
||||
const len = hexString.length;
|
||||
let start = 0;
|
||||
let bytes: number[] = [];
|
||||
|
||||
if(hexString.length % 2) {
|
||||
if(len % 2) { // read 0x581 as 0x0581
|
||||
bytes.push(parseInt(hexString.charAt(0), 16));
|
||||
start++;
|
||||
++start;
|
||||
}
|
||||
|
||||
for(i = start; i < len; i += 2) {
|
||||
for(let i = start; i < len; i += 2) {
|
||||
bytes.push(parseInt(hexString.substr(i, 2), 16));
|
||||
}
|
||||
|
||||
@ -26,24 +25,24 @@ export function bytesFromHex(hexString: string) {
|
||||
}
|
||||
|
||||
export function bytesToBase64(bytes: number[] | Uint8Array) {
|
||||
var mod3
|
||||
var result = ''
|
||||
let mod3: number;
|
||||
let result = '';
|
||||
|
||||
for (var nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
|
||||
mod3 = nIdx % 3
|
||||
nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24)
|
||||
if (mod3 === 2 || nLen - nIdx === 1) {
|
||||
for(let nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; ++nIdx) {
|
||||
mod3 = nIdx % 3;
|
||||
nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24);
|
||||
if(mod3 === 2 || nLen - nIdx === 1) {
|
||||
result += String.fromCharCode(
|
||||
uint6ToBase64(nUint24 >>> 18 & 63),
|
||||
uint6ToBase64(nUint24 >>> 12 & 63),
|
||||
uint6ToBase64(nUint24 >>> 6 & 63),
|
||||
uint6ToBase64(nUint24 & 63)
|
||||
)
|
||||
nUint24 = 0
|
||||
);
|
||||
nUint24 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result.replace(/A(?=A$|$)/g, '=')
|
||||
return result.replace(/A(?=A$|$)/g, '=');
|
||||
}
|
||||
|
||||
export function uint6ToBase64(nUint6: number) {
|
||||
@ -61,12 +60,12 @@ export function uint6ToBase64(nUint6: number) {
|
||||
}
|
||||
|
||||
export function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) {
|
||||
var len = bytes1.length;
|
||||
const len = bytes1.length;
|
||||
if(len !== bytes2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0; i < len; i++) {
|
||||
for(let i = 0; i < len; ++i) {
|
||||
if(bytes1[i] !== bytes2[i]) {
|
||||
return false;
|
||||
}
|
||||
@ -76,10 +75,10 @@ export function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8
|
||||
}
|
||||
|
||||
export function bytesXor(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) {
|
||||
var len = bytes1.length;
|
||||
var bytes = [];
|
||||
const len = bytes1.length;
|
||||
const bytes: number[] = [];
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
for(let i = 0; i < len; ++i) {
|
||||
bytes[i] = bytes1[i] ^ bytes2[i];
|
||||
}
|
||||
|
||||
@ -111,11 +110,11 @@ export function convertToUint8Array(bytes: Uint8Array | number[]): Uint8Array {
|
||||
}
|
||||
|
||||
export function bytesFromArrayBuffer(buffer: ArrayBuffer) {
|
||||
var len = buffer.byteLength;
|
||||
var byteView = new Uint8Array(buffer);
|
||||
var bytes = [];
|
||||
const len = buffer.byteLength;
|
||||
const byteView = new Uint8Array(buffer);
|
||||
const bytes: number[] = [];
|
||||
|
||||
for(var i = 0; i < len; ++i) {
|
||||
for(let i = 0; i < len; ++i) {
|
||||
bytes[i] = byteView[i];
|
||||
}
|
||||
|
||||
@ -123,9 +122,9 @@ export function bytesFromArrayBuffer(buffer: ArrayBuffer) {
|
||||
}
|
||||
|
||||
export function bufferConcat(buffer1: any, buffer2: any) {
|
||||
var l1 = buffer1.byteLength || buffer1.length;
|
||||
var l2 = buffer2.byteLength || buffer2.length;
|
||||
var tmp = new Uint8Array(l1 + l2);
|
||||
const l1 = buffer1.byteLength || buffer1.length;
|
||||
const l2 = buffer2.byteLength || buffer2.length;
|
||||
const tmp = new Uint8Array(l1 + l2);
|
||||
tmp.set(buffer1 instanceof ArrayBuffer ? new Uint8Array(buffer1) : buffer1, 0);
|
||||
tmp.set(buffer2 instanceof ArrayBuffer ? new Uint8Array(buffer2) : buffer2, l1);
|
||||
|
||||
@ -136,7 +135,7 @@ export function bufferConcats(...args: any[]) {
|
||||
let length = 0;
|
||||
args.forEach(b => length += b.byteLength || b.length);
|
||||
|
||||
var tmp = new Uint8Array(length);
|
||||
const tmp = new Uint8Array(length);
|
||||
|
||||
let lastLength = 0;
|
||||
args.forEach(b => {
|
||||
@ -148,8 +147,8 @@ export function bufferConcats(...args: any[]) {
|
||||
}
|
||||
|
||||
export function bytesFromWordss(input: Uint32Array) {
|
||||
var o = [];
|
||||
for(var i = 0; i < input.length * 4; i++) {
|
||||
const o: number[] = [];
|
||||
for(let i = 0, length = input.length * 4; i < length; ++i) {
|
||||
o.push((input[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
|
||||
}
|
||||
|
||||
@ -161,12 +160,17 @@ export function bytesToWordss(input: ArrayBuffer | Uint8Array) {
|
||||
if(input instanceof ArrayBuffer) bytes = new Uint8Array(input);
|
||||
else bytes = input;
|
||||
|
||||
var len = bytes.length;
|
||||
var words: number[] = [];
|
||||
var i;
|
||||
for(i = 0; i < len; i++) {
|
||||
const words: number[] = [];
|
||||
for(let i = 0, len = bytes.length; i < len; ++i) {
|
||||
words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8);
|
||||
}
|
||||
|
||||
return new Uint32Array(words);
|
||||
}
|
||||
}
|
||||
|
||||
// * https://stackoverflow.com/a/52827031
|
||||
/* export const isBigEndian = (() => {
|
||||
const array = new Uint8Array(4);
|
||||
const view = new Uint32Array(array.buffer);
|
||||
return !((view[0] = 1) & array[0]);
|
||||
})(); */
|
||||
|
@ -5,4 +5,4 @@ export function nextRandomInt(maxValue: number) {
|
||||
export function randomLong() {
|
||||
return '' + nextRandomInt(0xFFFFFFFF) + nextRandomInt(0xFFFFFF);
|
||||
//return '' + parseInt(nextRandomInt(0xFFFFFFFF).toString(16) + nextRandomInt(0xFFFFFFFF).toString(16), 16);
|
||||
}
|
||||
}
|
||||
|
@ -135,36 +135,6 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon tgico-arrow_back sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title">Archived Chats</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<div id="chats-archived-container">
|
||||
<ul id="dialogs-archived"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item" id="contacts-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon tgico-arrow_back sidebar-close-button"></button>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<div>
|
||||
<ul id="contacts" class="contacts-container"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-slider-item addmembers-container">
|
||||
<div class="sidebar-header">
|
||||
<button class="btn-icon tgico-arrow_back sidebar-close-button"></button>
|
||||
<div class="sidebar-header__title">Add Members</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<button class="btn-circle rp btn-corner tgico-next"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-column" id="column-center"></div>
|
||||
@ -190,7 +160,6 @@
|
||||
<avatar-element class="profile-avatar avatar-120" dialog="1" clickable></avatar-element>
|
||||
<div class="profile-name"></div>
|
||||
<div class="profile-subtitle"></div>
|
||||
|
||||
<div class="profile-row profile-row-bio tgico-info">
|
||||
<p></p>
|
||||
<p class="profile-row-label">Bio</p>
|
||||
|
@ -176,6 +176,7 @@ class ConnectionStatusComponent {
|
||||
export class AppDialogsManager {
|
||||
public _chatList = document.getElementById('dialogs') as HTMLUListElement;
|
||||
public chatList = this._chatList;
|
||||
public chatListArchived: HTMLUListElement;
|
||||
|
||||
public doms: {[peerId: number]: DialogDom} = {};
|
||||
|
||||
@ -191,10 +192,7 @@ export class AppDialogsManager {
|
||||
|
||||
public contextMenu = new DialogsContextMenu();
|
||||
|
||||
public chatLists: {[filterId: number]: HTMLUListElement} = {
|
||||
0: this.chatList,
|
||||
1: appSidebarLeft.archivedTab.chatList
|
||||
};
|
||||
public chatLists: {[filterId: number]: HTMLUListElement};
|
||||
public filterId = 0;
|
||||
private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {
|
||||
menu: document.getElementById('folders-tabs'),
|
||||
@ -222,6 +220,14 @@ export class AppDialogsManager {
|
||||
private lastActiveElements: Set<HTMLElement> = new Set();
|
||||
|
||||
constructor() {
|
||||
this.chatListArchived = document.createElement('ul');
|
||||
this.chatListArchived.id = 'dialogs-archived';
|
||||
|
||||
this.chatLists = {
|
||||
0: this.chatList,
|
||||
1: this.chatListArchived
|
||||
};
|
||||
|
||||
this.chatsPreloader = putPreloader(null, true);
|
||||
|
||||
this.allUnreadCount = this.folders.menu.querySelector('.badge');
|
||||
@ -434,10 +440,10 @@ export class AppDialogsManager {
|
||||
positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex);
|
||||
});
|
||||
|
||||
if(this.filterId) {
|
||||
/* if(this.filterId) {
|
||||
const tabIndex = order.indexOf(this.filterId) + 1;
|
||||
selectTab.prevId = tabIndex;
|
||||
}
|
||||
} */
|
||||
});
|
||||
|
||||
rootScope.on('peer_typings', (e) => {
|
||||
|
@ -183,13 +183,13 @@ export function pqPrimeLeemon(what: any) {
|
||||
var x = new Array(minLen);
|
||||
var y = new Array(minLen);
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
for(i = 0; i < 3; ++i) {
|
||||
q = (nextRandomInt(128) & 15) + 17;
|
||||
copyInt_(x, nextRandomInt(1000000000) + 1);
|
||||
copy_(y, x);
|
||||
lim = 1 << (i + 18);
|
||||
|
||||
for (j = 1; j < lim; j++) {
|
||||
for (j = 1; j < lim; ++j) {
|
||||
++it;
|
||||
copy_(a, x);
|
||||
copy_(b, x);
|
||||
|
@ -5,9 +5,12 @@ import {str2bigInt, isZero,
|
||||
import {logger, LogLevels} from '../logger';
|
||||
import { AccountPassword, PasswordKdfAlgo } from "../../layer";
|
||||
import { bufferConcats, bytesToHex, bytesFromHex, bufferConcat, bytesXor } from "../../helpers/bytes";
|
||||
//import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
|
||||
const log = logger('SRP', LogLevels.error);
|
||||
|
||||
//MOUNT_CLASS_TO && Object.assign(MOUNT_CLASS_TO, {str2bigInt, bigInt2str, int2bigInt});
|
||||
|
||||
export async function makePasswordHash(password: string, client_salt: Uint8Array, server_salt: Uint8Array): Promise<number[]> {
|
||||
let clientSaltString = '';
|
||||
for(let i = 0; i < client_salt.length; i++) clientSaltString += String.fromCharCode(client_salt[i]);
|
||||
@ -32,13 +35,12 @@ export async function makePasswordHash(password: string, client_salt: Uint8Array
|
||||
}
|
||||
|
||||
export async function computeSRP(password: string, state: AccountPassword, isNew: boolean) {
|
||||
console.log('computeSRP:', password, state, isNew);
|
||||
const algo = (isNew ? state.new_algo : state.current_algo) as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;
|
||||
//console.log('computeSRP:', password, state, isNew, algo);
|
||||
|
||||
let algo = (state.current_algo || state.new_algo) as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;
|
||||
|
||||
let p = str2bigInt(bytesToHex(algo.p), 16);
|
||||
let B = str2bigInt(bytesToHex(state.srp_B), 16);
|
||||
let g = int2bigInt(algo.g, 32, 256);
|
||||
const p = str2bigInt(bytesToHex(algo.p), 16);
|
||||
const B = str2bigInt(bytesToHex(state.srp_B), 16);
|
||||
const g = int2bigInt(algo.g, 32, 256);
|
||||
|
||||
//log('p', bigInt2str(p, 16));
|
||||
//log('B', bigInt2str(B, 16));
|
||||
@ -63,58 +65,27 @@ export async function computeSRP(password: string, state: AccountPassword, isNew
|
||||
|
||||
//check_prime_and_good(algo.p, g);
|
||||
|
||||
let pw_hash = await makePasswordHash(password, new Uint8Array(algo.salt1), new Uint8Array(algo.salt2));
|
||||
let x = str2bigInt(bytesToHex(new Uint8Array(pw_hash)), 16);
|
||||
const pw_hash = await makePasswordHash(password, new Uint8Array(algo.salt1), new Uint8Array(algo.salt2));
|
||||
const x = str2bigInt(bytesToHex(new Uint8Array(pw_hash)), 16);
|
||||
|
||||
//log('computed pw_hash:', pw_hash, x, bytesToHex(new Uint8Array(pw_hash)));
|
||||
|
||||
var padArray = function(arr: any[], len: number, fill = 0) {
|
||||
const padArray = function(arr: any[], len: number, fill = 0) {
|
||||
return Array(len).fill(fill).concat(arr).slice(-len);
|
||||
};
|
||||
|
||||
let pForHash = padArray(bytesFromHex(bigInt2str(p, 16)), 256);
|
||||
let gForHash = padArray(bytesFromHex(bigInt2str(g, 16)), 256); // like uint8array
|
||||
let b_for_hash = padArray(bytesFromHex(bigInt2str(B, 16)), 256);
|
||||
const pForHash = padArray(bytesFromHex(bigInt2str(p, 16)), 256);
|
||||
const gForHash = padArray(bytesFromHex(bigInt2str(g, 16)), 256); // like uint8array
|
||||
const b_for_hash = padArray(bytesFromHex(bigInt2str(B, 16)), 256);
|
||||
|
||||
/* log(bytesToHex(pForHash));
|
||||
log(bytesToHex(gForHash));
|
||||
log(bytesToHex(b_for_hash)); */
|
||||
|
||||
let g_x = powMod(g, x, p);
|
||||
const v = powMod(g, x, p);
|
||||
|
||||
// * https://core.telegram.org/api/srp#setting-a-new-2fa-password
|
||||
if(isNew) {
|
||||
return padArray(bytesFromHex(bigInt2str(g_x, 16)), 256);
|
||||
}
|
||||
|
||||
//log('g_x', bigInt2str(g_x, 16));
|
||||
|
||||
let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash));
|
||||
k = str2bigInt(bytesToHex(new Uint8Array(k)), 16);
|
||||
|
||||
//log('k', bigInt2str(k, 16));
|
||||
|
||||
// kg_x = (k * g_x) % p
|
||||
let kg_x = mod(mult(k, g_x), p);
|
||||
|
||||
// good
|
||||
|
||||
//log('kg_x', bigInt2str(kg_x, 16));
|
||||
|
||||
let is_good_mod_exp_first = (modexp: any, prime: any) => {
|
||||
let diff = sub(prime, modexp);
|
||||
let min_diff_bits_count = 2048 - 64;
|
||||
let max_mod_exp_size = 256;
|
||||
if(negative(diff) ||
|
||||
bitSize(diff) < min_diff_bits_count ||
|
||||
bitSize(modexp) < min_diff_bits_count ||
|
||||
Math.floor((bitSize(modexp) + 7) / 8) > max_mod_exp_size)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
var flipper = (arr: Uint8Array | number[]) => {
|
||||
let out = new Uint8Array(arr.length);
|
||||
const flipper = (arr: Uint8Array | number[]) => {
|
||||
const out = new Uint8Array(arr.length);
|
||||
for(let i = 0; i < arr.length; i += 4) {
|
||||
out[i] = arr[i + 3];
|
||||
out[i + 1] = arr[i + 2];
|
||||
@ -125,7 +96,39 @@ export async function computeSRP(password: string, state: AccountPassword, isNew
|
||||
return out;
|
||||
};
|
||||
|
||||
let generate_and_check_random = async() => {
|
||||
// * https://core.telegram.org/api/srp#setting-a-new-2fa-password
|
||||
if(isNew) {
|
||||
const bytes = bytesFromHex(bigInt2str(v, 16));
|
||||
return padArray(/* (isBigEndian ? bytes.reverse() : bytes) */bytes, 256);
|
||||
}
|
||||
|
||||
//log('g_x', bigInt2str(g_x, 16));
|
||||
|
||||
let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash));
|
||||
k = str2bigInt(bytesToHex(new Uint8Array(k)), 16);
|
||||
|
||||
//log('k', bigInt2str(k, 16));
|
||||
|
||||
// kg_x = (k * g_x) % p
|
||||
const k_v = mod(mult(k, v), p);
|
||||
|
||||
// good
|
||||
|
||||
//log('kg_x', bigInt2str(kg_x, 16));
|
||||
|
||||
const is_good_mod_exp_first = (modexp: any, prime: any) => {
|
||||
const diff = sub(prime, modexp);
|
||||
const min_diff_bits_count = 2048 - 64;
|
||||
const max_mod_exp_size = 256;
|
||||
if(negative(diff) ||
|
||||
bitSize(diff) < min_diff_bits_count ||
|
||||
bitSize(modexp) < min_diff_bits_count ||
|
||||
Math.floor((bitSize(modexp) + 7) / 8) > max_mod_exp_size)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const generate_and_check_random = async() => {
|
||||
while(true) {
|
||||
const a = str2bigInt(bytesToHex(flipper(state.secure_random)), 16);
|
||||
//const a = str2bigInt('9153faef8f2bb6da91f6e5bc96bc00860a530a572a0f45aac0842b4602d711f8bda8d59fb53705e4ae3e31a3c4f0681955425f224297b8e9efd898fec22046debb7ba8a0bcf2be1ada7b100424ea318fdcef6ccfe6d7ab7d978c0eb76a807d4ab200eb767a22de0d828bc53f42c5a35c2df6e6ceeef9a3487aae8e9ef2271f2f6742e83b8211161fb1a0e037491ab2c2c73ad63c8bd1d739de1b523fe8d461270cedcf240de8da75f31be4933576532955041dc5770c18d3e75d0b357df9da4a5c8726d4fced87d15752400883dc57fa1937ac17608c5446c4774dcd123676d683ce3a1ab9f7e020ca52faafc99969822717c8e07ea383d5fb1a007ba0d170cb', 16);
|
||||
@ -161,11 +164,11 @@ export async function computeSRP(password: string, state: AccountPassword, isNew
|
||||
log('B - kg_x', bigInt2str(sub(B, kg_x), 16)); */
|
||||
|
||||
let g_b;
|
||||
if(!greater(B, kg_x)) {
|
||||
if(!greater(B, k_v)) {
|
||||
//log('negative');
|
||||
g_b = add(B, p);
|
||||
} else g_b = B;
|
||||
g_b = mod(sub(g_b, kg_x), p);
|
||||
g_b = mod(sub(g_b, k_v), p);
|
||||
/* let g_b = sub(B, kg_x);
|
||||
if(negative(g_b)) g_b = add(g_b, p); */
|
||||
|
||||
@ -209,4 +212,4 @@ export async function computeSRP(password: string, state: AccountPassword, isNew
|
||||
return out;
|
||||
|
||||
/* console.log(gForHash, pForHash, bForHash); */
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { putPreloader } from '../components/misc';
|
||||
import mediaSizes from '../helpers/mediaSizes';
|
||||
import { AccountPassword } from '../layer';
|
||||
import appStateManager from '../lib/appManagers/appStateManager';
|
||||
import apiManager from '../lib/mtproto/mtprotoworker';
|
||||
import passwordManager from '../lib/mtproto/passwordManager';
|
||||
import Page from './page';
|
||||
import pageIm from './pageIm';
|
||||
@ -10,12 +9,13 @@ import Button from '../components/button';
|
||||
import PasswordInputField from '../components/passwordInputField';
|
||||
import PasswordMonkey from '../components/monkeys/password';
|
||||
import { ripple } from '../components/ripple';
|
||||
import RichTextProcessor from '../lib/richtextprocessor';
|
||||
|
||||
const TEST = false;
|
||||
let passwordInput: HTMLInputElement;
|
||||
|
||||
let onFirstMount = (): Promise<any> => {
|
||||
const btnNext = Button('btn-primary', {text: 'NEXT'});
|
||||
const btnNext = Button('btn-primary btn-color-primary', {text: 'NEXT'});
|
||||
|
||||
const passwordInputField = new PasswordInputField({
|
||||
label: 'Password',
|
||||
@ -37,7 +37,7 @@ let onFirstMount = (): Promise<any> => {
|
||||
return !TEST && passwordManager.getState().then(_state => {
|
||||
state = _state;
|
||||
|
||||
passwordInputField.label.innerText = state.hint ?? 'Password';
|
||||
passwordInputField.label.innerHTML = state.hint ? RichTextProcessor.wrapEmojiText(state.hint) : 'Password';
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -297,7 +297,7 @@ let onFirstMount = () => {
|
||||
});
|
||||
signedCheckboxField.input.checked = true;
|
||||
|
||||
btnNext = Button('btn-primary', {text: 'NEXT'});
|
||||
btnNext = Button('btn-primary btn-color-primary', {text: 'NEXT'});
|
||||
btnNext.style.visibility = 'hidden';
|
||||
|
||||
btnNext.addEventListener('click', function(this: HTMLElement, e) {
|
||||
|
@ -64,7 +64,7 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i
|
||||
maxLength: 64
|
||||
});
|
||||
|
||||
const btnSignUp = Button('btn-primary');
|
||||
const btnSignUp = Button('btn-primary btn-color-primary');
|
||||
btnSignUp.append('START MESSAGING');
|
||||
|
||||
inputWrapper.append(nameInputField.container, lastNameInputField.container, btnSignUp);
|
||||
|
@ -206,8 +206,6 @@
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: $color-blue;
|
||||
color: #fff;
|
||||
border-radius: $border-radius-medium;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
@ -227,6 +225,7 @@
|
||||
|
||||
&-transparent {
|
||||
background-color: transparent;
|
||||
|
||||
@include hover() {
|
||||
background: hover-color($color-blue);
|
||||
}
|
||||
@ -345,3 +344,12 @@
|
||||
|
||||
@include btn-hoverable();
|
||||
}
|
||||
|
||||
.btn-color-primary {
|
||||
background: $color-blue;
|
||||
color: #fff;
|
||||
|
||||
/* .c-ripple__circle {
|
||||
background-color: var(--color-blue-hover);
|
||||
} */
|
||||
}
|
||||
|
@ -903,29 +903,69 @@
|
||||
}
|
||||
|
||||
.two-step-verification {
|
||||
.sidebar-left-section-caption { // * main tab verified with mockup
|
||||
text-align: center;
|
||||
max-width: 342px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
font-size: 1rem;
|
||||
line-height: 1.3125;
|
||||
margin-bottom: 1.125rem;
|
||||
}
|
||||
|
||||
.btn-primary + .btn-primary {
|
||||
margin-top: .125rem !important;
|
||||
}
|
||||
|
||||
.media-sticker-wrapper {
|
||||
width: 168px;
|
||||
height: 168px;
|
||||
margin: .625rem auto 1.1875rem;
|
||||
}
|
||||
|
||||
.input-wrapper .btn-primary:first-child:last-child {
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
&-enter-password {
|
||||
.media-sticker-wrapper {
|
||||
margin: 1.125rem auto 1.8125rem;
|
||||
width: 157px;
|
||||
height: 157px;
|
||||
}
|
||||
}
|
||||
|
||||
&-hint, &-email {
|
||||
.btn-primary + .btn-primary {
|
||||
margin-top: .5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-hint {
|
||||
.media-sticker-wrapper {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin: .5rem auto 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&-email {
|
||||
.media-sticker-wrapper {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin: .5625rem auto 2.1875rem;
|
||||
}
|
||||
}
|
||||
|
||||
&-set {
|
||||
.media-sticker-wrapper {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin: 1rem auto 1.3125rem;
|
||||
|
||||
.rlottie, .rlottie-vector {
|
||||
left: .625rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -754,6 +754,12 @@ img.emoji {
|
||||
}
|
||||
}
|
||||
|
||||
.popup-disable-password, .popup-skip-email {
|
||||
.popup-description {
|
||||
max-width: 284px;
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
|
@ -22,7 +22,7 @@ test('2FA whole (with negative)', async() => {
|
||||
|
||||
new_algo: null,
|
||||
new_secure_algo: null
|
||||
}).then(res => {
|
||||
}, false).then(res => {
|
||||
expect(res.srp_id).toEqual(srp_id);
|
||||
expect(res.A).toEqual(A);
|
||||
expect(res.M1).toEqual(M1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user