Eduard Kuzmenko
4 years ago
3 changed files with 968 additions and 0 deletions
@ -0,0 +1,333 @@
@@ -0,0 +1,333 @@
|
||||
/* |
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/ |
||||
|
||||
import App from './config/app'; |
||||
import findUpClassName from './helpers/dom/findUpClassName'; |
||||
import fixSafariStickyInput from './helpers/dom/fixSafariStickyInput'; |
||||
import './materialize.scss'; |
||||
import './scss/style.scss'; |
||||
import './scss/tgico.scss'; |
||||
/* import { computeCheck } from './lib/crypto/srp'; |
||||
import { salt1, salt2, g, p, srp_id, secure_random, srp_B, password } from './mock/srp'; */ |
||||
|
||||
//console.log('pineapples are in my head');
|
||||
|
||||
/* console.time('get storage1'); |
||||
import * as a from './lib/config'; |
||||
import * as b from './lib/mtproto/mtproto_config'; |
||||
import * as c from './helpers/userAgent'; |
||||
import * as d from './lib/mtproto/mtprotoworker'; |
||||
import * as e from './lib/polyfill'; |
||||
import * as f from './lib/storage'; |
||||
a && b && c && d && e && f; |
||||
console.timeEnd('get storage1'); */ |
||||
|
||||
/* Promise.all([ |
||||
import('./components/pageIm'), |
||||
import('./components/pageSignIn'), |
||||
import('./components/misc'), |
||||
import('./lib/storage') |
||||
]).then(imports => { |
||||
let [pageIm, pageSignIn, misc, AppStorage] = imports; */ |
||||
|
||||
document.addEventListener('DOMContentLoaded', async() => { |
||||
//let socket = new Socket(2);
|
||||
|
||||
if(!Element.prototype.toggleAttribute) { |
||||
Element.prototype.toggleAttribute = function(name, force) { |
||||
if(force !== void 0) force = !!force; |
||||
|
||||
if(this.hasAttribute(name)) { |
||||
if(force) return true; |
||||
|
||||
this.removeAttribute(name); |
||||
return false; |
||||
} |
||||
if(force === false) return false; |
||||
|
||||
this.setAttribute(name, ""); |
||||
return true; |
||||
}; |
||||
} |
||||
|
||||
// We listen to the resize event (https://css-tricks.com/the-trick-to-viewport-units-on-mobile/)
|
||||
// @ts-ignore
|
||||
const w = window.visualViewport || window; // * handle iOS keyboard
|
||||
let setViewportVH = false; |
||||
const setVH = () => { |
||||
// @ts-ignore
|
||||
const vh = (setViewportVH && !rootScope.default.overlayIsActive ? w.height || w.innerHeight : window.innerHeight) * 0.01; |
||||
//const vh = document.documentElement.scrollHeight * 0.01;
|
||||
document.documentElement.style.setProperty('--vh', `${vh}px`); |
||||
|
||||
//console.log('setVH', vh, setViewportVH ? w : window);
|
||||
|
||||
/* if(setViewportVH && userAgent.isSafari && touchSupport.isTouchSupported && document.activeElement && (document.activeElement as HTMLElement).blur) { |
||||
const rect = document.activeElement.getBoundingClientRect(); |
||||
if(rect.top < 0 || rect.bottom >= (w as any).height) { |
||||
fastSmoothScroll(findUpClassName(document.activeElement, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'center', 4, undefined, FocusDirection.Static); |
||||
} |
||||
} */ |
||||
}; |
||||
|
||||
window.addEventListener('resize', setVH); |
||||
setVH(); |
||||
|
||||
// * hook worker constructor to set search parameters (test, debug, etc)
|
||||
const workerHandler = { |
||||
construct(target: any, args: any) { |
||||
//console.log(target, args);
|
||||
const url = args[0] + location.search; |
||||
|
||||
return new target(url); |
||||
} |
||||
}; |
||||
|
||||
const workerProxy = new Proxy(Worker, workerHandler); |
||||
Worker = workerProxy; |
||||
|
||||
const [_, touchSupport, userAgent, rootScope, appStateManager, I18n] = await Promise.all([ |
||||
import('./lib/polyfill'), |
||||
import('./helpers/touchSupport'), |
||||
import('./helpers/userAgent'), |
||||
import('./lib/rootScope'), |
||||
import('./lib/appManagers/appStateManager'), |
||||
import('./lib/langPack'), |
||||
]) |
||||
//console.timeEnd('get storage');
|
||||
|
||||
//console.log(new Uint8Array([255, 200, 145]).hex);
|
||||
|
||||
const toggleResizeMode = () => { |
||||
setViewportVH = tabId === 1 && userAgent.isSafari && touchSupport.isTouchSupported && !rootScope.default.overlayIsActive; |
||||
setVH(); |
||||
|
||||
if(w !== window) { |
||||
if(setViewportVH) { |
||||
window.removeEventListener('resize', setVH); |
||||
w.addEventListener('resize', setVH); |
||||
} else { |
||||
w.removeEventListener('resize', setVH); |
||||
window.addEventListener('resize', setVH); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
let tabId: number; |
||||
rootScope.default.on('im_tab_change', (id) => { |
||||
const wasTabId = tabId !== undefined; |
||||
tabId = id; |
||||
|
||||
if(wasTabId || tabId === 1) { |
||||
toggleResizeMode(); |
||||
} |
||||
}); |
||||
|
||||
rootScope.default.on('overlay_toggle', () => { |
||||
toggleResizeMode(); |
||||
}); |
||||
|
||||
if(userAgent.isApple) { |
||||
if(userAgent.isSafari) { |
||||
document.documentElement.classList.add('is-safari'); |
||||
|
||||
if(touchSupport.isTouchSupported) { |
||||
let key: 'clientY' | 'pageY' = 'clientY'; |
||||
let startY = 0; |
||||
const o = {capture: true, passive: false}; |
||||
const onTouchMove = (e: TouchEvent) => { |
||||
const touch = e.touches[0]; |
||||
|
||||
//console.log('touchmove y', touch[key], startY);
|
||||
|
||||
const scrollable = findUpClassName(touch.target, 'scrollable-y'); |
||||
if(scrollable) { |
||||
const y = touch[key]; |
||||
const scrolled = startY - y; |
||||
|
||||
/* if(y < startY) { |
||||
startY = y; |
||||
} */ |
||||
|
||||
const scrollTop = scrollable.scrollTop; |
||||
const scrollHeight = scrollable.scrollHeight; |
||||
const clientHeight = scrollable.clientHeight; |
||||
const nextScrollTop = scrollTop ? Math.round(scrollTop + scrollable.clientHeight + scrolled) : scrollTop + scrolled; |
||||
//const needCancel = scrollHeight !== clientHeight ? (scrollTop && diff <= 1) || (scrollTop - diff) < 0 : true;
|
||||
const needCancel = scrollHeight === clientHeight || nextScrollTop >= scrollHeight || nextScrollTop <= 0; |
||||
if(needCancel) { |
||||
e.preventDefault(); |
||||
} |
||||
|
||||
//console.log('touchmove with scrollable', scrollTop, startY, scrolled, nextScrollTop, needCancel, e.cancelable);
|
||||
} else { |
||||
e.preventDefault(); |
||||
|
||||
//console.log('touchmove no scrollable', e, touch);
|
||||
} |
||||
|
||||
//if(e.target === document.documentElement || e.target === document.body) e.preventDefault();
|
||||
}; |
||||
|
||||
document.addEventListener('focusin', (e) => { |
||||
if(!setViewportVH) return; |
||||
//console.log('focusin');
|
||||
|
||||
fixSafariStickyInput(e.target as HTMLElement); |
||||
|
||||
document.addEventListener('touchmove', onTouchMove, o); |
||||
document.addEventListener('touchstart', (e) => { |
||||
if(e.touches.length > 1) return; |
||||
const touchStart = e.touches[0]; |
||||
|
||||
startY = touchStart[key]; |
||||
}); |
||||
}); |
||||
|
||||
document.addEventListener('focusout', () => { |
||||
document.removeEventListener('touchmove', onTouchMove, o); |
||||
}); |
||||
|
||||
document.addEventListener('visibilitychange', () => { |
||||
if(!setViewportVH) return; |
||||
//console.log('window visibilitychange');
|
||||
if(document.activeElement && (document.activeElement as HTMLElement).blur) { |
||||
fixSafariStickyInput(document.activeElement as HTMLElement); |
||||
} |
||||
|
||||
/* blurActiveElement(); |
||||
window.scrollTo(0, 0); |
||||
setVH(); */ |
||||
}); |
||||
} |
||||
} |
||||
|
||||
document.documentElement.classList.add('is-mac', 'emoji-supported'); |
||||
|
||||
if(userAgent.isAppleMobile) { |
||||
document.documentElement.classList.add('is-ios'); |
||||
} |
||||
} else if(userAgent.isAndroid) { |
||||
document.documentElement.classList.add('is-android'); |
||||
} |
||||
|
||||
if(!touchSupport.isTouchSupported) { |
||||
document.documentElement.classList.add('no-touch'); |
||||
} else { |
||||
document.documentElement.classList.add('is-touch'); |
||||
/* document.addEventListener('touchmove', (event: any) => { |
||||
event = event.originalEvent || event; |
||||
if(event.scale && event.scale !== 1) { |
||||
event.preventDefault(); |
||||
} |
||||
}, {capture: true, passive: false}); */ |
||||
} |
||||
|
||||
/* if(config.isServiceWorkerSupported) { |
||||
await navigator.serviceWorker.ready; |
||||
navigator.serviceWorker.controller ? true : await new Promise((resolve, reject) => { |
||||
navigator.serviceWorker.addEventListener('controllerchange', resolve); |
||||
}); |
||||
} */ |
||||
|
||||
//console.time('get storage');
|
||||
|
||||
const perf = performance.now(); |
||||
|
||||
//import('./vendor/dateFormat');
|
||||
|
||||
const langPromise = I18n.default.getCacheLangPack(); |
||||
|
||||
const [state, langPack] = await Promise.all([ |
||||
appStateManager.default.getState(), |
||||
langPromise |
||||
]); |
||||
//I18n.getCacheLangPack();
|
||||
//console.log('got auth:', auth);
|
||||
//console.timeEnd('get storage');
|
||||
|
||||
if(langPack.appVersion !== App.langPackVersion) { |
||||
I18n.default.getLangPack(langPack.lang_code); |
||||
} |
||||
|
||||
console.log('got state, time:', performance.now() - perf); |
||||
|
||||
const authState = state.authState; |
||||
if(authState._ !== 'authStateSignedIn'/* || 1 === 1 */) { |
||||
console.log('Will mount auth page:', authState._, Date.now() / 1000); |
||||
|
||||
//langPromise.then(async() => {
|
||||
switch(authState._) { |
||||
case 'authStateSignIn': |
||||
(await import('./pages/pageSignIn')).default.mount(); |
||||
break; |
||||
case 'authStateAuthCode': |
||||
(await import('./pages/pageAuthCode')).default.mount(authState.sentCode); |
||||
break; |
||||
case 'authStatePassword': |
||||
(await import('./pages/pagePassword')).default.mount(); |
||||
break; |
||||
case 'authStateSignUp': |
||||
(await import('./pages/pageSignUp')).default.mount(authState.authCode); |
||||
break; |
||||
} |
||||
//});
|
||||
|
||||
/* computeCheck(password, { |
||||
current_algo: { |
||||
salt1, |
||||
salt2, |
||||
p, |
||||
g |
||||
}, |
||||
srp_id, |
||||
srp_B, |
||||
secure_random, |
||||
}).then(res => { |
||||
console.log(res); |
||||
}); */ |
||||
|
||||
/* setTimeout(async() => { |
||||
(await import('./pages/pageAuthCode')).default.mount({ |
||||
"_": "auth.sentCode", |
||||
"pFlags": {}, |
||||
"flags": 6, |
||||
"type": { |
||||
"_": "auth.sentCodeTypeSms", |
||||
"length": 5 |
||||
}, |
||||
"phone_code_hash": "", |
||||
"next_type": { |
||||
"_": "auth.codeTypeCall" |
||||
}, |
||||
"timeout": 120, |
||||
"phone_number": "" |
||||
}); |
||||
}, 500); */ |
||||
/* setTimeout(async() => { |
||||
(await import('./pages/pageSignQR')).default.mount(); |
||||
}, 500); */ |
||||
/* setTimeout(async() => { |
||||
(await import('./pages/pagePassword')).default.mount(); |
||||
}, 500); */ |
||||
/* setTimeout(async() => { |
||||
(await import('./pages/pageSignUp')).default.mount({ |
||||
"phone_code_hash": "", |
||||
"phone_number": "" |
||||
}); |
||||
}, 500); */ |
||||
} else { |
||||
console.log('Will mount IM page:', Date.now() / 1000); |
||||
(await import('./pages/pageIm')).default.mount(); |
||||
//getNearestDc();
|
||||
} |
||||
|
||||
const ripple = (await import('./components/ripple')).ripple; |
||||
(Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el)); |
||||
}); |
||||
//});
|
||||
|
||||
|
@ -0,0 +1,604 @@
@@ -0,0 +1,604 @@
|
||||
/* |
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
* |
||||
* Originally from: |
||||
* https://github.com/zhukov/webogram
|
||||
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com> |
||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||
*/ |
||||
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug"; |
||||
import { tsNow } from "../../helpers/date"; |
||||
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl"; |
||||
import { ChannelParticipantsFilter, ChannelsChannelParticipants, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, InputFileLocation, PhotoSize, UserFull, UserProfilePhoto } from "../../layer"; |
||||
//import apiManager from '../mtproto/apiManager';
|
||||
import apiManager from '../mtproto/mtprotoworker'; |
||||
import { RichTextProcessor } from "../richtextprocessor"; |
||||
import rootScope from "../rootScope"; |
||||
import apiUpdatesManager from "./apiUpdatesManager"; |
||||
import appChatsManager from "./appChatsManager"; |
||||
import appDownloadManager from "./appDownloadManager"; |
||||
import appNotificationsManager from "./appNotificationsManager"; |
||||
import appPeersManager from "./appPeersManager"; |
||||
import appPhotosManager, { MyPhoto } from "./appPhotosManager"; |
||||
import appUsersManager, { User } from "./appUsersManager"; |
||||
|
||||
type PeerPhotoSize = 'photo_small' | 'photo_big'; |
||||
|
||||
export class AppProfileManager { |
||||
private botInfos: any = {}; |
||||
private usersFull: {[id: string]: UserFull.userFull} = {}; |
||||
public chatsFull: {[id: string]: ChatFull} = {}; |
||||
private fullPromises: {[peerId: string]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {}; |
||||
|
||||
private savedAvatarURLs: { |
||||
[peerId: number]: { |
||||
[size in PeerPhotoSize]?: string | Promise<any> |
||||
} |
||||
} = {}; |
||||
|
||||
constructor() { |
||||
rootScope.on('apiUpdate', (update) => { |
||||
switch(update._) { |
||||
case 'updateChatParticipants': { |
||||
const participants = update.participants; |
||||
if(participants._ === 'chatParticipants') { |
||||
const chatId = participants.chat_id; |
||||
const chatFull = this.chatsFull[chatId] as ChatFull.chatFull; |
||||
if(chatFull !== undefined) { |
||||
chatFull.participants = participants; |
||||
rootScope.broadcast('chat_full_update', chatId); |
||||
} |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 'updateChatParticipantAdd': { |
||||
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; |
||||
if(chatFull !== undefined) { |
||||
const _participants = chatFull.participants as ChatParticipants.chatParticipants; |
||||
const participants = _participants.participants || []; |
||||
for(let i = 0, length = participants.length; i < length; i++) { |
||||
if(participants[i].user_id === update.user_id) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
participants.push({ |
||||
_: 'chatParticipant', |
||||
user_id: update.user_id, |
||||
inviter_id: update.inviter_id, |
||||
date: tsNow(true) |
||||
}); |
||||
|
||||
_participants.version = update.version; |
||||
rootScope.broadcast('chat_full_update', update.chat_id); |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 'updateChatParticipantDelete': { |
||||
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; |
||||
if(chatFull !== undefined) { |
||||
const _participants = chatFull.participants as ChatParticipants.chatParticipants; |
||||
const participants = _participants.participants || []; |
||||
for(let i = 0, length = participants.length; i < length; i++) { |
||||
if(participants[i].user_id === update.user_id) { |
||||
participants.splice(i, 1); |
||||
_participants.version = update.version; |
||||
rootScope.broadcast('chat_full_update', update.chat_id); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
}); |
||||
|
||||
rootScope.on('chat_update', (chatId) => { |
||||
const fullChat = this.chatsFull[chatId]; |
||||
const chat = appChatsManager.getChat(chatId); |
||||
if(!chat.photo || !fullChat) { |
||||
return; |
||||
} |
||||
const emptyPhoto = chat.photo._ === 'chatPhotoEmpty'; |
||||
//////console.log('chat_update:', fullChat);
|
||||
if(fullChat.chat_photo && emptyPhoto !== (fullChat.chat_photo._ === 'photoEmpty')) { |
||||
delete this.chatsFull[chatId]; |
||||
rootScope.broadcast('chat_full_update', chatId); |
||||
return; |
||||
} |
||||
if(emptyPhoto) { |
||||
return; |
||||
} |
||||
|
||||
const smallUserpic = chat.photo.photo_small; |
||||
const smallPhotoSize = fullChat.chat_photo ? appPhotosManager.choosePhotoSize(fullChat.chat_photo as MyPhoto, 0, 0) : undefined; |
||||
if(!smallPhotoSize || JSON.stringify(smallUserpic) !== JSON.stringify((smallPhotoSize as PhotoSize.photoSize).location)) { |
||||
delete this.chatsFull[chatId]; |
||||
rootScope.broadcast('chat_full_update', chatId); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public saveBotInfo(botInfo: any) { |
||||
const botId = botInfo && botInfo.user_id; |
||||
if(!botId) { |
||||
return null; |
||||
} |
||||
|
||||
const commands: any = {}; |
||||
botInfo.commands.forEach((botCommand: any) => { |
||||
commands[botCommand.command] = botCommand.description; |
||||
}); |
||||
|
||||
return this.botInfos[botId] = { |
||||
id: botId, |
||||
version: botInfo.version, |
||||
shareText: botInfo.share_text, |
||||
description: botInfo.description, |
||||
commands: commands |
||||
}; |
||||
} |
||||
|
||||
public getProfile(id: number, override?: true): Promise<UserFull> { |
||||
if(this.usersFull[id] && !override) { |
||||
return Promise.resolve(this.usersFull[id]); |
||||
} |
||||
|
||||
if(this.fullPromises[id]) { |
||||
return this.fullPromises[id] as any; |
||||
} |
||||
|
||||
return this.fullPromises[id] = apiManager.invokeApi('users.getFullUser', { |
||||
id: appUsersManager.getUserInput(id) |
||||
}).then((userFull) => { |
||||
const user = userFull.user as User; |
||||
/* if(override && isObject(override) && override.phone_number) { |
||||
user.phone = override.phone_number; |
||||
if(override.first_name || override.last_name) { |
||||
user.first_name = override.first_name; |
||||
user.last_name = override.last_name; |
||||
} |
||||
|
||||
appUsersManager.saveApiUser(user); |
||||
} else { */ |
||||
appUsersManager.saveApiUser(user, true); |
||||
//}
|
||||
|
||||
if(userFull.profile_photo) { |
||||
userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId: id}); |
||||
/* appPhotosManager.savePhoto(userFull.profile_photo, {user_id: id}); */ |
||||
} |
||||
|
||||
if(userFull.about !== undefined) { |
||||
userFull.rAbout = RichTextProcessor.wrapRichText(userFull.about, {noLinebreaks: true}); |
||||
} |
||||
|
||||
appNotificationsManager.savePeerSettings(id, userFull.notify_settings); |
||||
|
||||
if(userFull.bot_info) { |
||||
userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any; |
||||
} |
||||
|
||||
//appMessagesManager.savePinnedMessage(id, userFull.pinned_msg_id);
|
||||
|
||||
delete this.fullPromises[id]; |
||||
|
||||
return this.usersFull[id] = userFull; |
||||
}) as any; |
||||
} |
||||
|
||||
public getProfileByPeerId(peerId: number, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull.userFull> { |
||||
if(peerId < 0) return this.getChatFull(-peerId, override); |
||||
else return this.getProfile(peerId, override); |
||||
} |
||||
|
||||
public getFullPhoto(peerId: number) { |
||||
return this.getProfileByPeerId(peerId).then(profile => { |
||||
switch(profile._) { |
||||
case 'userFull': |
||||
return profile.profile_photo; |
||||
case 'channelFull': |
||||
case 'chatFull': |
||||
return profile.chat_photo; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/* public getPeerBots(peerId: number) { |
||||
var peerBots: any[] = []; |
||||
if(peerId >= 0 && !appUsersManager.isBot(peerId) || |
||||
(appPeersManager.isChannel(peerId) && !appPeersManager.isMegagroup(peerId))) { |
||||
return Promise.resolve(peerBots); |
||||
} |
||||
if(peerId >= 0) { |
||||
return this.getProfile(peerId).then((userFull: any) => { |
||||
var botInfo = userFull.bot_info; |
||||
if(botInfo && botInfo._ !== 'botInfoEmpty') { |
||||
peerBots.push(botInfo); |
||||
} |
||||
return peerBots; |
||||
}); |
||||
} |
||||
|
||||
return this.getChatFull(-peerId).then((chatFull: any) => { |
||||
chatFull.bot_info.forEach((botInfo: any) => { |
||||
peerBots.push(this.saveBotInfo(botInfo)) |
||||
}); |
||||
return peerBots; |
||||
}); |
||||
} */ |
||||
|
||||
public getChatFull(id: number, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull> { |
||||
if(appChatsManager.isChannel(id)) { |
||||
return this.getChannelFull(id, override); |
||||
} |
||||
|
||||
const fullChat = this.chatsFull[id] as ChatFull.chatFull; |
||||
if(fullChat && !override) { |
||||
const chat = appChatsManager.getChat(id); |
||||
if(chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version || |
||||
chat.pFlags.left) { |
||||
return Promise.resolve(fullChat); |
||||
} |
||||
} |
||||
|
||||
const peerId = -id; |
||||
if(this.fullPromises[peerId] !== undefined) { |
||||
return this.fullPromises[peerId] as any; |
||||
} |
||||
|
||||
// console.trace(dT(), 'Get chat full', id, appChatsManager.getChat(id))
|
||||
return this.fullPromises[peerId] = apiManager.invokeApi('messages.getFullChat', { |
||||
chat_id: id |
||||
}).then((result) => { |
||||
appChatsManager.saveApiChats(result.chats); |
||||
appUsersManager.saveApiUsers(result.users); |
||||
const fullChat = result.full_chat as ChatFull.chatFull; |
||||
if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) { |
||||
fullChat.chat_photo = appPhotosManager.savePhoto(fullChat.chat_photo, {type: 'profilePhoto', peerId: peerId}); |
||||
} |
||||
|
||||
//appMessagesManager.savePinnedMessage(peerId, fullChat.pinned_msg_id);
|
||||
appNotificationsManager.savePeerSettings(peerId, fullChat.notify_settings); |
||||
delete this.fullPromises[peerId]; |
||||
this.chatsFull[id] = fullChat; |
||||
rootScope.broadcast('chat_full_update', id); |
||||
|
||||
return fullChat; |
||||
}) as any; |
||||
} |
||||
|
||||
public getChatInviteLink(id: number, force?: boolean) { |
||||
return this.getChatFull(id).then((chatFull) => { |
||||
if(!force && |
||||
chatFull.exported_invite && |
||||
chatFull.exported_invite._ == 'chatInviteExported') { |
||||
return chatFull.exported_invite.link; |
||||
} |
||||
|
||||
return apiManager.invokeApi('messages.exportChatInvite', { |
||||
peer: appPeersManager.getInputPeerById(-id) |
||||
}).then((exportedInvite) => { |
||||
if(this.chatsFull[id] !== undefined) { |
||||
this.chatsFull[id].exported_invite = exportedInvite; |
||||
} |
||||
|
||||
return (exportedInvite as ExportedChatInvite.chatInviteExported).link; |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
public getChannelParticipants(id: number, filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'}, limit = 200, offset = 0) { |
||||
if(filter._ === 'channelParticipantsRecent') { |
||||
const chat = appChatsManager.getChat(id); |
||||
if(chat && |
||||
chat.pFlags && ( |
||||
chat.pFlags.kicked || |
||||
chat.pFlags.broadcast && !chat.pFlags.creator && !chat.admin_rights |
||||
)) { |
||||
return Promise.reject(); |
||||
} |
||||
} |
||||
|
||||
return apiManager.invokeApiCacheable('channels.getParticipants', { |
||||
channel: appChatsManager.getChannelInput(id), |
||||
filter, |
||||
offset, |
||||
limit, |
||||
hash: 0 |
||||
}, {cacheSeconds: 60}).then(result => { |
||||
appUsersManager.saveApiUsers((result as ChannelsChannelParticipants.channelsChannelParticipants).users); |
||||
return result as ChannelsChannelParticipants.channelsChannelParticipants; |
||||
}); |
||||
/* let maybeAddSelf = (participants: any[]) => { |
||||
let chat = appChatsManager.getChat(id); |
||||
let selfMustBeFirst = filter._ === 'channelParticipantsRecent' && |
||||
!offset && |
||||
!chat.pFlags.kicked && |
||||
!chat.pFlags.left; |
||||
|
||||
if(selfMustBeFirst) { |
||||
participants = copy(participants); |
||||
let myID = appUsersManager.getSelf().id; |
||||
let myIndex = participants.findIndex(p => p.user_id === myID); |
||||
let myParticipant; |
||||
|
||||
if(myIndex !== -1) { |
||||
myParticipant = participants[myIndex]; |
||||
participants.splice(myIndex, 1); |
||||
} else { |
||||
myParticipant = {_: 'channelParticipantSelf', user_id: myID}; |
||||
} |
||||
|
||||
participants.unshift(myParticipant); |
||||
} |
||||
|
||||
return participants; |
||||
} */ |
||||
} |
||||
|
||||
public getChannelParticipant(id: number, userId: number) { |
||||
return apiManager.invokeApiSingle('channels.getParticipant', { |
||||
channel: appChatsManager.getChannelInput(id), |
||||
user_id: appUsersManager.getUserInput(userId) |
||||
}).then(channelParticipant => { |
||||
appUsersManager.saveApiUsers(channelParticipant.users); |
||||
return channelParticipant.participant; |
||||
}); |
||||
} |
||||
|
||||
public getChannelFull(id: number, override?: true): Promise<ChatFull.channelFull> { |
||||
if(this.chatsFull[id] !== undefined && !override) { |
||||
return Promise.resolve(this.chatsFull[id] as ChatFull.channelFull); |
||||
} |
||||
|
||||
const peerId = -id; |
||||
if(this.fullPromises[peerId] !== undefined) { |
||||
return this.fullPromises[peerId] as any; |
||||
} |
||||
|
||||
return this.fullPromises[peerId] = apiManager.invokeApi('channels.getFullChannel', { |
||||
channel: appChatsManager.getChannelInput(id) |
||||
}).then((result) => { |
||||
appChatsManager.saveApiChats(result.chats); |
||||
appUsersManager.saveApiUsers(result.users); |
||||
const fullChannel = result.full_chat as ChatFull.channelFull; |
||||
if(fullChannel && fullChannel.chat_photo.id) { |
||||
fullChannel.chat_photo = appPhotosManager.savePhoto(fullChannel.chat_photo, {type: 'profilePhoto', peerId}); |
||||
//appPhotosManager.savePhoto(fullChannel.chat_photo);
|
||||
} |
||||
appNotificationsManager.savePeerSettings(peerId, fullChannel.notify_settings); |
||||
|
||||
delete this.fullPromises[peerId]; |
||||
this.chatsFull[id] = fullChannel; |
||||
rootScope.broadcast('chat_full_update', id); |
||||
|
||||
return fullChannel; |
||||
}, (error) => { |
||||
switch (error.type) { |
||||
case 'CHANNEL_PRIVATE': |
||||
let channel = appChatsManager.getChat(id); |
||||
channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title}; |
||||
apiUpdatesManager.processUpdateMessage({ |
||||
_: 'updates', |
||||
updates: [{ |
||||
_: 'updateChannel', |
||||
channel_id: id |
||||
}], |
||||
chats: [channel], |
||||
users: [] |
||||
}); |
||||
break; |
||||
} |
||||
|
||||
return Promise.reject(error); |
||||
}) as any; |
||||
} |
||||
|
||||
public invalidateChannelParticipants(id: number) { |
||||
delete this.chatsFull[id]; |
||||
delete this.fullPromises[-id]; |
||||
apiManager.clearCache('channels.getParticipants', (params) => (params.channel as InputChannel.inputChannel).channel_id === id); |
||||
rootScope.broadcast('chat_full_update', id); |
||||
} |
||||
|
||||
public updateProfile(first_name: string, last_name: string, about: string) { |
||||
return apiManager.invokeApi('account.updateProfile', { |
||||
first_name, |
||||
last_name, |
||||
about |
||||
}).then(user => { |
||||
appUsersManager.saveApiUser(user); |
||||
|
||||
return this.getProfile(rootScope.myId, true); |
||||
}); |
||||
} |
||||
|
||||
public uploadProfilePhoto(inputFile: InputFile) { |
||||
return apiManager.invokeApi('photos.uploadProfilePhoto', { |
||||
file: inputFile |
||||
}).then((updateResult) => { |
||||
appUsersManager.saveApiUsers(updateResult.users); |
||||
|
||||
const myId = rootScope.myId; |
||||
appPhotosManager.savePhoto(updateResult.photo, { |
||||
type: 'profilePhoto', |
||||
peerId: myId |
||||
}); |
||||
|
||||
apiUpdatesManager.processUpdateMessage({ |
||||
_: 'updateShort', |
||||
update: { |
||||
_: 'updateUserPhoto', |
||||
user_id: myId, |
||||
date: tsNow(true), |
||||
photo: appUsersManager.getUser(myId).photo, |
||||
previous: true |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
public removeFromAvatarsCache(peerId: number) { |
||||
if(this.savedAvatarURLs[peerId]) { |
||||
delete this.savedAvatarURLs[peerId]; |
||||
} |
||||
} |
||||
|
||||
public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image()) { |
||||
const inputPeer = appPeersManager.getInputPeerById(peerId); |
||||
|
||||
let needFadeIn = true; |
||||
let getAvatarPromise: Promise<any>; |
||||
let saved = this.savedAvatarURLs[peerId]; |
||||
if(!saved || !saved[size]) { |
||||
if(!saved) { |
||||
saved = this.savedAvatarURLs[peerId] = {}; |
||||
} |
||||
|
||||
//console.warn('will invoke downloadSmallFile:', peerId);
|
||||
const peerPhotoFileLocation: InputFileLocation.inputPeerPhotoFileLocation = { |
||||
_: 'inputPeerPhotoFileLocation', |
||||
pFlags: {}, |
||||
peer: inputPeer, |
||||
volume_id: photo[size].volume_id, |
||||
local_id: photo[size].local_id |
||||
}; |
||||
|
||||
if(size === 'photo_big') { |
||||
peerPhotoFileLocation.pFlags.big = true; |
||||
} |
||||
|
||||
const downloadOptions = {dcId: photo.dc_id, location: peerPhotoFileLocation}; |
||||
|
||||
/* let str: string; |
||||
const time = Date.now(); |
||||
if(peerId === 0) { |
||||
str = `download avatar ${peerId}`; |
||||
} */ |
||||
|
||||
const promise = appDownloadManager.download(downloadOptions); |
||||
getAvatarPromise = saved[size] = promise.then(blob => { |
||||
saved[size] = URL.createObjectURL(blob); |
||||
|
||||
/* if(str) { |
||||
console.log(str, Date.now() / 1000, Date.now() - time); |
||||
} */ |
||||
}); |
||||
} else if(typeof(saved[size]) !== 'string') { |
||||
getAvatarPromise = saved[size] as Promise<any>; |
||||
} else { |
||||
getAvatarPromise = Promise.resolve(); |
||||
needFadeIn = false; |
||||
} |
||||
|
||||
let callback: () => void; |
||||
if(!needFadeIn) { |
||||
// смотри в misc.ts: renderImageFromUrl
|
||||
callback = () => { |
||||
div.innerHTML = ''; |
||||
div.append(img); |
||||
div.dataset.color = ''; |
||||
}; |
||||
} else { |
||||
const animate = rootScope.settings.animationsEnabled; |
||||
if(animate) { |
||||
img.classList.add('fade-in'); |
||||
} |
||||
|
||||
callback = () => { |
||||
div.innerHTML = ''; |
||||
div.append(img); |
||||
|
||||
setTimeout(() => { |
||||
if(div.childElementCount) { |
||||
div.dataset.color = ''; |
||||
|
||||
if(animate) { |
||||
img.classList.remove('fade-in'); |
||||
} |
||||
} |
||||
}, animate ? 200 : 0); |
||||
}; |
||||
} |
||||
|
||||
const loadPromise = getAvatarPromise.then(() => { |
||||
return new Promise<void>((resolve) => { |
||||
renderImageFromUrl(img, saved[size] as string, () => { |
||||
callback(); |
||||
resolve(); |
||||
}, false); |
||||
}); |
||||
}); |
||||
|
||||
return {cached: !needFadeIn, loadPromise}; |
||||
} |
||||
|
||||
// peerId === peerId || title
|
||||
public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '') { |
||||
const photo = appPeersManager.getPeerPhoto(peerId); |
||||
|
||||
const size: PeerPhotoSize = 'photo_small'; |
||||
const avatarAvailable = photo && photo[size]; |
||||
const avatarRendered = !!div.firstElementChild; |
||||
|
||||
const myId = rootScope.myId; |
||||
|
||||
//console.log('loadDialogPhoto location:', location, inputPeer);
|
||||
if(peerId === myId && isDialog) { |
||||
div.innerHTML = ''; |
||||
div.dataset.color = ''; |
||||
div.classList.add('tgico-savedmessages'); |
||||
div.classList.remove('tgico-avatar_deletedaccount'); |
||||
return; |
||||
} |
||||
|
||||
if(peerId > 0) { |
||||
const user = appUsersManager.getUser(peerId); |
||||
if(user && user.pFlags && user.pFlags.deleted) { |
||||
div.innerHTML = ''; |
||||
div.dataset.color = appPeersManager.getPeerColorById(peerId); |
||||
div.classList.add('tgico-avatar_deletedaccount'); |
||||
div.classList.remove('tgico-savedmessages'); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) { |
||||
let color = ''; |
||||
if(peerId && (peerId !== myId || !isDialog)) { |
||||
color = appPeersManager.getPeerColorById(peerId); |
||||
} |
||||
|
||||
div.innerHTML = ''; |
||||
div.classList.remove('tgico-savedmessages', 'tgico-avatar_deletedaccount'); |
||||
div.dataset.color = color; |
||||
|
||||
let abbr: string; |
||||
if(!title) { |
||||
abbr = appPeersManager.getPeer(peerId).initials ?? ''; |
||||
} else { |
||||
abbr = RichTextProcessor.getAbbreviation(title); |
||||
} |
||||
|
||||
div.innerHTML = abbr; |
||||
//return Promise.resolve(true);
|
||||
} |
||||
|
||||
if(avatarAvailable/* && false */) { |
||||
return this.putAvatar(div, peerId, photo, size); |
||||
} |
||||
} |
||||
} |
||||
|
||||
const appProfileManager = new AppProfileManager(); |
||||
MOUNT_CLASS_TO.appProfileManager = appProfileManager; |
||||
export default appProfileManager; |
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
export const salt1 = new Uint8Array([114, 47, 217, 190, 196, 217, 91, 15, 205, 209, 189, 57, 98, 19, 110, 40, 47, 211, 245, 29, 58, 194, 205, 57, 205, 200, 225, 139, 244, 230, 206, 138, 1, 216, 18, 99, 130, 133, 226, 167]); |
||||
|
||||
export const salt2 = new Uint8Array([124, 249, 139, 209, 240, 124, 2, 97, 93, 249, 218, 19, 86, 31, 57, 215]); |
||||
|
||||
export const g = 3; |
||||
|
||||
export const p = new Uint8Array([ |
||||
199, 28, 174, 185, 198, 177, 201, 4, 142, 108, 82, 47, 112, 241, 63, 115, 152, 13, 64, 35, 142, 62, 33, 193, 73, 52, 208, 55, 86, 61, 147, 15, 72, 25, 138, 10, 167, 193, 64, 88, 34, 148, 147, 210, 37, 48, 244, 219, 250, 51, 111, 110, 10, 201, 37, 19, 149, 67, 174, 212, 76, 206, 124, 55, 32, 253, 81, 246, 148, 88, 112, 90, 198, 140, 212, 254, 107, 107, 19, 171, 220, 151, 70, 81, 41, 105, 50, 132, 84, 241, 143, 175, 140, 89, 95, 100, 36, 119, 254, 150, 187, 42, 148, 29, 91, 205, 29, 74, 200, 204, 73, 136, 7, 8, 250, 155, 55, 142, 60, 79, 58, 144, 96, 190, 230, 124, 249, 164, 164, 166, 149, 129, 16, 81, 144, 126, 22, 39, 83, 181, 107, 15, 107, 65, 13, 186, 116, 216, 168, 75, 42, 20, 179, 20, 78, 14, 241, 40, 71, 84, 253, 23, 237, 149, 13, 89, 101, 180, 185, 221, 70, 88, 45, 177, 23, 141, 22, 156, 107, 196, 101, 176, 214, 255, 156, 163, 146, 143, 239, 91, 154, 228, 228, 24, 252, 21, 232, 62, 190, 160, 248, 127, 169, 255, 94, 237, 112, 5, 13, 237, 40, 73, 244, 123, 249, 89, 217, 86, 133, 12, 233, 41, 133, 31, 13, 129, 21, 246, 53, 177, 5, 238, 46, 78, 21, 208, 75, 36, 84, 191, 111, 79, 173, 240, 52, 177, 4, 3, 17, 156, 216, 227, 185, 47, 204, 91 |
||||
]); |
||||
|
||||
export const srp_id = "14665952836034598759"; |
||||
|
||||
export const srp_B = new Uint8Array([ |
||||
36, 159, 225, 252, 202, 217, 105, 129, 128, 119, 70, 179, 96, 132, 49, 65, 196, 78, 171, 70, 83, 220, 92, 107, 121, 102, 245, 138, 85, 250, 184, 110, 175, 149, 165, 176, 128, 124, 14, 106, 253, 169, 235, 158, 234, 161, 245, 130, 11, 222, 7, 232, 201, 127, 69, 114, 135, 43, 245, 203, 106, 148, 195, 0, 29, 90, 59, 134, 216, 164, 155, 201, 92, 103, 211, 125, 242, 71, 143, 111, 9, 56, 16, 36, 104, 221, 145, 114, 164, 101, 253, 188, 203, 187, 162, 205, 200, 235, 83, 109, 52, 189, 78, 227, 132, 218, 57, 211, 196, 186, 156, 45, 126, 245, 211, 23, 4, 245, 231, 57, 2, 177, 227, 131, 180, 8, 48, 114, 127, 184, 133, 74, 118, 248, 0, 245, 224, 160, 109, 160, 254, 196, 108, 33, 74, 127, 26, 189, 74, 76, 63, 81, 131, 169, 139, 12, 134, 67, 129, 86, 10, 109, 90, 91, 161, 130, 56, 123, 173, 214, 236, 124, 16, 248, 232, 4, 196, 5, 191, 182, 81, 64, 165, 59, 87, 251, 76, 51, 96, 2, 34, 93, 47, 75, 179, 26, 217, 26, 152, 245, 100, 255, 91, 118, 44, 156, 90, 18, 232, 172, 101, 175, 8, 31, 215, 121, 74, 133, 243, 50, 19, 179, 239, 5, 174, 231, 146, 215, 56, 225, 154, 207, 7, 67, 85, 177, 72, 78, 184, 206, 249, 201, 226, 15, 190, 121, 91, 6, 85, 125, 217, 53, 31, 171, 4, 88 |
||||
]); |
||||
|
||||
export const secure_random = new Uint8Array([108, 48, 160, 103, 227, 55, 213, 54, 37, 175, 157, 206, 29, 139, 226, 92, 166, 135, 70, 221, 90, 88, 48, 239, 241, 242, 113, 108, 186, 90, 227, 66, 127, 15, 24, 53, 56, 173, 46, 100, 223, 108, 73, 64, 40, 4, 193, 112, 171, 183, 201, 232, 47, 75, 114, 73, 106, 214, 244, 216, 10, 188, 16, 54, 200, 220, 164, 106, 55, 165, 115, 165, 191, 218, 186, 171, 107, 75, 124, 168, 245, 100, 50, 60, 237, 90, 224, 9, 250, 135, 40, 111, 44, 180, 159, 13, 76, 15, 122, 118, 223, 162, 5, 164, 2, 225, 90, 215, 186, 180, 20, 218, 123, 249, 208, 186, 154, 149, 246, 44, 60, 240, 191, 111, 87, 62, 175, 2, 159, 234, 46, 216, 94, 160, 166, 60, 179, 139, 101, 16, 212, 112, 95, 198, 143, 111, 236, 203, 172, 99, 58, 162, 77, 52, 87, 64, 140, 74, 165, 107, 82, 191, 221, 64, 106, 204, 79, 87, 67, 160, 22, 133, 158, 152, 231, 72, 197, 127, 184, 161, 10, 196, 205, 95, 77, 116, 177, 66, 49, 8, 65, 11, 9, 168, 109, 224, 146, 24, 48, 55, 102, 150, 153, 122, 185, 12, 51, 137, 32, 8, 44, 162, 22, 129, 133, 132, 29, 72, 1, 11, 53, 21, 222, 179, 132, 126, 182, 206, 130, 185, 68, 71, 43, 217, 12, 12, 1, 193, 23, 49, 123, 82, 221, 197, 56, 48, 90, 30, 99, 64, 126, 117, 104, 211, 80, 242]); |
||||
|
||||
export const password = '101010'; |
||||
|
||||
export const A = new Uint8Array([ |
||||
93, 125, 125, 50, 15, 192, 164, 213, 62, 136, 32, 204, 201, 201, 203, 128, 158, 120, 110, 253, 158, 88, 176, 118, 71, 167, 172, 52, 37, 35, 71, 39, 97, 142, 196, 71, 213, 37, 182, 156, 57, 137, 14, 85, 25, 35, 110, 220, 228, 88, 41, 44, 185, 183, 127, 153, 199, 103, 238, 82, 158, 188, 32, 72, 178, 171, 66, 29, 221, 60, 169, 172, 185, 58, 95, 7, 192, 230, 36, 8, 138, 225, 242, 136, 202, 130, 49, 100, 56, 72, 209, 71, 31, 166, 112, 232, 33, 148, 114, 165, 89, 246, 36, 158, 241, 77, 179, 187, 204, 19, 5, 206, 184, 47, 122, 234, 245, 72, 226, 191, 188, 225, 236, 100, 152, 227, 130, 190, 207, 150, 110, 159, 28, 100, 189, 189, 66, 196, 250, 161, 80, 214, 140, 122, 19, 71, 76, 73, 134, 227, 197, 73, 41, 35, 123, 215, 86, 162, 11, 116, 148, 157, 216, 6, 212, 93, 52, 200, 244, 67, 29, 153, 171, 147, 12, 7, 65, 158, 17, 36, 10, 36, 90, 198, 163, 252, 194, 253, 104, 41, 137, 121, 80, 43, 181, 229, 204, 184, 227, 2, 175, 201, 250, 213, 247, 117, 196, 60, 27, 238, 240, 45, 214, 147, 94, 108, 102, 183, 129, 28, 200, 47, 1, 68, 212, 247, 73, 194, 200, 188, 33, 230, 92, 123, 83, 36, 23, 144, 185, 5, 196, 205, 33, 45, 211, 128, 234, 137, 110, 221, 214, 47, 30, 175, 14, 132 |
||||
]); |
||||
|
||||
export const M1 = new Uint8Array([ |
||||
72, 29, 26, 252, 69, 33, 152, 165, 104, 187, 154, 206, 10, 169, 23, 103, 35, 211, 240, 73, 60, 187, 50, 212, 42, 209, 241, 100, 91, 201, 77, 7 |
||||
]); |
||||
|
||||
export const passwordHashed = [ |
||||
66, 92, 210, 197, 237, 255, 209, 109, 38, 17, 14, 200, 177, 152, 124, 167, 92, 166, 132, 205, 195, 184, 24, 240, 111, 118, 45, 43, 66, 66, 248, 49 |
||||
]; |
Loading…
Reference in new issue