Browse Source

Fixed slider animation & added same animation to auth pages

master
morethanwords 4 years ago
parent
commit
43bc94b0c4
  1. 152
      src/components/misc.ts
  2. 194
      src/components/pageIm.ts
  3. 33
      src/components/wrappers.ts
  4. 337
      src/lib/appManagers/appDialogsManager.ts
  5. 54
      src/lib/appManagers/appImManager.ts
  6. 3
      src/lib/appManagers/appMediaViewer.ts
  7. 152
      src/lib/appManagers/appSidebarLeft.ts
  8. 2
      src/lib/services.ts
  9. 10
      src/lib/utils.js
  10. 28
      src/pages/page.ts
  11. 550
      src/pages/pageAuthCode.ts
  12. 111
      src/pages/pageIm.ts
  13. 267
      src/pages/pagePassword.ts
  14. 518
      src/pages/pageSignIn.ts
  15. 393
      src/pages/pageSignUp.ts
  16. 37
      src/pages/pagesManager.ts
  17. 2
      src/scss/partials/_leftSidebar.scss
  18. 35
      src/scss/style.scss

152
src/components/misc.ts

@ -1,4 +1,4 @@
import { whichChild, findUpTag } from "../lib/utils"; import { whichChild, findUpTag, cancelEvent } from "../lib/utils";
let rippleClickID = 0; let rippleClickID = 0;
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) { export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
@ -8,11 +8,17 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
elem.append(r); elem.append(r);
elem.addEventListener('mousedown', (e) => { elem.addEventListener('mousedown', (e) => {
if(elem.dataset.ripple == '0') {
return false;
}
let startTime = Date.now(); let startTime = Date.now();
let span = document.createElement('span'); let span = document.createElement('span');
let clickID = rippleClickID++; let clickID = rippleClickID++;
console.log('ripple mousedown');
let handler = () => { let handler = () => {
let elapsedTime = Date.now() - startTime; let elapsedTime = Date.now() - startTime;
if(elapsedTime < 700) { if(elapsedTime < 700) {
@ -135,87 +141,125 @@ export function putPreloader(elem: Element, returnDiv = false) {
elem.innerHTML += html; elem.innerHTML += html;
} }
export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void) { export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
let hideTimeout: number = 0; let hideTimeout: number = 0;
let prevTabContent: HTMLDivElement = null; let prevTabContent: HTMLDivElement = null;
let prevId = -1; let prevId = -1;
let children = Array.from(content.children);
tabs.addEventListener('click', function(e) { let tabsChildren = tabs ? Array.from(tabs.children) : [];
let target = e.target as HTMLLIElement; let activeInSlide: Set<Element> = new Set();
if(target.tagName != 'LI') { let selectTab = (id: number) => {
target = findUpTag(target, 'LI'); if(id == prevId) return false;
}
let p = prevTabContent;
///////console.log('tabs click:', target);
/* children.forEach(child => {
if(!target) return false; if(child != p) {
child.classList.remove('active');
}
}); */
let id = whichChild(target);
let tabContent = content.children[id] as HTMLDivElement; let tabContent = content.children[id] as HTMLDivElement;
if(onClick) onClick(id, tabContent);
if(target.classList.contains('active') || id == prevId) {
return false;
}
let prev = tabs.querySelector('li.active') as HTMLLIElement;
prev && prev.classList.remove('active');
target.classList.add('active');
tabContent.classList.add('active'); tabContent.classList.add('active');
/////console.log('mambo rap', prevId, id); if(!activeInSlide.has(tabContent)) {
activeInSlide.add(tabContent);
}
//content.style.marginLeft = id > 0 ? (-id * 100) + '%' : ''; //content.style.marginLeft = id > 0 ? (-id * 100) + '%' : '';
let toRight = prevId < id; let toRight = prevId < id;
if(prevId != -1) { if(prevId != -1) {
content.style.width = '200%'; content.style.cssText = `width: ${activeInSlide.size * 100}%; will-change: width, transform; transform: translateX(-${100 - 100 / activeInSlide.size}%);`;
//////console.log('mambo rap setting', toRight); //////console.log('mambo rap setting', toRight);
content.classList.remove('animated'); content.classList.remove('animated');
if(toRight) { if(toRight) {
content.classList.add('animated'); content.classList.add('animated');
content.style.marginLeft = '-100%';
} else { } else {
window.requestAnimationFrame(() => {
content.style.marginLeft = '-100%';
setTimeout(() => {
content.classList.add('animated'); content.classList.add('animated');
content.style.marginLeft = ''; content.style.transform = '';
}, 10); });
} }
} }
prevId = id; if(hideTimeout) clearTimeout(hideTimeout);
if(p/* && false */) {
let p = prevTabContent; //if(tabs) tabs.classList.add('disable-hover');
clearTimeout(hideTimeout);
if(p) hideTimeout = setTimeout(() => { if(tabs) {
if(toRight) { tabsChildren.forEach((c, idx) => {
p.classList.remove('active'); if(idx != prevId && idx != id) {
(c as HTMLElement).dataset.ripple = '0';
}
});
}
hideTimeout = setTimeout(() => {
children.forEach(child => {
if(child != tabContent) {
child.classList.remove('active');
activeInSlide.delete(child);
}
});
if(tabs) {
tabsChildren.forEach(c => {
delete (c as HTMLElement).dataset.ripple;
});
}
content.classList.remove('animated'); content.classList.remove('animated');
content.style.width = '100%'; content.style.cssText = '';
hideTimeout = 0;
if(onTransitionEnd) onTransitionEnd();
//if(tabs) tabs.classList.remove('disable-hover');
}, transitionTime);
}
prevId = id;
prevTabContent = tabContent;
};
if(tabs) {
tabs.addEventListener('click', function(e) {
let target = e.target as HTMLLIElement;
if(target.tagName != 'LI') {
target = findUpTag(target, 'LI');
} }
/* content.style.marginLeft = '0%'; //console.log('tabs click:', target);
content.style.width = '100%'; */
if(!toRight) { if(!target) return false;
p.classList.remove('active');
content.classList.remove('animated'); let id = whichChild(target);
content.style.width = '100%'; let tabContent = content.children[id] as HTMLDivElement;
if(activeInSlide.size >= 2 && !activeInSlide.has(tabContent)) {
cancelEvent(e);
return false;
}
if(onClick) onClick(id, tabContent);
if(target.classList.contains('active') || id == prevId) {
return false;
} }
content.style.marginLeft = ''; let prev = tabs.querySelector('li.active') as HTMLLIElement;
prev && prev.classList.remove('active');
if(onTransitionEnd) onTransitionEnd(); target.classList.add('active');
}, 200); selectTab(id);
});
prevTabContent = tabContent; }
});
return selectTab;
} }
export function formatPhoneNumber(str: string) { export function formatPhoneNumber(str: string) {

194
src/components/pageIm.ts

@ -1,194 +0,0 @@
//import { appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager } from "../lib/services";
import { openBtnMenu } from "./misc";
//import {stackBlurImage} from '../lib/StackBlur';
import appSidebarLeft from "../lib/appManagers/appSidebarLeft";
export default () => import('../lib/services').then(services => {
//console.log('included services', services);
let {appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager} = services;
//export default () => {
let pageEl = document.body.getElementsByClassName('page-chats')[0] as HTMLDivElement;
pageEl.style.display = '';
apiUpdatesManager.attach();
// @ts-ignore
document.addEventListener('user_update', (e: CustomEvent) => {
let userID = e.detail;
let user = appUsersManager.getUser(userID);
let dialog = appMessagesManager.getDialogByPeerID(user.id)[0];
//console.log('updating user:', user, dialog);
if(dialog && !appUsersManager.isBot(dialog.peerID) && dialog.peerID != appImManager.myID) {
let online = user.status && user.status._ == 'userStatusOnline';
let dom = appDialogsManager.getDialogDom(dialog.peerID);
if(dom) {
if(online) {
dom.avatarDiv.classList.add('is-online');
} else {
dom.avatarDiv.classList.remove('is-online');
}
}
}
if(appImManager.peerID == user.id) {
appImManager.setPeerStatus();
}
});
// @ts-ignore
document.addEventListener('dialog_top', (e: CustomEvent) => {
let dialog: any = e.detail;
appDialogsManager.setLastMessage(dialog);
appDialogsManager.sortDom();
});
// @ts-ignore
document.addEventListener('dialogs_multiupdate', (e: CustomEvent) => {
let dialogs = e.detail;
let performed = 0;
for(let id in dialogs) {
let dialog = dialogs[id];
/////console.log('updating dialog:', dialog);
++performed;
if(!(dialog.peerID in appDialogsManager.doms)) {
appDialogsManager.addDialog(dialog);
continue;
}
appDialogsManager.setLastMessage(dialog);
}
if(performed/* && false */) {
/////////console.log('will sortDom');
appDialogsManager.sortDom();
appDialogsManager.sortDom(true);
}
});
// @ts-ignore
document.addEventListener('dialog_unread', (e: CustomEvent) => {
let info: {
peerID: number,
count: number
} = e.detail;
let dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0];
if(dialog) {
appDialogsManager.setUnreadMessages(dialog);
if(dialog.peerID == appImManager.peerID) {
appImManager.updateUnreadByDialog(dialog);
}
}
});
/*
loadDialogs().then(result => {
//appImManager.setScroll(chatScroll);
});
return;
*/
/* function placeCaretAfterNode(node: HTMLElement) {
if (typeof window.getSelection != "undefined") {
var range = document.createRange();
range.setStartAfter(node);
range.collapse(true);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
messageInput.onclick = (e) => {
let target = e.target as HTMLElement;
if(target.classList.contains('emoji-inner')) {
placeCaretAfterNode(target.parentElement);
} else if(target.classList.contains('emoji-sizer')) {
placeCaretAfterNode(target);
}
console.log('lol', target);
}; */
/* window.addEventListener('click', function(this, e) {
// @ts-ignore
let isInput = e.target.tagName == 'INPUT';
if(!isInput && !window.getSelection().toString()) {
console.log('click');
messageInput.focus();
}
}); */
/* fetch('assets/img/camomile.jpg')
.then(res => res.blob())
.then(blob => {
let img = new Image();
let url = URL.createObjectURL(blob);
img.src = url;
img.onload = () => {
let id = 'chat-background-canvas';
var canvas = document.getElementById(id) as HTMLCanvasElement;
//URL.revokeObjectURL(url);
let elements = ['.chat-container'].map(selector => {
return document.querySelector(selector) as HTMLDivElement;
});
stackBlurImage(img, id, 15, 0);
canvas.toBlob(blob => {
//let dataUrl = canvas.toDataURL('image/jpeg', 1);
let dataUrl = URL.createObjectURL(blob);
elements.forEach(el => {
el.style.backgroundImage = 'url(' + dataUrl + ')';
});
}, 'image/jpeg', 1);
};
}); */
/* toggleEmoticons.onclick = (e) => {
if(!emoticonsDropdown) {
emoticonsDropdown = initEmoticonsDropdown(pageEl, appImManager,
appMessagesManager, messageInput, toggleEmoticons);
} else {
emoticonsDropdown.classList.toggle('active');
}
toggleEmoticons.classList.toggle('active');
}; */
Array.from(document.getElementsByClassName('btn-menu-toggle')).forEach((el) => {
el.addEventListener('click', (e) => {
//console.log('click pageIm');
if(!el.classList.contains('btn-menu-toggle')) return false;
//window.removeEventListener('mousemove', onMouseMove);
let openedMenu = el.querySelector('.btn-menu') as HTMLDivElement;
e.cancelBubble = true;
if(el.classList.contains('menu-open')) {
el.classList.remove('menu-open');
openedMenu.classList.remove('active');
} else {
openBtnMenu(openedMenu);
}
});
});
appSidebarLeft.loadDialogs().then(result => {
//appSidebarLeft.onChatsScroll();
appSidebarLeft.loadDialogs(true);
});
});

33
src/components/wrappers.ts

@ -3,7 +3,6 @@ import CryptoWorker from '../lib/crypto/cryptoworker';
import LottieLoader from '../lib/lottieLoader'; import LottieLoader from '../lib/lottieLoader';
import appStickersManager from "../lib/appManagers/appStickersManager"; import appStickersManager from "../lib/appManagers/appStickersManager";
import appDocsManager from "../lib/appManagers/appDocsManager"; import appDocsManager from "../lib/appManagers/appDocsManager";
import {AppImManager} from "../lib/appManagers/appImManager";
import { formatBytes } from "../lib/utils"; import { formatBytes } from "../lib/utils";
import ProgressivePreloader from './preloader'; import ProgressivePreloader from './preloader';
import LazyLoadQueue from './lazyLoadQueue'; import LazyLoadQueue from './lazyLoadQueue';
@ -60,9 +59,21 @@ export type MTPhotoSize = {
bytes?: Uint8Array // if type == 'i' bytes?: Uint8Array // if type == 'i'
}; };
export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDivElement, message: any, justLoader = true, preloader?: ProgressivePreloader, controls = true, round = false, boxWidth = 380, boxHeight = 380, withTail = false, isOut = false) { export function wrapVideo({doc, container, message, justLoader, preloader, round, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue}: {
doc: MTDocument,
container: HTMLDivElement,
message: any,
justLoader: boolean,
preloader?: ProgressivePreloader,
round: boolean,
boxWidth: number,
boxHeight: number,
withTail?: boolean,
isOut?: boolean,
middleware: () => boolean,
lazyLoadQueue: LazyLoadQueue
}) {
let img: HTMLImageElement | SVGImageElement; let img: HTMLImageElement | SVGImageElement;
let peerID = this.peerID;
if(withTail) { if(withTail) {
img = wrapMediaWithTail(doc, message, container, boxWidth, boxHeight, isOut); img = wrapMediaWithTail(doc, message, container, boxWidth, boxHeight, isOut);
@ -104,8 +115,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
preloader.attach(container, true, promise); preloader.attach(container, true, promise);
return promise.then(blob => { return promise.then(blob => {
if(this.peerID != peerID) { if(!middleware()) {
this.log.warn('peer changed');
return; return;
} }
@ -141,7 +151,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
}; };
if(doc.type == 'gif' || true) { // extra fix if(doc.type == 'gif' || true) { // extra fix
return doc.downloaded ? loadVideo() : this.lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true}); return doc.downloaded ? loadVideo() : lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true});
} /* else { // if video } /* else { // if video
let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => { let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => {
if((this.peerID ? this.peerID : this.currentMessageID) != peerID) { if((this.peerID ? this.peerID : this.currentMessageID) != peerID) {
@ -481,9 +491,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
return image; return image;
} }
export async function wrapPhoto(this: AppImManager, photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false) { export async function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean) {
let peerID = this.peerID;
let photo = appPhotosManager.getPhoto(photoID); let photo = appPhotosManager.getPhoto(photoID);
let size: MTPhotoSize; let size: MTPhotoSize;
@ -512,10 +520,7 @@ export async function wrapPhoto(this: AppImManager, photoID: string, message: an
} }
return promise.then(() => { return promise.then(() => {
if(this.peerID != peerID) { if(!middleware()) return;
this.log.warn('peer changed');
return;
}
renderImageFromUrl(image, photo.url); renderImageFromUrl(image, photo.url);
}); });
@ -523,7 +528,7 @@ export async function wrapPhoto(this: AppImManager, photoID: string, message: an
/////////console.log('wrapPhoto', load, container, image); /////////console.log('wrapPhoto', load, container, image);
return photo.downloaded ? load() : this.lazyLoadQueue.push({div: container, load: load, wasSeen: true}); return photo.downloaded ? load() : lazyLoadQueue.push({div: container, load: load, wasSeen: true});
} }
export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean, play = false, onlyThumb = false) { export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean, play = false, onlyThumb = false) {

337
src/lib/appManagers/appDialogsManager.ts

@ -1,14 +1,13 @@
import apiManager from "../mtproto/apiManager"; import { langPack, findUpClassName, $rootScope } from "../utils";
import apiFileManager from '../mtproto/apiFileManager';
import { $rootScope, langPack, findUpClassName } from "../utils";
import appImManager, { AppImManager } from "./appImManager"; import appImManager, { AppImManager } from "./appImManager";
import appPeersManager from './appPeersManager'; import appPeersManager from './appPeersManager';
import appMessagesManager from "./appMessagesManager"; import appMessagesManager, { AppMessagesManager } from "./appMessagesManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import { ripple, renderImageFromUrl } from "../../components/misc"; import { ripple, putPreloader } from "../../components/misc";
import appSidebarLeft from "./appSidebarLeft";
import Scrollable from "../../components/scrollable"; import Scrollable from "../../components/scrollable";
import appProfileManager from "./appProfileManager";
import { logger } from "../polyfill";
type DialogDom = { type DialogDom = {
avatarDiv: HTMLDivElement, avatarDiv: HTMLDivElement,
@ -22,6 +21,8 @@ type DialogDom = {
listEl: HTMLLIElement listEl: HTMLLIElement
}; };
let testScroll = false;
export class AppDialogsManager { export class AppDialogsManager {
public chatList = document.getElementById('dialogs') as HTMLUListElement; public chatList = document.getElementById('dialogs') as HTMLUListElement;
public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement; public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement;
@ -31,42 +32,228 @@ export class AppDialogsManager {
public chatsArchivedHidden: Scrollable["hiddenElements"]; public chatsArchivedHidden: Scrollable["hiddenElements"];
public chatsArchivedVisible: Scrollable["visibleElements"]; public chatsArchivedVisible: Scrollable["visibleElements"];
public myID = 0;
public doms: {[peerID: number]: DialogDom} = {}; public doms: {[peerID: number]: DialogDom} = {};
public domsArchived: {[peerID: number]: DialogDom} = {}; public domsArchived: {[peerID: number]: DialogDom} = {};
public lastActiveListElement: HTMLElement = null; public lastActiveListElement: HTMLElement = null;
public savedAvatarURLs: {[peerID: number]: string} = {};
private rippleCallback: (value?: boolean | PromiseLike<boolean>) => void = null; private rippleCallback: (value?: boolean | PromiseLike<boolean>) => void = null;
private lastClickID = 0; private lastClickID = 0;
private lastGoodClickID = 0; private lastGoodClickID = 0;
public chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement;
public chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
private chatsArchivedOffsetIndex = 0;
private chatsOffsetIndex = 0;
private chatsPreloader: HTMLDivElement;
//private chatsLoadCount = 0;
//private loadDialogsPromise: Promise<any>;
private loadDialogsPromise: ReturnType<AppMessagesManager["getConversations"]>;
private loadedAll = false;
private loadedArchivedAll = false;
public scroll: Scrollable = null;
public scrollArchived: Scrollable = null;
private log = logger('DIALOGS');
constructor() { constructor() {
this.chatsPreloader = putPreloader(null, true);
//this.chatsContainer.append(this.chatsPreloader);
this.pinnedDelimiter = document.createElement('div'); this.pinnedDelimiter = document.createElement('div');
this.pinnedDelimiter.classList.add('pinned-delimiter'); this.pinnedDelimiter.classList.add('pinned-delimiter');
this.pinnedDelimiter.appendChild(document.createElement('span')); this.pinnedDelimiter.appendChild(document.createElement('span'));
apiManager.getUserID().then((id) => { //this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
this.myID = id;
let splitOffset = 1110;
this.scroll = new Scrollable(this.chatsContainer, 'y', splitOffset, 'CL', this.chatList, 500);
this.scroll.setVirtualContainer(this.chatList);
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
this.chatsHidden = this.scroll.hiddenElements;
this.chatsVisible = this.scroll.visibleElements;
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', splitOffset, 'CLA', this.chatListArchived, 500);
this.scrollArchived.setVirtualContainer(this.chatListArchived);
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
this.chatsArchivedHidden = this.scrollArchived.hiddenElements;
this.chatsArchivedVisible = this.scrollArchived.visibleElements;
//this.scrollArchived.container.addEventListener('scroll', this.onChatsArchivedScroll.bind(this));
//let chatClosedDiv = document.getElementById('chat-closed');
this.setListClickListener(this.chatList);
this.setListClickListener(this.chatListArchived);
if(testScroll) {
for(let i = 0; i < 1000; ++i) {
let li = document.createElement('li');
li.dataset.id = '' + i;
li.innerHTML = `<div class="rp"><div class="user-avatar" style="background-color: rgb(166, 149, 231); font-size: 0px;"><img src="#"></div><div class="user-caption"><p><span class="user-title">${i}</span><span><span class="message-status"></span><span class="message-time">18:33</span></span></p><p><span class="user-last-message"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;
this.scroll.append(li);
}
}
window.addEventListener('resize', () => {
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
setTimeout(() => {
this.onChatsArchivedScroll();
}, 0);
}); });
$rootScope.$on('user_auth', (e: CustomEvent) => { $rootScope.$on('user_update', (e: CustomEvent) => {
let userAuth = e.detail; let userID = e.detail;
this.myID = userAuth ? userAuth.id : 0;
let user = appUsersManager.getUser(userID);
let dialog = appMessagesManager.getDialogByPeerID(user.id)[0];
//console.log('updating user:', user, dialog);
if(dialog && !appUsersManager.isBot(dialog.peerID) && dialog.peerID != $rootScope.myID) {
let online = user.status && user.status._ == 'userStatusOnline';
let dom = this.getDialogDom(dialog.peerID);
if(dom) {
if(online) {
dom.avatarDiv.classList.add('is-online');
} else {
dom.avatarDiv.classList.remove('is-online');
}
}
}
if(appImManager.peerID == user.id) {
appImManager.setPeerStatus();
}
}); });
$rootScope.$on('history_request', () => { // will call at history request api or cache RENDERED! $rootScope.$on('dialog_top', (e: CustomEvent) => {
if(this.rippleCallback) { let dialog: any = e.detail;
this.rippleCallback();
this.rippleCallback = null; this.setLastMessage(dialog);
this.sortDom();
});
$rootScope.$on('dialogs_multiupdate', (e: CustomEvent) => {
let dialogs = e.detail;
let performed = 0;
for(let id in dialogs) {
let dialog = dialogs[id];
/////console.log('updating dialog:', dialog);
++performed;
if(!(dialog.peerID in this.doms)) {
this.addDialog(dialog);
continue;
}
this.setLastMessage(dialog);
}
if(performed/* && false */) {
/////////console.log('will sortDom');
this.sortDom();
this.sortDom(true);
} }
}); });
//let chatClosedDiv = document.getElementById('chat-closed'); $rootScope.$on('dialog_unread', (e: CustomEvent) => {
let info: {
peerID: number,
count: number
} = e.detail;
this.setListClickListener(this.chatList); let dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0];
this.setListClickListener(this.chatListArchived); if(dialog) {
this.setUnreadMessages(dialog);
if(dialog.peerID == appImManager.peerID) {
appImManager.updateUnreadByDialog(dialog);
}
}
});
this.loadDialogs().then(result => {
//appSidebarLeft.onChatsScroll();
this.loadDialogs(true);
});
}
public async loadDialogs(archived = false) {
if(testScroll) {
return;
}
if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise;
(archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader);
//let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */;
let offset = archived ? this.chatsArchivedOffsetIndex : this.chatsOffsetIndex;
//let offset = 0;
let scroll = archived ? this.scrollArchived : this.scroll;
scroll.lock();
try {
console.time('getDialogs time');
let loadCount = 50/*this.chatsLoadCount */;
this.loadDialogsPromise = appMessagesManager.getConversations('', offset, loadCount, +archived);
let result = await this.loadDialogsPromise;
console.timeEnd('getDialogs time');
if(result && result.dialogs && result.dialogs.length) {
let index = result.dialogs[result.dialogs.length - 1].index;
if(archived) this.chatsArchivedOffsetIndex = index;
else this.chatsOffsetIndex = index;
result.dialogs.forEach((dialog: any) => {
this.addDialog(dialog);
});
}
if(!result.dialogs.length || (archived ? this.scrollArchived.length == result.count : this.scroll.length == result.count)) { // loaded all
if(archived) this.loadedArchivedAll = true;
else this.loadedAll = true;
}
/* if(archived) {
let count = result.count;
this.archivedCount.innerText = '' + count;
} */
this.log('getDialogs ' + loadCount + ' dialogs by offset:', offset, result, this.scroll.length);
this.scroll.onScroll();
} catch(err) {
this.log.error(err);
}
this.chatsPreloader.remove();
this.loadDialogsPromise = undefined;
scroll.unlock();
}
public onChatsScroll() {
if(this.loadedAll || this.scroll.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs();
}
public onChatsArchivedScroll() {
if(this.loadedArchivedAll || this.scrollArchived.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs(true);
} }
public setListClickListener(list: HTMLUListElement, onFound?: () => void) { public setListClickListener(list: HTMLUListElement, onFound?: () => void) {
@ -142,94 +329,6 @@ export class AppDialogsManager {
}); });
} }
// peerID == peerID || title
public async loadDialogPhoto(div: HTMLDivElement, peerID: number, isDialog = false, title = ''): Promise<boolean> {
let inputPeer: any;
let location: any;
if(peerID) {
inputPeer = appPeersManager.getInputPeerByID(peerID);
location = appPeersManager.getPeerPhoto(peerID);
}
//console.log('loadDialogPhoto location:', location, inputPeer);
if(peerID == this.myID && (isDialog || $rootScope.selectedPeerID == this.myID)) {
if(div.firstChild) {
div.firstChild.remove();
}
div.style.backgroundColor = '';
div.classList.add('tgico-savedmessages');
div.classList.remove('tgico-avatar_deletedaccount');
return true;
}
if(peerID) {
let user = appUsersManager.getUser(peerID);
if(user && user.pFlags && user.pFlags.deleted) {
if(div.firstChild) {
div.firstChild.remove();
}
div.style.backgroundColor = '';
div.classList.add('tgico-avatar_deletedaccount');
return true;
}
}
//if(!location || location.empty || !location.photo_small) {
if(div.firstChild) {
div.firstChild.remove();
}
let color = '';
if(peerID && peerID != this.myID) {
color = appPeersManager.getPeerColorByID(peerID);
}
div.classList.remove('tgico-savedmessages', 'tgico-avatar_deletedaccount');
div.style.backgroundColor = color;
let abbrSplitted = (!title && peerID ? appPeersManager.getPeerTitle(peerID, true) : title).split(' ');
let abbr = (abbrSplitted.length == 2 ?
abbrSplitted[0][0] + abbrSplitted[1][0] :
abbrSplitted[0][0]).toUpperCase();
//div.innerText = peer.initials.toUpperCase();
div.innerText = abbr.toUpperCase();
//return Promise.resolve(true);
//}
if(!location || location.empty || !location.photo_small) {
return true;
}
if(!this.savedAvatarURLs[peerID]) {
let res = await apiFileManager.downloadSmallFile({
_: 'inputPeerPhotoFileLocation',
dc_id: location.dc_id,
flags: 0,
peer: inputPeer,
volume_id: location.photo_small.volume_id,
local_id: location.photo_small.local_id
});
this.savedAvatarURLs[peerID] = URL.createObjectURL(res);
}
let img = new Image();
renderImageFromUrl(img, this.savedAvatarURLs[peerID]);
div.innerHTML = '';
//div.style.fontSize = '0'; // need
//div.style.backgroundColor = '';
//window.requestAnimationFrame(() => {
div.append(img);
//});
return true;
}
public sortDom(archived = false) { public sortDom(archived = false) {
//return; //return;
//if(archived) return; //if(archived) return;
@ -299,7 +398,7 @@ export class AppDialogsManager {
let child = concated.find(obj => obj.element == dom.listEl); let child = concated.find(obj => obj.element == dom.listEl);
if(!child) { if(!child) {
return console.error('no child by listEl:', dom.listEl, archived, concated); return this.log.error('no child by listEl:', dom.listEl, archived, concated);
} }
if(inUpper.length < hiddenLength) { if(inUpper.length < hiddenLength) {
@ -412,7 +511,7 @@ export class AppDialogsManager {
let senderBold = document.createElement('b'); let senderBold = document.createElement('b');
let str = ''; let str = '';
if(sender.id == this.myID) { if(sender.id == $rootScope.myID) {
str = 'You'; str = 'You';
} else { } else {
str = sender.first_name || sender.last_name || sender.username; str = sender.first_name || sender.last_name || sender.username;
@ -459,7 +558,7 @@ export class AppDialogsManager {
dom.statusSpan.innerHTML = ''; dom.statusSpan.innerHTML = '';
let lastMessage = appMessagesManager.getMessage(dialog.top_message); let lastMessage = appMessagesManager.getMessage(dialog.top_message);
if(lastMessage._ != 'messageEmpty' && if(lastMessage._ != 'messageEmpty' &&
lastMessage.from_id == this.myID && lastMessage.peerID != this.myID && lastMessage.from_id == $rootScope.myID && lastMessage.peerID != $rootScope.myID &&
dialog.read_outbox_max_id) { // maybe comment, 06.20.2020 dialog.read_outbox_max_id) { // maybe comment, 06.20.2020
let outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread) let outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)
/* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020 /* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020
@ -497,7 +596,7 @@ export class AppDialogsManager {
return acc; return acc;
}, 0); }, 0);
appSidebarLeft.archivedCount.innerText = '' + sum; $rootScope.$broadcast('dialogs_archived_unread', {count: sum});
} }
} }
@ -520,7 +619,7 @@ export class AppDialogsManager {
let avatarDiv = document.createElement('div'); let avatarDiv = document.createElement('div');
avatarDiv.classList.add('user-avatar'); avatarDiv.classList.add('user-avatar');
if(drawStatus && peerID != this.myID) { if(drawStatus && peerID != $rootScope.myID) {
let peer = dialog.peer; let peer = dialog.peer;
switch(peer._) { switch(peer._) {
@ -544,12 +643,12 @@ export class AppDialogsManager {
let titleSpan = document.createElement('span'); let titleSpan = document.createElement('span');
titleSpan.classList.add('user-title'); titleSpan.classList.add('user-title');
if(peerID == this.myID) { if(peerID == $rootScope.myID) {
title = 'Saved Messages'; title = 'Saved Messages';
} }
//console.log('trying to load photo for:', title); //console.log('trying to load photo for:', title);
this.loadDialogPhoto(avatarDiv, dialog.peerID, true); appProfileManager.putPhoto(avatarDiv, dialog.peerID, true);
titleSpan.innerHTML = title; titleSpan.innerHTML = title;
//p.classList.add('') //p.classList.add('')
@ -565,7 +664,7 @@ export class AppDialogsManager {
paddingDiv.append(avatarDiv, captionDiv); paddingDiv.append(avatarDiv, captionDiv);
ripple(paddingDiv, (id) => { ripple(paddingDiv, (id) => {
console.log('dialogs click element'); this.log('dialogs click element');
this.lastClickID = id; this.lastClickID = id;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -617,10 +716,10 @@ export class AppDialogsManager {
if(!container) { if(!container) {
if(dialog.folder_id && dialog.folder_id == 1) { if(dialog.folder_id && dialog.folder_id == 1) {
appSidebarLeft.scrollArchived.append(li); this.scrollArchived.append(li);
this.domsArchived[dialog.peerID] = dom; this.domsArchived[dialog.peerID] = dom;
} else { } else {
appSidebarLeft.scroll.append(li); this.scroll.append(li);
this.doms[dialog.peerID] = dom; this.doms[dialog.peerID] = dom;
} }

54
src/lib/appManagers/appImManager.ts

@ -120,7 +120,7 @@ export class AppImManager {
this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement; this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement;
apiManager.getUserID().then((id) => { apiManager.getUserID().then((id) => {
this.myID = id; this.myID = $rootScope.myID = id;
}); });
this.topbar = document.getElementById('topbar') as HTMLDivElement; this.topbar = document.getElementById('topbar') as HTMLDivElement;
@ -128,7 +128,7 @@ export class AppImManager {
$rootScope.$on('user_auth', (e: CustomEvent) => { $rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail; let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0; this.myID = $rootScope.myID = userAuth ? userAuth.id : 0;
}); });
// will call when message is sent (only 1) // will call when message is sent (only 1)
@ -558,6 +558,7 @@ export class AppImManager {
setInterval(() => this.setPeerStatus(), 60e3); setInterval(() => this.setPeerStatus(), 60e3);
this.setScroll(); this.setScroll();
apiUpdatesManager.attach();
} }
public deleteMessages(revoke = false) { public deleteMessages(revoke = false) {
@ -882,8 +883,8 @@ export class AppImManager {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null; let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null;
//////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID); //////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID);
appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID); appProfileManager.putPhoto(this.avatarEl, this.peerID);
appDialogsManager.loadDialogPhoto(appSidebarRight.profileElements.avatar, this.peerID); appProfileManager.putPhoto(appSidebarRight.profileElements.avatar, this.peerID);
this.firstTopMsgID = dialog ? dialog.top_message : 0; this.firstTopMsgID = dialog ? dialog.top_message : 0;
@ -1248,7 +1249,9 @@ export class AppImManager {
bubble.classList.add('hide-name', 'photo'); bubble.classList.add('hide-name', 'photo');
wrapPhoto.call(this, photo.id, message, attachmentDiv, undefined, undefined, true, our); wrapPhoto(photo.id, message, attachmentDiv, undefined, undefined, true, our, this.lazyLoadQueue, () => {
return this.peerID == peerID;
});
break; break;
} }
@ -1291,7 +1294,20 @@ export class AppImManager {
if(doc.type == 'gif' || doc.type == 'video') { if(doc.type == 'gif' || doc.type == 'video') {
//if(doc.size <= 20e6) { //if(doc.size <= 20e6) {
bubble.classList.add('video'); bubble.classList.add('video');
wrapVideo.call(this, doc, preview, message, true, null, false, false, 380, 300); wrapVideo({
doc,
container: preview,
message,
justLoader: true,
preloader: null,
round: false,
boxWidth: 380,
boxHeight: 300,
lazyLoadQueue: this.lazyLoadQueue,
middleware: () => {
return this.peerID == peerID;
}
});
//} //}
} else { } else {
doc = null; doc = null;
@ -1301,7 +1317,9 @@ export class AppImManager {
if(webpage.photo && !doc) { if(webpage.photo && !doc) {
bubble.classList.add('photo'); bubble.classList.add('photo');
wrapPhoto.call(this, webpage.photo.id, message, preview, 380, 300, false); wrapPhoto(webpage.photo.id, message, preview, 380, 300, false, null, this.lazyLoadQueue, () => {
return this.peerID == peerID;
});
} }
if(preview) { if(preview) {
@ -1366,7 +1384,23 @@ export class AppImManager {
} }
bubble.classList.add('hide-name', 'video'); bubble.classList.add('hide-name', 'video');
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round', 380, 380, doc.type != 'round', our); //wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round', 380, 380, doc.type != 'round', our);
wrapVideo({
doc,
container: attachmentDiv,
message,
justLoader: true,
preloader: null,
round: doc.type == 'round',
boxWidth: 380,
boxHeight: 380,
withTail: doc.type != 'round',
isOut: our,
lazyLoadQueue: this.lazyLoadQueue,
middleware: () => {
return this.peerID == peerID;
}
});
break; break;
} else if(doc.mime_type == 'audio/ogg') { } else if(doc.mime_type == 'audio/ogg') {
@ -1479,11 +1513,11 @@ export class AppImManager {
/////////this.log('exec loadDialogPhoto', message); /////////this.log('exec loadDialogPhoto', message);
if(message.fromID) { // if no - user hidden if(message.fromID) { // if no - user hidden
appDialogsManager.loadDialogPhoto(avatarDiv, message.fromID); appProfileManager.putPhoto(avatarDiv, message.fromID);
} else if(!title && message.fwd_from && message.fwd_from.from_name) { } else if(!title && message.fwd_from && message.fwd_from.from_name) {
title = message.fwd_from.from_name; title = message.fwd_from.from_name;
appDialogsManager.loadDialogPhoto(avatarDiv, 0, false, title); appProfileManager.putPhoto(avatarDiv, 0, false, title);
} }
avatarDiv.dataset.peerID = message.fromID; avatarDiv.dataset.peerID = message.fromID;

3
src/lib/appManagers/appMediaViewer.ts

@ -9,6 +9,7 @@ import { findUpClassName, $rootScope, generatePathData } from "../utils";
import appDocsManager from "./appDocsManager"; import appDocsManager from "./appDocsManager";
import { wrapPlayer } from "../ckin"; import { wrapPlayer } from "../ckin";
import { renderImageFromUrl } from "../../components/misc"; import { renderImageFromUrl } from "../../components/misc";
import appProfileManager from "./appProfileManager";
export class AppMediaViewer { export class AppMediaViewer {
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement; private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
@ -592,7 +593,7 @@ export class AppMediaViewer {
this.content.caption.innerHTML = ''; this.content.caption.innerHTML = '';
} }
appDialogsManager.loadDialogPhoto(this.author.avatarEl, message.fromID); appProfileManager.putPhoto(this.author.avatarEl, message.fromID);
// ok set // ok set

152
src/lib/appManagers/appSidebarLeft.ts

@ -1,16 +1,14 @@
import { logger } from "../polyfill"; import { logger } from "../polyfill";
import { putPreloader, formatPhoneNumber } from "../../components/misc"; import { formatPhoneNumber } from "../../components/misc";
import Scrollable from '../../components/scrollable'; import Scrollable from '../../components/scrollable';
import appMessagesManager, { AppMessagesManager } from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appDialogsManager from "./appDialogsManager"; import appDialogsManager from "./appDialogsManager";
import { isElementInViewport, numberWithCommas } from "../utils"; import { isElementInViewport, numberWithCommas, $rootScope } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager"; import appMessagesIDsManager from "./appMessagesIDsManager";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
import { appPeersManager } from "../services";
import apiManager from "../mtproto/apiManager"; import apiManager from "../mtproto/apiManager";
import appPeersManager from './appPeersManager';
let testScroll = false;
class SearchGroup { class SearchGroup {
container: HTMLDivElement; container: HTMLDivElement;
@ -56,18 +54,6 @@ class AppSidebarLeft {
private listsContainer: HTMLDivElement = null; private listsContainer: HTMLDivElement = null;
private chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement;
private chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
private chatsArchivedOffsetIndex = 0;
private chatsOffsetIndex = 0;
private chatsPreloader: HTMLDivElement;
//private chatsLoadCount = 0;
//private loadDialogsPromise: Promise<any>;
private loadDialogsPromise: ReturnType<AppMessagesManager["getConversations"]>;
private loadedAll = false;
private loadedArchivedAll = false;
private log = logger('SL'); private log = logger('SL');
private peerID = 0; private peerID = 0;
@ -81,37 +67,16 @@ class AppSidebarLeft {
private query = ''; private query = '';
public scroll: Scrollable = null; public searchGroups: {[group: string]: SearchGroup} = {};
public scrollArchived: Scrollable = null;
public searchGroups: {[group: string]: SearchGroup} = {
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
globalContacts: new SearchGroup('Global Search', 'contacts'),
globalMessages: new SearchGroup('Global Search', 'messages'),
privateMessages: new SearchGroup('Private Search', 'messages')
};
constructor() { constructor() {
this.chatsPreloader = putPreloader(null, true); this.searchGroups = {
//this.chatsContainer.append(this.chatsPreloader); contacts: new SearchGroup('Contacts and Chats', 'contacts'),
globalContacts: new SearchGroup('Global Search', 'contacts'),
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); globalMessages: new SearchGroup('Global Search', 'messages'),
privateMessages: new SearchGroup('Private Search', 'messages')
let splitOffset = 1110; };
this.scroll = new Scrollable(this.chatsContainer, 'y', splitOffset, 'CL', appDialogsManager.chatList, 500);
this.scroll.setVirtualContainer(appDialogsManager.chatList);
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
appDialogsManager.chatsHidden = this.scroll.hiddenElements;
appDialogsManager.chatsVisible = this.scroll.visibleElements;
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', splitOffset, 'CLA', appDialogsManager.chatListArchived, 500);
this.scrollArchived.setVirtualContainer(appDialogsManager.chatListArchived);
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
appDialogsManager.chatsArchivedHidden = this.scrollArchived.hiddenElements;
appDialogsManager.chatsArchivedVisible = this.scrollArchived.visibleElements;
//this.scrollArchived.container.addEventListener('scroll', this.onChatsArchivedScroll.bind(this));
this.listsContainer = new Scrollable(this.searchContainer).container; this.listsContainer = new Scrollable(this.searchContainer).container;
for(let i in this.searchGroups) { for(let i in this.searchGroups) {
this.listsContainer.append(this.searchGroups[i].container); this.listsContainer.append(this.searchGroups[i].container);
@ -126,7 +91,7 @@ class AppSidebarLeft {
}); });
this.archivedBtn.addEventListener('click', (e) => { this.archivedBtn.addEventListener('click', (e) => {
this.chatsArchivedContainer.classList.add('active'); appDialogsManager.chatsArchivedContainer.classList.add('active');
this.toolsBtn.classList.remove('active'); this.toolsBtn.classList.remove('active');
this.backBtn.classList.add('active'); this.backBtn.classList.add('active');
//this.toolsBtn.classList.remove('tgico-menu', 'btn-menu-toggle'); //this.toolsBtn.classList.remove('tgico-menu', 'btn-menu-toggle');
@ -137,15 +102,6 @@ class AppSidebarLeft {
apiManager.logOut(); apiManager.logOut();
}); });
if(testScroll) {
for(let i = 0; i < 1000; ++i) {
let li = document.createElement('li');
li.dataset.id = '' + i;
li.innerHTML = `<div class="rp"><div class="user-avatar" style="background-color: rgb(166, 149, 231); font-size: 0px;"><img src="#"></div><div class="user-caption"><p><span class="user-title">${i}</span><span><span class="message-status"></span><span class="message-time">18:33</span></span></p><p><span class="user-last-message"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;
this.scroll.append(li);
}
}
this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this)); this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this));
this.searchInput.addEventListener('focus', (e) => { this.searchInput.addEventListener('focus', (e) => {
@ -198,101 +154,31 @@ class AppSidebarLeft {
}); });
this.backBtn.addEventListener('click', (e) => { this.backBtn.addEventListener('click', (e) => {
this.chatsArchivedContainer.classList.remove('active'); appDialogsManager.chatsArchivedContainer.classList.remove('active');
this.toolsBtn.classList.add('active'); this.toolsBtn.classList.add('active');
this.backBtn.classList.remove('active'); this.backBtn.classList.remove('active');
this.searchInput.value = ''; this.searchInput.value = '';
this.searchContainer.classList.remove('active'); this.searchContainer.classList.remove('active');
this.peerID = 0; this.peerID = 0;
}); });
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); //this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
setTimeout(() => { setTimeout(() => {
this.onSidebarScroll(); this.onSidebarScroll();
this.scroll.onScroll();
//this.onChatsScroll();
this.onChatsArchivedScroll();
}, 0); }, 0);
}); });
$rootScope.$on('dialogs_archived_unread', (e: CustomEvent) => {
this.archivedCount.innerText = '' + e.detail.count;
});
/* appUsersManager.getTopPeers().then(categories => { /* appUsersManager.getTopPeers().then(categories => {
this.log('got top categories:', categories); this.log('got top categories:', categories);
}); */ }); */
} }
public async loadDialogs(archived = false) {
if(testScroll) {
return;
}
if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise;
(archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader);
//let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */;
let offset = archived ? this.chatsArchivedOffsetIndex : this.chatsOffsetIndex;
//let offset = 0;
let scroll = archived ? this.scrollArchived : this.scroll;
scroll.lock();
try {
console.time('getDialogs time');
let loadCount = 50/*this.chatsLoadCount */;
this.loadDialogsPromise = appMessagesManager.getConversations('', offset, loadCount, +archived);
let result = await this.loadDialogsPromise;
console.timeEnd('getDialogs time');
if(result && result.dialogs && result.dialogs.length) {
let index = result.dialogs[result.dialogs.length - 1].index;
if(archived) this.chatsArchivedOffsetIndex = index;
else this.chatsOffsetIndex = index;
result.dialogs.forEach((dialog: any) => {
appDialogsManager.addDialog(dialog);
});
}
if(!result.dialogs.length || (archived ? this.scrollArchived.length == result.count : this.scroll.length == result.count)) { // loaded all
if(archived) this.loadedArchivedAll = true;
else this.loadedAll = true;
}
/* if(archived) {
let count = result.count;
this.archivedCount.innerText = '' + count;
} */
this.log('getDialogs ' + loadCount + ' dialogs by offset:', offset, result, this.scroll.length);
this.scroll.onScroll();
} catch(err) {
this.log.error(err);
}
this.chatsPreloader.remove();
this.loadDialogsPromise = undefined;
scroll.unlock();
}
public onChatsScroll() {
if(this.loadedAll || this.scroll.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs();
}
public onChatsArchivedScroll() {
if(this.loadedArchivedAll || this.scrollArchived.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs(true);
}
public onSidebarScroll() { public onSidebarScroll() {
if(!this.query.trim()) return; if(!this.query.trim()) return;

2
src/lib/services.ts

@ -22,7 +22,6 @@ export const appChatsManager = AppChatsManager;
export const appMessagesIDsManager = AppMessagesIDsManager; export const appMessagesIDsManager = AppMessagesIDsManager;
export const apiUpdatesManager = ApiUpdatesManager; export const apiUpdatesManager = ApiUpdatesManager;
export const appPhotosManager = AppPhotosManager; export const appPhotosManager = AppPhotosManager;
export const appDialogsManager = AppDialogsManager;
export const appMessagesManager = AppMessagesManager; export const appMessagesManager = AppMessagesManager;
export const appProfileManager = AppProfileManager; export const appProfileManager = AppProfileManager;
export const appImManager = AppImManager; export const appImManager = AppImManager;
@ -33,6 +32,7 @@ export const appDocsManager = AppDocsManager;
export const appSidebarRight = AppSidebarRight; export const appSidebarRight = AppSidebarRight;
export const appSidebarLeft = AppSidebarLeft; export const appSidebarLeft = AppSidebarLeft;
export const appMediaViewer = AppMediaViewer; export const appMediaViewer = AppMediaViewer;
export const appDialogsManager = AppDialogsManager;
(window as any).Services = { (window as any).Services = {
appUsersManager, appUsersManager,

10
src/lib/utils.js

@ -61,15 +61,6 @@ export function cancelEvent (event) {
return false return false
} }
export function onCtrlEnter (textarea, cb) {
$(textarea).on('keydown', function (e) {
if (e.keyCode == 13 && (e.ctrlKey || e.metaKey)) {
cb()
return cancelEvent(e)
}
})
}
export function setFieldSelection (field, from, to) { export function setFieldSelection (field, from, to) {
field = $(field)[0] field = $(field)[0]
try { try {
@ -307,6 +298,7 @@ export const $rootScope = {
}, },
selectedPeerID: 0, selectedPeerID: 0,
myID: 0,
idle: { idle: {
isIDLE: false isIDLE: false
} }

28
src/pages/page.ts

@ -0,0 +1,28 @@
import pagesManager from "./pagesManager";
export default class Page {
public pageEl: HTMLDivElement;
private installed = false;
constructor(className: string, public isAuthPage: boolean, private onFirstMount?: (...args: any[]) => void, private onMount?: (...args: any[]) => void) {
this.pageEl = document.body.getElementsByClassName(className)[0] as HTMLDivElement;
}
public mount(...args: any[]) {
//this.pageEl.style.display = '';
if(this.onMount) {
this.onMount(...args);
}
if(!this.installed) {
if(this.onFirstMount) {
this.onFirstMount(...args);
}
this.installed = true;
}
pagesManager.setPage(this);
}
}

550
src/components/pageAuthCode.ts → src/pages/pageAuthCode.ts

@ -1,276 +1,274 @@
import pageSignIn from './pageSignIn'; import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp'; import pageSignUp from './pageSignUp';
import pageIm from './pageIm'; import pageIm from './pageIm';
import pagePassword from './pagePassword'; import pagePassword from './pagePassword';
import CryptoWorker from '../lib/crypto/cryptoworker'; import CryptoWorker from '../lib/crypto/cryptoworker';
import LottieLoader from '../lib/lottieLoader'; import LottieLoader from '../lib/lottieLoader';
import apiManager from '../lib/mtproto/apiManager'; import apiManager from '../lib/mtproto/apiManager';
import Page from './page';
let installed = false;
let authCode: { let authCode: {
_: string, // 'auth.sentCode' _: string, // 'auth.sentCode'
pFlags: any, // {} pFlags: any, // {}
flags: number, flags: number,
type: { type: {
_: string, // 'auth.sentCodeTypeSms', _: string, // 'auth.sentCodeTypeSms',
length: number length: number
}, },
phone_code_hash: string, phone_code_hash: string,
phone_number: string phone_number: string
} = null; } = null;
const EDITONSAMEPAGE = false; const EDITONSAMEPAGE = false;
export default async(_authCode: typeof authCode) => { let headerElement: HTMLHeadElement = null;
authCode = _authCode; let sentTypeElement: HTMLParagraphElement = null;
//let LottieLoader = (await import('../lib/lottieLoader')).default; let onFirstMount = () => {
let needFrame = 0, lastLength = 0;
let pageElement = document.body.getElementsByClassName('page-authCode')[0] as HTMLDivElement; let animation: /* AnimationItem */any = undefined;
pageElement.style.display = '';
const CODELENGTH = authCode.type.length;
let headerElement = pageElement.getElementsByClassName('phone')[0] as HTMLHeadElement;
headerElement.innerText = authCode.phone_number; fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs')
.then(res => res.arrayBuffer())
let sentTypeElement = pageElement.getElementsByClassName('sent-type')[0] as HTMLParagraphElement; .then(async(data) => {
let str = await CryptoWorker.gzipUncompress<string>(data, true);
switch(authCode.type._) {
case 'auth.sentCodeTypeSms': animation = await LottieLoader.loadAnimation({
sentTypeElement.innerHTML = 'We have sent you an SMS<br>with the code.'; container: page.pageEl.querySelector('.auth-image'),
break; renderer: 'svg',
case 'auth.sentCodeTypeApp': loop: false,
sentTypeElement.innerHTML = 'We have sent you a message in Telegram<br>with the code.'; autoplay: false,
break; animationData: JSON.parse(str)
case 'auth.sentCodeTypeCall': });
sentTypeElement.innerHTML = 'We will call you and voice<br>the code.';
break; animation.setSpeed(1);
default: //console.log(animation.getDuration(), animation.getDuration(true));
sentTypeElement.innerHTML = `Please check everything<br>for a code (type: ${authCode.type._})`;
break; animation.addEventListener('enterFrame', (e: any) => {
} //console.log('enterFrame', e, needFrame);
let currentFrame = Math.round(e.currentTime);
if(installed) return;
installed = true; if((e.direction == 1 && currentFrame >= needFrame) ||
(e.direction == -1 && currentFrame <= needFrame)) {
let needFrame = 0, lastLength = 0; animation.setSpeed(1);
let animation: /* AnimationItem */any = undefined; animation.pause();
}
const CODELENGTH = authCode.type.length; });
});
fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs')
.then(res => res.arrayBuffer()) const codeInput = page.pageEl.querySelector('#code') as HTMLInputElement;
.then(async(data) => { const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
let str = await CryptoWorker.gzipUncompress<string>(data, true); const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement;
animation = await LottieLoader.loadAnimation({ if(EDITONSAMEPAGE) {
container: document.body.querySelector('.page-authCode .auth-image'), let editable = false;
renderer: 'svg', let changePhonePromise: Promise<unknown>;
loop: false,
autoplay: false, let changePhone = () => {
animationData: JSON.parse(str) if(changePhonePromise) return;
});
let phone_number = '+' + headerElement.innerText.replace(/\D/g, '');
animation.setSpeed(1); if(authCode.phone_number == phone_number) return;
//console.log(animation.getDuration(), animation.getDuration(true));
codeInput.setAttribute('disabled', 'true');
animation.addEventListener('enterFrame', (e: any) => {
//console.log('enterFrame', e, needFrame); changePhonePromise = apiManager.invokeApi('auth.sendCode', {
let currentFrame = Math.round(e.currentTime); /* flags: 0, */
phone_number: phone_number,
if((e.direction == 1 && currentFrame >= needFrame) || api_id: Config.App.id,
(e.direction == -1 && currentFrame <= needFrame)) { api_hash: Config.App.hash,
animation.setSpeed(1); settings: {
animation.pause(); _: 'codeSettings', // that's how we sending Type
} flags: 0
}); }
}); /* lang_code: navigator.language || 'en' */
}).then((code: any) => {
const codeInput = document.getElementById('code') as HTMLInputElement; console.log('got code 2', code);
const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement;
const editButton = document.querySelector('.phone-edit') as HTMLElement; authCode = Object.assign(code, {phone_number});
if(EDITONSAMEPAGE) { changePhonePromise = undefined;
let editable = false; codeInput.removeAttribute('disabled');
let changePhonePromise: Promise<unknown>; codeInput.focus();
}).catch(err => {
let changePhone = () => { switch(err.type) {
if(changePhonePromise) return; case 'PHONE_NUMBER_INVALID':
headerElement.classList.add('error');
let phone_number = '+' + headerElement.innerText.replace(/\D/g, ''); editable = true;
if(authCode.phone_number == phone_number) return; headerElement.setAttribute('contenteditable', '' + editable);
headerElement.focus();
codeInput.setAttribute('disabled', 'true'); break;
default:
changePhonePromise = apiManager.invokeApi('auth.sendCode', { codeInputLabel.innerText = err.type;
/* flags: 0, */ break;
phone_number: phone_number, }
api_id: Config.App.id,
api_hash: Config.App.hash, changePhonePromise = undefined;
settings: { codeInput.removeAttribute('disabled');
_: 'codeSettings', // that's how we sending Type });
flags: 0 };
}
/* lang_code: navigator.language || 'en' */ headerElement.addEventListener('keypress', function(this, e) {
}).then((code: any) => { if(e.key == 'Enter') {
console.log('got code 2', code); editable = false;
headerElement.setAttribute('contenteditable', '' + editable);
authCode = Object.assign(code, {phone_number}); changePhone();
}
changePhonePromise = undefined;
codeInput.removeAttribute('disabled'); if(/\D/.test(e.key)) {
codeInput.focus(); e.preventDefault();
}).catch(err => { return false;
switch(err.type) { }
case 'PHONE_NUMBER_INVALID':
headerElement.classList.add('error'); this.classList.remove('error');
editable = true; });
headerElement.setAttribute('contenteditable', '' + editable);
headerElement.focus(); editButton.addEventListener('click', function() {
break; if(changePhonePromise) return;
default:
codeInputLabel.innerText = err.type; editable = !editable;
break; headerElement.setAttribute('contenteditable', '' + editable);
}
if(!editable) changePhone();
changePhonePromise = undefined; });
codeInput.removeAttribute('disabled'); } else {
}); editButton.addEventListener('click', function() {
}; return pageSignIn.mount();
});
headerElement.addEventListener('keypress', function(this, e) { }
if(e.key == 'Enter') {
editable = false; let submitCode = (code: string) => {
headerElement.setAttribute('contenteditable', '' + editable); codeInput.setAttribute('disabled', 'true');
changePhone();
} let params = {
phone_number: authCode.phone_number,
if(/\D/.test(e.key)) { phone_code_hash: authCode.phone_code_hash,
e.preventDefault(); phone_code: code
return false; };
}
console.log('invoking auth.signIn with params:', params);
this.classList.remove('error');
}); apiManager.invokeApi('auth.signIn', params)
.then((response: any) => {
editButton.addEventListener('click', function() { console.log('auth.signIn response:', response);
if(changePhonePromise) return;
switch(response._) {
editable = !editable; case 'auth.authorization':
headerElement.setAttribute('contenteditable', '' + editable); apiManager.setUserAuth({
id: response.user.id
if(!editable) changePhone(); });
});
} else { pageIm.mount();
editButton.addEventListener('click', function() { if(animation) animation.destroy();
pageElement.style.display = 'none'; break;
return pageSignIn(); case 'auth.authorizationSignUpRequired':
}); console.log('Registration needed!');
}
pageSignUp.mount({
let submitCode = (code: string) => { 'phone_number': authCode.phone_number,
codeInput.setAttribute('disabled', 'true'); 'phone_code_hash': authCode.phone_code_hash
});
let params = {
phone_number: authCode.phone_number, if(animation) animation.destroy();
phone_code_hash: authCode.phone_code_hash, break;
phone_code: code default:
}; codeInput.innerText = response._;
break;
console.log('invoking auth.signIn with params:', params); }
}).catch(err => {
apiManager.invokeApi('auth.signIn', params) codeInput.removeAttribute('disabled');
.then((response: any) => {
console.log('auth.signIn response:', response); switch(err.type) {
case 'SESSION_PASSWORD_NEEDED':
switch(response._) { console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED');
case 'auth.authorization': err.handled = true;
apiManager.setUserAuth({ if(animation) animation.destroy();
id: response.user.id pagePassword.mount();
}); break;
case 'PHONE_CODE_EMPTY':
pageElement.style.display = 'none'; case 'PHONE_CODE_INVALID':
pageIm(); codeInput.classList.add('error');
if(animation) animation.destroy(); codeInputLabel.innerText = 'Invalid Code';
break; break;
case 'auth.authorizationSignUpRequired': default:
console.log('Registration needed!'); codeInputLabel.innerText = err.type;
break;
pageElement.style.display = 'none'; }
pageSignUp({ });
'phone_number': authCode.phone_number, };
'phone_code_hash': authCode.phone_code_hash
}); const max = 45;
// 1st symbol = frame 15
if(animation) animation.destroy(); // end symbol = frame 165
break; codeInput.addEventListener('input', function(this: typeof codeInput, e) {
default: this.classList.remove('error');
codeInput.innerText = response._;
break; this.value = this.value.replace(/\D/g, '');
} if(this.value.length > CODELENGTH) {
}).catch(err => { this.value = this.value.slice(0, CODELENGTH);
codeInput.removeAttribute('disabled'); }
switch(err.type) { let length = this.value.length;
case 'SESSION_PASSWORD_NEEDED': if(length == CODELENGTH) { // submit code
console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED'); submitCode(this.value);
err.handled = true; } else if(length == lastLength) {
pageElement.style.display = 'none'; return;
if(animation) animation.destroy(); }
pagePassword();
break; lastLength = length;
case 'PHONE_CODE_EMPTY':
case 'PHONE_CODE_INVALID': if(!animation) return;
codeInput.classList.add('error');
codeInputLabel.innerText = 'Invalid Code'; let frame: number;
break; if(length) frame = Math.round((length > max ? max : length) * (165 / max) + 11.33);
default: else frame = 0;
codeInputLabel.innerText = err.type; //animation.playSegments([1, 2]);
break;
} let direction = needFrame > frame ? -1 : 1;
}); //console.log('keydown', length, frame, direction);
};
animation.setDirection(direction);
const max = 45; if(needFrame != 0 && frame == 0) {
// 1st symbol = frame 15 animation.setSpeed(7);
// end symbol = frame 165 }
codeInput.addEventListener('input', function(this: typeof codeInput, e) { /* let diff = Math.abs(needFrame - frame * direction);
this.classList.remove('error'); if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */
needFrame = frame;
this.value = this.value.replace(/\D/g, '');
if(this.value.length > CODELENGTH) { animation.play();
this.value = this.value.slice(0, CODELENGTH);
} /* animation.goToAndStop(15, true); */
//animation.goToAndStop(length / max * );
let length = this.value.length; });
if(length == CODELENGTH) { // submit code };
submitCode(this.value);
} else if(length == lastLength) { const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof authCode) => {
return; authCode = _authCode;
}
if(!headerElement) {
lastLength = length; headerElement = page.pageEl.getElementsByClassName('phone')[0] as HTMLHeadElement;
sentTypeElement = page.pageEl.getElementsByClassName('sent-type')[0] as HTMLParagraphElement;
if(!animation) return; }
let frame: number; //let LottieLoader = (await import('../lib/lottieLoader')).default;
if(length) frame = Math.round((length > max ? max : length) * (165 / max) + 11.33);
else frame = 0; headerElement.innerText = authCode.phone_number;
//animation.playSegments([1, 2]); switch(authCode.type._) {
case 'auth.sentCodeTypeSms':
let direction = needFrame > frame ? -1 : 1; sentTypeElement.innerHTML = 'We have sent you an SMS<br>with the code.';
//console.log('keydown', length, frame, direction); break;
// @ts-ignore case 'auth.sentCodeTypeApp':
animation.setDirection(direction); sentTypeElement.innerHTML = 'We have sent you a message in Telegram<br>with the code.';
if(needFrame != 0 && frame == 0) { break;
animation.setSpeed(7); case 'auth.sentCodeTypeCall':
} sentTypeElement.innerHTML = 'We will call you and voice<br>the code.';
/* let diff = Math.abs(needFrame - frame * direction); break;
if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */ default:
needFrame = frame; sentTypeElement.innerHTML = `Please check everything<br>for a code (type: ${authCode.type._})`;
break;
animation.play(); }
});
/* animation.goToAndStop(15, true); */
//animation.goToAndStop(length / max * ); export default page;
});
};

111
src/pages/pageIm.ts

@ -0,0 +1,111 @@
import { openBtnMenu, ripple } from "../components/misc";
//import {stackBlurImage} from '../lib/StackBlur';
import Page from "./page";
//import appImManager from '../lib/appManagers/appImManager';
let onFirstMount = () => import('../lib/appManagers/appImManager').then(() => {//import('../lib/services').then(services => {
//console.log('included services', services);
//export default () => {
/*
loadDialogs().then(result => {
//appImManager.setScroll(chatScroll);
});
return;
*/
/* function placeCaretAfterNode(node: HTMLElement) {
if (typeof window.getSelection != "undefined") {
var range = document.createRange();
range.setStartAfter(node);
range.collapse(true);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
messageInput.onclick = (e) => {
let target = e.target as HTMLElement;
if(target.classList.contains('emoji-inner')) {
placeCaretAfterNode(target.parentElement);
} else if(target.classList.contains('emoji-sizer')) {
placeCaretAfterNode(target);
}
console.log('lol', target);
}; */
/* window.addEventListener('click', function(this, e) {
// @ts-ignore
let isInput = e.target.tagName == 'INPUT';
if(!isInput && !window.getSelection().toString()) {
console.log('click');
messageInput.focus();
}
}); */
/* fetch('assets/img/camomile.jpg')
.then(res => res.blob())
.then(blob => {
let img = new Image();
let url = URL.createObjectURL(blob);
img.src = url;
img.onload = () => {
let id = 'chat-background-canvas';
var canvas = document.getElementById(id) as HTMLCanvasElement;
//URL.revokeObjectURL(url);
let elements = ['.chat-container'].map(selector => {
return document.querySelector(selector) as HTMLDivElement;
});
stackBlurImage(img, id, 15, 0);
canvas.toBlob(blob => {
//let dataUrl = canvas.toDataURL('image/jpeg', 1);
let dataUrl = URL.createObjectURL(blob);
elements.forEach(el => {
el.style.backgroundImage = 'url(' + dataUrl + ')';
});
}, 'image/jpeg', 1);
};
}); */
/* toggleEmoticons.onclick = (e) => {
if(!emoticonsDropdown) {
emoticonsDropdown = initEmoticonsDropdown(pageEl, appImManager,
appMessagesManager, messageInput, toggleEmoticons);
} else {
emoticonsDropdown.classList.toggle('active');
}
toggleEmoticons.classList.toggle('active');
}; */
(Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el));
Array.from(document.getElementsByClassName('btn-menu-toggle')).forEach((el) => {
el.addEventListener('click', (e) => {
//console.log('click pageIm');
if(!el.classList.contains('btn-menu-toggle')) return false;
//window.removeEventListener('mousemove', onMouseMove);
let openedMenu = el.querySelector('.btn-menu') as HTMLDivElement;
e.cancelBubble = true;
if(el.classList.contains('menu-open')) {
el.classList.remove('menu-open');
openedMenu.classList.remove('active');
} else {
openBtnMenu(openedMenu);
}
});
});
});
const page = new Page('page-chats', false, onFirstMount);
export default page;

267
src/components/pagePassword.ts → src/pages/pagePassword.ts

@ -1,136 +1,131 @@
import pageIm from './pageIm'; import pageIm from './pageIm';
import CryptoWorker from '../lib/crypto/cryptoworker'; import CryptoWorker from '../lib/crypto/cryptoworker';
import { putPreloader } from './misc'; import { putPreloader } from '../components/misc';
import LottieLoader from '../lib/lottieLoader'; import LottieLoader from '../lib/lottieLoader';
import passwordManager from '../lib/mtproto/passwordManager'; import passwordManager from '../lib/mtproto/passwordManager';
import apiManager from '../lib/mtproto/apiManager'; import apiManager from '../lib/mtproto/apiManager';
import Page from './page';
let installed = false;
let onFirstMount = () => {
export default async() => { let needFrame = 0;
//let LottieLoader = (await import('../lib/lottieLoader')).default; let animation: /* AnimationItem */any = undefined;
if(installed) return; let passwordVisible = false;
installed = true;
fetch('assets/img/TwoFactorSetupMonkeyClose.tgs')
let needFrame = 0; .then(res => res.arrayBuffer())
let animation: /* AnimationItem */any = undefined; .then(async(data) => {
let str = await CryptoWorker.gzipUncompress<string>(data, true);
let passwordVisible = false;
let pageElement = document.body.getElementsByClassName('page-password')[0] as HTMLDivElement; animation = await LottieLoader.loadAnimation({
pageElement.style.display = ''; container: page.pageEl.querySelector('.auth-image'),
renderer: 'svg',
fetch('assets/img/TwoFactorSetupMonkeyClose.tgs') loop: false,
.then(res => res.arrayBuffer()) autoplay: false,
.then(async(data) => { animationData: JSON.parse(str)
let str = await CryptoWorker.gzipUncompress<string>(data, true); });
animation = await LottieLoader.loadAnimation({ console.log(animation.getDuration(true));
container: pageElement.querySelector('.auth-image'), //animation.goToAndStop(822);
renderer: 'svg',
loop: false, animation.addEventListener('enterFrame', (e: any) => {
autoplay: false, //console.log('enterFrame', e, needFrame);
animationData: JSON.parse(str) let currentFrame = Math.round(e.currentTime);
});
if((e.direction == 1 && currentFrame >= needFrame) ||
console.log(animation.getDuration(true)); (e.direction == -1 && currentFrame <= needFrame)) {
//animation.goToAndStop(822); animation.setSpeed(1);
animation.pause();
animation.addEventListener('enterFrame', (e: any) => { }
//console.log('enterFrame', e, needFrame); });
let currentFrame = Math.round(e.currentTime);
needFrame = 49;
if((e.direction == 1 && currentFrame >= needFrame) || animation.play();
(e.direction == -1 && currentFrame <= needFrame)) { });
animation.setSpeed(1);
animation.pause(); const btnNext = page.pageEl.querySelector('button') as HTMLButtonElement;
} const passwordInput = document.getElementById('password') as HTMLInputElement;
}); //const passwordInputLabel = passwordInput.nextElementSibling as HTMLLabelElement;
const toggleVisible = page.pageEl.querySelector('.toggle-visible') as HTMLSpanElement;
needFrame = 49;
animation.play(); let handleError = (err: any) => {
}); btnNext.removeAttribute('disabled');
const btnNext = pageElement.querySelector('button') as HTMLButtonElement; switch(err.type) {
const passwordInput = document.getElementById('password') as HTMLInputElement; default:
//const passwordInputLabel = passwordInput.nextElementSibling as HTMLLabelElement; btnNext.innerText = err.type;
const toggleVisible = pageElement.querySelector('.toggle-visible') as HTMLSpanElement; break;
}
let handleError = (err: any) => { };
btnNext.removeAttribute('disabled');
toggleVisible.addEventListener('click', function(this, e) {
switch(err.type) { if(!passwordVisible) {
default: this.classList.add('tgico-eye2');
btnNext.innerText = err.type; passwordInput.setAttribute('type', 'text');
break; animation.setDirection(-1);
} needFrame = 0;
}; animation.play();
} else {
toggleVisible.addEventListener('click', function(this, e) { this.classList.remove('tgico-eye2');
if(!passwordVisible) { passwordInput.setAttribute('type', 'password');
this.classList.add('tgico-eye2'); animation.setDirection(1);
passwordInput.setAttribute('type', 'text'); needFrame = 49;
animation.setDirection(-1); animation.play();
needFrame = 0; }
animation.play();
} else { passwordVisible = !passwordVisible;
this.classList.remove('tgico-eye2'); });
passwordInput.setAttribute('type', 'password');
animation.setDirection(1); btnNext.addEventListener('click', function(this, e) {
needFrame = 49; if(!passwordInput.value.length) {
animation.play(); passwordInput.classList.add('error');
} return;
}
passwordVisible = !passwordVisible;
}); this.setAttribute('disabled', 'true');
let value = passwordInput.value;
btnNext.addEventListener('click', function(this, e) {
if(!passwordInput.value.length) { this.textContent = 'PLEASE WAIT...';
passwordInput.classList.add('error'); putPreloader(this);
return;
} passwordManager.getState()
.then(state => {
this.setAttribute('disabled', 'true'); console.log(state);
let value = passwordInput.value; passwordManager.check(state, value).then((response: any) => {
console.log('passwordManager response:', response);
this.textContent = 'PLEASE WAIT...';
putPreloader(this); switch(response._) {
case 'auth.authorization':
passwordManager.getState() apiManager.setUserAuth({
.then(state => { id: response.user.id
console.log(state); });
passwordManager.check(state, value).then((response: any) => {
console.log('passwordManager response:', response); pageIm.mount();
if(animation) animation.destroy();
switch(response._) { break;
case 'auth.authorization': default:
apiManager.setUserAuth({ btnNext.removeAttribute('disabled');
id: response.user.id btnNext.innerText = response._;
}); break;
}
pageElement.style.display = 'none'; }).catch(handleError);
pageIm(); }).catch(handleError);
if(animation) animation.destroy(); });
break;
default: passwordInput.addEventListener('keypress', function(this, e) {
btnNext.removeAttribute('disabled'); this.classList.remove('error');
btnNext.innerText = response._;
break; if(e.key == 'Enter') {
} return btnNext.click();
}).catch(handleError); }
}).catch(handleError); });
});
/* passwordInput.addEventListener('input', function(this, e) {
passwordInput.addEventListener('keypress', function(this, e) {
this.classList.remove('error'); }); */
};
if(e.key == 'Enter') {
return btnNext.click(); const page = new Page('page-password', true, onFirstMount);
}
}); export default page;
/* passwordInput.addEventListener('input', function(this, e) {
}); */
};

518
src/components/pageSignIn.ts → src/pages/pageSignIn.ts

@ -1,263 +1,255 @@
import { putPreloader, formatPhoneNumber } from "./misc"; import { putPreloader, formatPhoneNumber } from "../components/misc";
import Scrollable from './scrollable'; import Scrollable from '../components/scrollable';
import {RichTextProcessor} from '../lib/richtextprocessor'; import {RichTextProcessor} from '../lib/richtextprocessor';
import * as Config from '../lib/config'; import * as Config from '../lib/config';
import { findUpTag } from "../lib/utils"; import { findUpTag } from "../lib/utils";
import pageAuthCode from "./pageAuthCode"; import pageAuthCode from "./pageAuthCode";
import apiManager from "../lib/mtproto/apiManager"; import apiManager from "../lib/mtproto/apiManager";
import Page from "./page";
let installed = false;
type Country = {
type Country = { name: string,
name: string, code: string,
code: string, phoneCode: string,
phoneCode: string, pattern: string,
pattern: string, emoji: string,
emoji: string, li?: HTMLLIElement[]
li?: HTMLLIElement[] };
};
//import _countries from '../countries_pretty.json';
//import _countries from '../countries_pretty.json'; let btnNext: HTMLButtonElement = null;
export default () => { let onFirstMount = () => {
//export default () => import('../countries.json').then(_countries => { //const countries: Country[] = _countries.default.filter(c => c.emoji);
//let pageAuthCode = await import('./pageAuthCode'); const countries: Country[] = Config.Countries.filter(c => c.emoji).sort((a, b) => a.name.localeCompare(b.name));
//Array.from(document.querySelectorAll('body > .whole:not(.page-authCode)')).forEach(div => div.style.display = 'none');
const pageEl = document.body.getElementsByClassName('page-sign')[0] as HTMLDivElement; let lastCountrySelected = '';
pageEl.style.display = '';
var selectCountryCode = page.pageEl.querySelector('input[name="countryCode"]')! as HTMLInputElement;
let btnNext = pageEl.querySelector('button'); var parent = selectCountryCode.parentElement;
if(installed) { var wrapper = document.createElement('div');
btnNext.textContent = 'NEXT'; wrapper.classList.add('select-wrapper', 'z-depth-4');
btnNext.removeAttribute('disabled');
return; var list = document.createElement('ul');
} wrapper.appendChild(list);
installed = true; //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions);
let scroll = new Scrollable(wrapper);
//const countries: Country[] = _countries.default.filter(c => c.emoji);
const countries: Country[] = Config.Countries.filter(c => c.emoji).sort((a, b) => a.name.localeCompare(b.name)); let initedSelect = false;
let lastCountrySelected = ''; selectCountryCode.addEventListener('focus', function(this: typeof selectCountryCode, e) {
/* this.removeAttribute('readonly'); */
var selectCountryCode = pageEl.querySelector('input[name="countryCode"]')! as HTMLInputElement; if(!initedSelect) {
var parent = selectCountryCode.parentElement; countries.forEach((c) => {
initedSelect = true;
var wrapper = document.createElement('div');
wrapper.classList.add('select-wrapper', 'z-depth-4'); /* let unified = unifiedCountryCodeEmoji(c.code);
let emoji = unified.split('-').reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), ''); */
var list = document.createElement('ul'); //let emoji = countryCodeEmoji(c.code);
wrapper.appendChild(list); let emoji = c.emoji;
//let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); let liArr: Array<HTMLLIElement> = [];
let scroll = new Scrollable(wrapper); c.phoneCode.split(' and ').forEach((phoneCode: string) => {
let li = document.createElement('li');
let initedSelect = false; var spanEmoji = document.createElement('span');
/* spanEmoji.innerHTML = countryCodeEmoji(c.code); */
selectCountryCode.addEventListener('focus', function(this: typeof selectCountryCode, e) { //spanEmoji.classList.add('emoji-outer', 'emoji-sizer');
/* this.removeAttribute('readonly'); */ //spanEmoji.innerHTML = `<span class="emoji-inner" style="background: url(${sheetUrl}${sheetNo}.png);background-position:${xPos}% ${yPos}%;background-size:${sizeX}% ${sizeY}%" data-codepoints="${unified}"></span>`;
if(!initedSelect) {
countries.forEach((c) => {
initedSelect = true;
let kek = RichTextProcessor.wrapRichText(emoji);
/* let unified = unifiedCountryCodeEmoji(c.code); //console.log(c.name, emoji, kek, spanEmoji.innerHTML);
let emoji = unified.split('-').reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), ''); */
//let emoji = countryCodeEmoji(c.code); li.appendChild(spanEmoji);
let emoji = c.emoji; spanEmoji.outerHTML = kek;
let liArr: Array<HTMLLIElement> = []; li.append(c.name);
c.phoneCode.split(' and ').forEach((phoneCode: string) => {
let li = document.createElement('li'); var span = document.createElement('span');
var spanEmoji = document.createElement('span'); span.classList.add('phone-code');
/* spanEmoji.innerHTML = countryCodeEmoji(c.code); */ span.innerText = '+' + phoneCode;
//spanEmoji.classList.add('emoji-outer', 'emoji-sizer'); li.appendChild(span);
//spanEmoji.innerHTML = `<span class="emoji-inner" style="background: url(${sheetUrl}${sheetNo}.png);background-position:${xPos}% ${yPos}%;background-size:${sizeX}% ${sizeY}%" data-codepoints="${unified}"></span>`;
liArr.push(li);
list.append(li);
});
let kek = RichTextProcessor.wrapRichText(emoji);
//console.log(c.name, emoji, kek, spanEmoji.innerHTML); c.li = liArr;
});
li.appendChild(spanEmoji);
spanEmoji.outerHTML = kek; list.addEventListener('mousedown', function(e) {
let target = e.target as HTMLElement;
li.append(c.name); if(target.tagName != 'LI') target = findUpTag(target, 'LI');
var span = document.createElement('span'); let countryName = target.childNodes[1].textContent;//target.innerText.split('\n').shift();
span.classList.add('phone-code'); let phoneCode = target.querySelector<HTMLElement>('.phone-code').innerText;
span.innerText = '+' + phoneCode;
li.appendChild(span); selectCountryCode.value = countryName;
lastCountrySelected = countryName;
liArr.push(li);
list.append(li); telEl.value = phoneCode;
}); setTimeout(() => telEl.focus(), 0);
console.log('clicked', e, countryName, phoneCode);
c.li = liArr; });
}); }
list.addEventListener('mousedown', function(e) { parent.appendChild(wrapper);
let target = e.target as HTMLElement; }/* , {once: true} */);
if(target.tagName != 'LI') target = findUpTag(target, 'LI'); selectCountryCode.addEventListener('blur', function(this: typeof selectCountryCode, e) {
parent.removeChild(wrapper);
let countryName = target.childNodes[1].textContent;//target.innerText.split('\n').shift(); e.cancelBubble = true;
let phoneCode = target.querySelector<HTMLElement>('.phone-code').innerText; }, {capture: true});
selectCountryCode.value = countryName; selectCountryCode.addEventListener('keyup', function(this: typeof selectCountryCode, e) {
lastCountrySelected = countryName; if(e.ctrlKey || e.key == 'Control') return false;
telEl.value = phoneCode; //let i = new RegExp('^' + this.value, 'i');
setTimeout(() => telEl.focus(), 0); let _value = this.value.toLowerCase();
console.log('clicked', e, countryName, phoneCode); let matches: Country[] = [];
}); countries.forEach((c) => {
} let good = c.name.toLowerCase().indexOf(_value) !== -1/* == 0 */;//i.test(c.name);
parent.appendChild(wrapper); c.li.forEach(li => li.style.display = good ? '' : 'none');
}/* , {once: true} */); if(good) matches.push(c);
selectCountryCode.addEventListener('blur', function(this: typeof selectCountryCode, e) { });
parent.removeChild(wrapper);
e.cancelBubble = true; if(matches.length == 1 && matches[0].li.length == 1) {
}, {capture: true}); if(matches[0].name == lastCountrySelected) return false;
console.log('clicking', matches[0]);
selectCountryCode.addEventListener('keyup', function(this: typeof selectCountryCode, e) {
if(e.ctrlKey || e.key == 'Control') return false; var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent('mousedown', true, true);
//let i = new RegExp('^' + this.value, 'i'); matches[0].li[0].dispatchEvent(clickEvent);
let _value = this.value.toLowerCase(); return false;
let matches: Country[] = []; } else if(matches.length == 0) {
countries.forEach((c) => { countries.forEach((c) => {
let good = c.name.toLowerCase().indexOf(_value) !== -1/* == 0 */;//i.test(c.name); c.li.forEach(li => li.style.display = '');
});
c.li.forEach(li => li.style.display = good ? '' : 'none'); }
if(good) matches.push(c); });
});
let arrowDown = page.pageEl.querySelector('.arrow-down') as HTMLSpanElement;
if(matches.length == 1 && matches[0].li.length == 1) { arrowDown.addEventListener('mousedown', function(this: typeof arrowDown, e) {
if(matches[0].name == lastCountrySelected) return false; e.cancelBubble = true;
console.log('clicking', matches[0]); e.preventDefault();
if(selectCountryCode.matches(':focus')) selectCountryCode.blur();
var clickEvent = document.createEvent('MouseEvents'); else selectCountryCode.focus();
clickEvent.initEvent('mousedown', true, true); });
matches[0].li[0].dispatchEvent(clickEvent);
return false; let sortedCountries = countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length);
} else if(matches.length == 0) {
countries.forEach((c) => { let telEl = page.pageEl.querySelector('input[name="phone"]') as HTMLInputElement;
c.li.forEach(li => li.style.display = ''); telEl.addEventListener('input', function(this: typeof telEl, e) {
}); this.classList.remove('error');
}
}); let {formatted, country} = formatPhoneNumber(this.value);
this.value = formatted ? '+' + formatted : '';
let arrowDown = pageEl.querySelector('.arrow-down') as HTMLSpanElement;
arrowDown.addEventListener('mousedown', function(this: typeof arrowDown, e) { console.log(formatted, country);
e.cancelBubble = true;
e.preventDefault(); let countryName = country ? country.name : ''/* 'Unknown' */;
if(selectCountryCode.matches(':focus')) selectCountryCode.blur(); if(countryName != selectCountryCode.value) {
else selectCountryCode.focus(); selectCountryCode.value = countryName;
}); lastCountrySelected = countryName;
}
let sortedCountries = countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length);
if(country && (this.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) {
let telEl = pageEl.querySelector('input[name="phone"]') as HTMLInputElement; btnNext.style.visibility = '';
telEl.addEventListener('input', function(this: typeof telEl, e) { } else {
this.classList.remove('error'); btnNext.style.visibility = 'hidden';
}
let {formatted, country} = formatPhoneNumber(this.value); });
this.value = formatted ? '+' + formatted : '';
telEl.addEventListener('keypress', function(this: typeof telEl, e) {
console.log(formatted, country); if(this.value.length >= 9 && e.key == 'Enter') {
return btnNext.click();
let countryName = country ? country.name : ''/* 'Unknown' */; } else if(/\D/.test(e.key)) {
if(countryName != selectCountryCode.value) { e.preventDefault();
selectCountryCode.value = countryName; return false;
lastCountrySelected = countryName; }
} });
if(country && (this.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) { /* telEl.addEventListener('focus', function(this: typeof telEl, e) {
btnNext.style.visibility = ''; this.removeAttribute('readonly'); // fix autocomplete
} else { });*/
btnNext.style.visibility = 'hidden';
} /* authorizer.auth(2);
}); networkerFactory.startAll(); */
telEl.addEventListener('keypress', function(this: typeof telEl, e) { btnNext.addEventListener('click', function(this: HTMLElement, e) {
if(this.value.length >= 9 && e.key == 'Enter') { this.setAttribute('disabled', 'true');
return btnNext.click();
} else if(/\D/.test(e.key)) { this.textContent = 'PLEASE WAIT...';
e.preventDefault(); putPreloader(this);
return false; //this.innerHTML = 'PLEASE WAIT...';
}
}); let phone_number = telEl.value;
apiManager.invokeApi('auth.sendCode', {
/* telEl.addEventListener('focus', function(this: typeof telEl, e) { /* flags: 0, */
this.removeAttribute('readonly'); // fix autocomplete phone_number: phone_number,
});*/ api_id: Config.App.id,
api_hash: Config.App.hash,
/* authorizer.auth(2); settings: {
networkerFactory.startAll(); */ _: 'codeSettings', // that's how we sending Type
flags: 0
btnNext.addEventListener('click', function(this: HTMLElement, e) { }
this.setAttribute('disabled', 'true'); /* lang_code: navigator.language || 'en' */
}).then((code: any) => {
this.textContent = 'PLEASE WAIT...'; console.log('got code', code);
putPreloader(this);
//this.innerHTML = 'PLEASE WAIT...'; pageAuthCode.mount(Object.assign(code, {phone_number: phone_number}));
}).catch(err => {
let phone_number = telEl.value; this.removeAttribute('disabled');
apiManager.invokeApi('auth.sendCode', {
/* flags: 0, */ this.innerText = 'NEXT';
phone_number: phone_number, switch(err.type) {
api_id: Config.App.id, case 'PHONE_NUMBER_INVALID':
api_hash: Config.App.hash, telEl.classList.add('error');
settings: { break;
_: 'codeSettings', // that's how we sending Type default:
flags: 0 console.error('auth.sendCode error:', err);
} this.innerText = err.type;
/* lang_code: navigator.language || 'en' */ break;
}).then((code: any) => { }
console.log('got code', code); });
});
pageEl.style.display = 'none';
let tryAgain = () => {
// @ts-ignore apiManager.invokeApi('help.getNearestDc').then((nearestDcResult: any) => {
pageAuthCode(Object.assign(code, {phone_number: phone_number})); if(nearestDcResult.nearest_dc != nearestDcResult.this_dc) {
}).catch(err => { //MTProto.apiManager.baseDcID = nearestDcResult.nearest_dc;
this.removeAttribute('disabled'); apiManager.getNetworker(nearestDcResult.nearest_dc);
}
this.innerText = 'NEXT';
switch(err.type) { return nearestDcResult;
case 'PHONE_NUMBER_INVALID': }).then((nearestDcResult: any) => {
telEl.classList.add('error'); let country = countries.find((c) => c.code == nearestDcResult.country);
break; if(country) {
default: if(!selectCountryCode.value.length && !telEl.value.length) {
this.innerText = err.type; selectCountryCode.value = country.name;
break; lastCountrySelected = country.name;
} telEl.value = '+' + country.phoneCode.split(' and ').shift();
}); }
}); }
let tryAgain = () => { return console.log('woohoo', nearestDcResult, country);
apiManager.invokeApi('help.getNearestDc').then((nearestDcResult: any) => { })//.catch(tryAgain);
if(nearestDcResult.nearest_dc != nearestDcResult.this_dc) { };
//MTProto.apiManager.baseDcID = nearestDcResult.nearest_dc;
apiManager.getNetworker(nearestDcResult.nearest_dc); tryAgain();
} };
return nearestDcResult; const page = new Page('page-sign', true, onFirstMount, () => {
}).then((nearestDcResult: any) => { if(!btnNext) {
let country = countries.find((c) => c.code == nearestDcResult.country); btnNext = page.pageEl.querySelector('button');
if(country) { }
if(!selectCountryCode.value.length && !telEl.value.length) {
selectCountryCode.value = country.name; btnNext.textContent = 'NEXT';
lastCountrySelected = country.name; btnNext.removeAttribute('disabled');
telEl.value = '+' + country.phoneCode.split(' and ').shift(); });
}
} export default page;
return console.log('woohoo', nearestDcResult, country);
})//.catch(tryAgain);
};
tryAgain();
};

393
src/components/pageSignUp.ts → src/pages/pageSignUp.ts

@ -1,198 +1,195 @@
import {putPreloader} from './misc'; import {putPreloader} from '../components/misc';
import resizeableImage from '../lib/cropper';
let installed = false; import pageIm from './pageIm';
let authCode: { import apiManager from '../lib/mtproto/apiManager';
'phone_number': string, import apiFileManager from '../lib/mtproto/apiFileManager';
'phone_code_hash': string import Page from './page';
} = null;
let authCode: {
import resizeableImage from '../lib/cropper'; 'phone_number': string,
import pageIm from './pageIm'; 'phone_code_hash': string
import apiManager from '../lib/mtproto/apiManager'; } = null;
import apiFileManager from '../lib/mtproto/apiFileManager';
let onFirstMount = () => {
export default (_authCode: typeof authCode) => { const pageElement = page.pageEl;
authCode = _authCode; const avatarInput = document.getElementById('avatar-input') as HTMLInputElement;
if(installed) return; const avatarPopup = pageElement.getElementsByClassName('popup-avatar')[0];
installed = true; const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement;
const cropContainer = avatarPopup.getElementsByClassName('crop')[0];
let pageElement = document.body.getElementsByClassName('page-signUp')[0] as HTMLDivElement; let avatarImage = new Image();
pageElement.style.display = ''; cropContainer.append(avatarImage);
const avatarInput = document.getElementById('avatar-input') as HTMLInputElement; let avatarBlob: Blob;
const avatarPopup = pageElement.getElementsByClassName('popup-avatar')[0];
const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement; (avatarPopup.getElementsByClassName('popup-close')[0] as HTMLButtonElement)
const cropContainer = avatarPopup.getElementsByClassName('crop')[0]; .addEventListener('click', function(this, e) {
let avatarImage = new Image(); /* let popup = findUpClassName(this, 'popup');
cropContainer.append(avatarImage); popup.classList.remove('active'); */
let avatarBlob: Blob; setTimeout(() => {
cropper.removeHandlers();
(avatarPopup.getElementsByClassName('popup-close')[0] as HTMLButtonElement) if(avatarImage) {
.addEventListener('click', function(this, e) { avatarImage.remove();
/* let popup = findUpClassName(this, 'popup'); }
popup.classList.remove('active'); */ }, 200);
setTimeout(() => { /* e.cancelBubble = true;
cropper.removeHandlers(); return false; */
if(avatarImage) { });
avatarImage.remove();
} let cropper = {
}, 200); crop: () => {},
removeHandlers: () => {}
/* e.cancelBubble = true; };
return false; */
}); // apply
avatarPopup.getElementsByClassName('btn-crop')[0].addEventListener('click', () => {
let cropper = { cropper.crop();
crop: () => {}, avatarPopup.classList.remove('active');
removeHandlers: () => {} cropper.removeHandlers();
};
avatarPreview.toBlob(blob => {
// apply avatarBlob = blob; // save blob to send after reg
avatarPopup.getElementsByClassName('btn-crop')[0].addEventListener('click', () => {
cropper.crop(); // darken
avatarPopup.classList.remove('active'); let ctx = avatarPreview.getContext('2d');
cropper.removeHandlers(); ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
ctx.fillRect(0, 0, avatarPreview.width, avatarPreview.height);
avatarPreview.toBlob(blob => { }, 'image/jpeg', 1);
avatarBlob = blob; // save blob to send after reg
avatarImage.remove();
// darken });
let ctx = avatarPreview.getContext('2d');
ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; avatarInput.addEventListener('change', (e: any) => {
ctx.fillRect(0, 0, avatarPreview.width, avatarPreview.height); var file = e.target.files[0];
}, 'image/jpeg', 1); if(!file) {
return;
avatarImage.remove(); }
});
var reader = new FileReader();
avatarInput.addEventListener('change', (e: any) => { reader.onload = (e) => {
var file = e.target.files[0]; var contents = e.target.result as string;
if(!file) {
return; avatarImage = new Image();
} cropContainer.append(avatarImage);
avatarImage.src = contents;
var reader = new FileReader();
reader.onload = (e) => { avatarImage.onload = () => {
var contents = e.target.result as string; cropper = resizeableImage(avatarImage, avatarPreview);
avatarInput.value = '';
avatarImage = new Image(); };
cropContainer.append(avatarImage);
avatarImage.src = contents; avatarPopup.classList.add('active');
};
avatarImage.onload = () => {
cropper = resizeableImage(avatarImage, avatarPreview); reader.readAsDataURL(file);
avatarInput.value = ''; }, false);
};
pageElement.querySelector('.auth-image').addEventListener('click', () => {
avatarPopup.classList.add('active'); avatarInput.click();
}; });
reader.readAsDataURL(file); const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement;
}, false);
let handleInput = function(this: typeof fieldName, e: Event) {
pageElement.querySelector('.auth-image').addEventListener('click', () => { let name = fieldName.value || '';
avatarInput.click(); let lastName = fieldLastName.value || '';
});
let fullName = name || lastName
const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement; ? (name + ' ' + lastName).trim()
: 'Your Name';
let handleInput = function(this: typeof fieldName, e: Event) {
let name = fieldName.value || ''; if(headerName.innerText != fullName) headerName.innerText = fullName;
let lastName = fieldLastName.value || ''; this.classList.remove('error');
};
let fullName = name || lastName
? (name + ' ' + lastName).trim() let sendAvatar = () => new Promise((resolve, reject) => {
: 'Your Name'; if(!avatarBlob) {
console.log('User has not selected avatar');
if(headerName.innerText != fullName) headerName.innerText = fullName; return resolve();
this.classList.remove('error'); }
};
console.log('invoking uploadFile...');
let sendAvatar = () => new Promise((resolve, reject) => { apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => {
if(!avatarBlob) { console.log('uploaded smthn', inputFile);
console.log('User has not selected avatar');
return resolve(); apiManager.invokeApi('photos.uploadProfilePhoto', {
} file: inputFile
}).then((updateResult) => {
console.log('invoking uploadFile...'); console.log('updated photo!');
apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => { resolve();
console.log('uploaded smthn', inputFile); }, reject);
}, reject);
apiManager.invokeApi('photos.uploadProfilePhoto', { });
file: inputFile
}).then((updateResult) => { const fieldName = document.getElementById('name') as HTMLInputElement;
console.log('updated photo!'); fieldName.addEventListener('input', handleInput);
resolve();
}, reject); const fieldLastName = document.getElementById('lastName') as HTMLInputElement;
}, reject); fieldLastName.addEventListener('input', handleInput);
});
const signUpButton = document.getElementById('signUp') as HTMLButtonElement;
const fieldName = document.getElementById('name') as HTMLInputElement; signUpButton.addEventListener('click', function(this: typeof signUpButton, e) {
fieldName.addEventListener('input', handleInput); this.setAttribute('disabled', 'true');
const fieldLastName = document.getElementById('lastName') as HTMLInputElement; if(!fieldName.value.length) {
fieldLastName.addEventListener('input', handleInput); fieldName.classList.add('error');
return false;
const signUpButton = document.getElementById('signUp') as HTMLButtonElement; }
signUpButton.addEventListener('click', function(this: typeof signUpButton, e) {
this.setAttribute('disabled', 'true'); let name = fieldName.value;
let lastName = fieldLastName.value;
if(!fieldName.value.length) {
fieldName.classList.add('error'); let params = {
return false; 'phone_number': authCode.phone_number,
} 'phone_code_hash': authCode.phone_code_hash,
'first_name': name,
let name = fieldName.value; 'last_name': lastName
let lastName = fieldLastName.value; };
let params = { console.log('invoking auth.signUp with params:', params);
'phone_number': authCode.phone_number,
'phone_code_hash': authCode.phone_code_hash, this.textContent = 'PLEASE WAIT...';
'first_name': name, putPreloader(this);
'last_name': lastName
}; apiManager.invokeApi('auth.signUp', params)
.then((response: any) => {
console.log('invoking auth.signUp with params:', params); console.log('auth.signUp response:', response);
this.textContent = 'PLEASE WAIT...'; switch(response._) {
putPreloader(this); case 'auth.authorization': // success
apiManager.setUserAuth({ // warning
apiManager.invokeApi('auth.signUp', params) id: response.user.id
.then((response: any) => { });
console.log('auth.signUp response:', response);
sendAvatar().then(() => {
switch(response._) { pageIm.mount();
case 'auth.authorization': // success }, () => {
apiManager.setUserAuth({ // warning pageIm.mount();
id: response.user.id });
});
break;
sendAvatar().then(() => { default:
pageElement.style.display = 'none'; this.innerText = response._;
pageIm(); break;
}, () => { }
pageElement.style.display = 'none';
pageIm(); /* (document.body.getElementsByClassName('page-sign')[0] as HTMLDivElement).style.display = 'none';
}); pageAuthCode(Object.assign(code, {phoneNumber})); */
}).catch(err => {
break; this.removeAttribute('disabled');
default:
this.innerText = response._; switch(err.type) {
break; default:
} this.innerText = err.type;
break;
/* (document.body.getElementsByClassName('page-sign')[0] as HTMLDivElement).style.display = 'none'; }
pageAuthCode(Object.assign(code, {phoneNumber})); */ });
}).catch(err => { });
this.removeAttribute('disabled'); };
switch(err.type) { const page = new Page('page-signUp', true, onFirstMount, (_authCode: typeof authCode) => {
default: authCode = _authCode;
this.innerText = err.type; });
break;
} export default page;
});
});
};

37
src/pages/pagesManager.ts

@ -0,0 +1,37 @@
import Page from "./page";
import { whichChild } from "../lib/utils";
import { horizontalMenu } from "../components/misc";
class PagesManager {
private pageID = -1;
private selectTab: ReturnType<typeof horizontalMenu>;
public pagesDiv: HTMLDivElement;
constructor() {
this.pagesDiv = document.getElementById('auth-pages') as HTMLDivElement;
this.selectTab = horizontalMenu(null, this.pagesDiv.firstElementChild as HTMLDivElement, null, null, 420);
}
public setPage(page: Page) {
if(page.isAuthPage) {
this.pagesDiv.style.display = '';
let id = whichChild(page.pageEl);
if(this.pageID == id) return;
this.selectTab(id);
this.pageID = id;
} else {
this.pagesDiv.style.display = 'none';
page.pageEl.style.display = '';
this.pageID = -1;
}
}
}
const pagesManager = new PagesManager();
(window as any).pagesManager = pagesManager;
export default pagesManager;

2
src/scss/partials/_leftSidebar.scss

@ -62,7 +62,7 @@
} }
&.active { &.active {
margin-top: 1px; //margin-top: 1px;
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
color: #707579; color: #707579;

35
src/scss/style.scss

@ -133,8 +133,8 @@ input {
.btn-icon { .btn-icon {
text-align: center; text-align: center;
font-size: 1.65rem; font-size: 1.5rem;
line-height: 1.65rem; line-height: 1.5rem;
border-radius: 50%; border-radius: 50%;
-webkit-transition: background-color .15s ease-out; -webkit-transition: background-color .15s ease-out;
transition: background-color .15s ease-out; transition: background-color .15s ease-out;
@ -496,6 +496,32 @@ input {
} }
} }
#auth-pages {
max-width: 720px; // 360 + 360 / 2
overflow: hidden;
.tabs-container {
&.animated {
transition: .42s transform;
}
> div {
justify-content: center;
/* &.active {
flex-direction: row;
} */
> div {
padding: 0;
overflow: visible;
/* display: flex;
flex-direction: column;
justify-content: center; */
}
}
}
}
.page-sign { .page-sign {
.auth-image { .auth-image {
width: 160px; width: 160px;
@ -1302,7 +1328,7 @@ div.scrollable::-webkit-scrollbar-thumb {
max-height: 100%; max-height: 100%;
//position: relative; //position: relative;
will-change: transform; //will-change: transform;
transform: translateZ(0); transform: translateZ(0);
-webkit-transform: translateZ(0); -webkit-transform: translateZ(0);
@ -1412,12 +1438,13 @@ div.scrollable::-webkit-scrollbar-thumb {
.tabs-container { .tabs-container {
min-width: 100%; min-width: 100%;
width: 100%;
display: flex; display: flex;
/* overflow: hidden; */ /* overflow: hidden; */
overflow-x: hidden; overflow-x: hidden;
&.animated { &.animated {
transition: .2s margin-left; transition: .3s transform;
} }
> div { > div {

Loading…
Cancel
Save