From 43bc94b0c4f0262a85808adac27c5ea41f3e1087 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Mon, 20 Apr 2020 00:40:00 +0300 Subject: [PATCH] Fixed slider animation & added same animation to auth pages --- src/components/misc.ts | 152 +++--- src/components/pageIm.ts | 194 -------- src/components/wrappers.ts | 33 +- src/lib/appManagers/appDialogsManager.ts | 337 ++++++++----- src/lib/appManagers/appImManager.ts | 54 ++- src/lib/appManagers/appMediaViewer.ts | 3 +- src/lib/appManagers/appSidebarLeft.ts | 152 +----- src/lib/services.ts | 2 +- src/lib/utils.js | 10 +- src/pages/page.ts | 28 ++ src/{components => pages}/pageAuthCode.ts | 550 +++++++++++----------- src/pages/pageIm.ts | 111 +++++ src/{components => pages}/pagePassword.ts | 267 ++++++----- src/{components => pages}/pageSignIn.ts | 518 ++++++++++---------- src/{components => pages}/pageSignUp.ts | 393 ++++++++-------- src/pages/pagesManager.ts | 37 ++ src/scss/partials/_leftSidebar.scss | 2 +- src/scss/style.scss | 35 +- 18 files changed, 1465 insertions(+), 1413 deletions(-) delete mode 100644 src/components/pageIm.ts create mode 100644 src/pages/page.ts rename src/{components => pages}/pageAuthCode.ts (85%) create mode 100644 src/pages/pageIm.ts rename src/{components => pages}/pagePassword.ts (81%) rename src/{components => pages}/pageSignIn.ts (85%) rename src/{components => pages}/pageSignUp.ts (89%) create mode 100644 src/pages/pagesManager.ts diff --git a/src/components/misc.ts b/src/components/misc.ts index 800e5aaf..3b1a0e08 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -1,4 +1,4 @@ -import { whichChild, findUpTag } from "../lib/utils"; +import { whichChild, findUpTag, cancelEvent } from "../lib/utils"; let rippleClickID = 0; export function ripple(elem: HTMLElement, callback: (id: number) => Promise = () => Promise.resolve(), onEnd: (id: number) => void = null) { @@ -8,11 +8,17 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise { + if(elem.dataset.ripple == '0') { + return false; + } + let startTime = Date.now(); let span = document.createElement('span'); let clickID = rippleClickID++; + console.log('ripple mousedown'); + let handler = () => { let elapsedTime = Date.now() - startTime; if(elapsedTime < 700) { @@ -135,87 +141,125 @@ export function putPreloader(elem: Element, returnDiv = false) { 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 prevTabContent: HTMLDivElement = null; let prevId = -1; - - tabs.addEventListener('click', function(e) { - let target = e.target as HTMLLIElement; - - if(target.tagName != 'LI') { - target = findUpTag(target, 'LI'); - } - - ///////console.log('tabs click:', target); - - if(!target) return false; + let children = Array.from(content.children); + let tabsChildren = tabs ? Array.from(tabs.children) : []; + let activeInSlide: Set = new Set(); + + let selectTab = (id: number) => { + if(id == prevId) return false; + + let p = prevTabContent; + + /* children.forEach(child => { + if(child != p) { + child.classList.remove('active'); + } + }); */ - let id = whichChild(target); 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'); - - /////console.log('mambo rap', prevId, id); - + + if(!activeInSlide.has(tabContent)) { + activeInSlide.add(tabContent); + } + //content.style.marginLeft = id > 0 ? (-id * 100) + '%' : ''; let toRight = prevId < id; 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); content.classList.remove('animated'); - if(toRight) { content.classList.add('animated'); - content.style.marginLeft = '-100%'; } else { - - content.style.marginLeft = '-100%'; - setTimeout(() => { + window.requestAnimationFrame(() => { content.classList.add('animated'); - content.style.marginLeft = ''; - }, 10); + content.style.transform = ''; + }); } } - prevId = id; - - let p = prevTabContent; - clearTimeout(hideTimeout); - if(p) hideTimeout = setTimeout(() => { - if(toRight) { - p.classList.remove('active'); + if(hideTimeout) clearTimeout(hideTimeout); + if(p/* && false */) { + //if(tabs) tabs.classList.add('disable-hover'); + + if(tabs) { + tabsChildren.forEach((c, idx) => { + 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.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%'; - content.style.width = '100%'; */ + //console.log('tabs click:', target); - if(!toRight) { - p.classList.remove('active'); - content.classList.remove('animated'); - content.style.width = '100%'; + if(!target) return false; + + let id = whichChild(target); + 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(); - }, 200); - - prevTabContent = tabContent; - }); + target.classList.add('active'); + selectTab(id); + }); + } + + return selectTab; } export function formatPhoneNumber(str: string) { diff --git a/src/components/pageIm.ts b/src/components/pageIm.ts deleted file mode 100644 index 327583d7..00000000 --- a/src/components/pageIm.ts +++ /dev/null @@ -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); - }); -}); diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 8636ebaa..a16d56af 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -3,7 +3,6 @@ import CryptoWorker from '../lib/crypto/cryptoworker'; import LottieLoader from '../lib/lottieLoader'; import appStickersManager from "../lib/appManagers/appStickersManager"; import appDocsManager from "../lib/appManagers/appDocsManager"; -import {AppImManager} from "../lib/appManagers/appImManager"; import { formatBytes } from "../lib/utils"; import ProgressivePreloader from './preloader'; import LazyLoadQueue from './lazyLoadQueue'; @@ -60,9 +59,21 @@ export type MTPhotoSize = { 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 peerID = this.peerID; if(withTail) { 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); return promise.then(blob => { - if(this.peerID != peerID) { - this.log.warn('peer changed'); + if(!middleware()) { return; } @@ -141,7 +151,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi }; 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 let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => { if((this.peerID ? this.peerID : this.currentMessageID) != peerID) { @@ -481,9 +491,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string}, return image; } -export async function wrapPhoto(this: AppImManager, photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false) { - let peerID = this.peerID; - +export async function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean) { let photo = appPhotosManager.getPhoto(photoID); let size: MTPhotoSize; @@ -512,10 +520,7 @@ export async function wrapPhoto(this: AppImManager, photoID: string, message: an } return promise.then(() => { - if(this.peerID != peerID) { - this.log.warn('peer changed'); - return; - } + if(!middleware()) return; renderImageFromUrl(image, photo.url); }); @@ -523,7 +528,7 @@ export async function wrapPhoto(this: AppImManager, photoID: string, message: an /////////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) { diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index cab86a2b..bdf6d037 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1,14 +1,13 @@ -import apiManager from "../mtproto/apiManager"; -import apiFileManager from '../mtproto/apiFileManager'; -import { $rootScope, langPack, findUpClassName } from "../utils"; +import { langPack, findUpClassName, $rootScope } from "../utils"; import appImManager, { AppImManager } from "./appImManager"; import appPeersManager from './appPeersManager'; -import appMessagesManager from "./appMessagesManager"; +import appMessagesManager, { AppMessagesManager } from "./appMessagesManager"; import appUsersManager from "./appUsersManager"; import { RichTextProcessor } from "../richtextprocessor"; -import { ripple, renderImageFromUrl } from "../../components/misc"; -import appSidebarLeft from "./appSidebarLeft"; +import { ripple, putPreloader } from "../../components/misc"; import Scrollable from "../../components/scrollable"; +import appProfileManager from "./appProfileManager"; +import { logger } from "../polyfill"; type DialogDom = { avatarDiv: HTMLDivElement, @@ -22,6 +21,8 @@ type DialogDom = { listEl: HTMLLIElement }; +let testScroll = false; + export class AppDialogsManager { public chatList = document.getElementById('dialogs') as HTMLUListElement; public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement; @@ -31,42 +32,228 @@ export class AppDialogsManager { public chatsArchivedHidden: Scrollable["hiddenElements"]; public chatsArchivedVisible: Scrollable["visibleElements"]; - public myID = 0; public doms: {[peerID: number]: DialogDom} = {}; public domsArchived: {[peerID: number]: DialogDom} = {}; public lastActiveListElement: HTMLElement = null; - public savedAvatarURLs: {[peerID: number]: string} = {}; - private rippleCallback: (value?: boolean | PromiseLike) => void = null; private lastClickID = 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; + private loadDialogsPromise: ReturnType; + + private loadedAll = false; + private loadedArchivedAll = false; + + public scroll: Scrollable = null; + public scrollArchived: Scrollable = null; + + private log = logger('DIALOGS'); + constructor() { + this.chatsPreloader = putPreloader(null, true); + //this.chatsContainer.append(this.chatsPreloader); + this.pinnedDelimiter = document.createElement('div'); this.pinnedDelimiter.classList.add('pinned-delimiter'); this.pinnedDelimiter.appendChild(document.createElement('span')); - apiManager.getUserID().then((id) => { - this.myID = id; + //this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); + + 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 = `

${i}18:33

-_-_-_-: qweasd

`; + 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) => { - let userAuth = e.detail; - this.myID = userAuth ? userAuth.id : 0; + $rootScope.$on('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 != $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! - if(this.rippleCallback) { - this.rippleCallback(); - this.rippleCallback = null; + $rootScope.$on('dialog_top', (e: CustomEvent) => { + let dialog: any = e.detail; + + 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); - this.setListClickListener(this.chatListArchived); + let dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0]; + 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) { @@ -142,94 +329,6 @@ export class AppDialogsManager { }); } - // peerID == peerID || title - public async loadDialogPhoto(div: HTMLDivElement, peerID: number, isDialog = false, title = ''): Promise { - 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) { //return; //if(archived) return; @@ -299,7 +398,7 @@ export class AppDialogsManager { let child = concated.find(obj => obj.element == dom.listEl); 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) { @@ -412,7 +511,7 @@ export class AppDialogsManager { let senderBold = document.createElement('b'); let str = ''; - if(sender.id == this.myID) { + if(sender.id == $rootScope.myID) { str = 'You'; } else { str = sender.first_name || sender.last_name || sender.username; @@ -459,7 +558,7 @@ export class AppDialogsManager { dom.statusSpan.innerHTML = ''; let lastMessage = appMessagesManager.getMessage(dialog.top_message); 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 let outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread) /* && dialog.read_outbox_max_id != 0 */; // maybe uncomment, 31.01.2020 @@ -497,7 +596,7 @@ export class AppDialogsManager { return acc; }, 0); - appSidebarLeft.archivedCount.innerText = '' + sum; + $rootScope.$broadcast('dialogs_archived_unread', {count: sum}); } } @@ -520,7 +619,7 @@ export class AppDialogsManager { let avatarDiv = document.createElement('div'); avatarDiv.classList.add('user-avatar'); - if(drawStatus && peerID != this.myID) { + if(drawStatus && peerID != $rootScope.myID) { let peer = dialog.peer; switch(peer._) { @@ -544,12 +643,12 @@ export class AppDialogsManager { let titleSpan = document.createElement('span'); titleSpan.classList.add('user-title'); - if(peerID == this.myID) { + if(peerID == $rootScope.myID) { title = 'Saved Messages'; } //console.log('trying to load photo for:', title); - this.loadDialogPhoto(avatarDiv, dialog.peerID, true); + appProfileManager.putPhoto(avatarDiv, dialog.peerID, true); titleSpan.innerHTML = title; //p.classList.add('') @@ -565,7 +664,7 @@ export class AppDialogsManager { paddingDiv.append(avatarDiv, captionDiv); ripple(paddingDiv, (id) => { - console.log('dialogs click element'); + this.log('dialogs click element'); this.lastClickID = id; return new Promise((resolve, reject) => { @@ -617,10 +716,10 @@ export class AppDialogsManager { if(!container) { if(dialog.folder_id && dialog.folder_id == 1) { - appSidebarLeft.scrollArchived.append(li); + this.scrollArchived.append(li); this.domsArchived[dialog.peerID] = dom; } else { - appSidebarLeft.scroll.append(li); + this.scroll.append(li); this.doms[dialog.peerID] = dom; } diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index dad67732..f1a1f235 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -120,7 +120,7 @@ export class AppImManager { this.popupDeleteMessage.cancelBtn = this.popupDeleteMessage.popupEl.querySelector('.popup-close') as HTMLButtonElement; apiManager.getUserID().then((id) => { - this.myID = id; + this.myID = $rootScope.myID = id; }); this.topbar = document.getElementById('topbar') as HTMLDivElement; @@ -128,7 +128,7 @@ export class AppImManager { $rootScope.$on('user_auth', (e: CustomEvent) => { 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) @@ -558,6 +558,7 @@ export class AppImManager { setInterval(() => this.setPeerStatus(), 60e3); this.setScroll(); + apiUpdatesManager.attach(); } public deleteMessages(revoke = false) { @@ -882,8 +883,8 @@ export class AppImManager { let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null; //////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID); - appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID); - appDialogsManager.loadDialogPhoto(appSidebarRight.profileElements.avatar, this.peerID); + appProfileManager.putPhoto(this.avatarEl, this.peerID); + appProfileManager.putPhoto(appSidebarRight.profileElements.avatar, this.peerID); this.firstTopMsgID = dialog ? dialog.top_message : 0; @@ -1248,7 +1249,9 @@ export class AppImManager { 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; } @@ -1291,7 +1294,20 @@ export class AppImManager { if(doc.type == 'gif' || doc.type == 'video') { //if(doc.size <= 20e6) { 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 { doc = null; @@ -1301,7 +1317,9 @@ export class AppImManager { if(webpage.photo && !doc) { 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) { @@ -1366,7 +1384,23 @@ export class AppImManager { } 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; } else if(doc.mime_type == 'audio/ogg') { @@ -1479,11 +1513,11 @@ export class AppImManager { /////////this.log('exec loadDialogPhoto', message); 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) { title = message.fwd_from.from_name; - appDialogsManager.loadDialogPhoto(avatarDiv, 0, false, title); + appProfileManager.putPhoto(avatarDiv, 0, false, title); } avatarDiv.dataset.peerID = message.fromID; diff --git a/src/lib/appManagers/appMediaViewer.ts b/src/lib/appManagers/appMediaViewer.ts index b2715d08..2fdac69f 100644 --- a/src/lib/appManagers/appMediaViewer.ts +++ b/src/lib/appManagers/appMediaViewer.ts @@ -9,6 +9,7 @@ import { findUpClassName, $rootScope, generatePathData } from "../utils"; import appDocsManager from "./appDocsManager"; import { wrapPlayer } from "../ckin"; import { renderImageFromUrl } from "../../components/misc"; +import appProfileManager from "./appProfileManager"; export class AppMediaViewer { private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement; @@ -592,7 +593,7 @@ export class AppMediaViewer { this.content.caption.innerHTML = ''; } - appDialogsManager.loadDialogPhoto(this.author.avatarEl, message.fromID); + appProfileManager.putPhoto(this.author.avatarEl, message.fromID); // ok set diff --git a/src/lib/appManagers/appSidebarLeft.ts b/src/lib/appManagers/appSidebarLeft.ts index b6db478f..85987da9 100644 --- a/src/lib/appManagers/appSidebarLeft.ts +++ b/src/lib/appManagers/appSidebarLeft.ts @@ -1,16 +1,14 @@ import { logger } from "../polyfill"; -import { putPreloader, formatPhoneNumber } from "../../components/misc"; +import { formatPhoneNumber } from "../../components/misc"; import Scrollable from '../../components/scrollable'; -import appMessagesManager, { AppMessagesManager } from "./appMessagesManager"; +import appMessagesManager from "./appMessagesManager"; import appDialogsManager from "./appDialogsManager"; -import { isElementInViewport, numberWithCommas } from "../utils"; +import { isElementInViewport, numberWithCommas, $rootScope } from "../utils"; import appMessagesIDsManager from "./appMessagesIDsManager"; import appImManager from "./appImManager"; import appUsersManager from "./appUsersManager"; -import { appPeersManager } from "../services"; import apiManager from "../mtproto/apiManager"; - -let testScroll = false; +import appPeersManager from './appPeersManager'; class SearchGroup { container: HTMLDivElement; @@ -56,18 +54,6 @@ class AppSidebarLeft { 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; - private loadDialogsPromise: ReturnType; - - private loadedAll = false; - private loadedArchivedAll = false; - private log = logger('SL'); private peerID = 0; @@ -81,37 +67,16 @@ class AppSidebarLeft { private query = ''; - public scroll: Scrollable = null; - 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') - }; + public searchGroups: {[group: string]: SearchGroup} = {}; constructor() { - this.chatsPreloader = putPreloader(null, true); - //this.chatsContainer.append(this.chatsPreloader); - - //this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); - - 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.searchGroups = { + 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') + }; + this.listsContainer = new Scrollable(this.searchContainer).container; for(let i in this.searchGroups) { this.listsContainer.append(this.searchGroups[i].container); @@ -126,7 +91,7 @@ class AppSidebarLeft { }); this.archivedBtn.addEventListener('click', (e) => { - this.chatsArchivedContainer.classList.add('active'); + appDialogsManager.chatsArchivedContainer.classList.add('active'); this.toolsBtn.classList.remove('active'); this.backBtn.classList.add('active'); //this.toolsBtn.classList.remove('tgico-menu', 'btn-menu-toggle'); @@ -137,15 +102,6 @@ class AppSidebarLeft { apiManager.logOut(); }); - if(testScroll) { - for(let i = 0; i < 1000; ++i) { - let li = document.createElement('li'); - li.dataset.id = '' + i; - li.innerHTML = `

${i}18:33

-_-_-_-: qweasd

`; - this.scroll.append(li); - } - } - this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this)); this.searchInput.addEventListener('focus', (e) => { @@ -198,101 +154,31 @@ class AppSidebarLeft { }); this.backBtn.addEventListener('click', (e) => { - this.chatsArchivedContainer.classList.remove('active'); + appDialogsManager.chatsArchivedContainer.classList.remove('active'); this.toolsBtn.classList.add('active'); this.backBtn.classList.remove('active'); this.searchInput.value = ''; this.searchContainer.classList.remove('active'); this.peerID = 0; }); - + window.addEventListener('resize', () => { //this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); setTimeout(() => { this.onSidebarScroll(); - this.scroll.onScroll(); - //this.onChatsScroll(); - this.onChatsArchivedScroll(); }, 0); }); + $rootScope.$on('dialogs_archived_unread', (e: CustomEvent) => { + this.archivedCount.innerText = '' + e.detail.count; + }); + /* appUsersManager.getTopPeers().then(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() { if(!this.query.trim()) return; diff --git a/src/lib/services.ts b/src/lib/services.ts index 9b4750cd..73872f99 100644 --- a/src/lib/services.ts +++ b/src/lib/services.ts @@ -22,7 +22,6 @@ export const appChatsManager = AppChatsManager; export const appMessagesIDsManager = AppMessagesIDsManager; export const apiUpdatesManager = ApiUpdatesManager; export const appPhotosManager = AppPhotosManager; -export const appDialogsManager = AppDialogsManager; export const appMessagesManager = AppMessagesManager; export const appProfileManager = AppProfileManager; export const appImManager = AppImManager; @@ -33,6 +32,7 @@ export const appDocsManager = AppDocsManager; export const appSidebarRight = AppSidebarRight; export const appSidebarLeft = AppSidebarLeft; export const appMediaViewer = AppMediaViewer; +export const appDialogsManager = AppDialogsManager; (window as any).Services = { appUsersManager, diff --git a/src/lib/utils.js b/src/lib/utils.js index 857d1a70..56643ef3 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -61,15 +61,6 @@ export function cancelEvent (event) { 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) { field = $(field)[0] try { @@ -307,6 +298,7 @@ export const $rootScope = { }, selectedPeerID: 0, + myID: 0, idle: { isIDLE: false } diff --git a/src/pages/page.ts b/src/pages/page.ts new file mode 100644 index 00000000..08e1859f --- /dev/null +++ b/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); + } +} \ No newline at end of file diff --git a/src/components/pageAuthCode.ts b/src/pages/pageAuthCode.ts similarity index 85% rename from src/components/pageAuthCode.ts rename to src/pages/pageAuthCode.ts index 61de694e..19b2dc38 100644 --- a/src/components/pageAuthCode.ts +++ b/src/pages/pageAuthCode.ts @@ -1,276 +1,274 @@ -import pageSignIn from './pageSignIn'; -import pageSignUp from './pageSignUp'; -import pageIm from './pageIm'; -import pagePassword from './pagePassword'; -import CryptoWorker from '../lib/crypto/cryptoworker'; -import LottieLoader from '../lib/lottieLoader'; -import apiManager from '../lib/mtproto/apiManager'; - -let installed = false; -let authCode: { - _: string, // 'auth.sentCode' - pFlags: any, // {} - flags: number, - type: { - _: string, // 'auth.sentCodeTypeSms', - length: number - }, - phone_code_hash: string, - phone_number: string -} = null; - -const EDITONSAMEPAGE = false; - -export default async(_authCode: typeof authCode) => { - authCode = _authCode; - - //let LottieLoader = (await import('../lib/lottieLoader')).default; - - let pageElement = document.body.getElementsByClassName('page-authCode')[0] as HTMLDivElement; - pageElement.style.display = ''; - - let headerElement = pageElement.getElementsByClassName('phone')[0] as HTMLHeadElement; - headerElement.innerText = authCode.phone_number; - - let sentTypeElement = pageElement.getElementsByClassName('sent-type')[0] as HTMLParagraphElement; - - switch(authCode.type._) { - case 'auth.sentCodeTypeSms': - sentTypeElement.innerHTML = 'We have sent you an SMS
with the code.'; - break; - case 'auth.sentCodeTypeApp': - sentTypeElement.innerHTML = 'We have sent you a message in Telegram
with the code.'; - break; - case 'auth.sentCodeTypeCall': - sentTypeElement.innerHTML = 'We will call you and voice
the code.'; - break; - default: - sentTypeElement.innerHTML = `Please check everything
for a code (type: ${authCode.type._})`; - break; - } - - if(installed) return; - installed = true; - - let needFrame = 0, lastLength = 0; - let animation: /* AnimationItem */any = undefined; - - const CODELENGTH = authCode.type.length; - - fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs') - .then(res => res.arrayBuffer()) - .then(async(data) => { - let str = await CryptoWorker.gzipUncompress(data, true); - - animation = await LottieLoader.loadAnimation({ - container: document.body.querySelector('.page-authCode .auth-image'), - renderer: 'svg', - loop: false, - autoplay: false, - animationData: JSON.parse(str) - }); - - animation.setSpeed(1); - //console.log(animation.getDuration(), animation.getDuration(true)); - - animation.addEventListener('enterFrame', (e: any) => { - //console.log('enterFrame', e, needFrame); - let currentFrame = Math.round(e.currentTime); - - if((e.direction == 1 && currentFrame >= needFrame) || - (e.direction == -1 && currentFrame <= needFrame)) { - animation.setSpeed(1); - animation.pause(); - } - }); - }); - - const codeInput = document.getElementById('code') as HTMLInputElement; - const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement; - const editButton = document.querySelector('.phone-edit') as HTMLElement; - - if(EDITONSAMEPAGE) { - let editable = false; - let changePhonePromise: Promise; - - let changePhone = () => { - if(changePhonePromise) return; - - let phone_number = '+' + headerElement.innerText.replace(/\D/g, ''); - if(authCode.phone_number == phone_number) return; - - codeInput.setAttribute('disabled', 'true'); - - changePhonePromise = apiManager.invokeApi('auth.sendCode', { - /* flags: 0, */ - phone_number: phone_number, - api_id: Config.App.id, - api_hash: Config.App.hash, - settings: { - _: 'codeSettings', // that's how we sending Type - flags: 0 - } - /* lang_code: navigator.language || 'en' */ - }).then((code: any) => { - console.log('got code 2', code); - - authCode = Object.assign(code, {phone_number}); - - changePhonePromise = undefined; - codeInput.removeAttribute('disabled'); - codeInput.focus(); - }).catch(err => { - switch(err.type) { - case 'PHONE_NUMBER_INVALID': - headerElement.classList.add('error'); - editable = true; - headerElement.setAttribute('contenteditable', '' + editable); - headerElement.focus(); - break; - default: - codeInputLabel.innerText = err.type; - break; - } - - changePhonePromise = undefined; - codeInput.removeAttribute('disabled'); - }); - }; - - headerElement.addEventListener('keypress', function(this, e) { - if(e.key == 'Enter') { - editable = false; - headerElement.setAttribute('contenteditable', '' + editable); - changePhone(); - } - - if(/\D/.test(e.key)) { - e.preventDefault(); - return false; - } - - this.classList.remove('error'); - }); - - editButton.addEventListener('click', function() { - if(changePhonePromise) return; - - editable = !editable; - headerElement.setAttribute('contenteditable', '' + editable); - - if(!editable) changePhone(); - }); - } else { - editButton.addEventListener('click', function() { - pageElement.style.display = 'none'; - return pageSignIn(); - }); - } - - let submitCode = (code: string) => { - codeInput.setAttribute('disabled', 'true'); - - let params = { - phone_number: authCode.phone_number, - phone_code_hash: authCode.phone_code_hash, - phone_code: code - }; - - console.log('invoking auth.signIn with params:', params); - - apiManager.invokeApi('auth.signIn', params) - .then((response: any) => { - console.log('auth.signIn response:', response); - - switch(response._) { - case 'auth.authorization': - apiManager.setUserAuth({ - id: response.user.id - }); - - pageElement.style.display = 'none'; - pageIm(); - if(animation) animation.destroy(); - break; - case 'auth.authorizationSignUpRequired': - console.log('Registration needed!'); - - pageElement.style.display = 'none'; - pageSignUp({ - 'phone_number': authCode.phone_number, - 'phone_code_hash': authCode.phone_code_hash - }); - - if(animation) animation.destroy(); - break; - default: - codeInput.innerText = response._; - break; - } - }).catch(err => { - codeInput.removeAttribute('disabled'); - - switch(err.type) { - case 'SESSION_PASSWORD_NEEDED': - console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED'); - err.handled = true; - pageElement.style.display = 'none'; - if(animation) animation.destroy(); - pagePassword(); - break; - case 'PHONE_CODE_EMPTY': - case 'PHONE_CODE_INVALID': - codeInput.classList.add('error'); - codeInputLabel.innerText = 'Invalid Code'; - break; - default: - codeInputLabel.innerText = err.type; - break; - } - }); - }; - - const max = 45; - // 1st symbol = frame 15 - // end symbol = frame 165 - codeInput.addEventListener('input', function(this: typeof codeInput, e) { - this.classList.remove('error'); - - this.value = this.value.replace(/\D/g, ''); - if(this.value.length > CODELENGTH) { - this.value = this.value.slice(0, CODELENGTH); - } - - let length = this.value.length; - if(length == CODELENGTH) { // submit code - submitCode(this.value); - } else if(length == lastLength) { - return; - } - - lastLength = length; - - if(!animation) return; - - let frame: number; - if(length) frame = Math.round((length > max ? max : length) * (165 / max) + 11.33); - else frame = 0; - //animation.playSegments([1, 2]); - - let direction = needFrame > frame ? -1 : 1; - //console.log('keydown', length, frame, direction); - // @ts-ignore - animation.setDirection(direction); - if(needFrame != 0 && frame == 0) { - animation.setSpeed(7); - } - /* let diff = Math.abs(needFrame - frame * direction); - if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */ - needFrame = frame; - - animation.play(); - - /* animation.goToAndStop(15, true); */ - //animation.goToAndStop(length / max * ); - }); -}; +import pageSignIn from './pageSignIn'; +import pageSignUp from './pageSignUp'; +import pageIm from './pageIm'; +import pagePassword from './pagePassword'; +import CryptoWorker from '../lib/crypto/cryptoworker'; +import LottieLoader from '../lib/lottieLoader'; +import apiManager from '../lib/mtproto/apiManager'; +import Page from './page'; + +let authCode: { + _: string, // 'auth.sentCode' + pFlags: any, // {} + flags: number, + type: { + _: string, // 'auth.sentCodeTypeSms', + length: number + }, + phone_code_hash: string, + phone_number: string +} = null; + +const EDITONSAMEPAGE = false; + +let headerElement: HTMLHeadElement = null; +let sentTypeElement: HTMLParagraphElement = null; + +let onFirstMount = () => { + let needFrame = 0, lastLength = 0; + let animation: /* AnimationItem */any = undefined; + + const CODELENGTH = authCode.type.length; + + fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs') + .then(res => res.arrayBuffer()) + .then(async(data) => { + let str = await CryptoWorker.gzipUncompress(data, true); + + animation = await LottieLoader.loadAnimation({ + container: page.pageEl.querySelector('.auth-image'), + renderer: 'svg', + loop: false, + autoplay: false, + animationData: JSON.parse(str) + }); + + animation.setSpeed(1); + //console.log(animation.getDuration(), animation.getDuration(true)); + + animation.addEventListener('enterFrame', (e: any) => { + //console.log('enterFrame', e, needFrame); + let currentFrame = Math.round(e.currentTime); + + if((e.direction == 1 && currentFrame >= needFrame) || + (e.direction == -1 && currentFrame <= needFrame)) { + animation.setSpeed(1); + animation.pause(); + } + }); + }); + + const codeInput = page.pageEl.querySelector('#code') as HTMLInputElement; + const codeInputLabel = codeInput.nextElementSibling as HTMLLabelElement; + const editButton = page.pageEl.querySelector('.phone-edit') as HTMLElement; + + if(EDITONSAMEPAGE) { + let editable = false; + let changePhonePromise: Promise; + + let changePhone = () => { + if(changePhonePromise) return; + + let phone_number = '+' + headerElement.innerText.replace(/\D/g, ''); + if(authCode.phone_number == phone_number) return; + + codeInput.setAttribute('disabled', 'true'); + + changePhonePromise = apiManager.invokeApi('auth.sendCode', { + /* flags: 0, */ + phone_number: phone_number, + api_id: Config.App.id, + api_hash: Config.App.hash, + settings: { + _: 'codeSettings', // that's how we sending Type + flags: 0 + } + /* lang_code: navigator.language || 'en' */ + }).then((code: any) => { + console.log('got code 2', code); + + authCode = Object.assign(code, {phone_number}); + + changePhonePromise = undefined; + codeInput.removeAttribute('disabled'); + codeInput.focus(); + }).catch(err => { + switch(err.type) { + case 'PHONE_NUMBER_INVALID': + headerElement.classList.add('error'); + editable = true; + headerElement.setAttribute('contenteditable', '' + editable); + headerElement.focus(); + break; + default: + codeInputLabel.innerText = err.type; + break; + } + + changePhonePromise = undefined; + codeInput.removeAttribute('disabled'); + }); + }; + + headerElement.addEventListener('keypress', function(this, e) { + if(e.key == 'Enter') { + editable = false; + headerElement.setAttribute('contenteditable', '' + editable); + changePhone(); + } + + if(/\D/.test(e.key)) { + e.preventDefault(); + return false; + } + + this.classList.remove('error'); + }); + + editButton.addEventListener('click', function() { + if(changePhonePromise) return; + + editable = !editable; + headerElement.setAttribute('contenteditable', '' + editable); + + if(!editable) changePhone(); + }); + } else { + editButton.addEventListener('click', function() { + return pageSignIn.mount(); + }); + } + + let submitCode = (code: string) => { + codeInput.setAttribute('disabled', 'true'); + + let params = { + phone_number: authCode.phone_number, + phone_code_hash: authCode.phone_code_hash, + phone_code: code + }; + + console.log('invoking auth.signIn with params:', params); + + apiManager.invokeApi('auth.signIn', params) + .then((response: any) => { + console.log('auth.signIn response:', response); + + switch(response._) { + case 'auth.authorization': + apiManager.setUserAuth({ + id: response.user.id + }); + + pageIm.mount(); + if(animation) animation.destroy(); + break; + case 'auth.authorizationSignUpRequired': + console.log('Registration needed!'); + + pageSignUp.mount({ + 'phone_number': authCode.phone_number, + 'phone_code_hash': authCode.phone_code_hash + }); + + if(animation) animation.destroy(); + break; + default: + codeInput.innerText = response._; + break; + } + }).catch(err => { + codeInput.removeAttribute('disabled'); + + switch(err.type) { + case 'SESSION_PASSWORD_NEEDED': + console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED'); + err.handled = true; + if(animation) animation.destroy(); + pagePassword.mount(); + break; + case 'PHONE_CODE_EMPTY': + case 'PHONE_CODE_INVALID': + codeInput.classList.add('error'); + codeInputLabel.innerText = 'Invalid Code'; + break; + default: + codeInputLabel.innerText = err.type; + break; + } + }); + }; + + const max = 45; + // 1st symbol = frame 15 + // end symbol = frame 165 + codeInput.addEventListener('input', function(this: typeof codeInput, e) { + this.classList.remove('error'); + + this.value = this.value.replace(/\D/g, ''); + if(this.value.length > CODELENGTH) { + this.value = this.value.slice(0, CODELENGTH); + } + + let length = this.value.length; + if(length == CODELENGTH) { // submit code + submitCode(this.value); + } else if(length == lastLength) { + return; + } + + lastLength = length; + + if(!animation) return; + + let frame: number; + if(length) frame = Math.round((length > max ? max : length) * (165 / max) + 11.33); + else frame = 0; + //animation.playSegments([1, 2]); + + let direction = needFrame > frame ? -1 : 1; + //console.log('keydown', length, frame, direction); + + animation.setDirection(direction); + if(needFrame != 0 && frame == 0) { + animation.setSpeed(7); + } + /* let diff = Math.abs(needFrame - frame * direction); + if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */ + needFrame = frame; + + animation.play(); + + /* animation.goToAndStop(15, true); */ + //animation.goToAndStop(length / max * ); + }); +}; + +const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof authCode) => { + authCode = _authCode; + + if(!headerElement) { + headerElement = page.pageEl.getElementsByClassName('phone')[0] as HTMLHeadElement; + sentTypeElement = page.pageEl.getElementsByClassName('sent-type')[0] as HTMLParagraphElement; + } + + //let LottieLoader = (await import('../lib/lottieLoader')).default; + + headerElement.innerText = authCode.phone_number; + switch(authCode.type._) { + case 'auth.sentCodeTypeSms': + sentTypeElement.innerHTML = 'We have sent you an SMS
with the code.'; + break; + case 'auth.sentCodeTypeApp': + sentTypeElement.innerHTML = 'We have sent you a message in Telegram
with the code.'; + break; + case 'auth.sentCodeTypeCall': + sentTypeElement.innerHTML = 'We will call you and voice
the code.'; + break; + default: + sentTypeElement.innerHTML = `Please check everything
for a code (type: ${authCode.type._})`; + break; + } +}); + +export default page; diff --git a/src/pages/pageIm.ts b/src/pages/pageIm.ts new file mode 100644 index 00000000..d9f1e67c --- /dev/null +++ b/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; diff --git a/src/components/pagePassword.ts b/src/pages/pagePassword.ts similarity index 81% rename from src/components/pagePassword.ts rename to src/pages/pagePassword.ts index f7d7682d..8dda12c5 100644 --- a/src/components/pagePassword.ts +++ b/src/pages/pagePassword.ts @@ -1,136 +1,131 @@ -import pageIm from './pageIm'; -import CryptoWorker from '../lib/crypto/cryptoworker'; -import { putPreloader } from './misc'; - -import LottieLoader from '../lib/lottieLoader'; -import passwordManager from '../lib/mtproto/passwordManager'; -import apiManager from '../lib/mtproto/apiManager'; - -let installed = false; - -export default async() => { - //let LottieLoader = (await import('../lib/lottieLoader')).default; - - if(installed) return; - installed = true; - - let needFrame = 0; - let animation: /* AnimationItem */any = undefined; - - let passwordVisible = false; - let pageElement = document.body.getElementsByClassName('page-password')[0] as HTMLDivElement; - pageElement.style.display = ''; - - fetch('assets/img/TwoFactorSetupMonkeyClose.tgs') - .then(res => res.arrayBuffer()) - .then(async(data) => { - let str = await CryptoWorker.gzipUncompress(data, true); - - animation = await LottieLoader.loadAnimation({ - container: pageElement.querySelector('.auth-image'), - renderer: 'svg', - loop: false, - autoplay: false, - animationData: JSON.parse(str) - }); - - console.log(animation.getDuration(true)); - //animation.goToAndStop(822); - - animation.addEventListener('enterFrame', (e: any) => { - //console.log('enterFrame', e, needFrame); - let currentFrame = Math.round(e.currentTime); - - if((e.direction == 1 && currentFrame >= needFrame) || - (e.direction == -1 && currentFrame <= needFrame)) { - animation.setSpeed(1); - animation.pause(); - } - }); - - needFrame = 49; - animation.play(); - }); - - const btnNext = pageElement.querySelector('button') as HTMLButtonElement; - const passwordInput = document.getElementById('password') as HTMLInputElement; - //const passwordInputLabel = passwordInput.nextElementSibling as HTMLLabelElement; - const toggleVisible = pageElement.querySelector('.toggle-visible') as HTMLSpanElement; - - let handleError = (err: any) => { - btnNext.removeAttribute('disabled'); - - switch(err.type) { - default: - btnNext.innerText = err.type; - break; - } - }; - - toggleVisible.addEventListener('click', function(this, e) { - if(!passwordVisible) { - this.classList.add('tgico-eye2'); - passwordInput.setAttribute('type', 'text'); - animation.setDirection(-1); - needFrame = 0; - animation.play(); - } else { - this.classList.remove('tgico-eye2'); - passwordInput.setAttribute('type', 'password'); - animation.setDirection(1); - needFrame = 49; - animation.play(); - } - - passwordVisible = !passwordVisible; - }); - - btnNext.addEventListener('click', function(this, e) { - if(!passwordInput.value.length) { - passwordInput.classList.add('error'); - return; - } - - this.setAttribute('disabled', 'true'); - let value = passwordInput.value; - - this.textContent = 'PLEASE WAIT...'; - putPreloader(this); - - passwordManager.getState() - .then(state => { - console.log(state); - passwordManager.check(state, value).then((response: any) => { - console.log('passwordManager response:', response); - - switch(response._) { - case 'auth.authorization': - apiManager.setUserAuth({ - id: response.user.id - }); - - pageElement.style.display = 'none'; - pageIm(); - if(animation) animation.destroy(); - break; - default: - btnNext.removeAttribute('disabled'); - btnNext.innerText = response._; - break; - } - }).catch(handleError); - }).catch(handleError); - }); - - passwordInput.addEventListener('keypress', function(this, e) { - this.classList.remove('error'); - - if(e.key == 'Enter') { - return btnNext.click(); - } - }); - - /* passwordInput.addEventListener('input', function(this, e) { - - }); */ -}; +import pageIm from './pageIm'; +import CryptoWorker from '../lib/crypto/cryptoworker'; +import { putPreloader } from '../components/misc'; + +import LottieLoader from '../lib/lottieLoader'; +import passwordManager from '../lib/mtproto/passwordManager'; +import apiManager from '../lib/mtproto/apiManager'; +import Page from './page'; + +let onFirstMount = () => { + let needFrame = 0; + let animation: /* AnimationItem */any = undefined; + + let passwordVisible = false; + + fetch('assets/img/TwoFactorSetupMonkeyClose.tgs') + .then(res => res.arrayBuffer()) + .then(async(data) => { + let str = await CryptoWorker.gzipUncompress(data, true); + + animation = await LottieLoader.loadAnimation({ + container: page.pageEl.querySelector('.auth-image'), + renderer: 'svg', + loop: false, + autoplay: false, + animationData: JSON.parse(str) + }); + + console.log(animation.getDuration(true)); + //animation.goToAndStop(822); + + animation.addEventListener('enterFrame', (e: any) => { + //console.log('enterFrame', e, needFrame); + let currentFrame = Math.round(e.currentTime); + + if((e.direction == 1 && currentFrame >= needFrame) || + (e.direction == -1 && currentFrame <= needFrame)) { + animation.setSpeed(1); + animation.pause(); + } + }); + + needFrame = 49; + animation.play(); + }); + + 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; + + let handleError = (err: any) => { + btnNext.removeAttribute('disabled'); + + switch(err.type) { + default: + btnNext.innerText = err.type; + break; + } + }; + + toggleVisible.addEventListener('click', function(this, e) { + if(!passwordVisible) { + this.classList.add('tgico-eye2'); + passwordInput.setAttribute('type', 'text'); + animation.setDirection(-1); + needFrame = 0; + animation.play(); + } else { + this.classList.remove('tgico-eye2'); + passwordInput.setAttribute('type', 'password'); + animation.setDirection(1); + needFrame = 49; + animation.play(); + } + + passwordVisible = !passwordVisible; + }); + + btnNext.addEventListener('click', function(this, e) { + if(!passwordInput.value.length) { + passwordInput.classList.add('error'); + return; + } + + this.setAttribute('disabled', 'true'); + let value = passwordInput.value; + + this.textContent = 'PLEASE WAIT...'; + putPreloader(this); + + passwordManager.getState() + .then(state => { + console.log(state); + passwordManager.check(state, value).then((response: any) => { + console.log('passwordManager response:', response); + + switch(response._) { + case 'auth.authorization': + apiManager.setUserAuth({ + id: response.user.id + }); + + pageIm.mount(); + if(animation) animation.destroy(); + break; + default: + btnNext.removeAttribute('disabled'); + btnNext.innerText = response._; + break; + } + }).catch(handleError); + }).catch(handleError); + }); + + passwordInput.addEventListener('keypress', function(this, e) { + this.classList.remove('error'); + + if(e.key == 'Enter') { + return btnNext.click(); + } + }); + + /* passwordInput.addEventListener('input', function(this, e) { + + }); */ +}; + +const page = new Page('page-password', true, onFirstMount); + +export default page; diff --git a/src/components/pageSignIn.ts b/src/pages/pageSignIn.ts similarity index 85% rename from src/components/pageSignIn.ts rename to src/pages/pageSignIn.ts index 7494237b..2ab016cc 100644 --- a/src/components/pageSignIn.ts +++ b/src/pages/pageSignIn.ts @@ -1,263 +1,255 @@ -import { putPreloader, formatPhoneNumber } from "./misc"; -import Scrollable from './scrollable'; -import {RichTextProcessor} from '../lib/richtextprocessor'; -import * as Config from '../lib/config'; - -import { findUpTag } from "../lib/utils"; -import pageAuthCode from "./pageAuthCode"; -import apiManager from "../lib/mtproto/apiManager"; - -let installed = false; - -type Country = { - name: string, - code: string, - phoneCode: string, - pattern: string, - emoji: string, - li?: HTMLLIElement[] -}; - -//import _countries from '../countries_pretty.json'; - -export default () => { -//export default () => import('../countries.json').then(_countries => { - //let pageAuthCode = await import('./pageAuthCode'); - //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; - pageEl.style.display = ''; - - let btnNext = pageEl.querySelector('button'); - - if(installed) { - btnNext.textContent = 'NEXT'; - btnNext.removeAttribute('disabled'); - return; - } - - installed = true; - - //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 lastCountrySelected = ''; - - var selectCountryCode = pageEl.querySelector('input[name="countryCode"]')! as HTMLInputElement; - var parent = selectCountryCode.parentElement; - - var wrapper = document.createElement('div'); - wrapper.classList.add('select-wrapper', 'z-depth-4'); - - var list = document.createElement('ul'); - wrapper.appendChild(list); - - //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); - let scroll = new Scrollable(wrapper); - - let initedSelect = false; - - selectCountryCode.addEventListener('focus', function(this: typeof selectCountryCode, e) { - /* this.removeAttribute('readonly'); */ - if(!initedSelect) { - countries.forEach((c) => { - initedSelect = true; - - /* let unified = unifiedCountryCodeEmoji(c.code); - let emoji = unified.split('-').reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), ''); */ - //let emoji = countryCodeEmoji(c.code); - let emoji = c.emoji; - - let liArr: Array = []; - c.phoneCode.split(' and ').forEach((phoneCode: string) => { - let li = document.createElement('li'); - var spanEmoji = document.createElement('span'); - /* spanEmoji.innerHTML = countryCodeEmoji(c.code); */ - //spanEmoji.classList.add('emoji-outer', 'emoji-sizer'); - //spanEmoji.innerHTML = ``; - - - - let kek = RichTextProcessor.wrapRichText(emoji); - //console.log(c.name, emoji, kek, spanEmoji.innerHTML); - - li.appendChild(spanEmoji); - spanEmoji.outerHTML = kek; - - li.append(c.name); - - var span = document.createElement('span'); - span.classList.add('phone-code'); - span.innerText = '+' + phoneCode; - li.appendChild(span); - - liArr.push(li); - list.append(li); - }); - - c.li = liArr; - }); - - list.addEventListener('mousedown', function(e) { - let target = e.target as HTMLElement; - if(target.tagName != 'LI') target = findUpTag(target, 'LI'); - - let countryName = target.childNodes[1].textContent;//target.innerText.split('\n').shift(); - let phoneCode = target.querySelector('.phone-code').innerText; - - selectCountryCode.value = countryName; - lastCountrySelected = countryName; - - telEl.value = phoneCode; - setTimeout(() => telEl.focus(), 0); - console.log('clicked', e, countryName, phoneCode); - }); - } - - parent.appendChild(wrapper); - }/* , {once: true} */); - selectCountryCode.addEventListener('blur', function(this: typeof selectCountryCode, e) { - parent.removeChild(wrapper); - e.cancelBubble = true; - }, {capture: true}); - - selectCountryCode.addEventListener('keyup', function(this: typeof selectCountryCode, e) { - if(e.ctrlKey || e.key == 'Control') return false; - - //let i = new RegExp('^' + this.value, 'i'); - let _value = this.value.toLowerCase(); - let matches: Country[] = []; - countries.forEach((c) => { - let good = c.name.toLowerCase().indexOf(_value) !== -1/* == 0 */;//i.test(c.name); - - c.li.forEach(li => li.style.display = good ? '' : 'none'); - if(good) matches.push(c); - }); - - if(matches.length == 1 && matches[0].li.length == 1) { - if(matches[0].name == lastCountrySelected) return false; - console.log('clicking', matches[0]); - - var clickEvent = document.createEvent('MouseEvents'); - clickEvent.initEvent('mousedown', true, true); - matches[0].li[0].dispatchEvent(clickEvent); - return false; - } else if(matches.length == 0) { - countries.forEach((c) => { - c.li.forEach(li => li.style.display = ''); - }); - } - }); - - let arrowDown = pageEl.querySelector('.arrow-down') as HTMLSpanElement; - arrowDown.addEventListener('mousedown', function(this: typeof arrowDown, e) { - e.cancelBubble = true; - e.preventDefault(); - if(selectCountryCode.matches(':focus')) selectCountryCode.blur(); - else selectCountryCode.focus(); - }); - - let sortedCountries = countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length); - - let telEl = pageEl.querySelector('input[name="phone"]') as HTMLInputElement; - telEl.addEventListener('input', function(this: typeof telEl, e) { - this.classList.remove('error'); - - let {formatted, country} = formatPhoneNumber(this.value); - this.value = formatted ? '+' + formatted : ''; - - console.log(formatted, country); - - let countryName = country ? country.name : ''/* 'Unknown' */; - if(countryName != selectCountryCode.value) { - selectCountryCode.value = countryName; - lastCountrySelected = countryName; - } - - if(country && (this.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) { - btnNext.style.visibility = ''; - } else { - btnNext.style.visibility = 'hidden'; - } - }); - - telEl.addEventListener('keypress', function(this: typeof telEl, e) { - if(this.value.length >= 9 && e.key == 'Enter') { - return btnNext.click(); - } else if(/\D/.test(e.key)) { - e.preventDefault(); - return false; - } - }); - - /* telEl.addEventListener('focus', function(this: typeof telEl, e) { - this.removeAttribute('readonly'); // fix autocomplete - });*/ - - /* authorizer.auth(2); - networkerFactory.startAll(); */ - - btnNext.addEventListener('click', function(this: HTMLElement, e) { - this.setAttribute('disabled', 'true'); - - this.textContent = 'PLEASE WAIT...'; - putPreloader(this); - //this.innerHTML = 'PLEASE WAIT...'; - - let phone_number = telEl.value; - apiManager.invokeApi('auth.sendCode', { - /* flags: 0, */ - phone_number: phone_number, - api_id: Config.App.id, - api_hash: Config.App.hash, - settings: { - _: 'codeSettings', // that's how we sending Type - flags: 0 - } - /* lang_code: navigator.language || 'en' */ - }).then((code: any) => { - console.log('got code', code); - - pageEl.style.display = 'none'; - - // @ts-ignore - pageAuthCode(Object.assign(code, {phone_number: phone_number})); - }).catch(err => { - this.removeAttribute('disabled'); - - this.innerText = 'NEXT'; - switch(err.type) { - case 'PHONE_NUMBER_INVALID': - telEl.classList.add('error'); - break; - default: - this.innerText = err.type; - break; - } - }); - }); - - let tryAgain = () => { - apiManager.invokeApi('help.getNearestDc').then((nearestDcResult: any) => { - if(nearestDcResult.nearest_dc != nearestDcResult.this_dc) { - //MTProto.apiManager.baseDcID = nearestDcResult.nearest_dc; - apiManager.getNetworker(nearestDcResult.nearest_dc); - } - - return nearestDcResult; - }).then((nearestDcResult: any) => { - let country = countries.find((c) => c.code == nearestDcResult.country); - if(country) { - if(!selectCountryCode.value.length && !telEl.value.length) { - selectCountryCode.value = country.name; - lastCountrySelected = country.name; - telEl.value = '+' + country.phoneCode.split(' and ').shift(); - } - } - - return console.log('woohoo', nearestDcResult, country); - })//.catch(tryAgain); - }; - - tryAgain(); - -}; +import { putPreloader, formatPhoneNumber } from "../components/misc"; +import Scrollable from '../components/scrollable'; +import {RichTextProcessor} from '../lib/richtextprocessor'; +import * as Config from '../lib/config'; + +import { findUpTag } from "../lib/utils"; +import pageAuthCode from "./pageAuthCode"; +import apiManager from "../lib/mtproto/apiManager"; +import Page from "./page"; + +type Country = { + name: string, + code: string, + phoneCode: string, + pattern: string, + emoji: string, + li?: HTMLLIElement[] +}; + +//import _countries from '../countries_pretty.json'; +let btnNext: HTMLButtonElement = null; + +let onFirstMount = () => { + //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 lastCountrySelected = ''; + + var selectCountryCode = page.pageEl.querySelector('input[name="countryCode"]')! as HTMLInputElement; + var parent = selectCountryCode.parentElement; + + var wrapper = document.createElement('div'); + wrapper.classList.add('select-wrapper', 'z-depth-4'); + + var list = document.createElement('ul'); + wrapper.appendChild(list); + + //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); + let scroll = new Scrollable(wrapper); + + let initedSelect = false; + + selectCountryCode.addEventListener('focus', function(this: typeof selectCountryCode, e) { + /* this.removeAttribute('readonly'); */ + if(!initedSelect) { + countries.forEach((c) => { + initedSelect = true; + + /* let unified = unifiedCountryCodeEmoji(c.code); + let emoji = unified.split('-').reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), ''); */ + //let emoji = countryCodeEmoji(c.code); + let emoji = c.emoji; + + let liArr: Array = []; + c.phoneCode.split(' and ').forEach((phoneCode: string) => { + let li = document.createElement('li'); + var spanEmoji = document.createElement('span'); + /* spanEmoji.innerHTML = countryCodeEmoji(c.code); */ + //spanEmoji.classList.add('emoji-outer', 'emoji-sizer'); + //spanEmoji.innerHTML = ``; + + + + let kek = RichTextProcessor.wrapRichText(emoji); + //console.log(c.name, emoji, kek, spanEmoji.innerHTML); + + li.appendChild(spanEmoji); + spanEmoji.outerHTML = kek; + + li.append(c.name); + + var span = document.createElement('span'); + span.classList.add('phone-code'); + span.innerText = '+' + phoneCode; + li.appendChild(span); + + liArr.push(li); + list.append(li); + }); + + c.li = liArr; + }); + + list.addEventListener('mousedown', function(e) { + let target = e.target as HTMLElement; + if(target.tagName != 'LI') target = findUpTag(target, 'LI'); + + let countryName = target.childNodes[1].textContent;//target.innerText.split('\n').shift(); + let phoneCode = target.querySelector('.phone-code').innerText; + + selectCountryCode.value = countryName; + lastCountrySelected = countryName; + + telEl.value = phoneCode; + setTimeout(() => telEl.focus(), 0); + console.log('clicked', e, countryName, phoneCode); + }); + } + + parent.appendChild(wrapper); + }/* , {once: true} */); + selectCountryCode.addEventListener('blur', function(this: typeof selectCountryCode, e) { + parent.removeChild(wrapper); + e.cancelBubble = true; + }, {capture: true}); + + selectCountryCode.addEventListener('keyup', function(this: typeof selectCountryCode, e) { + if(e.ctrlKey || e.key == 'Control') return false; + + //let i = new RegExp('^' + this.value, 'i'); + let _value = this.value.toLowerCase(); + let matches: Country[] = []; + countries.forEach((c) => { + let good = c.name.toLowerCase().indexOf(_value) !== -1/* == 0 */;//i.test(c.name); + + c.li.forEach(li => li.style.display = good ? '' : 'none'); + if(good) matches.push(c); + }); + + if(matches.length == 1 && matches[0].li.length == 1) { + if(matches[0].name == lastCountrySelected) return false; + console.log('clicking', matches[0]); + + var clickEvent = document.createEvent('MouseEvents'); + clickEvent.initEvent('mousedown', true, true); + matches[0].li[0].dispatchEvent(clickEvent); + return false; + } else if(matches.length == 0) { + countries.forEach((c) => { + c.li.forEach(li => li.style.display = ''); + }); + } + }); + + let arrowDown = page.pageEl.querySelector('.arrow-down') as HTMLSpanElement; + arrowDown.addEventListener('mousedown', function(this: typeof arrowDown, e) { + e.cancelBubble = true; + e.preventDefault(); + if(selectCountryCode.matches(':focus')) selectCountryCode.blur(); + else selectCountryCode.focus(); + }); + + let sortedCountries = countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length); + + let telEl = page.pageEl.querySelector('input[name="phone"]') as HTMLInputElement; + telEl.addEventListener('input', function(this: typeof telEl, e) { + this.classList.remove('error'); + + let {formatted, country} = formatPhoneNumber(this.value); + this.value = formatted ? '+' + formatted : ''; + + console.log(formatted, country); + + let countryName = country ? country.name : ''/* 'Unknown' */; + if(countryName != selectCountryCode.value) { + selectCountryCode.value = countryName; + lastCountrySelected = countryName; + } + + if(country && (this.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) { + btnNext.style.visibility = ''; + } else { + btnNext.style.visibility = 'hidden'; + } + }); + + telEl.addEventListener('keypress', function(this: typeof telEl, e) { + if(this.value.length >= 9 && e.key == 'Enter') { + return btnNext.click(); + } else if(/\D/.test(e.key)) { + e.preventDefault(); + return false; + } + }); + + /* telEl.addEventListener('focus', function(this: typeof telEl, e) { + this.removeAttribute('readonly'); // fix autocomplete + });*/ + + /* authorizer.auth(2); + networkerFactory.startAll(); */ + + btnNext.addEventListener('click', function(this: HTMLElement, e) { + this.setAttribute('disabled', 'true'); + + this.textContent = 'PLEASE WAIT...'; + putPreloader(this); + //this.innerHTML = 'PLEASE WAIT...'; + + let phone_number = telEl.value; + apiManager.invokeApi('auth.sendCode', { + /* flags: 0, */ + phone_number: phone_number, + api_id: Config.App.id, + api_hash: Config.App.hash, + settings: { + _: 'codeSettings', // that's how we sending Type + flags: 0 + } + /* lang_code: navigator.language || 'en' */ + }).then((code: any) => { + console.log('got code', code); + + pageAuthCode.mount(Object.assign(code, {phone_number: phone_number})); + }).catch(err => { + this.removeAttribute('disabled'); + + this.innerText = 'NEXT'; + switch(err.type) { + case 'PHONE_NUMBER_INVALID': + telEl.classList.add('error'); + break; + default: + console.error('auth.sendCode error:', err); + this.innerText = err.type; + break; + } + }); + }); + + let tryAgain = () => { + apiManager.invokeApi('help.getNearestDc').then((nearestDcResult: any) => { + if(nearestDcResult.nearest_dc != nearestDcResult.this_dc) { + //MTProto.apiManager.baseDcID = nearestDcResult.nearest_dc; + apiManager.getNetworker(nearestDcResult.nearest_dc); + } + + return nearestDcResult; + }).then((nearestDcResult: any) => { + let country = countries.find((c) => c.code == nearestDcResult.country); + if(country) { + if(!selectCountryCode.value.length && !telEl.value.length) { + selectCountryCode.value = country.name; + lastCountrySelected = country.name; + telEl.value = '+' + country.phoneCode.split(' and ').shift(); + } + } + + return console.log('woohoo', nearestDcResult, country); + })//.catch(tryAgain); + }; + + tryAgain(); +}; + +const page = new Page('page-sign', true, onFirstMount, () => { + if(!btnNext) { + btnNext = page.pageEl.querySelector('button'); + } + + btnNext.textContent = 'NEXT'; + btnNext.removeAttribute('disabled'); +}); + +export default page; diff --git a/src/components/pageSignUp.ts b/src/pages/pageSignUp.ts similarity index 89% rename from src/components/pageSignUp.ts rename to src/pages/pageSignUp.ts index deab03f0..1a0b190b 100644 --- a/src/components/pageSignUp.ts +++ b/src/pages/pageSignUp.ts @@ -1,198 +1,195 @@ -import {putPreloader} from './misc'; - -let installed = false; -let authCode: { - 'phone_number': string, - 'phone_code_hash': string -} = null; - -import resizeableImage from '../lib/cropper'; -import pageIm from './pageIm'; -import apiManager from '../lib/mtproto/apiManager'; -import apiFileManager from '../lib/mtproto/apiFileManager'; - -export default (_authCode: typeof authCode) => { - authCode = _authCode; - if(installed) return; - installed = true; - - let pageElement = document.body.getElementsByClassName('page-signUp')[0] as HTMLDivElement; - pageElement.style.display = ''; - - const avatarInput = document.getElementById('avatar-input') as HTMLInputElement; - const avatarPopup = pageElement.getElementsByClassName('popup-avatar')[0]; - const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement; - const cropContainer = avatarPopup.getElementsByClassName('crop')[0]; - let avatarImage = new Image(); - cropContainer.append(avatarImage); - - let avatarBlob: Blob; - - (avatarPopup.getElementsByClassName('popup-close')[0] as HTMLButtonElement) - .addEventListener('click', function(this, e) { - /* let popup = findUpClassName(this, 'popup'); - popup.classList.remove('active'); */ - - setTimeout(() => { - cropper.removeHandlers(); - if(avatarImage) { - avatarImage.remove(); - } - }, 200); - - /* e.cancelBubble = true; - return false; */ - }); - - let cropper = { - crop: () => {}, - removeHandlers: () => {} - }; - - // apply - avatarPopup.getElementsByClassName('btn-crop')[0].addEventListener('click', () => { - cropper.crop(); - avatarPopup.classList.remove('active'); - cropper.removeHandlers(); - - avatarPreview.toBlob(blob => { - avatarBlob = blob; // save blob to send after reg - - // darken - let ctx = avatarPreview.getContext('2d'); - ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; - ctx.fillRect(0, 0, avatarPreview.width, avatarPreview.height); - }, 'image/jpeg', 1); - - avatarImage.remove(); - }); - - avatarInput.addEventListener('change', (e: any) => { - var file = e.target.files[0]; - if(!file) { - return; - } - - var reader = new FileReader(); - reader.onload = (e) => { - var contents = e.target.result as string; - - avatarImage = new Image(); - cropContainer.append(avatarImage); - avatarImage.src = contents; - - avatarImage.onload = () => { - cropper = resizeableImage(avatarImage, avatarPreview); - avatarInput.value = ''; - }; - - avatarPopup.classList.add('active'); - }; - - reader.readAsDataURL(file); - }, false); - - pageElement.querySelector('.auth-image').addEventListener('click', () => { - avatarInput.click(); - }); - - const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement; - - let handleInput = function(this: typeof fieldName, e: Event) { - let name = fieldName.value || ''; - let lastName = fieldLastName.value || ''; - - let fullName = name || lastName - ? (name + ' ' + lastName).trim() - : 'Your Name'; - - if(headerName.innerText != fullName) headerName.innerText = fullName; - this.classList.remove('error'); - }; - - let sendAvatar = () => new Promise((resolve, reject) => { - if(!avatarBlob) { - console.log('User has not selected avatar'); - return resolve(); - } - - console.log('invoking uploadFile...'); - apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => { - console.log('uploaded smthn', inputFile); - - apiManager.invokeApi('photos.uploadProfilePhoto', { - file: inputFile - }).then((updateResult) => { - console.log('updated photo!'); - resolve(); - }, reject); - }, reject); - }); - - const fieldName = document.getElementById('name') as HTMLInputElement; - fieldName.addEventListener('input', handleInput); - - const fieldLastName = document.getElementById('lastName') as HTMLInputElement; - fieldLastName.addEventListener('input', handleInput); - - const signUpButton = document.getElementById('signUp') as HTMLButtonElement; - signUpButton.addEventListener('click', function(this: typeof signUpButton, e) { - this.setAttribute('disabled', 'true'); - - if(!fieldName.value.length) { - fieldName.classList.add('error'); - return false; - } - - let name = fieldName.value; - let lastName = fieldLastName.value; - - let params = { - 'phone_number': authCode.phone_number, - 'phone_code_hash': authCode.phone_code_hash, - 'first_name': name, - 'last_name': lastName - }; - - console.log('invoking auth.signUp with params:', params); - - this.textContent = 'PLEASE WAIT...'; - putPreloader(this); - - apiManager.invokeApi('auth.signUp', params) - .then((response: any) => { - console.log('auth.signUp response:', response); - - switch(response._) { - case 'auth.authorization': // success - apiManager.setUserAuth({ // warning - id: response.user.id - }); - - sendAvatar().then(() => { - pageElement.style.display = 'none'; - pageIm(); - }, () => { - pageElement.style.display = 'none'; - pageIm(); - }); - - break; - default: - this.innerText = response._; - 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) { - default: - this.innerText = err.type; - break; - } - }); - }); -}; +import {putPreloader} from '../components/misc'; +import resizeableImage from '../lib/cropper'; +import pageIm from './pageIm'; +import apiManager from '../lib/mtproto/apiManager'; +import apiFileManager from '../lib/mtproto/apiFileManager'; +import Page from './page'; + +let authCode: { + 'phone_number': string, + 'phone_code_hash': string +} = null; + +let onFirstMount = () => { + const pageElement = page.pageEl; + const avatarInput = document.getElementById('avatar-input') as HTMLInputElement; + const avatarPopup = pageElement.getElementsByClassName('popup-avatar')[0]; + const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement; + const cropContainer = avatarPopup.getElementsByClassName('crop')[0]; + let avatarImage = new Image(); + cropContainer.append(avatarImage); + + let avatarBlob: Blob; + + (avatarPopup.getElementsByClassName('popup-close')[0] as HTMLButtonElement) + .addEventListener('click', function(this, e) { + /* let popup = findUpClassName(this, 'popup'); + popup.classList.remove('active'); */ + + setTimeout(() => { + cropper.removeHandlers(); + if(avatarImage) { + avatarImage.remove(); + } + }, 200); + + /* e.cancelBubble = true; + return false; */ + }); + + let cropper = { + crop: () => {}, + removeHandlers: () => {} + }; + + // apply + avatarPopup.getElementsByClassName('btn-crop')[0].addEventListener('click', () => { + cropper.crop(); + avatarPopup.classList.remove('active'); + cropper.removeHandlers(); + + avatarPreview.toBlob(blob => { + avatarBlob = blob; // save blob to send after reg + + // darken + let ctx = avatarPreview.getContext('2d'); + ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; + ctx.fillRect(0, 0, avatarPreview.width, avatarPreview.height); + }, 'image/jpeg', 1); + + avatarImage.remove(); + }); + + avatarInput.addEventListener('change', (e: any) => { + var file = e.target.files[0]; + if(!file) { + return; + } + + var reader = new FileReader(); + reader.onload = (e) => { + var contents = e.target.result as string; + + avatarImage = new Image(); + cropContainer.append(avatarImage); + avatarImage.src = contents; + + avatarImage.onload = () => { + cropper = resizeableImage(avatarImage, avatarPreview); + avatarInput.value = ''; + }; + + avatarPopup.classList.add('active'); + }; + + reader.readAsDataURL(file); + }, false); + + pageElement.querySelector('.auth-image').addEventListener('click', () => { + avatarInput.click(); + }); + + const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement; + + let handleInput = function(this: typeof fieldName, e: Event) { + let name = fieldName.value || ''; + let lastName = fieldLastName.value || ''; + + let fullName = name || lastName + ? (name + ' ' + lastName).trim() + : 'Your Name'; + + if(headerName.innerText != fullName) headerName.innerText = fullName; + this.classList.remove('error'); + }; + + let sendAvatar = () => new Promise((resolve, reject) => { + if(!avatarBlob) { + console.log('User has not selected avatar'); + return resolve(); + } + + console.log('invoking uploadFile...'); + apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => { + console.log('uploaded smthn', inputFile); + + apiManager.invokeApi('photos.uploadProfilePhoto', { + file: inputFile + }).then((updateResult) => { + console.log('updated photo!'); + resolve(); + }, reject); + }, reject); + }); + + const fieldName = document.getElementById('name') as HTMLInputElement; + fieldName.addEventListener('input', handleInput); + + const fieldLastName = document.getElementById('lastName') as HTMLInputElement; + fieldLastName.addEventListener('input', handleInput); + + const signUpButton = document.getElementById('signUp') as HTMLButtonElement; + signUpButton.addEventListener('click', function(this: typeof signUpButton, e) { + this.setAttribute('disabled', 'true'); + + if(!fieldName.value.length) { + fieldName.classList.add('error'); + return false; + } + + let name = fieldName.value; + let lastName = fieldLastName.value; + + let params = { + 'phone_number': authCode.phone_number, + 'phone_code_hash': authCode.phone_code_hash, + 'first_name': name, + 'last_name': lastName + }; + + console.log('invoking auth.signUp with params:', params); + + this.textContent = 'PLEASE WAIT...'; + putPreloader(this); + + apiManager.invokeApi('auth.signUp', params) + .then((response: any) => { + console.log('auth.signUp response:', response); + + switch(response._) { + case 'auth.authorization': // success + apiManager.setUserAuth({ // warning + id: response.user.id + }); + + sendAvatar().then(() => { + pageIm.mount(); + }, () => { + pageIm.mount(); + }); + + break; + default: + this.innerText = response._; + 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) { + default: + this.innerText = err.type; + break; + } + }); + }); +}; + +const page = new Page('page-signUp', true, onFirstMount, (_authCode: typeof authCode) => { + authCode = _authCode; +}); + +export default page; diff --git a/src/pages/pagesManager.ts b/src/pages/pagesManager.ts new file mode 100644 index 00000000..e1fda750 --- /dev/null +++ b/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; + 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; \ No newline at end of file diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index 9bc4ba3c..34eec602 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -62,7 +62,7 @@ } &.active { - margin-top: 1px; + //margin-top: 1px; opacity: 1; visibility: visible; color: #707579; diff --git a/src/scss/style.scss b/src/scss/style.scss index d935cbeb..b03ca90d 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -133,8 +133,8 @@ input { .btn-icon { text-align: center; - font-size: 1.65rem; - line-height: 1.65rem; + font-size: 1.5rem; + line-height: 1.5rem; border-radius: 50%; -webkit-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 { .auth-image { width: 160px; @@ -1302,7 +1328,7 @@ div.scrollable::-webkit-scrollbar-thumb { max-height: 100%; //position: relative; - will-change: transform; + //will-change: transform; transform: translateZ(0); -webkit-transform: translateZ(0); @@ -1412,12 +1438,13 @@ div.scrollable::-webkit-scrollbar-thumb { .tabs-container { min-width: 100%; + width: 100%; display: flex; /* overflow: hidden; */ overflow-x: hidden; &.animated { - transition: .2s margin-left; + transition: .3s transform; } > div {