From 76a9abc67843ae8d2fa4f58cb5e07568246d19e9 Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sat, 13 Mar 2021 06:22:42 +0400 Subject: [PATCH] Handle peer title and bio change --- src/components/avatar.ts | 9 +- src/components/chat/bubbles.ts | 16 +-- src/components/chat/topbar.ts | 10 +- src/components/peerTitle.ts | 59 +++++++++++ .../sidebarLeft/tabs/editProfile.ts | 4 +- src/components/sidebarRight/tabs/editGroup.ts | 27 +++++ .../sidebarRight/tabs/sharedMedia.ts | 75 ++++++++++--- src/lib/appManagers/appChatsManager.ts | 100 +++++++++++++----- src/lib/appManagers/appDialogsManager.ts | 42 ++++---- src/lib/appManagers/appImManager.ts | 4 + src/lib/appManagers/appUsersManager.ts | 31 +++++- src/lib/mtproto/networker.ts | 8 +- src/lib/rootScope.ts | 3 + src/scss/partials/_button.scss | 26 ++--- src/scss/partials/_rightSidebar.scss | 6 +- 15 files changed, 319 insertions(+), 101 deletions(-) create mode 100644 src/components/peerTitle.ts diff --git a/src/components/avatar.ts b/src/components/avatar.ts index c0938ba7..a39e3c7c 100644 --- a/src/components/avatar.ts +++ b/src/components/avatar.ts @@ -7,15 +7,16 @@ import { Photo } from "../layer"; import appPeersManager from "../lib/appManagers/appPeersManager"; //import type { LazyLoadQueueIntersector } from "./lazyLoadQueue"; -rootScope.on('avatar_update', (e) => { - let peerId = e; - +const onAvatarUpdate = (peerId: number) => { appProfileManager.removeFromAvatarsCache(peerId); (Array.from(document.querySelectorAll('avatar-element[peer="' + peerId + '"]')) as AvatarElement[]).forEach(elem => { //console.log('updating avatar:', elem); elem.update(); }); -}); +}; + +rootScope.on('avatar_update', onAvatarUpdate); +rootScope.on('peer_title_edit', onAvatarUpdate); export default class AvatarElement extends HTMLElement { private peerId: number; diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 378f7e0a..01903d49 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -47,6 +47,7 @@ import RepliesElement from "./replies"; import DEBUG from "../../config/debug"; import { SliceEnd } from "../../helpers/slicedArray"; import serverTimeManager from "../../lib/mtproto/serverTimeManager"; +import PeerTitle from "../peerTitle"; const USE_MEDIA_TAILS = false; const IGNORE_ACTIONS = ['messageActionHistoryClear']; @@ -155,7 +156,7 @@ export default class ChatBubbles { const message = this.chat.getMessage(mid); - if(+bubble.dataset.timestamp >= (message.date - serverTimeManager.serverTimeOffset - 1)) { + if(+bubble.dataset.timestamp >= (message.date + serverTimeManager.serverTimeOffset - 1)) { return; } @@ -2353,16 +2354,19 @@ export default class ChatBubbles { const needName = (peerId < 0 && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId; if(needName || message.fwd_from || message.reply_to_mid) { // chat - let title = this.appPeersManager.getPeerTitle(message.fwdFromId || message.fromId); + let title: HTMLSpanElement; const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === message.fwdFromId; let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id; if(isHidden) { ///////this.log('message to render hidden', message); - title = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name); + title = document.createElement('span'); + title.innerHTML = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name); //title = message.fwd_from.from_name; bubble.classList.add('hidden-profile'); + } else { + title = new PeerTitle({peerId: message.fwdFromId || message.fromId}).element; } //this.log(title); @@ -2383,11 +2387,11 @@ export default class ChatBubbles { if(this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || isForwardFromChannel) { nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fwdFromId, false); - nameDiv.innerHTML = title; + nameDiv.append(title); } else { /* const fromTitle = message.fromId === this.myID || appPeersManager.isBroadcast(message.fwdFromId || message.fromId) ? '' : `
${appPeersManager.getPeerTitle(message.fromId)}
`; nameDiv.innerHTML = fromTitle + 'Forwarded from ' + title; */ - nameDiv.innerHTML = 'Forwarded from ' + title; + nameDiv.append('Forwarded from ', title); if(savedFrom) { nameDiv.dataset.savedFrom = savedFrom; @@ -2400,7 +2404,7 @@ export default class ChatBubbles { if(!bubble.classList.contains('sticker') && needName) { let nameDiv = document.createElement('div'); nameDiv.classList.add('name'); - nameDiv.innerHTML = title; + nameDiv.append(title); if(!our) { nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fromId, false); diff --git a/src/components/chat/topbar.ts b/src/components/chat/topbar.ts index fdec123a..6e6acf80 100644 --- a/src/components/chat/topbar.ts +++ b/src/components/chat/topbar.ts @@ -22,7 +22,7 @@ import PopupDeleteDialog from "../popups/deleteDialog"; import appNavigationController from "../appNavigationController"; import { LEFT_COLUMN_ACTIVE_CLASSNAME } from "../sidebarLeft"; import AppPrivateSearchTab from "../sidebarRight/tabs/search"; -import { SliderSuperTab } from "../slider"; +import PeerTitle from "../peerTitle"; export default class ChatTopbar { container: HTMLDivElement; @@ -482,8 +482,12 @@ export default class ChatTopbar { }); } } else if(this.chat.type === 'chat') { - if(this.peerId === rootScope.myId) title = 'Saved Messages'; - else title = this.appPeersManager.getPeerTitle(this.peerId); + this.title.innerHTML = ''; + this.title.append(new PeerTitle({ + peerId: this.peerId, + dialog: true, + }).element); + return; } this.title.innerHTML = title; diff --git a/src/components/peerTitle.ts b/src/components/peerTitle.ts new file mode 100644 index 00000000..a92f056d --- /dev/null +++ b/src/components/peerTitle.ts @@ -0,0 +1,59 @@ +import { MOUNT_CLASS_TO } from "../config/debug"; +import appPeersManager from "../lib/appManagers/appPeersManager"; +import rootScope from "../lib/rootScope"; + +export type PeerTitleOptions = { + peerId: number, + plainText?: boolean, + onlyFirstName?: boolean, + dialog?: boolean +}; + +const weakMap: WeakMap = new WeakMap(); + +MOUNT_CLASS_TO && (MOUNT_CLASS_TO.peerTitleWeakMap = weakMap); + +rootScope.on('peer_title_edit', (peerId) => { + const elements = Array.from(document.querySelectorAll(`.peer-title[data-peer-id="${peerId}"]`)) as HTMLElement[]; + elements.forEach(element => { + const peerTitle = weakMap.get(element); + //console.log('in the summer silence i was doing nothing', peerTitle, peerId); + + if(peerTitle) { + peerTitle.update(); + } + }); +}); + +export default class PeerTitle { + public element: HTMLElement; + public peerId: number; + public plainText = false; + public onlyFirstName = false; + public dialog = false; + + constructor(options: PeerTitleOptions) { + this.element = document.createElement('span'); + this.element.classList.add('peer-title'); + + this.update(options); + weakMap.set(this.element, this); + } + + public update(options?: PeerTitleOptions) { + if(options) { + for(let i in options) { + // @ts-ignore + this.element.dataset[i] = options[i] ? '' + (typeof(options[i]) === 'boolean' ? +options[i] : options[i]) : '0'; + // @ts-ignore + this[i] = options[i]; + } + } + + if(this.peerId !== rootScope.myId || !this.dialog) { + this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName); + } else { + this.element.innerHTML = this.onlyFirstName ? 'Saved' : 'Saved Messages'; + } + } +} diff --git a/src/components/sidebarLeft/tabs/editProfile.ts b/src/components/sidebarLeft/tabs/editProfile.ts index 957907d8..41b1aa9e 100644 --- a/src/components/sidebarLeft/tabs/editProfile.ts +++ b/src/components/sidebarLeft/tabs/editProfile.ts @@ -158,14 +158,14 @@ export default class AppEditProfileTab extends SliderSuperTab { let promises: Promise[] = []; promises.push(appProfileManager.updateProfile(this.firstNameInputField.value, this.lastNameInputField.value, this.bioInputField.value).then(() => { - this.slider.selectTab(0); + this.close(); }, (err) => { console.error('updateProfile error:', err); })); if(this.editPeer.uploadAvatar) { promises.push(this.editPeer.uploadAvatar().then(inputFile => { - appProfileManager.uploadProfilePhoto(inputFile); + return appProfileManager.uploadProfilePhoto(inputFile); })); } diff --git a/src/components/sidebarRight/tabs/editGroup.ts b/src/components/sidebarRight/tabs/editGroup.ts index ddfacde5..9d558923 100644 --- a/src/components/sidebarRight/tabs/editGroup.ts +++ b/src/components/sidebarRight/tabs/editGroup.ts @@ -7,6 +7,7 @@ import CheckboxField from "../../checkboxField"; import Button from "../../button"; import appChatsManager from "../../../lib/appManagers/appChatsManager"; import appProfileManager from "../../../lib/appManagers/appProfileManager"; +import { attachClickEvent } from "../../../helpers/dom"; export default class AppEditGroupTab extends SliderSuperTab { private groupNameInputField: InputField; @@ -77,6 +78,32 @@ export default class AppEditGroupTab extends SliderSuperTab { section.content.append(this.editPeer.avatarEdit.container, inputWrapper, groupTypeRow.container, permissionsRow.container, administratorsRow.container); this.scrollable.append(section.container); + + attachClickEvent(this.editPeer.nextBtn, () => { + this.editPeer.nextBtn.disabled = true; + + let promises: Promise[] = []; + + const id = -this.peerId; + if(this.groupNameInputField.isValid()) { + promises.push(appChatsManager.editTitle(id, this.groupNameInputField.value)); + } + + if(this.descriptionInputField.isValid()) { + promises.push(appChatsManager.editAbout(id, this.descriptionInputField.value)); + } + + if(this.editPeer.uploadAvatar) { + promises.push(this.editPeer.uploadAvatar().then(inputFile => { + return appChatsManager.editPhoto(id, inputFile); + })); + } + + Promise.race(promises).finally(() => { + this.editPeer.nextBtn.removeAttribute('disabled'); + this.close(); + }); + }, {listenerSetter: this.listenerSetter}); } { diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts index ff6b082c..b4714ca7 100644 --- a/src/components/sidebarRight/tabs/sharedMedia.ts +++ b/src/components/sidebarRight/tabs/sharedMedia.ts @@ -11,11 +11,12 @@ import AvatarElement from "../../avatar"; import Scrollable from "../../scrollable"; import { SliderTab } from "../../slider"; import CheckboxField from "../../checkboxField"; -import { attachClickEvent, cancelEvent } from "../../../helpers/dom"; +import { attachClickEvent } from "../../../helpers/dom"; import appSidebarRight from ".."; import { TransitionSlider } from "../../transition"; import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager"; import AppEditGroupTab from "./editGroup"; +import PeerTitle from "../../peerTitle"; let setText = (text: string, el: HTMLDivElement) => { window.requestAnimationFrame(() => { @@ -66,6 +67,8 @@ export default class AppSharedMediaTab implements SliderTab { cleaned: boolean; searchSuper: AppSearchSuper; + private setBioTimeout: number; + public init() { this.container = document.getElementById('shared-media-container'); this.closeBtn = this.container.querySelector('.sidebar-header .btn-icon'); @@ -164,6 +167,12 @@ export default class AppSharedMediaTab implements SliderTab { } }); + rootScope.on('peer_bio_edit', (peerId) => { + if(peerId === this.peerId) { + this.setBio(true); + } + }); + rootScope.on('user_update', (e) => { const userId = e; @@ -276,6 +285,10 @@ export default class AppSharedMediaTab implements SliderTab { this.profileElements.notificationsCheckbox.checked = true; this.profileElements.notificationsStatus.innerText = 'Enabled'; this.editBtn.style.display = 'none'; + if(this.setBioTimeout) { + window.clearTimeout(this.setBioTimeout); + this.setBioTimeout = 0; + } this.searchSuper.cleanupHTML(); this.searchSuper.selectTab(0, false); @@ -312,7 +325,6 @@ export default class AppSharedMediaTab implements SliderTab { this.cleaned = false; const peerId = this.peerId; - const threadId = this.threadId; this.cleanupHTML(); @@ -342,11 +354,42 @@ export default class AppSharedMediaTab implements SliderTab { if(user.phone && peerId !== rootScope.myId) { setText(user.rPhone, this.profileElements.phone); } - - appProfileManager.getProfile(peerId).then(userFull => { + }/* else { + //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : ''; + } */ + + this.setBio(); + + this.profileElements.name.innerHTML = ''; + this.profileElements.name.append(new PeerTitle({ + peerId, + dialog: true + }).element); + + this.editBtn.style.display = ''; + + this.setPeerStatus(true); + } + + public setBio(override?: true) { + if(this.setBioTimeout) { + window.clearTimeout(this.setBioTimeout); + this.setBioTimeout = 0; + } + + const peerId = this.peerId; + const threadId = this.threadId; + + if(!peerId) { + return; + } + + let promise: Promise; + if(peerId > 0) { + promise = appProfileManager.getProfile(peerId, override).then(userFull => { if(this.peerId !== peerId || this.threadId !== threadId) { this.log.warn('peer changed'); - return; + return false; } if(userFull.rAbout && peerId !== rootScope.myId) { @@ -354,15 +397,13 @@ export default class AppSharedMediaTab implements SliderTab { } //this.log('userFull', userFull); + return true; }); } else { - //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : ''; - let chat = appPeersManager.getPeer(peerId); - - appProfileManager.getChatFull(chat.id).then((chatFull) => { + promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => { if(this.peerId !== peerId || this.threadId !== threadId) { this.log.warn('peer changed'); - return; + return false; } //this.log('chatInfo res 2:', chatFull); @@ -370,16 +411,16 @@ export default class AppSharedMediaTab implements SliderTab { if(chatFull.about) { setText(RichTextProcessor.wrapRichText(chatFull.about), this.profileElements.bio); } + + return true; }); } - let title: string; - if(peerId === rootScope.myId) title = 'Saved Messages'; - else title = appPeersManager.getPeerTitle(peerId); - this.profileElements.name.innerHTML = title; - this.editBtn.style.display = ''; - - this.setPeerStatus(true); + promise.then((canSetNext) => { + if(canSetNext) { + this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3); + } + }); } onOpenAfterTimeout() { diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts index 210d4957..ae806772 100644 --- a/src/lib/appManagers/appChatsManager.ts +++ b/src/lib/appManagers/appChatsManager.ts @@ -7,6 +7,7 @@ import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; import apiUpdatesManager from "./apiUpdatesManager"; import appMessagesManager from "./appMessagesManager"; +import appPeersManager from "./appPeersManager"; import appProfileManager from "./appProfileManager"; import appStateManager from "./appStateManager"; import appUsersManager from "./appUsersManager"; @@ -137,7 +138,7 @@ export class AppChatsManager { this.usernames[searchUsername] = chat.id; } */ - let changedPhoto = false; + let changedPhoto = false, changedTitle = false; if(oldChat === undefined) { this.chats[chat.id] = chat; } else { @@ -147,6 +148,10 @@ export class AppChatsManager { changedPhoto = true; } + if(oldChat.title !== chat.title) { + changedTitle = true; + } + safeReplaceObject(oldChat, chat); rootScope.broadcast('chat_update', chat.id); } @@ -159,6 +164,10 @@ export class AppChatsManager { if(changedPhoto) { rootScope.broadcast('avatar_update', -chat.id); } + + if(changedTitle) { + rootScope.broadcast('peer_title_edit', -chat.id); + } } public getChat(id: number) { @@ -413,7 +422,10 @@ export class AppChatsManager { }).then((updates: any) => { apiUpdatesManager.processUpdateMessage(updates); - return updates.chats[0].id; + const channelId = updates.chats[0].id; + rootScope.broadcast('history_focus', -channelId); + + return channelId; }); } @@ -436,33 +448,11 @@ export class AppChatsManager { }).then(updates => { apiUpdatesManager.processUpdateMessage(updates); - return (updates as any as Updates.updates).chats[0].id; - }); - } - - public editPhoto(id: number, inputFile: InputFile) { - const isChannel = this.isChannel(id); + const chatId = (updates as any as Updates.updates).chats[0].id; + rootScope.broadcast('history_focus', -chatId); - const inputChatPhoto: InputChatPhoto.inputChatUploadedPhoto = { - _: 'inputChatUploadedPhoto', - file: inputFile - }; - - if(isChannel) { - return apiManager.invokeApi('channels.editPhoto', { - channel: this.getChannelInput(id), - photo: inputChatPhoto - }).then(updates => { - apiUpdatesManager.processUpdateMessage(updates); - }); - } else { - return apiManager.invokeApi('messages.editChatPhoto', { - chat_id: id, - photo: inputChatPhoto - }).then(updates => { - apiUpdatesManager.processUpdateMessage(updates); - }); - } + return chatId; + }); } public async getOnlines(id: number): Promise { @@ -544,6 +534,60 @@ export class AppChatsManager { public leave(id: number) { return this.isChannel(id) ? this.leaveChannel(id) : this.leaveChat(id); } + + public editPhoto(id: number, inputFile: InputFile) { + const inputChatPhoto: InputChatPhoto = { + _: 'inputChatUploadedPhoto', + file: inputFile + }; + + let promise: any; + if(this.isChannel(id)) { + promise = apiManager.invokeApi('channels.editPhoto', { + channel: this.getChannelInput(id), + photo: inputChatPhoto + }); + } else { + promise = apiManager.invokeApi('messages.editChatPhoto', { + chat_id: id, + photo: inputChatPhoto + }); + } + + return promise.then((updates: any) => { + apiUpdatesManager.processUpdateMessage(updates); + }); + } + + public editTitle(id: number, title: string) { + let promise: any; + + if(this.isChannel(id)) { + promise = apiManager.invokeApi('channels.editTitle', { + channel: this.getChannelInput(id), + title + }); + } else { + promise = apiManager.invokeApi('messages.editChatTitle', { + chat_id: id, + title + }); + } + + return promise.then((updates: any) => { + apiUpdatesManager.processUpdateMessage(updates); + }); + } + + public editAbout(id: number, about: string) { + return apiManager.invokeApi('messages.editChatAbout', { + peer: appPeersManager.getInputPeerById(-id), + about + }).then(bool => { + //apiUpdatesManager.processUpdateMessage(updates); + rootScope.broadcast('peer_bio_edit', -id); + }); + } } const appChatsManager = new AppChatsManager(); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 844c929b..eb5c6617 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -28,6 +28,7 @@ import App from "../../config/app"; import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug"; import appNotificationsManager from "./appNotificationsManager"; import { InputNotifyPeer } from "../../layer"; +import PeerTitle from "../../components/peerTitle"; type DialogDom = { avatarEl: AvatarElement, @@ -43,8 +44,8 @@ type DialogDom = { muteAnimationTimeout?: number }; -const testScroll = false; -let testTopSlice = 1; +//const testScroll = false; +//let testTopSlice = 1; class ConnectionStatusComponent { public static CHANGE_STATE_DELAY = 1000; @@ -270,7 +271,7 @@ export class AppDialogsManager { this.setListClickListener(this.chatList, null, true); - if(testScroll) { + /* if(testScroll) { let i = 0; let add = () => { let li = document.createElement('li'); @@ -284,7 +285,7 @@ export class AppDialogsManager { add(); } (window as any).addElement = add; - } + } */ rootScope.on('user_update', (e) => { const userId = e; @@ -712,9 +713,9 @@ export class AppDialogsManager { } private loadDialogs(side: SliceSides = 'bottom') { - if(testScroll) { + /* if(testScroll) { return; - } + } */ if(this.loadDialogsPromise/* || 1 === 1 */) return this.loadDialogsPromise; @@ -1081,16 +1082,17 @@ export class AppDialogsManager { if(sender && sender.id) { const senderBold = document.createElement('b'); - let str = ''; if(sender.id === rootScope.myId) { - str = 'You'; + senderBold.innerHTML = 'You'; } else { //str = sender.first_name || sender.last_name || sender.username; - str = appPeersManager.getPeerTitle(lastMessage.fromId, true, true); + senderBold.append(new PeerTitle({ + peerId: lastMessage.fromId, + onlyFirstName: true, + }).element); } - //senderBold.innerText = str + ': '; - senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreaks: true, noLinks: true}) + ': '; + senderBold.append(': '); //console.log(sender, senderBold.innerText); dom.lastMessageSpan.prepend(senderBold); } //////// else console.log('no sender', lastMessage, peerId); @@ -1229,8 +1231,6 @@ export class AppDialogsManager { } } - let title = appPeersManager.getPeerTitle(peerId, false, onlyFirstName); - const avatarEl = new AvatarElement(); avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0'); avatarEl.setAttribute('peer', '' + peerId); @@ -1260,14 +1260,14 @@ export class AppDialogsManager { const titleSpanContainer = document.createElement('span'); titleSpanContainer.classList.add('user-title'); - const titleSpan = document.createElement('span'); - - if(peerId === rootScope.myId && meAsSaved) { - title = onlyFirstName ? 'Saved' : 'Saved Messages'; - } + const peerTitle = new PeerTitle({ + peerId, + dialog: meAsSaved, + onlyFirstName, + plainText: false + }); - titleSpan.innerHTML = title; - titleSpanContainer.append(titleSpan); + titleSpanContainer.append(peerTitle.element); //p.classList.add('') // в других случаях иконка верификации не нужна (а первый - это главные чатлисты) @@ -1329,7 +1329,7 @@ export class AppDialogsManager { const dom: DialogDom = { avatarEl, captionDiv, - titleSpan, + titleSpan: peerTitle.element, titleSpanContainer, statusSpan, lastTimeSpan, diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index c4c92647..0bec2707 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -192,6 +192,10 @@ export class AppImManager { } }); + rootScope.on('history_focus', (peerId) => { + this.setInnerPeer(peerId); + }); + /* rootScope.on('peer_changing', (chat) => { this.saveChatPosition(chat); }); diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 39aebcbd..4067de98 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -40,7 +40,7 @@ export class AppUsersManager { const update = e as Update; //console.log('on apiUpdate', update); switch(update._) { - case 'updateUserStatus': + case 'updateUserStatus': { const userId = update.user_id; const user = this.users[userId]; if(user) { @@ -58,7 +58,9 @@ export class AppUsersManager { user.sortStatus = this.getUserStatusForSort(user.status); rootScope.broadcast('user_update', userId); } //////else console.warn('No user by id:', userId); + break; + } case 'updateUserPhoto': { const userId = update.user_id; @@ -84,6 +86,22 @@ export class AppUsersManager { break; } + case 'updateUserName': { + const userId = update.user_id; + const user = this.users[userId]; + if(user) { + this.forceUserOnline(userId); + + this.saveApiUser(Object.assign({}, user, { + first_name: update.first_name, + last_name: update.last_name, + username: update.username + })); + } + + break; + } + /* case 'updateContactLink': this.onContactUpdated(update.user_id, update.my_link._ === 'contactLinkContact'); break; */ @@ -305,10 +323,17 @@ export class AppUsersManager { user.sortStatus = this.getUserStatusForSort(user.status); } + let changedTitle = false; const oldUser = this.users[userId]; if(oldUser === undefined) { this.users[userId] = user; } else { + if(user.first_name !== oldUser.first_name + || user.last_name !== oldUser.last_name + || user.username !== oldUser.username) { + changedTitle = true; + } + safeReplaceObject(oldUser, user); } @@ -318,6 +343,10 @@ export class AppUsersManager { safeReplaceObject(this.cachedPhotoLocations[userId], user && user.photo ? user.photo : {empty: true}); } + + if(changedTitle) { + rootScope.broadcast('peer_title_edit', user.id); + } } /* public saveUserAccess(id: number, accessHash: string) { diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index 7a22649c..64f9615a 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -1249,23 +1249,23 @@ export default class MTPNetworker { const nextReq = Date.now() + (delay || 0); if(this.nextReq && (delay === undefined || this.nextReq <= nextReq)) { - this.debug && this.log('scheduleRequest: nextReq', this.nextReq, nextReq); + //this.debug && this.log('scheduleRequest: nextReq', this.nextReq, nextReq); return; } - this.debug && this.log('scheduleRequest: delay', delay); + //this.debug && this.log('scheduleRequest: delay', delay); /* if(this.nextReqTimeout) { return; } */ - const perf = performance.now(); + //const perf = performance.now(); if(this.nextReqTimeout) { clearTimeout(this.nextReqTimeout); } const cb = () => { - this.debug && this.log('scheduleRequest: timeout delay was:', performance.now() - perf); + //this.debug && this.log('scheduleRequest: timeout delay was:', performance.now() - perf); this.nextReqTimeout = 0; this.nextReq = 0; diff --git a/src/lib/rootScope.ts b/src/lib/rootScope.ts index da5302ef..ed3e1ca0 100644 --- a/src/lib/rootScope.ts +++ b/src/lib/rootScope.ts @@ -21,6 +21,8 @@ export type BroadcastEvents = { 'peer_pinned_hidden': {peerId: number, maxId: number}, 'peer_typings': {peerId: number, typings: UserTyping[]}, 'peer_block': {peerId: number, blocked: boolean}, + 'peer_title_edit': number, + 'peer_bio_edit': number, 'filter_delete': MyDialogFilter, 'filter_update': MyDialogFilter, @@ -43,6 +45,7 @@ export type BroadcastEvents = { 'history_delete': {peerId: number, msgs: {[mid: number]: true}}, 'history_forbidden': number, 'history_reload': number, + 'history_focus': number, //'history_request': void, 'message_edit': {storage: MessagesStorage, peerId: number, mid: number}, diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss index 26965470..0775938a 100644 --- a/src/scss/partials/_button.scss +++ b/src/scss/partials/_button.scss @@ -1,3 +1,16 @@ +.btn, .btn-icon { + background: none; + outline: none; + border: none; + cursor: pointer; + + body.animation-level-0 & { + transition: none; + } + + @include btn-hoverable(); +} + .btn-icon { text-align: center; font-size: 1.5rem; @@ -339,19 +352,6 @@ } } -.btn, .btn-icon { - background: none; - outline: none; - border: none; - cursor: pointer; - - body.animation-level-0 & { - transition: none; - } - - @include btn-hoverable(); -} - .btn-color-primary { background: $color-blue; color: #fff; diff --git a/src/scss/partials/_rightSidebar.scss b/src/scss/partials/_rightSidebar.scss index 8e461c90..10424651 100644 --- a/src/scss/partials/_rightSidebar.scss +++ b/src/scss/partials/_rightSidebar.scss @@ -776,11 +776,13 @@ } .sidebar-left-section { - padding-bottom: 0; - &:first-child { padding-top: 0; } + + &:not(:last-child) { + padding-bottom: 0; + } } .checkbox-field {