Browse Source

Translated 2FA

Fix blinking QR
Preload monkeys in filters and 2FA
master
Eduard Kuzmenko 4 years ago
parent
commit
a720439b6f
  1. 5
      src/components/checkboxField.ts
  2. 2
      src/components/codeInputField.ts
  3. 23
      src/components/inputField.ts
  4. 2
      src/components/misc.ts
  5. 4
      src/components/monkeys/password.ts
  6. 8
      src/components/monkeys/tracking.ts
  7. 3
      src/components/passwordInputField.ts
  8. 16
      src/components/sidebarLeft/tabs/2fa/email.ts
  9. 22
      src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts
  10. 36
      src/components/sidebarLeft/tabs/2fa/enterPassword.ts
  11. 11
      src/components/sidebarLeft/tabs/2fa/hint.ts
  12. 21
      src/components/sidebarLeft/tabs/2fa/index.ts
  13. 8
      src/components/sidebarLeft/tabs/2fa/passwordSet.ts
  14. 17
      src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts
  15. 38
      src/components/sidebarLeft/tabs/chatFolders.ts
  16. 32
      src/components/sidebarLeft/tabs/editFolder.ts
  17. 16
      src/components/sidebarLeft/tabs/settings.ts
  18. 7
      src/components/sliderTab.ts
  19. 1
      src/config/app.ts
  20. 2
      src/helpers/schedulers.ts
  21. 1
      src/index.hbs
  22. 39
      src/lang.ts
  23. 33
      src/lib/lottieLoader.ts
  24. 2
      src/lib/mtproto/networker.ts
  25. 24
      src/pages/pageSignIn.ts
  26. 26
      src/pages/pageSignQR.ts
  27. 4
      src/scss/components/_global.scss
  28. 4
      src/scss/partials/_button.scss
  29. 13
      src/scss/partials/_checkbox.scss
  30. 4
      src/scss/partials/_leftSidebar.scss
  31. 24
      src/scss/partials/pages/_pages.scss

5
src/components/checkboxField.ts

@ -12,7 +12,8 @@ export type CheckboxFieldOptions = { @@ -12,7 +12,8 @@ export type CheckboxFieldOptions = {
disabled?: boolean,
checked?: boolean,
restriction?: boolean,
withRipple?: boolean
withRipple?: boolean,
withHover?: boolean,
};
export default class CheckboxField {
public input: HTMLInputElement;
@ -92,6 +93,8 @@ export default class CheckboxField { @@ -92,6 +93,8 @@ export default class CheckboxField {
if(options.withRipple) {
label.classList.add('checkbox-ripple', 'hover-effect');
ripple(label, undefined, undefined, true);
} else if(options.withHover) {
label.classList.add('hover-effect');
}
}

2
src/components/codeInputField.ts

@ -20,7 +20,7 @@ export default class CodeInputField extends InputField { @@ -20,7 +20,7 @@ export default class CodeInputField extends InputField {
let lastLength = 0;
this.input.addEventListener('input', (e) => {
this.input.classList.remove('error');
this.label.innerText = options.label;
this.setLabel();
const value = this.value.replace(/\D/g, '').slice(0, options.length);
this.setValueSilently(value);

23
src/components/inputField.ts

@ -62,6 +62,7 @@ export type InputFieldOptions = { @@ -62,6 +62,7 @@ export type InputFieldOptions = {
placeholder?: LangPackKey,
label?: LangPackKey,
labelOptions?: any[],
labelText?: string,
name?: string,
maxLength?: number,
showLengthOn?: number,
@ -89,7 +90,9 @@ class InputField { @@ -89,7 +90,9 @@ class InputField {
options.showLengthOn = Math.round(options.maxLength / 3);
}
const {placeholder, label, maxLength, showLengthOn, name, plainText} = options;
const {placeholder, maxLength, showLengthOn, name, plainText} = options;
let label = options.label || options.labelText;
let input: HTMLElement;
if(!plainText) {
@ -148,7 +151,7 @@ class InputField { @@ -148,7 +151,7 @@ class InputField {
if(label) {
this.label = document.createElement('label');
this.label.append(i18n(label, options.labelOptions));
this.setLabel();
this.container.append(this.label);
}
@ -168,12 +171,11 @@ class InputField { @@ -168,12 +171,11 @@ class InputField {
//this.onLengthChange && this.onLengthChange(inputLength, isError);
if(isError || diff <= showLengthOn) {
labelEl.innerHTML = '';
labelEl.append(i18n(label, options.labelOptions), ` (${maxLength - inputLength})`);
this.setLabel();
labelEl.append(` (${maxLength - inputLength})`);
if(!showingLength) showingLength = true;
} else if((wasError && !isError) || showingLength) {
labelEl.innerHTML = '';
labelEl.append(i18n(label, options.labelOptions));
this.setLabel();
showingLength = false;
}
};
@ -184,6 +186,15 @@ class InputField { @@ -184,6 +186,15 @@ class InputField {
this.input = input;
}
public setLabel() {
this.label.textContent = '';
if(this.options.labelText) {
this.label.innerHTML = this.options.labelText;
} else {
this.label.append(i18n(this.options.label, this.options.labelOptions));
}
}
public onFakeInput() {
const {scrollHeight, clientHeight} = this.inputFake;
if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {

2
src/components/misc.ts

@ -73,7 +73,7 @@ export function putPreloader(elem: Element, returnDiv = false): HTMLElement { @@ -73,7 +73,7 @@ export function putPreloader(elem: Element, returnDiv = false): HTMLElement {
return div;
}
elem.innerHTML += html;
elem.insertAdjacentHTML('beforeend', html);
return elem.lastElementChild as HTMLElement;
}

4
src/components/monkeys/password.ts

@ -5,7 +5,7 @@ export default class PasswordMonkey { @@ -5,7 +5,7 @@ export default class PasswordMonkey {
public container: HTMLElement;
public animation: RLottiePlayer;
public needFrame = 0;
protected loadPromise: Promise<any>;
protected loadPromise: Promise<void>;
constructor(protected passwordInputField: PasswordInputField, protected size: number) {
this.container = document.createElement('div');
@ -48,6 +48,8 @@ export default class PasswordMonkey { @@ -48,6 +48,8 @@ export default class PasswordMonkey {
this.animation.play();
}
};
return lottieLoader.waitForFirstFrame(_animation);
});
}

8
src/components/monkeys/tracking.ts

@ -95,6 +95,8 @@ export default class TrackingMonkey { @@ -95,6 +95,8 @@ export default class TrackingMonkey {
if(!this.inputField.value.length) {
animation.play();
}
return lottieLoader.waitForFirstFrame(animation);
}),
lottieLoader.loadAnimationFromURL({
@ -131,6 +133,8 @@ export default class TrackingMonkey { @@ -131,6 +133,8 @@ export default class TrackingMonkey {
}
});
//console.log(animation.getDuration(), animation.getDuration(true));
return lottieLoader.waitForFirstFrame(_animation);
})
]);
}
@ -139,6 +143,4 @@ export default class TrackingMonkey { @@ -139,6 +143,4 @@ export default class TrackingMonkey {
if(this.animation) this.animation.remove();
if(this.idleAnimation) this.idleAnimation.remove();
}
}
}

3
src/components/passwordInputField.ts

@ -8,7 +8,8 @@ export default class PasswordInputField extends InputField { @@ -8,7 +8,8 @@ export default class PasswordInputField extends InputField {
constructor(options: {
label?: string,
name?: string
name?: string,
labelText?: string,
} = {}) {
super({
plainText: true,

16
src/components/sidebarLeft/tabs/2fa/email.ts

@ -23,7 +23,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -23,7 +23,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
protected init() {
this.container.classList.add('two-step-verification', 'two-step-verification-email');
this.title.innerHTML = 'Recovery Email';
this.setTitle('RecoveryEmailTitle');
const section = new SettingSection({
caption: '',
@ -59,7 +59,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -59,7 +59,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
const inputField = this.inputField = new InputField({
name: 'recovery-email',
label: 'Recovery Email',
label: 'RecoveryEmail',
plainText: true
});
@ -74,8 +74,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -74,8 +74,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
inputField.input.classList.remove('error');
});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});
const goNext = () => {
new AppTwoStepVerificationSetTab(this.slider).open();
@ -131,10 +131,10 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -131,10 +131,10 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
attachClickEvent(btnSkip, (e) => {
const popup = new PopupPeer('popup-skip-email', {
buttons: [{
text: 'CANCEL',
langKey: 'Cancel',
isCancel: true
}, {
text: 'SKIP',
langKey: 'YourEmailSkip',
callback: () => {
//inputContent.classList.add('sidebar-left-section-disabled');
toggleButtons(true);
@ -152,8 +152,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { @@ -152,8 +152,8 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
},
isDanger: true,
}],
titleLangKey: 'Warning',
descriptionLangKey: '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.'
titleLangKey: 'YourEmailSkipWarning',
descriptionLangKey: 'YourEmailSkipWarningText'
});
popup.show();

22
src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts

@ -4,12 +4,13 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager"; @@ -4,12 +4,13 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import { attachClickEvent, canFocus, toggleDisability } from "../../../../helpers/dom";
import { attachClickEvent, canFocus, replaceContent, toggleDisability } from "../../../../helpers/dom";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import AppTwoStepVerificationSetTab from "./passwordSet";
import CodeInputField from "../../../codeInputField";
import AppTwoStepVerificationEmailTab from "./email";
import { putPreloader } from "../../../misc";
import { i18n, _i18n } from "../../../../lib/langPack";
export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {
public codeInputField: CodeInputField;
@ -20,14 +21,14 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -20,14 +21,14 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
protected init() {
this.container.classList.add('two-step-verification', 'two-step-verification-email-confirmation');
this.title.innerHTML = 'Recovery Email';
this.setTitle('TwoStepAuth.RecoveryTitle');
const section = new SettingSection({
caption: 'Please enter code we\'ve just emailed at <b></b>',
caption: true,
noDelimiter: true
});
(section.caption.lastElementChild as HTMLElement).innerText = this.email;
_i18n(section.caption, 'TwoStepAuth.ConfirmEmailCodeDesc', [this.email]);
const emoji = '📬';
const doc = appStickersManager.getAnimatedEmojiSticker(emoji);
@ -58,7 +59,7 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -58,7 +59,7 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
const inputField = this.codeInputField = new CodeInputField({
name: 'recovery-email-code',
label: 'Code',
label: 'TwoStepAuth.RecoveryCode',
length: this.length,
onFill: (code) => {
freeze(true);
@ -75,7 +76,12 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -75,7 +76,12 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
switch(err.type) {
case 'CODE_INVALID':
inputField.input.classList.add('error');
inputField.label.innerText = 'Invalid Code';
replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeInvalid'));
break;
case 'EMAIL_HASH_EXPIRED':
inputField.input.classList.add('error');
replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeExpired'));
break;
default:
@ -88,8 +94,8 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu @@ -88,8 +94,8 @@ export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSu
}
});
const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'CHANGE EMAIL'});
const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'RE-SEND CODE'});
const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'TwoStepAuth.EmailCodeChangeEmail'});
const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'ResendCode'});
const goNext = () => {
new AppTwoStepVerificationSetTab(this.slider).open();

36
src/components/sidebarLeft/tabs/2fa/enterPassword.ts

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
import AppTwoStepVerificationTab from ".";
import { SettingSection } from "../..";
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
import { attachClickEvent, cancelEvent, canFocus, replaceContent } from "../../../../helpers/dom";
import { AccountPassword } from "../../../../layer";
import I18n, { i18n } from "../../../../lib/langPack";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import RichTextProcessor from "../../../../lib/richtextprocessor";
import Button from "../../../button";
import { putPreloader } from "../../../misc";
import PasswordMonkey from "../../../monkeys/password";
import PasswordInputField from "../../../passwordInputField";
import { ripple } from "../../../ripple";
import { SliderSuperTab } from "../../../slider";
import AppTwoStepVerificationReEnterPasswordTab from "./reEnterPassword";
@ -21,7 +21,7 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -21,7 +21,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', 'two-step-verification-enter-password');
this.title.innerHTML = isNew ? 'Enter a Password' : 'Enter your Password';
this.setTitle(isNew ? 'PleaseEnterFirstPassword' : 'PleaseEnterCurrentPassword');
const section = new SettingSection({
noDelimiter: true
@ -32,13 +32,16 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -32,13 +32,16 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
const passwordInputField = this.passwordInputField = new PasswordInputField({
name: 'enter-password',
label: isNew ? 'Enter a Password' : (this.state.hint ?? 'Password')
label: isNew ? 'PleaseEnterFirstPassword' : (this.state.hint ? undefined : 'LoginPassword'),
labelText: !isNew && this.state.hint ? RichTextProcessor.wrapEmojiText(this.state.hint) : undefined
});
const monkey = new PasswordMonkey(passwordInputField, 157);
monkey.load();
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnContinue = Button('btn-primary btn-color-primary');
const textEl = new I18n.IntlElement({key: 'Continue'});
btnContinue.append(textEl.element);
inputWrapper.append(passwordInputField.container, btnContinue);
section.content.append(monkey.container, inputWrapper);
@ -48,8 +51,8 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -48,8 +51,8 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
passwordInputField.input.addEventListener('keypress', (e) => {
if(passwordInputField.input.classList.contains('error')) {
passwordInputField.input.classList.remove('error');
btnContinue.innerText = 'CONTINUE';
ripple(btnContinue);
textEl.key = 'Continue';
textEl.update();
}
if(e.key === 'Enter') {
@ -79,7 +82,11 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -79,7 +82,11 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
return passwordManager.getState().then(_state => {
this.state = _state;
passwordInputField.label.innerHTML = this.state.hint ? RichTextProcessor.wrapEmojiText(this.state.hint) : 'Password';
if(this.state.hint) {
passwordInputField.label.innerHTML = RichTextProcessor.wrapEmojiText(this.state.hint);
} else {
replaceContent(passwordInputField.label, i18n('LoginPassword'));
}
});
};
@ -90,8 +97,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -90,8 +97,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
}
btnContinue.setAttribute('disabled', 'true');
btnContinue.textContent = 'PLEASE WAIT...';
putPreloader(btnContinue);
textEl.key = 'PleaseWait';
textEl.update();
const preloader = putPreloader(btnContinue);
const plainPassword = passwordInputField.value;
passwordManager.check(passwordInputField.value, this.state).then(auth => {
@ -113,7 +121,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -113,7 +121,9 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
switch(err.type) {
default:
//btnContinue.innerText = err.type;
btnContinue.innerText = 'INVALID PASSWORD';
textEl.key = 'TwoStepAuth.InvalidPassword';
textEl.update();
preloader.remove();
break;
}
@ -141,6 +151,8 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT @@ -141,6 +151,8 @@ export default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperT
}
attachClickEvent(btnContinue, onContinueClick);
return monkey.load();
}
onOpenAfterTimeout() {

11
src/components/sidebarLeft/tabs/2fa/hint.ts

@ -8,6 +8,7 @@ import InputField from "../../../inputField"; @@ -8,6 +8,7 @@ import InputField from "../../../inputField";
import AppTwoStepVerificationEmailTab from "./email";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { toast } from "../../../toast";
import I18n from "../../../../lib/langPack";
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
public inputField: InputField;
@ -17,7 +18,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -17,7 +18,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
protected init() {
this.container.classList.add('two-step-verification', 'two-step-verification-hint');
this.title.innerHTML = 'Password Hint';
this.setTitle('TwoStepAuth.SetupHintTitle');
const section = new SettingSection({
noDelimiter: true
@ -50,7 +51,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -50,7 +51,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
const inputField = this.inputField = new InputField({
name: 'hint',
label: 'Hint'
label: 'TwoStepAuth.SetupHintPlaceholder'
});
inputField.input.addEventListener('keypress', (e) => {
@ -67,7 +68,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -67,7 +68,7 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
const hint = saveHint ? inputField.value : undefined;
if(hint && this.newPassword === hint) {
toast('Hint must be different from your password');
toast(I18n.format('PasswordAsHintError', true));
return;
}
@ -80,8 +81,8 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab { @@ -80,8 +81,8 @@ export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
tab.open();
};
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'SKIP'});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});
const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});
const onContinueClick = (e?: Event) => goNext(e, true);
const onSkipClick = (e?: Event) => goNext(e, false);

21
src/components/sidebarLeft/tabs/2fa/index.ts

@ -2,6 +2,7 @@ import { SettingSection } from "../.."; @@ -2,6 +2,7 @@ import { SettingSection } from "../..";
import { attachClickEvent } from "../../../../helpers/dom";
import { AccountPassword } from "../../../../layer";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import { _i18n } from "../../../../lib/langPack";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import Button from "../../../button";
import PopupPeer from "../../../popups/peer";
@ -17,7 +18,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -17,7 +18,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
protected init() {
this.container.classList.add('two-step-verification', 'two-step-verification-main');
this.title.innerHTML = 'Two-Step Verification';
this.setTitle('TwoStepVerificationTitle');
const section = new SettingSection({
caption: ' ',
@ -48,11 +49,11 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -48,11 +49,11 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
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.';
_i18n(section.caption, 'TwoStepAuth.GenericHelp');
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'});
const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: this.state.pFlags.has_recovery ? 'Change Recovery Email' : 'Set Recovery Email'});
const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'TwoStepAuth.ChangePassword'});
const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'TwoStepAuth.RemovePassword'});
const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: this.state.pFlags.has_recovery ? 'TwoStepAuth.ChangeEmail' : 'TwoStepAuth.SetupEmail'});
attachClickEvent(btnChangePassword, () => {
const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);
@ -64,7 +65,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -64,7 +65,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
attachClickEvent(btnDisablePassword, () => {
const popup = new PopupPeer('popup-disable-password', {
buttons: [{
text: 'DISABLE',
langKey: 'Disable',
callback: () => {
passwordManager.updateSettings({currentPassword: this.plainPassword}).then(() => {
this.slider.sliceTabsUntilTab(AppSettingsTab, this);
@ -73,8 +74,8 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -73,8 +74,8 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
},
isDanger: true,
}],
titleLangKey: 'Warning',
descriptionLangKey: 'Are you sure you want to disable<br/>your password?'
titleLangKey: 'TurnPasswordOffQuestionTitle',
descriptionLangKey: 'TurnPasswordOffQuestion'
});
popup.show();
@ -92,12 +93,12 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { @@ -92,12 +93,12 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab {
c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);
} 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.';
_i18n(section.caption, 'TwoStepAuth.SetPasswordHelp');
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const btnSetPassword = Button('btn-primary btn-color-primary', {text: 'SET PASSWORD'});
const btnSetPassword = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationSetPassword'});
inputWrapper.append(btnSetPassword);
c.append(inputWrapper);

8
src/components/sidebarLeft/tabs/2fa/passwordSet.ts

@ -2,17 +2,17 @@ import { SettingSection } from "../.."; @@ -2,17 +2,17 @@ import { SettingSection } from "../..";
import { attachClickEvent } from "../../../../helpers/dom";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import SidebarSlider, { SliderSuperTab } from "../../../slider";
import { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import AppSettingsTab from "../settings";
export default class AppTwoStepVerificationSetTab extends SliderSuperTab {
protected init() {
this.container.classList.add('two-step-verification', 'two-step-verification-set');
this.title.innerHTML = 'Password Set!';
this.setTitle('TwoStepVerificationPasswordSet');
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.',
caption: 'TwoStepVerificationPasswordSetInfo',
noDelimiter: true
});
@ -42,7 +42,7 @@ export default class AppTwoStepVerificationSetTab extends SliderSuperTab { @@ -42,7 +42,7 @@ export default class AppTwoStepVerificationSetTab extends SliderSuperTab {
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const btnReturn = Button('btn-primary btn-color-primary', {text: 'RETURN TO SETTINGS'});
const btnReturn = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationPasswordReturnSettings'});
attachClickEvent(btnReturn, (e) => {
this.close();

17
src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts

@ -3,10 +3,10 @@ import { attachClickEvent, cancelEvent } from "../../../../helpers/dom"; @@ -3,10 +3,10 @@ import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { AccountPassword } from "../../../../layer";
import Button from "../../../button";
import PasswordInputField from "../../../passwordInputField";
import { ripple } from "../../../ripple";
import { SliderSuperTab } from "../../../slider";
import TrackingMonkey from "../../../monkeys/tracking";
import AppTwoStepVerificationHintTab from "./hint";
import { InputState } from "../../../inputField";
export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {
public state: AccountPassword;
@ -16,7 +16,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -16,7 +16,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
protected init() {
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';
this.setTitle('PleaseReEnterPassword');
const section = new SettingSection({
noDelimiter: true
@ -27,13 +27,12 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -27,13 +27,12 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
const passwordInputField = this.passwordInputField = new PasswordInputField({
name: 're-enter-password',
label: 'Re-Enter your Password'
label: 'PleaseReEnterPassword'
});
const monkey = new TrackingMonkey(passwordInputField, 157);
monkey.load();
const btnContinue = Button('btn-primary btn-color-primary', {text: 'CONTINUE'});
const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});
inputWrapper.append(passwordInputField.container, btnContinue);
section.content.append(monkey.container, inputWrapper);
@ -42,9 +41,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -42,9 +41,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
passwordInputField.input.addEventListener('keypress', (e) => {
if(passwordInputField.input.classList.contains('error')) {
passwordInputField.input.classList.remove('error');
btnContinue.innerText = 'CONTINUE';
ripple(btnContinue);
passwordInputField.setState(InputState.Neutral);
}
if(e.key === 'Enter') {
@ -54,7 +51,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -54,7 +51,7 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
const verifyInput = () => {
if(this.newPassword !== passwordInputField.value) {
passwordInputField.input.classList.add('error');
passwordInputField.setError();
return false;
}
@ -75,6 +72,8 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe @@ -75,6 +72,8 @@ export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSupe
tab.open();
};
attachClickEvent(btnContinue, onContinueClick);
return monkey.load();
}
onOpenAfterTimeout() {

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

@ -25,6 +25,7 @@ export default class AppChatFoldersTab extends SliderSuperTab { @@ -25,6 +25,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
private animation: RLottiePlayer;
private filtersRendered: {[filterId: number]: HTMLElement} = {};
private loadAnimationPromise: Promise<void>;
private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, div?: HTMLElement) {
let filter: DialogFilter | MyDialogFilter;
@ -101,7 +102,7 @@ export default class AppChatFoldersTab extends SliderSuperTab { @@ -101,7 +102,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
return div;
}
protected init() {
protected async init() {
this.container.classList.add('chat-folders-container');
this.setTitle('ChatList.Filter.List.Title');
@ -139,16 +140,6 @@ export default class AppChatFoldersTab extends SliderSuperTab { @@ -139,16 +140,6 @@ export default class AppChatFoldersTab extends SliderSuperTab {
}
}, {listenerSetter: this.listenerSetter});
lottieLoader.loadAnimationFromURL({
container: this.stickerContainer,
loop: false,
autoplay: true,
width: 86,
height: 86
}, 'assets/img/Folders_1.tgs').then(player => {
this.animation = player;
});
const onFiltersContainerUpdate = () => {
this.foldersSection.container.style.display = Object.keys(this.filtersRendered).length ? '' : 'none';
};
@ -200,6 +191,25 @@ export default class AppChatFoldersTab extends SliderSuperTab { @@ -200,6 +191,25 @@ export default class AppChatFoldersTab extends SliderSuperTab {
});
this.getSuggestedFilters();
return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({
container: this.stickerContainer,
loop: false,
autoplay: false,
width: 86,
height: 86
}, 'assets/img/Folders_1.tgs').then(player => {
this.animation = player;
return lottieLoader.waitForFirstFrame(player);
});
}
onOpenAfterTimeout() {
this.loadAnimationPromise.then(() => {
this.animation.autoplay = true;
this.animation.play();
});
}
private getSuggestedFilters() {
@ -234,10 +244,4 @@ export default class AppChatFoldersTab extends SliderSuperTab { @@ -234,10 +244,4 @@ export default class AppChatFoldersTab extends SliderSuperTab {
});
});
}
onOpen() {
if(this.animation) {
this.animation.restart();
}
}
}

32
src/components/sidebarLeft/tabs/editFolder.ts

@ -34,6 +34,7 @@ export default class AppEditFolderTab extends SliderSuperTab { @@ -34,6 +34,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
private originalFilter: DialogFilter;
private type: 'edit' | 'create';
private loadAnimationPromise: Promise<void>;
protected init() {
this.container.classList.add('edit-folder-container');
@ -160,16 +161,6 @@ export default class AppEditFolderTab extends SliderSuperTab { @@ -160,16 +161,6 @@ export default class AppEditFolderTab extends SliderSuperTab {
new AppIncludedChatsTab(this.slider).open(this.filter, 'excluded', this);
});
lottieLoader.loadAnimationFromURL({
container: this.stickerContainer,
loop: false,
autoplay: true,
width: 86,
height: 86
}, 'assets/img/Folders_2.tgs').then(player => {
this.animation = player;
});
this.confirmBtn.addEventListener('click', () => {
if(this.nameInputField.input.classList.contains('error')) {
return;
@ -216,12 +207,25 @@ export default class AppEditFolderTab extends SliderSuperTab { @@ -216,12 +207,25 @@ export default class AppEditFolderTab extends SliderSuperTab {
this.filter.title = this.nameInputField.value;
this.editCheckForChange();
});
return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({
container: this.stickerContainer,
loop: false,
autoplay: false,
width: 86,
height: 86
}, 'assets/img/Folders_2.tgs').then(player => {
this.animation = player;
return lottieLoader.waitForFirstFrame(player);
});
}
onOpen() {
if(this.animation) {
this.animation.restart();
}
onOpenAfterTimeout() {
this.loadAnimationPromise.then(() => {
this.animation.autoplay = true;
this.animation.play();
});
}
private onCreateOpen() {

16
src/components/sidebarLeft/tabs/settings.ts

@ -11,6 +11,7 @@ import AppChatFoldersTab from "./chatFolders"; @@ -11,6 +11,7 @@ import AppChatFoldersTab from "./chatFolders";
import AppNotificationsTab from "./notifications";
import PeerTitle from "../../peerTitle";
import AppLanguageTab from "./language";
import lottieLoader from "../../../lib/lottieLoader";
//import AppMediaViewer from "../../appMediaViewerNew";
export default class AppSettingsTab extends SliderSuperTab {
@ -27,7 +28,7 @@ export default class AppSettingsTab extends SliderSuperTab { @@ -27,7 +28,7 @@ export default class AppSettingsTab extends SliderSuperTab {
language: HTMLButtonElement
} = {} as any;
init() {
protected init() {
this.container.classList.add('settings-container');
this.setTitle('Settings');
@ -135,6 +136,10 @@ export default class AppSettingsTab extends SliderSuperTab { @@ -135,6 +136,10 @@ export default class AppSettingsTab extends SliderSuperTab {
this.buttons.language.addEventListener('click', () => {
new AppLanguageTab(this.slider).open();
});
lottieLoader.loadLottieWorkers();
this.fillElements();
}
public fillElements() {
@ -144,13 +149,4 @@ export default class AppSettingsTab extends SliderSuperTab { @@ -144,13 +149,4 @@ export default class AppSettingsTab extends SliderSuperTab {
this.nameDiv.append(new PeerTitle({peerId: user.id}).element);
this.phoneDiv.innerHTML = user.rPhone || '';
}
public onOpen() {
if(this.init) {
this.init();
this.init = null;
}
this.fillElements();
}
}

7
src/components/sliderTab.ts

@ -71,8 +71,13 @@ export default class SliderSuperTab implements SliderTab { @@ -71,8 +71,13 @@ export default class SliderSuperTab implements SliderTab {
if(this.init) {
const result = this.init();
this.init = null;
if(result instanceof Promise) {
await result;
try {
await result;
} catch(err) {
console.error('open tab error', err);
}
}
}

1
src/config/app.ts

@ -3,6 +3,7 @@ const App = { @@ -3,6 +3,7 @@ const App = {
hash: '452b0359b988148995f22ff0f4229750',
version: '0.4.0',
langPackVersion: '0.0.5',
langPack: 'macos',
domains: [] as string[],
baseDcId: 2
};

2
src/helpers/schedulers.ts

@ -105,7 +105,7 @@ function runNow(fn: NoneToVoidFunction) { @@ -105,7 +105,7 @@ function runNow(fn: NoneToVoidFunction) {
fn();
} */
export const pause = (ms: number) => new Promise((resolve) => {
export const pause = (ms: number) => new Promise<void>((resolve) => {
setTimeout(resolve, ms);
});

1
src/index.hbs

@ -48,7 +48,6 @@ @@ -48,7 +48,6 @@
</div>
<h4>Scan from mobile Telegram</h4>
<p class="qr-description">1. Open Telegram on your phone<br>2. Go to settings > Devices > Scan QR<br>3. Scan this image to Log in</p>
<div class="qr"><a href="#" class="a-qr">Or log in using your phone number</a></div>
</div>
</div>
<div class="page-authCode">

39
src/lang.ts

@ -87,6 +87,9 @@ const lang = { @@ -87,6 +87,9 @@ const lang = {
"Popup.Unpin.HideTitle": "Hide pinned messages",
"Popup.Unpin.HideDescription": "Do you want to hide the pinned message bar? It wil stay hidden until a new message is pinned.",
"Popup.Unpin.Hide": "Hide",
"TwoStepAuth.InvalidPassword": "Invalid password",
"TwoStepAuth.EmailCodeChangeEmail": "Change Email",
"PleaseWait": "Please wait...",
// * android
"ActionCreateChannel": "Channel created",
@ -197,6 +200,7 @@ const lang = { @@ -197,6 +200,7 @@ const lang = {
"BlockedUsersInfo": "Blocked users will not be able to contact you and will not see your Last Seen time.",
"BlockedEmpty": "None",
"TwoStepVerification": "Two-Step Verification",
"TwoStepVerificationTitle": "Two-Step Verification",
"PinnedMessage": "Pinned Message",
"PinnedMessagesCount": {
"one_value": "Pinned Message",
@ -352,6 +356,25 @@ const lang = { @@ -352,6 +356,25 @@ const lang = {
"ChannelLeaveAlertWithName": "Are you sure you want to leave **%1$s**?",
"LeaveMegaMenu": "Leave group",
"DeleteChatUser": "Delete chat",
"PleaseEnterCurrentPassword": "Enter your password",
"PleaseEnterFirstPassword": "Enter a password",
"PleaseReEnterPassword": "Re-enter your password",
"LoginPassword": "Password",
"Continue": "Continue",
"YourEmailSkip": "Skip",
"YourEmailSkipWarning": "Warning",
"YourEmailSkipWarningText": "No, seriously.\n\nIf you forget your password, you will lose access to your Telegram account. There will be no way to restore it.",
"TurnPasswordOffQuestionTitle": "Disable password",
"TurnPasswordOffQuestion": "Are you sure you want to disable your password?",
"Disable": "Disable",
"TwoStepVerificationSetPassword": "Set Password",
"TwoStepVerificationPasswordSet": "Password Set!",
"TwoStepVerificationPasswordSetInfo": "This password will be required when you log in on a new device in addition to the code you get in the SMS.",
"TwoStepVerificationPasswordReturnSettings": "Return to Settings",
"RecoveryEmail": "Recovery email",
"RecoveryEmailTitle": "Recovery Email",
"ResendCode": "Resend code",
"PasswordAsHintError": "Hint must be different from your password",
// * macos
"AccountSettings.Filters": "Chat Folders",
@ -563,7 +586,21 @@ const lang = { @@ -563,7 +586,21 @@ const lang = {
"GroupPermission.Delete": "Delete Exception",
"Schedule.SendToday": "Send today at %@",
"Schedule.SendDate": "Send on %@ at %@",
//"Schedule.SendWhenOnline": "Send When Online"
//"Schedule.SendWhenOnline": "Send When Online",
"TwoStepAuth.SetPasswordHelp": "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.",
"TwoStepAuth.GenericHelp": "You have enabled Two-Step verification.\nYou'll need the password you set up here to log in to your Telegram account.",
"TwoStepAuth.ChangePassword": "Change Password",
"TwoStepAuth.RemovePassword": "Turn Password Off",
"TwoStepAuth.SetupEmail": "Set Recovery Email",
"TwoStepAuth.ChangeEmail": "Change Recovery Email",
"TwoStepAuth.ConfirmEmailCodeDesc": "Please enter the code we've just emailed to %@.",
"TwoStepAuth.RecoveryTitle": "Email Code",
"TwoStepAuth.RecoveryCode": "Code",
"TwoStepAuth.RecoveryCodeInvalid": "Invalid code. Please try again.",
"TwoStepAuth.RecoveryCodeExpired": "Code Expired",
"TwoStepAuth.SetupHintTitle": "Password Hint",
"TwoStepAuth.SetupHintPlaceholder": "Hint",
"PHONE_CODE_INVALID": "Invalid code",
};
export default lang;

33
src/lib/lottieLoader.ts

@ -4,6 +4,7 @@ import { MOUNT_CLASS_TO } from '../config/debug'; @@ -4,6 +4,7 @@ import { MOUNT_CLASS_TO } from '../config/debug';
import EventListenerBase from "../helpers/eventListenerBase";
import mediaSizes from "../helpers/mediaSizes";
import { clamp } from '../helpers/number';
import { pause } from '../helpers/schedulers';
import { isAndroid, isApple, isAppleMobile, isSafari } from "../helpers/userAgent";
import { logger, LogLevels } from "./logger";
import apiManager from "./mtproto/mtprotoworker";
@ -501,7 +502,8 @@ class QueryableWorker extends EventListenerBase<any> { @@ -501,7 +502,8 @@ class QueryableWorker extends EventListenerBase<any> {
}
class LottieLoader {
public loadPromise: Promise<void>;
public isWebAssemblySupported = typeof(WebAssembly) !== 'undefined';
public loadPromise: Promise<void> = !this.isWebAssemblySupported ? Promise.reject() : undefined;
public loaded = false;
// https://github.com/telegramdesktop/tdesktop/blob/97d8ee75d51874fcb74a9bfadc79f835c82be54a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp#L46
@ -569,9 +571,9 @@ class LottieLoader { @@ -569,9 +571,9 @@ class LottieLoader {
}
public loadLottieWorkers() {
if(typeof(WebAssembly) === 'undefined') return Promise.reject();
if(this.loadPromise) return this.loadPromise;
if(this.loadPromise) {
return this.loadPromise;
}
return this.loadPromise = new Promise((resolve, reject) => {
let remain = this.workersLimit;
@ -633,7 +635,11 @@ class LottieLoader { @@ -633,7 +635,11 @@ class LottieLoader {
}
}
public loadAnimationFromURL(params: Omit<RLottieOptions, 'animationData'>, url: string) {
public loadAnimationFromURL(params: Omit<RLottieOptions, 'animationData'>, url: string): Promise<RLottiePlayer> {
if(!this.isWebAssemblySupported) {
return this.loadPromise as any;
}
if(!this.loaded) {
this.loadLottieWorkers();
}
@ -641,12 +647,27 @@ class LottieLoader { @@ -641,12 +647,27 @@ class LottieLoader {
return fetch(url)
.then(res => res.arrayBuffer())
.then(data => apiManager.gzipUncompress<string>(data, true))
/* .then(str => {
return new Promise<string>((resolve) => setTimeout(() => resolve(str), 2e3));
}) */
.then(str => {
return this.loadAnimationWorker(Object.assign(params, {animationData: str/* JSON.parse(str) */, needUpscale: true}));
});
}
public async loadAnimationWorker(params: RLottieOptions, group = '', toneIndex = -1) {
public waitForFirstFrame(player: RLottiePlayer): Promise<void> {
return Promise.race([
new Promise<void>((resolve) => {
player.addEventListener('firstFrame', resolve, true);
}),
pause(2500)
]);
}
public async loadAnimationWorker(params: RLottieOptions, group = '', toneIndex = -1): Promise<RLottiePlayer> {
if(!this.isWebAssemblySupported) {
return this.loadPromise as any;
}
//params.autoplay = true;
if(toneIndex >= 1 && toneIndex <= 5) {

2
src/lib/mtproto/networker.ts

@ -293,7 +293,7 @@ export default class MTPNetworker { @@ -293,7 +293,7 @@ export default class MTPNetworker {
serializer.storeString(navigator.platform || 'Unknown Platform', 'system_version');
serializer.storeString(App.version, 'app_version');
serializer.storeString(navigator.language || 'en', 'system_lang_code');
serializer.storeString('', 'lang_pack');
serializer.storeString(App.langPack, 'lang_pack');
serializer.storeString(navigator.language || 'en', 'lang_code');
//serializer.storeInt(0x0, 'proxy');
/* serializer.storeMethod('initConnection', {

24
src/pages/pageSignIn.ts

@ -4,10 +4,9 @@ import Countries, { Country as _Country } from "../countries"; @@ -4,10 +4,9 @@ import Countries, { Country as _Country } from "../countries";
import appStateManager from "../lib/appManagers/appStateManager";
import apiManager from "../lib/mtproto/mtprotoworker";
import { RichTextProcessor } from '../lib/richtextprocessor';
import { findUpTag, findUpClassName } from "../helpers/dom";
import { findUpTag } from "../helpers/dom";
import Page from "./page";
import pageAuthCode from "./pageAuthCode";
import pageSignQR from './pageSignQR';
import InputField from "../components/inputField";
import CheckboxField from "../components/checkboxField";
import Button from "../components/button";
@ -301,7 +300,8 @@ let onFirstMount = () => { @@ -301,7 +300,8 @@ let onFirstMount = () => {
const signedCheckboxField = new CheckboxField({
text: 'Keep me signed in',
name: 'keepSession'
name: 'keepSession',
withRipple: true
});
signedCheckboxField.input.checked = true;
@ -346,22 +346,16 @@ let onFirstMount = () => { @@ -346,22 +346,16 @@ let onFirstMount = () => {
}
});
});
const qrDiv = document.createElement('div');
qrDiv.classList.add('qr');
const qrLink = document.createElement('a');
qrLink.href = '#';
qrLink.classList.add('a-qr');
qrLink.innerText = 'Quick log in using QR code';
qrDiv.append(qrLink);
const btnQr = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Quick log in using QR code'});
qrLink.addEventListener('click', () => {
pageSignQR.mount();
btnQr.addEventListener('click', () => {
import('./pageSignQR').then(module => {
module.default.mount();
});
});
inputWrapper.append(countryInputField.container, telInputField.container, signedCheckboxField.label, btnNext, qrDiv);
inputWrapper.append(countryInputField.container, telInputField.container, signedCheckboxField.label, btnNext, btnQr);
page.pageEl.querySelector('.container').append(inputWrapper);

26
src/pages/pageSignQR.ts

@ -9,12 +9,20 @@ import { AuthAuthorization, AuthLoginToken } from '../layer'; @@ -9,12 +9,20 @@ import { AuthAuthorization, AuthLoginToken } from '../layer';
import { bytesCmp, bytesToBase64 } from '../helpers/bytes';
import { pause } from '../helpers/schedulers';
import App from '../config/app';
import Button from '../components/button';
let onFirstMount = async() => {
const pageElement = page.pageEl;
const imageDiv = pageElement.querySelector('.auth-image') as HTMLDivElement;
page.pageEl.querySelector('.a-qr').addEventListener('click', () => {
const inputWrapper = document.createElement('div');
inputWrapper.classList.add('input-wrapper');
const btnBack = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Or log in using your phone number'});
inputWrapper.append(btnBack);
imageDiv.parentElement.append(inputWrapper);
btnBack.addEventListener('click', () => {
pageSignIn.mount();
stop = true;
});
@ -76,11 +84,10 @@ let onFirstMount = async() => { @@ -76,11 +84,10 @@ let onFirstMount = async() => {
let encoded = bytesToBase64(loginToken.token);
let url = "tg://login?token=" + encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/\=+$/, "");
imageDiv.innerHTML = '';
const qrCode = new QRCodeStyling({
width: 166,
height: 166,
width: 166 * window.devicePixelRatio,
height: 166 * window.devicePixelRatio,
data: url,
image: "assets/img/logo_padded.svg",
dotsOptions: {
@ -97,7 +104,16 @@ let onFirstMount = async() => { @@ -97,7 +104,16 @@ let onFirstMount = async() => {
errorCorrectionLevel: "L"
}
});
qrCode.append(imageDiv);
(imageDiv.lastChild as HTMLCanvasElement).classList.add('qr-canvas');
// * это костыль, но библиотека не предоставляет никаких событий
qrCode._drawingPromise.then(() => {
Array.from(imageDiv.children).slice(0, -1).forEach(el => {
el.remove();
});
});
}
let timestamp = Date.now() / 1000;

4
src/scss/components/_global.scss

@ -139,6 +139,10 @@ Utility Classes @@ -139,6 +139,10 @@ Utility Classes
display: inline-table;
}
.text-uppercase {
text-transform: uppercase;
}
/* .flex-grow {
flex-grow: 1;
}

4
src/scss/partials/_button.scss

@ -363,6 +363,10 @@ @@ -363,6 +363,10 @@
}
}
.btn-secondary:not(:first-child) {
margin-top: .5rem !important;
}
.btn-color-primary {
background: $color-blue;
color: #fff;

13
src/scss/partials/_checkbox.scss

@ -90,6 +90,19 @@ @@ -90,6 +90,19 @@
transition: none;
}
}
&.hover-effect {
display: flex;
align-items: center;
height: 3.5rem;
padding: 0 1.1875rem;
margin-left: 0;
margin-right: 0;
.checkbox-box {
left: auto;
}
}
}
.checkbox-ripple {

4
src/scss/partials/_leftSidebar.scss

@ -908,8 +908,8 @@ @@ -908,8 +908,8 @@
}
}
.btn-secondary {
margin-top: .5rem !important;
.btn-primary:not(.btn-transparent) {
text-transform: uppercase;
}
.media-sticker-wrapper {

24
src/scss/partials/pages/_pages.scss

@ -116,6 +116,13 @@ @@ -116,6 +116,13 @@
}
}
.page-sign {
.checkbox-field {
margin-top: .5rem;
margin-bottom: .5rem;
}
}
.page-sign, .page-signUp {
.auth-image {
width: 7.5rem;
@ -142,6 +149,10 @@ @@ -142,6 +149,10 @@
}
.page-sign, .page-signQR {
.btn-secondary {
font-weight: normal;
}
.qr {
margin-top: 1.5rem;
}
@ -161,9 +172,18 @@ @@ -161,9 +172,18 @@
width: 166px;
height: 166px;
}
.qr-canvas {
width: 100%;
height: 100%;
}
}
.input-wrapper {
margin-top: 1rem !important;
}
h4, .qr-description, .qr {
h4 {
flex: 0 0 auto;
}
}
@ -214,4 +234,4 @@ @@ -214,4 +234,4 @@
.btn-primary {
margin-top: 1.1875rem; // * verified with mockup
}
}
}

Loading…
Cancel
Save