Temp commit
This commit is contained in:
parent
a720439b6f
commit
6475479390
@ -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
23
src/langSign.ts
Normal 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;
|
@ -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,41 +70,87 @@ 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) {
|
||||
// @ts-ignore
|
||||
const v = __langPack.default[i];
|
||||
if(typeof(v) === 'string') {
|
||||
strings.push({
|
||||
_: 'langPackString',
|
||||
key: i,
|
||||
value: v
|
||||
});
|
||||
} else {
|
||||
strings.push({
|
||||
_: 'langPackStringPluralized',
|
||||
key: i,
|
||||
...v
|
||||
});
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
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 = strings[i];
|
||||
if(typeof(v) === 'string') {
|
||||
pushTo.push({
|
||||
_: 'langPackString',
|
||||
key: i,
|
||||
value: v
|
||||
});
|
||||
} else {
|
||||
pushTo.push({
|
||||
_: 'langPackStringPluralized',
|
||||
key: i,
|
||||
...v
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -110,13 +159,17 @@ namespace I18n {
|
||||
}
|
||||
|
||||
langPack.strings = strings;
|
||||
// @ts-ignore
|
||||
langPack.appVersion = App.langPackVersion;
|
||||
return saveLangPack(langPack);
|
||||
});
|
||||
}
|
||||
|
||||
return sessionStorage.set({langPack}).then(() => {
|
||||
applyLangPack(langPack);
|
||||
return langPack;
|
||||
});
|
||||
export function saveLangPack(langPack: LangPackDifference) {
|
||||
// @ts-ignore
|
||||
langPack.appVersion = App.langPackVersion;
|
||||
|
||||
return sessionStorage.set({langPack}).then(() => {
|
||||
applyLangPack(langPack);
|
||||
return langPack;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user