Temp commit

This commit is contained in:
morethanwords 2021-03-31 17:02:23 +04:00
parent a720439b6f
commit 6475479390
6 changed files with 224 additions and 72 deletions

View File

@ -37,17 +37,11 @@
<use href="#logo" />
</svg>
</div>
<h4>Sign in to Telegram</h4>
<p class="subtitle">Please confirm your country and<br> enter your phone number.</p>
</div>
</div>
<div class="page-signQR">
<div class="container center-align">
<div class="auth-image">
<canvas id="qr-code"></canvas>
</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="auth-image"></div>
</div>
</div>
<div class="page-authCode">

23
src/langSign.ts Normal file
View File

@ -0,0 +1,23 @@
const lang = {
"Login.Title": "Sign in to Telegram",
"Login.CountrySelectorLabel": "Country",
"Login.PhoneLabel": "Phone Number",
"Login.PhoneLabelInvalid": "Phone Number Invalid",
"Login.KeepSigned": "Keep me signed in",
"Login.StartText": "Please confirm your country and\nenter your phone number.",
// * android
// * macos
"Login.Next": "Next",
"Login.ContinueOnLanguage": "Continue in English",
"Login.QR.Title": "Log in to Telegram by QR Code",
"Login.QR.Help1": "Open Telegram on your phone",
"Login.QR.Help2": "Go to **Settings** > **Devices** > **Scan QR**",
"Login.QR.Help3": "Point your phone at this screen to confirm login",
"Login.QR.Cancel": "Log in by phone Number",
"Login.QR.Login": "Log in by QR Code",
};
export default lang;

View File

@ -2,6 +2,7 @@ import DEBUG, { MOUNT_CLASS_TO } from "../config/debug";
import { safeAssign } from "../helpers/object";
import { capitalizeFirstLetter } from "../helpers/string";
import type lang from "../lang";
import type langSign from "../langSign";
import { LangPackDifference, LangPackString } from "../layer";
import apiManager from "./mtproto/mtprotoworker";
import sessionStorage from "./sessionStorage";
@ -41,21 +42,23 @@ export const langPack: {[actionType: string]: LangPackKey} = {
"messageActionBotAllowed": "Chat.Service.BotPermissionAllowed"
};
export type LangPackKey = string | keyof typeof lang;
export type LangPackKey = string | keyof typeof lang | keyof typeof langSign;
namespace I18n {
export const strings: Map<LangPackKey, LangPackString> = new Map();
let pluralRules: Intl.PluralRules;
let lastRequestedLangCode: string;
let cacheLangPackPromise: Promise<LangPackDifference>;
export let lastRequestedLangCode: string;
export function getCacheLangPack(): Promise<LangPackDifference> {
return Promise.all([
if(cacheLangPackPromise) return cacheLangPackPromise;
return cacheLangPackPromise = Promise.all([
sessionStorage.get('langPack'),
polyfillPromise
]).then(([langPack]) => {
if(!langPack/* || true */) {
return getLangPack('en');
} else if(DEBUG) {
return loadLocalLangPack();
} else if(DEBUG/* && false */) {
return getLangPack(langPack.lang_code);
} else if(langPack.appVersion !== App.langPackVersion) {
return getLangPack(langPack.lang_code);
@ -67,35 +70,69 @@ namespace I18n {
applyLangPack(langPack);
return langPack;
}).finally(() => {
cacheLangPackPromise = undefined;
});
}
export function getLangPack(langCode: string) {
lastRequestedLangCode = langCode;
export function loadLocalLangPack() {
const defaultCode = 'en';
lastRequestedLangCode = defaultCode;
return Promise.all([
apiManager.invokeApi('langpack.getLangPack', {
import('../lang'),
import('../langSign')
]).then(([lang, langSign]) => {
const strings: LangPackString[] = [];
formatLocalStrings(lang, strings);
formatLocalStrings(langSign, strings);
const langPack: LangPackDifference = {
_: 'langPackDifference',
from_version: 0,
lang_code: defaultCode,
strings,
version: 0
};
return saveLangPack(langPack);
});
}
export function loadLangPack(langCode: string) {
return Promise.all([
apiManager.invokeApiCacheable('langpack.getLangPack', {
lang_code: langCode,
lang_pack: 'macos'
lang_pack: App.langPack
}),
apiManager.invokeApi('langpack.getLangPack', {
apiManager.invokeApiCacheable('langpack.getLangPack', {
lang_code: langCode,
lang_pack: 'android'
}),
import('../lang'),
import('../langSign'),
polyfillPromise
]).then(([langPack, _langPack, __langPack, _]) => {
let strings: LangPackString[] = [];
for(const i in __langPack.default) {
]);
}
export function getStrings(langCode: string, strings: string[]) {
return apiManager.invokeApi('langpack.getStrings', {
lang_pack: App.langPack,
lang_code: langCode,
keys: strings
});
}
export function formatLocalStrings(strings: any, pushTo: LangPackString[] = []) {
for(const i in strings) {
// @ts-ignore
const v = __langPack.default[i];
const v = strings[i];
if(typeof(v) === 'string') {
strings.push({
pushTo.push({
_: 'langPackString',
key: i,
value: v
});
} else {
strings.push({
pushTo.push({
_: 'langPackStringPluralized',
key: i,
...v
@ -103,6 +140,18 @@ namespace I18n {
}
}
return pushTo;
}
export function getLangPack(langCode: string) {
lastRequestedLangCode = langCode;
return loadLangPack(langCode).then(([langPack, _langPack, __langPack, ___langPack, _]) => {
let strings: LangPackString[] = [];
[__langPack, ___langPack].forEach(l => {
formatLocalStrings(l.default as any, strings);
});
strings = strings.concat(langPack.strings);
for(const string of _langPack.strings) {
@ -110,6 +159,11 @@ namespace I18n {
}
langPack.strings = strings;
return saveLangPack(langPack);
});
}
export function saveLangPack(langPack: LangPackDifference) {
// @ts-ignore
langPack.appVersion = App.langPackVersion;
@ -117,7 +171,6 @@ namespace I18n {
applyLangPack(langPack);
return langPack;
});
});
}
export const polyfillPromise = (function checkIfPolyfillNeeded() {

View File

@ -4,7 +4,7 @@ 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 } from "../helpers/dom";
import { findUpTag, attachClickEvent, cancelEvent, replaceContent } from "../helpers/dom";
import Page from "./page";
import pageAuthCode from "./pageAuthCode";
import InputField from "../components/inputField";
@ -15,6 +15,8 @@ import fastSmoothScroll from "../helpers/fastSmoothScroll";
import { isTouchSupported } from "../helpers/touchSupport";
import App from "../config/app";
import Modes from "../config/modes";
import I18n, { _i18n, i18n } from "../lib/langPack";
import { LangPackString } from "../layer";
type Country = _Country & {
li?: HTMLLIElement[]
@ -45,7 +47,7 @@ let onFirstMount = () => {
inputWrapper.classList.add('input-wrapper');
const countryInputField = new InputField({
label: 'Country',
label: 'Login.CountrySelectorLabel',
name: 'countryCode',
plainText: true
});
@ -227,14 +229,13 @@ let onFirstMount = () => {
let lastValue = '';
const telInputField = new InputField({
label: 'Phone Number',
label: 'Login.PhoneLabel',
plainText: true,
name: 'phone'
});
let telEl = telInputField.input as HTMLInputElement;
telEl.type = 'tel';
telEl.autocomplete = 'rr55RandomRR55';
const telLabel = telEl.nextElementSibling as HTMLLabelElement;
telEl.addEventListener('input', function(this: typeof telEl, e) {
//console.log('input', this.value);
this.classList.remove('error');
@ -247,7 +248,7 @@ let onFirstMount = () => {
pasted = false;
telLabel.innerText = 'Phone Number';
telInputField.setLabel();
let formatted: string, country: Country;
if(this.value.replace(/\++/, '+') === '+') {
@ -299,19 +300,19 @@ let onFirstMount = () => {
});*/
const signedCheckboxField = new CheckboxField({
text: 'Keep me signed in',
text: 'Login.KeepSigned',
name: 'keepSession',
withRipple: true
});
signedCheckboxField.input.checked = true;
btnNext = Button('btn-primary btn-color-primary', {text: 'NEXT'});
btnNext = Button('btn-primary btn-color-primary', {text: 'Login.Next'});
btnNext.style.visibility = 'hidden';
btnNext.addEventListener('click', function(this: HTMLElement, e) {
this.setAttribute('disabled', 'true');
this.textContent = 'PLEASE WAIT...';
replaceContent(this, i18n('PleaseWait'));
putPreloader(this);
//this.innerHTML = 'PLEASE WAIT...';
@ -333,11 +334,12 @@ let onFirstMount = () => {
}).catch(err => {
this.removeAttribute('disabled');
this.innerText = 'NEXT';
switch(err.type) {
case 'PHONE_NUMBER_INVALID':
telLabel.innerText = 'Phone Number Invalid';
telInputField.setError();
replaceContent(telInputField.label, i18n('Login.PhoneLabelInvalid'));
telEl.classList.add('error');
replaceContent(this, i18n('Login.Next'));
break;
default:
console.error('auth.sendCode error:', err);
@ -347,7 +349,7 @@ let onFirstMount = () => {
});
});
const btnQr = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Quick log in using QR code'});
const btnQr = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Login.QR.Login'});
btnQr.addEventListener('click', () => {
import('./pageSignQR').then(module => {
@ -357,7 +359,14 @@ let onFirstMount = () => {
inputWrapper.append(countryInputField.container, telInputField.container, signedCheckboxField.label, btnNext, btnQr);
page.pageEl.querySelector('.container').append(inputWrapper);
const h4 = document.createElement('h4');
_i18n(h4, 'Login.Title');
const subtitle = document.createElement('div');
subtitle.classList.add('subtitle');
_i18n(subtitle, 'Login.StartText');
page.pageEl.querySelector('.container').append(h4, subtitle, inputWrapper);
let tryAgain = () => {
apiManager.invokeApi('help.getNearestDc').then((nearestDcResult) => {
@ -405,12 +414,52 @@ let onFirstMount = () => {
}, 0);
}
apiManager.invokeApi('help.getConfig').then(config => {
if(config.suggested_lang_code !== I18n.lastRequestedLangCode) {
//I18n.loadLangPack(config.suggested_lang_code);
Promise.all([
I18n.getStrings(config.suggested_lang_code, ['Login.ContinueOnLanguage']),
I18n.getCacheLangPack()
]).then(res => {
const backup: LangPackString[] = [];
res[0].forEach(string => {
const backupString = I18n.strings.get(string.key);
if(!backupString) {
return;
}
backup.push(backupString);
I18n.strings.set(string.key, string);
});
const btnChangeLanguage = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Login.ContinueOnLanguage'});
inputWrapper.append(btnChangeLanguage);
backup.forEach(string => {
I18n.strings.set(string.key, string);
});
attachClickEvent(btnChangeLanguage, (e) => {
cancelEvent(e);
btnChangeLanguage.disabled = true;
putPreloader(btnChangeLanguage);
I18n.getLangPack(config.suggested_lang_code).then(() => {
btnChangeLanguage.remove();
});
});
});
}
});
tryAgain();
};
const page = new Page('page-sign', true, onFirstMount, () => {
if(btnNext) {
btnNext.textContent = 'NEXT';
replaceContent(btnNext, i18n('Login.Next'));
btnNext.removeAttribute('disabled');
}

View File

@ -10,6 +10,7 @@ import { bytesCmp, bytesToBase64 } from '../helpers/bytes';
import { pause } from '../helpers/schedulers';
import App from '../config/app';
import Button from '../components/button';
import { _i18n, i18n } from '../lib/langPack';
let onFirstMount = async() => {
const pageElement = page.pageEl;
@ -18,9 +19,23 @@ let onFirstMount = async() => {
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'});
const btnBack = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Login.QR.Cancel'});
inputWrapper.append(btnBack);
imageDiv.parentElement.append(inputWrapper);
const container = imageDiv.parentElement;
const h4 = document.createElement('h4');
_i18n(h4, 'Login.QR.Title');
const helpList = document.createElement('ol');
helpList.classList.add('qr-description');
['Login.QR.Help1', 'Login.QR.Help2', 'Login.QR.Help3'].forEach((key) => {
const li = document.createElement('li');
li.append(i18n(key));
helpList.append(li);
});
container.append(h4, helpList, inputWrapper);
btnBack.addEventListener('click', () => {
pageSignIn.mount();
@ -86,8 +101,8 @@ let onFirstMount = async() => {
let url = "tg://login?token=" + encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/\=+$/, "");
const qrCode = new QRCodeStyling({
width: 166 * window.devicePixelRatio,
height: 166 * window.devicePixelRatio,
width: 240 * window.devicePixelRatio,
height: 240 * window.devicePixelRatio,
data: url,
image: "assets/img/logo_padded.svg",
dotsOptions: {
@ -108,8 +123,22 @@ let onFirstMount = async() => {
qrCode.append(imageDiv);
(imageDiv.lastChild as HTMLCanvasElement).classList.add('qr-canvas');
let promise: Promise<void>;
if(qrCode._drawingPromise) {
promise = qrCode._drawingPromise;
} else {
promise = Promise.race([
pause(1000),
new Promise<void>((resolve) => {
qrCode._canvas._image.addEventListener('load', () => {
window.requestAnimationFrame(() => resolve());
}, {once: true});
})
]);
}
// * это костыль, но библиотека не предоставляет никаких событий
qrCode._drawingPromise.then(() => {
promise.then(() => {
Array.from(imageDiv.children).slice(0, -1).forEach(el => {
el.remove();
});

View File

@ -3,6 +3,8 @@
overflow: hidden;
.btn-primary {
text-transform: uppercase;
@include respond-to(handhelds) {
height: 50px;
}
@ -89,7 +91,7 @@
flex-direction: column;
@media screen and (max-height: 810px) {
height: 700px;
height: 760px;
}
}
}
@ -156,22 +158,13 @@
.qr {
margin-top: 1.5rem;
}
p.qr-description {
color: #707579;
line-height: 1.85;
text-align: left;
margin-left: auto;
margin-right: auto;
}
}
.page-signQR {
.auth-image {
@include respond-to(handhelds) {
width: 166px;
height: 166px;
}
width: 240px !important;
height: 240px !important;
overflow: hidden;
.qr-canvas {
width: 100%;
@ -186,6 +179,17 @@
h4 {
flex: 0 0 auto;
}
.qr-description {
max-width: 480px;
margin: 1rem auto;
line-height: 1.3125;
text-align: left;
li {
margin-top: .5rem;
}
}
}
/* .page-signQR {