Browse Source

Change reply width

Fix some layout issues on handhelds
Improve loading avatar speeds (state)
master
morethanwords 4 years ago
parent
commit
ef7e4141eb
  1. 37
      src/lib/appManagers/appChatsManager.ts
  2. 2
      src/lib/appManagers/appDialogsManager.ts
  3. 9
      src/lib/appManagers/appDocsManager.ts
  4. 29
      src/lib/appManagers/appImManager.ts
  5. 111
      src/lib/appManagers/appMessagesManager.ts
  6. 24
      src/lib/appManagers/appPeersManager.ts
  7. 17
      src/lib/appManagers/appStateManager.ts
  8. 70
      src/lib/appManagers/appUsersManager.ts
  9. 2
      src/lib/mtproto/mtproto_config.ts
  10. 4
      src/lib/utils.ts
  11. 4
      src/scss/components/_global.scss
  12. 28
      src/scss/partials/_chat.scss
  13. 11
      src/scss/partials/_chatBubble.scss

37
src/lib/appManagers/appChatsManager.ts

@ -3,10 +3,11 @@ import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import searchIndexManager from "../searchIndexManager"; import searchIndexManager from "../searchIndexManager";
import { copy, defineNotNumerableProperties, getAbbreviation, isObject, numberWithCommas, safeReplaceObject } from "../utils"; import { copy, getAbbreviation, isObject, numberWithCommas, safeReplaceObject } from "../utils";
import apiUpdatesManager from "./apiUpdatesManager"; import apiUpdatesManager from "./apiUpdatesManager";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appProfileManager from "./appProfileManager"; import appProfileManager from "./appProfileManager";
import appStateManager from "./appStateManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
export type Channel = { export type Channel = {
@ -64,10 +65,10 @@ export type ChatRights = 'send' | 'edit_title' | 'edit_photo' | 'invite' | 'pin'
export class AppChatsManager { export class AppChatsManager {
public chats: {[id: number]: Channel | Chat | any} = {}; public chats: {[id: number]: Channel | Chat | any} = {};
public usernames: any = {}; //public usernames: any = {};
public channelAccess: any = {}; //public channelAccess: any = {};
public megagroups: any = {}; public megagroups: {[id: number]: true} = {};
public cachedPhotoLocations: any = {}; public cachedPhotoLocations: {[id: number]: any} = {};
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {}; public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
@ -83,6 +84,10 @@ export class AppChatsManager {
break; break;
} }
}); });
appStateManager.getState().then((state) => {
this.chats = state.chats;
});
} }
public saveApiChats(apiChats: any[]) { public saveApiChats(apiChats: any[]) {
@ -95,7 +100,7 @@ export class AppChatsManager {
} }
// * exclude from state // * exclude from state
defineNotNumerableProperties(chat, ['rTitle', 'initials']); // defineNotNumerableProperties(chat, ['rTitle', 'initials']);
//chat.rTitle = chat.title || 'chat_title_deleted'; //chat.rTitle = chat.title || 'chat_title_deleted';
chat.rTitle = RichTextProcessor.wrapRichText(chat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted'; chat.rTitle = RichTextProcessor.wrapRichText(chat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted';
@ -121,10 +126,10 @@ export class AppChatsManager {
chat.participants_count = oldChat.participants_count; chat.participants_count = oldChat.participants_count;
} }
if(chat.username) { /* if(chat.username) {
let searchUsername = searchIndexManager.cleanUsername(chat.username); let searchUsername = searchIndexManager.cleanUsername(chat.username);
this.usernames[searchUsername] = chat.id; this.usernames[searchUsername] = chat.id;
} } */
let changedPhoto = false; let changedPhoto = false;
if(oldChat === undefined) { if(oldChat === undefined) {
@ -152,7 +157,7 @@ export class AppChatsManager {
public getChat(id: number) { public getChat(id: number) {
if(id < 0) id = -id; if(id < 0) id = -id;
return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: this.channelAccess[id]}; return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: ''/* this.channelAccess[id] */};
} }
public hasRights(id: number, action: ChatRights, flag?: keyof ChatBannedRights['pFlags']) { public hasRights(id: number, action: ChatRights, flag?: keyof ChatBannedRights['pFlags']) {
@ -239,13 +244,13 @@ export class AppChatsManager {
return true; return true;
} }
public resolveUsername(username: string) { /* public resolveUsername(username: string) {
return this.usernames[username] || 0; return this.usernames[username] || 0;
} } */
public saveChannelAccess(id: number, accessHash: string) { /* public saveChannelAccess(id: number, accessHash: string) {
this.channelAccess[id] = accessHash; this.channelAccess[id] = accessHash;
} } */
public saveIsMegagroup(id: number) { public saveIsMegagroup(id: number) {
this.megagroups[id] = true; this.megagroups[id] = true;
@ -254,7 +259,7 @@ export class AppChatsManager {
public isChannel(id: number) { public isChannel(id: number) {
if(id < 0) id = -id; if(id < 0) id = -id;
let chat = this.chats[id]; let chat = this.chats[id];
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden') || this.channelAccess[id]) { if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden')/* || this.channelAccess[id] */) {
return true; return true;
} }
return false; return false;
@ -281,7 +286,7 @@ export class AppChatsManager {
return { return {
_: 'inputChannel', _: 'inputChannel',
channel_id: id, channel_id: id,
access_hash: this.getChat(id).access_hash || this.channelAccess[id] || 0 access_hash: this.getChat(id).access_hash/* || this.channelAccess[id] */ || 0
}; };
} }
@ -296,7 +301,7 @@ export class AppChatsManager {
return { return {
_: 'inputPeerChannel', _: 'inputPeerChannel',
channel_id: id, channel_id: id,
access_hash: this.getChat(id).access_hash || this.channelAccess[id] || 0 access_hash: this.getChat(id).access_hash/* || this.channelAccess[id] */ || 0
}; };
} }

2
src/lib/appManagers/appDialogsManager.ts

@ -703,7 +703,7 @@ export class AppDialogsManager {
} }
/* if(lastMessage.from_id == auth.id) { // You: */ /* if(lastMessage.from_id == auth.id) { // You: */
if(peer._ != 'peerUser' && peerID != lastMessage.fromID) { if(peer._ != 'peerUser' && peerID != lastMessage.fromID && !lastMessage.action) {
const sender = appPeersManager.getPeer(lastMessage.fromID); const sender = appPeersManager.getPeer(lastMessage.fromID);
if(sender && sender.id) { if(sender && sender.id) {
const senderBold = document.createElement('b'); const senderBold = document.createElement('b');

9
src/lib/appManagers/appDocsManager.ts

@ -50,10 +50,11 @@ class AppDocsManager {
this.docs[doc.id] = doc; this.docs[doc.id] = doc;
// * exclude from state // * exclude from state
defineNotNumerableProperties(doc, [/* 'thumbs', */'type', 'h', 'w', 'file_name', // defineNotNumerableProperties(doc, [/* 'thumbs', */'type', 'h', 'w', 'file_name',
'file', 'duration', 'downloaded', 'url', 'audioTitle', // 'file', 'duration', 'downloaded', 'url', 'audioTitle',
'audioPerformer', 'sticker', 'stickerEmoji', 'stickerEmojiRaw', // 'audioPerformer', 'sticker', 'stickerEmoji', 'stickerEmojiRaw',
'stickerSetInput', 'stickerThumbConverted', 'animated', 'supportsStreaming']); // 'stickerSetInput', 'stickerThumbConverted', 'animated', 'supportsStreaming']);
defineNotNumerableProperties(doc, ['downloaded', 'url']);
doc.attributes.forEach(attribute => { doc.attributes.forEach(attribute => {
switch(attribute._) { switch(attribute._) {

29
src/lib/appManagers/appImManager.ts

@ -36,7 +36,7 @@ import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config'; import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from '../rootScope'; import $rootScope from '../rootScope';
import { cancelEvent, findUpClassName, findUpTag, getObjectKeysAndSort, langPack, numberWithCommas, placeCaretAtEnd, whichChild } from "../utils"; import { cancelEvent, defineNotNumerableProperties, findUpClassName, findUpTag, getObjectKeysAndSort, langPack, numberWithCommas, placeCaretAtEnd, whichChild } from "../utils";
import apiUpdatesManager from './apiUpdatesManager'; import apiUpdatesManager from './apiUpdatesManager';
import appChatsManager, { Channel, Chat } from "./appChatsManager"; import appChatsManager, { Channel, Chat } from "./appChatsManager";
import appDialogsManager from "./appDialogsManager"; import appDialogsManager from "./appDialogsManager";
@ -258,6 +258,8 @@ export class AppImManager {
const photo = appPhotosManager.getPhoto('' + tempID); const photo = appPhotosManager.getPhoto('' + tempID);
if(/* photo._ != 'photoEmpty' */photo) { if(/* photo._ != 'photoEmpty' */photo) {
const newPhoto = message.media.photo; const newPhoto = message.media.photo;
// костыль
defineNotNumerableProperties(newPhoto, ['downloaded', 'url']);
newPhoto.downloaded = photo.downloaded; newPhoto.downloaded = photo.downloaded;
newPhoto.url = photo.url; newPhoto.url = photo.url;
} }
@ -1651,30 +1653,7 @@ export class AppImManager {
bubble.className = 'bubble service'; bubble.className = 'bubble service';
let title = appPeersManager.getPeerTitle(message.fromID); bubbleContainer.innerHTML = `<div class="service-msg">${message.rReply}</div>`;
let name = document.createElement('div');
name.classList.add('name');
name.dataset.peerID = message.fromID;
name.innerHTML = title;
let str = '';
if(action.message) {
str = RichTextProcessor.wrapRichText(action.message, {noLinebreaks: true});
} else {
if(_ == "messageActionPhoneCall") {
_ += '.' + action.type;
}
// @ts-ignore
let l = langPack[_];
if(!l) {
l = '[' + _ + ']';
}
str = l[0].toUpperCase() == l[0] ? l : (name.innerText ? name.outerHTML + ' ' : '') + l;
}
bubbleContainer.innerHTML = `<div class="service-msg">${str}</div>`;
if(updatePosition) { if(updatePosition) {
this.renderMessagesQueue(message, bubble, reverse); this.renderMessagesQueue(message, bubble, reverse);

111
src/lib/appManagers/appMessagesManager.ts

@ -996,11 +996,13 @@ export class AppMessagesManager {
size: file.size size: file.size
}], }],
w: options.width, w: options.width,
h: options.height, h: options.height
downloaded: file.size,
url: options.objectURL || ''
} as any; } as any;
defineNotNumerableProperties(photo, ['downloaded', 'url']);
photo.downloaded = file.size;
photo.url = options.objectURL || '';
appPhotosManager.savePhoto(photo); appPhotosManager.savePhoto(photo);
} else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) { } else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) {
attachType = 'audio'; attachType = 'audio';
@ -1063,13 +1065,16 @@ export class AppMessagesManager {
attributes, attributes,
w: options.width, w: options.width,
h: options.height, h: options.height,
downloaded: file.size,
thumbs, thumbs,
mime_type: fileType, mime_type: fileType,
url: options.objectURL || '',
size: file.size size: file.size
} as any; } as any;
defineNotNumerableProperties(doc, ['downloaded', 'url']);
// @ts-ignore
doc.downloaded = file.size;
doc.url = options.objectURL || '';
if(isPhoto) { if(isPhoto) {
attributes.push({ attributes.push({
_: 'documentAttributeImageSize', _: 'documentAttributeImageSize',
@ -1375,13 +1380,16 @@ export class AppMessagesManager {
_: 'document', _: 'document',
id: '' + messageID, id: '' + messageID,
attributes: [videoAttribute], attributes: [videoAttribute],
downloaded: file.size,
thumbs: [], thumbs: [],
mime_type: file.type, mime_type: file.type,
url: details.objectURL || '',
size: file.size size: file.size
} as any; } as any;
defineNotNumerableProperties(doc, ['downloaded', 'url']);
// @ts-ignore
doc.downloaded = file.size;
doc.url = details.objectURL || '';
appDocsManager.saveDoc(doc); appDocsManager.saveDoc(doc);
media.document = doc; media.document = doc;
} else { } else {
@ -1396,11 +1404,14 @@ export class AppMessagesManager {
size: file.size size: file.size
} as PhotoSize], } as PhotoSize],
w: details.width, w: details.width,
h: details.height, h: details.height
downloaded: file.size,
url: details.objectURL || ''
}; };
defineNotNumerableProperties(photo, ['downloaded', 'url']);
// @ts-ignore
photo.downloaded = file.size;
photo.url = details.objectURL || '';
appPhotosManager.savePhoto(photo); appPhotosManager.savePhoto(photo);
media.photo = photo; media.photo = photo;
} }
@ -2218,7 +2229,7 @@ export class AppMessagesManager {
} }
// * exclude from state // * exclude from state
defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromID', 'fromID', 'peerID', 'reply_to_mid', 'viaBotID']); // defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromID', 'fromID', 'peerID', 'reply_to_mid', 'viaBotID']);
const peerID = this.getMessagePeer(message); const peerID = this.getMessagePeer(message);
const isChannel = message.peer_id._ == 'peerChannel'; const isChannel = message.peer_id._ == 'peerChannel';
@ -2481,52 +2492,88 @@ export class AppMessagesManager {
} }
if(message.action) { if(message.action) {
let action = message.action; const str = this.wrapMessageActionText(message);
messageText = str ? '<i>' + str + '</i>' : '';
}
let messageWrapped = '';
if(text) {
// * 80 for chatlist in landscape orientation
text = limitSymbols(text, 75, 80);
let entities = RichTextProcessor.parseEntities(text.replace(/\n/g, ' '));
messageWrapped = RichTextProcessor.wrapRichText(text, {
noLinebreaks: true,
entities: entities,
noTextFormat: true
});
}
return messageText + messageWrapped;
}
public wrapMessageActionText(message: any) {
const action = message.action;
let str = ''; let str = '';
if(action.message) { if(action.message) {
str = RichTextProcessor.wrapRichText(action.message, {noLinebreaks: true}); str = RichTextProcessor.wrapRichText(action.message, {noLinebreaks: true});
} else { } else {
let suffix = '';
let _ = action._; let _ = action._;
if(_ == "messageActionPhoneCall") { let suffix = '';
let l = '';
const getNameDivHTML = (peerID: number) => {
const title = appPeersManager.getPeerTitle(peerID);
return title ? `<div class="name inline" data-peer-i-d="${peerID}">${title}</div> ` : '';
};
switch(_) {
case "messageActionPhoneCall": {
_ += '.' + action.type; _ += '.' + action.type;
let duration = action.duration; const duration = action.duration;
if(duration) { if(duration) {
let d = []; const d: string[] = [];
d.push(duration % 60 + ' s'); d.push(duration % 60 + ' s');
if(duration >= 60) d.push((duration / 60 | 0) + ' min'); if(duration >= 60) d.push((duration / 60 | 0) + ' min');
//if(duration >= 3600) d.push((duration / 3600 | 0) + ' h'); //if(duration >= 3600) d.push((duration / 3600 | 0) + ' h');
suffix = ' (' + d.reverse().join(' ') + ')'; suffix = ' (' + d.reverse().join(' ') + ')';
} }
}
// @ts-ignore return langPack[_] + suffix;
str = (langPack[_] || action._) + suffix;
} }
//this.log('message action:', action); case 'messageActionChatDeleteUser':
case 'messageActionChatAddUsers':
case 'messageActionChatAddUser': {
let users: number[] = action.users || [action.user_id];
messageText = str ? '<i>' + str + '</i>' : ''; l = langPack[_].replace('{}', users.map((userID: number) => getNameDivHTML(userID)).join(', '));
break;
} }
let messageWrapped = ''; default:
if(text) { str = langPack[_] || `[${action._}]`;
// * 80 for chatlist in landscape orientation break;
text = limitSymbols(text, 75, 80); }
let entities = RichTextProcessor.parseEntities(text.replace(/\n/g, ' ')); if(!l) {
l = langPack[_];
if(!l) {
l = '[' + _ + ']';
}
}
messageWrapped = RichTextProcessor.wrapRichText(text, { str = l[0].toUpperCase() == l[0] ? l : getNameDivHTML(message.fromID) + l + (suffix ? ' ' : '');
noLinebreaks: true,
entities: entities,
noTextFormat: true
});
} }
return messageText + messageWrapped; //this.log('message action:', action);
return str;
} }
public editPeerFolders(peerIDs: number[], folderID: number) { public editPeerFolders(peerIDs: number[], folderID: number) {

24
src/lib/appManagers/appPeersManager.ts

@ -2,7 +2,6 @@ import { DialogPeer, InputDialogPeer, InputPeer, Peer } from "../../layer";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import { isObject } from "../utils"; import { isObject } from "../utils";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
import appStateManager from "./appStateManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC // https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
@ -22,19 +21,10 @@ const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#e
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5]; const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
export class AppPeersManager { export class AppPeersManager {
constructor() { /* public savePeerInstance(peerID: number, instance: any) {
appStateManager.getState().then((state) => { if(peerID < 0) appChatsManager.saveApiChat(instance);
for(let peerID in state.peers) {
let peer = state.peers[peerID];
this.savePeerInstance(+peerID, peer);
}
});
}
public savePeerInstance(peerID: number, instance: any) {
if(+peerID < 0) appChatsManager.saveApiChat(instance);
else appUsersManager.saveApiUser(instance); else appUsersManager.saveApiUser(instance);
} } */
public getPeerPhoto(peerID: number) { public getPeerPhoto(peerID: number) {
return peerID > 0 return peerID > 0
@ -150,13 +140,13 @@ export class AppPeersManager {
return (peerID > 0) && appUsersManager.isBot(peerID); return (peerID > 0) && appUsersManager.isBot(peerID);
} }
public getInputPeer(peerString: string): InputPeer { /* public getInputPeer(peerString: string): InputPeer {
var firstChar = peerString.charAt(0); var firstChar = peerString.charAt(0);
var peerParams = peerString.substr(1).split('_'); var peerParams = peerString.substr(1).split('_');
let id = +peerParams[0]; let id = +peerParams[0];
if(firstChar == 'u') { if(firstChar == 'u') {
appUsersManager.saveUserAccess(id, peerParams[1]); //appUsersManager.saveUserAccess(id, peerParams[1]);
return { return {
_: 'inputPeerUser', _: 'inputPeerUser',
@ -164,7 +154,7 @@ export class AppPeersManager {
access_hash: peerParams[1] access_hash: peerParams[1]
}; };
} else if(firstChar == 'c' || firstChar == 's') { } else if(firstChar == 'c' || firstChar == 's') {
appChatsManager.saveChannelAccess(id, peerParams[1]); //appChatsManager.saveChannelAccess(id, peerParams[1]);
if(firstChar == 's') { if(firstChar == 's') {
appChatsManager.saveIsMegagroup(id); appChatsManager.saveIsMegagroup(id);
} }
@ -180,7 +170,7 @@ export class AppPeersManager {
chat_id: id chat_id: id
}; };
} }
} } */
public getInputPeerByID(peerID: number): InputPeer { public getInputPeerByID(peerID: number): InputPeer {
if(!peerID) { if(!peerID) {

17
src/lib/appManagers/appStateManager.ts

@ -6,6 +6,8 @@ import EventListenerBase from '../../helpers/eventListenerBase';
import $rootScope from '../rootScope'; import $rootScope from '../rootScope';
import AppStorage from '../storage'; import AppStorage from '../storage';
import { logger } from '../logger'; import { logger } from '../logger';
import type { AppUsersManager } from './appUsersManager';
import type { AppChatsManager } from './appChatsManager';
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
const STATE_VERSION = App.version; const STATE_VERSION = App.version;
@ -13,7 +15,9 @@ const STATE_VERSION = App.version;
type State = Partial<{ type State = Partial<{
dialogs: Dialog[], dialogs: Dialog[],
allDialogsLoaded: DialogsStorage['allDialogsLoaded'], allDialogsLoaded: DialogsStorage['allDialogsLoaded'],
peers: {[peerID: string]: ReturnType<AppPeersManager['getPeer']>}, //peers: {[peerID: string]: ReturnType<AppPeersManager['getPeer']>},
chats: {[peerID: string]: ReturnType<AppChatsManager['getChat']>},
users: {[peerID: string]: ReturnType<AppUsersManager['getUser']>},
messages: any[], messages: any[],
contactsList: number[], contactsList: number[],
updates: any, updates: any,
@ -61,11 +65,9 @@ export class AppStateManager extends EventListenerBase<{
} }
} }
// will not throw error because state can be `FALSE`
const {peers} = state;
this.state = state || {}; this.state = state || {};
this.state.peers = peers || {}; this.state.chats = state.chats || {};
this.state.users = state.users || {};
this.state.version = STATE_VERSION; this.state.version = STATE_VERSION;
// ??= doesn't compiles // ??= doesn't compiles
@ -114,8 +116,9 @@ export class AppStateManager extends EventListenerBase<{
} }
public setPeer(peerID: number, peer: any) { public setPeer(peerID: number, peer: any) {
if(this.state.peers.hasOwnProperty(peerID)) return; const container = peerID > 0 ? this.state.users : this.state.chats;
this.state.peers[peerID] = peer; if(container.hasOwnProperty(peerID)) return;
container[peerID] = peer;
} }
} }

70
src/lib/appManagers/appUsersManager.ts

@ -6,57 +6,30 @@ import serverTimeManager from "../mtproto/serverTimeManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import searchIndexManager from "../searchIndexManager"; import searchIndexManager from "../searchIndexManager";
import { defineNotNumerableProperties, getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils"; import { getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
import appPeersManager from "./appPeersManager"; import appPeersManager from "./appPeersManager";
import appStateManager from "./appStateManager"; import appStateManager from "./appStateManager";
// TODO: updateUserBlocked // TODO: updateUserBlocked
/* export type User = {
_: 'user',
access_hash: string,
first_name: string,
last_name: string,
username: string,
flags: number,
id: number,
phone: string,
photo: any,
status?: Partial<{
_: 'userStatusOffline' | 'userStatusOnline' | 'userStatusRecently' | 'userStatusLastWeek' | 'userStatusLastMonth' | 'userStatusEmpty',
wasStatus: any,
was_online: number,
expires: number
}>,
initials?: string,
num?: number,
pFlags: Partial<{verified: boolean, support: boolean, self: boolean, bot: boolean, min: number, deleted: boolean}>,
rFirstName?: string,
rFullName?: string,
rPhone?: string,
sortName?: string,
sortStatus?: number,
}; */
export type User = MTUser.user; export type User = MTUser.user;
export class AppUsersManager { export class AppUsersManager {
public users: {[userID: number]: User} = {}; public users: {[userID: number]: User} = {};
public usernames: {[username: string]: number} = {}; public usernames: {[username: string]: number} = {};
public userAccess: {[userID: number]: string} = {}; //public userAccess: {[userID: number]: string} = {};
public cachedPhotoLocations: any = {}; public cachedPhotoLocations: any = {};
public contactsIndex = searchIndexManager.createIndex(); public contactsIndex = searchIndexManager.createIndex();
public contactsFillPromise: Promise<Set<number>>; public contactsFillPromise: Promise<Set<number>>;
public contactsList: Set<number> = new Set(); public contactsList: Set<number> = new Set();
public getPeersPromise: Promise<number[]>; public getTopPeersPromise: Promise<number[]>;
constructor() { constructor() {
setInterval(this.updateUsersStatuses.bind(this), 60000); setInterval(this.updateUsersStatuses, 60000);
$rootScope.$on('stateSynchronized', this.updateUsersStatuses.bind(this)); $rootScope.$on('stateSynchronized', this.updateUsersStatuses);
$rootScope.$on('apiUpdate', (e) => { $rootScope.$on('apiUpdate', (e) => {
const update = e.detail as Update; const update = e.detail as Update;
@ -137,6 +110,8 @@ export class AppUsersManager {
}); });
this.contactsFillPromise = Promise.resolve(this.contactsList); this.contactsFillPromise = Promise.resolve(this.contactsList);
} }
this.users = state.users;
}); });
} }
@ -147,12 +122,14 @@ export class AppUsersManager {
return this.contactsFillPromise = apiManager.invokeApi('contacts.getContacts', { return this.contactsFillPromise = apiManager.invokeApi('contacts.getContacts', {
hash: 0 hash: 0
}).then((result: any) => { }).then((result) => {
if(result._ == 'contacts.contacts') {
this.saveApiUsers(result.users); this.saveApiUsers(result.users);
result.contacts.forEach((contact: any) => { result.contacts.forEach((contact) => {
this.pushContact(contact.user_id); this.pushContact(contact.user_id);
}); });
}
return this.contactsList; return this.contactsList;
}); });
@ -221,10 +198,6 @@ export class AppUsersManager {
}); });
} }
/* public resolveUsername(username: string) {
return this.usernames[username] || 0;
} */
public saveApiUsers(apiUsers: any[]) { public saveApiUsers(apiUsers: any[]) {
apiUsers.forEach((user) => this.saveApiUser(user)); apiUsers.forEach((user) => this.saveApiUser(user));
} }
@ -251,7 +224,7 @@ export class AppUsersManager {
} }
// * exclude from state // * exclude from state
defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']); // defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']);
if(user.phone) { if(user.phone) {
user.rPhone = '+' + formatPhoneNumber(user.phone).formatted; user.rPhone = '+' + formatPhoneNumber(user.phone).formatted;
@ -306,9 +279,9 @@ export class AppUsersManager {
} }
} }
public saveUserAccess(id: number, accessHash: string) { /* public saveUserAccess(id: number, accessHash: string) {
this.userAccess[id] = accessHash; this.userAccess[id] = accessHash;
} } */
public getUserStatusForSort(status: User['status']) { public getUserStatusForSort(status: User['status']) {
if(status) { if(status) {
@ -336,7 +309,7 @@ export class AppUsersManager {
return id; return id;
} }
return this.users[id] || {id: id, pFlags: {deleted: true}, access_hash: this.userAccess[id]} as User; return this.users[id] || {id: id, pFlags: {deleted: true}, access_hash: ''/* this.userAccess[id] */} as User;
} }
public getSelf() { public getSelf() {
@ -462,7 +435,7 @@ export class AppUsersManager {
}; };
} }
public updateUsersStatuses() { public updateUsersStatuses = () => {
const timestampNow = tsNow(true); const timestampNow = tsNow(true);
for(const i in this.users) { for(const i in this.users) {
const user = this.users[i]; const user = this.users[i];
@ -475,7 +448,7 @@ export class AppUsersManager {
$rootScope.$broadcast('user_update', user.id); $rootScope.$broadcast('user_update', user.id);
} }
} }
} };
public forceUserOnline(id: number) { public forceUserOnline(id: number) {
if(this.isBot(id)) { if(this.isBot(id)) {
@ -571,15 +544,14 @@ export class AppUsersManager {
} */ } */
public getTopPeers(): Promise<number[]> { public getTopPeers(): Promise<number[]> {
if(this.getPeersPromise) return this.getPeersPromise; if(this.getTopPeersPromise) return this.getTopPeersPromise;
return this.getPeersPromise = appStateManager.getState().then((state) => { return this.getTopPeersPromise = appStateManager.getState().then((state) => {
if(state?.topPeers?.length) { if(state?.topPeers?.length) {
return state.topPeers; return state.topPeers;
} }
return apiManager.invokeApi('contacts.getTopPeers', { return apiManager.invokeApi('contacts.getTopPeers', {
flags: 1,
correspondents: true, correspondents: true,
offset: 0, offset: 0,
limit: 30, limit: 30,
@ -643,9 +615,9 @@ export class AppUsersManager {
return; return;
} }
var user = this.users[userID]; const user = this.users[userID];
if(user) { if(user) {
var status: any = offline ? { const status: any = offline ? {
_: 'userStatusOffline', _: 'userStatusOffline',
was_online: tsNow(true) was_online: tsNow(true)
} : { } : {

2
src/lib/mtproto/mtproto_config.ts

@ -16,7 +16,7 @@ export type UserAuth = {
export const App = { export const App = {
id: 1025907, id: 1025907,
hash: '452b0359b988148995f22ff0f4229750', hash: '452b0359b988148995f22ff0f4229750',
version: '0.3.0', version: '0.3.1',
domains: [] as string[], domains: [] as string[],
baseDcID: 2 baseDcID: 2
}; };

4
src/lib/utils.ts

@ -204,10 +204,10 @@ export const langPack: {[actionType: string]: string} = {
"messageActionChatDeletePhoto": "removed group photo", "messageActionChatDeletePhoto": "removed group photo",
"messageActionChatReturn": "returned to group", "messageActionChatReturn": "returned to group",
"messageActionChatJoined": "joined the group", "messageActionChatJoined": "joined the group",
"messageActionChatAddUser": "invited {user}", "messageActionChatAddUser": "invited {}",
"messageActionChatAddUsers": "invited {} users", "messageActionChatAddUsers": "invited {} users",
"messageActionChatLeave": "left the group", "messageActionChatLeave": "left the group",
"messageActionChatDeleteUser": "removed user", "messageActionChatDeleteUser": "removed user {}",
"messageActionChatJoinedByLink": "joined the group", "messageActionChatJoinedByLink": "joined the group",
"messageActionPinMessage": "pinned message", "messageActionPinMessage": "pinned message",
"messageActionContactSignUp": "joined Telegram", "messageActionContactSignUp": "joined Telegram",

4
src/scss/components/_global.scss

@ -96,6 +96,10 @@ Utility Classes
} }
} */ } */
.inline {
display: inline;
}
.center-align, .text-center { .center-align, .text-center {
text-align: center; text-align: center;
} }

28
src/scss/partials/_chat.scss

@ -305,7 +305,7 @@ $chat-helper-size: 39px;
width: 100%; width: 100%;
padding: 9px; padding: 9px;
/* height: 100%; */ /* height: 100%; */
max-height: 30rem; max-height: calc(30rem - var(--padding-vertical) * 2);
overflow-y: none; overflow-y: none;
resize: none; resize: none;
border: none; border: none;
@ -733,6 +733,10 @@ $chat-helper-size: 39px;
.pinned-message-content, .reply-content { .pinned-message-content, .reply-content {
padding-left: 40px; padding-left: 40px;
} }
.emoji:first-child {
margin-right: .25rem;
}
} }
html.no-touch &:hover { html.no-touch &:hover {
@ -935,7 +939,9 @@ $chat-helper-size: 39px;
} }
.input-message { .input-message {
--padding: .3125rem .5rem; --padding-vertical: .3125rem;
--padding-horizontal: .5rem;
--padding: var(--padding-vertical) var(--padding-horizontal);
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
@ -974,7 +980,8 @@ $chat-helper-size: 39px;
} */ } */
@include respond-to(handhelds) { @include respond-to(handhelds) {
--padding: .5px .5rem; --padding-vertical: .5px;
--padding-horizontal: .5rem;
width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin}); width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin});
max-width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin}); max-width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin});
min-height: $chat-input-handhelds-size; min-height: $chat-input-handhelds-size;
@ -985,14 +992,16 @@ $chat-helper-size: 39px;
} }
@include respond-to(esg-bottom) { @include respond-to(esg-bottom) {
--padding: .5px .5rem; --padding-vertical: .5px;
--padding-horizontal: .5rem;
min-height: $chat-input-handhelds-size; min-height: $chat-input-handhelds-size;
} }
&:after { &:after {
content: ''; content: '';
position: absolute; position: absolute;
bottom: -.1875rem; //bottom: -.1875rem;
bottom: -.1925rem;
right: -8.4px; right: -8.4px;
width: .5625rem; width: .5625rem;
height: 1.25rem; height: 1.25rem;
@ -1044,6 +1053,10 @@ $chat-helper-size: 39px;
z-index: 1; z-index: 1;
user-select: none; user-select: none;
@include respond-to(handhelds) {
padding-top: .25rem;
}
.chat-container.is-helper-active & { .chat-container.is-helper-active & {
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
@ -1069,7 +1082,6 @@ $chat-helper-size: 39px;
//padding: 4.5px 0; //padding: 4.5px 0;
//padding-bottom: 4.5px; //padding-bottom: 4.5px;
align-items: flex-end; align-items: flex-end;
overflow: hidden;
.btn-icon:before { .btn-icon:before {
vertical-align: bottom; vertical-align: bottom;
@ -1207,6 +1219,10 @@ $chat-helper-size: 39px;
&.is-chat-input-hidden.is-selecting:not(.backwards) { &.is-chat-input-hidden.is-selecting:not(.backwards) {
--translateY: -79px; --translateY: -79px;
@include respond-to(handhelds) {
--translateY: -58px;
}
#bubbles-inner { #bubbles-inner {
transform: translateY(calc(var(--translateY) * -1)); transform: translateY(calc(var(--translateY) * -1));
//margin-top: $chat-helper-size; //margin-top: $chat-helper-size;

11
src/scss/partials/_chatBubble.scss

@ -707,10 +707,13 @@ $bubble-margin: .25rem;
} }
.reply { .reply {
max-width: 300px;
margin-bottom: 6px; margin-bottom: 6px;
margin-top: 0; margin-top: 0;
cursor: pointer; cursor: pointer;
&-content {
max-width: 300px;
}
} }
&.is-reply { &.is-reply {
@ -1160,9 +1163,13 @@ $bubble-margin: .25rem;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
i {
font-style: normal;
}
.name { .name {
cursor: pointer; cursor: pointer;
margin-right: 5px; //margin-right: 5px;
} }
img.emoji { img.emoji {

Loading…
Cancel
Save