/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ import indexOfAndSplice from '../../helpers/array/indexOfAndSplice'; import callbackify from '../../helpers/callbackify'; import ListenerSetter from '../../helpers/listenerSetter'; import {getMiddleware} from '../../helpers/middleware'; import {modifyAckedPromise} from '../../helpers/modifyAckedResult'; import {ChatFull} from '../../layer'; import {AppManagers} from '../../lib/appManagers/managers'; import getPeerId from '../../lib/appManagers/utils/peers/getPeerId'; import {i18n} from '../../lib/langPack'; import {AckedResult} from '../../lib/mtproto/superMessagePort'; import rootScope from '../../lib/rootScope'; import AvatarElement from '../avatar'; import ButtonMenu, {ButtonMenuItemOptions} from '../buttonMenu'; import ButtonMenuToggle from '../buttonMenuToggle'; import PeerTitle from '../peerTitle'; import SetTransition from '../singleTransition'; import getChatMembersString from '../wrappers/getChatMembersString'; const SEND_AS_ANIMATION_DURATION = 300; export default class ChatSendAs { private avatar: AvatarElement; private container: HTMLElement; private closeBtn: HTMLElement; private btnMenu: HTMLElement; private sendAsPeerIds: PeerId[]; private sendAsPeerId: PeerId; private updatingPromise: ReturnType; private middleware: ReturnType; private listenerSetter: ListenerSetter; private peerId: PeerId; private addedListener: boolean; constructor( private managers: AppManagers, private onReady: (container: HTMLElement, skipAnimation?: boolean) => void, private onChange: (sendAsPeerId: PeerId) => void ) { this.middleware = getMiddleware(); this.listenerSetter = new ListenerSetter(); this.construct(); } private construct() { this.container = document.createElement('div'); this.container.classList.add('new-message-send-as-container'); this.closeBtn = document.createElement('div'); this.closeBtn.classList.add('new-message-send-as-close', 'new-message-send-as-avatar', 'tgico-close'); const sendAsButtons: ButtonMenuItemOptions[] = [{ text: 'SendMessageAsTitle', onClick: undefined }]; let previousAvatar: HTMLElement; const onSendAsMenuToggle = (visible: boolean) => { if(visible) { previousAvatar = this.avatar; } const isChanged = this.avatar !== previousAvatar; const useRafs = !visible && isChanged ? 2 : 0; SetTransition(this.closeBtn, 'is-visible', visible, SEND_AS_ANIMATION_DURATION, undefined, useRafs); if(!isChanged) { SetTransition(previousAvatar, 'is-visible', !visible, SEND_AS_ANIMATION_DURATION, undefined, useRafs); } }; ButtonMenuToggle({ noRipple: true, listenerSetter: this.listenerSetter, container: this.container }, 'top-right', sendAsButtons, () => { onSendAsMenuToggle(true); }, () => { onSendAsMenuToggle(false); }); sendAsButtons[0].element.classList.add('btn-menu-item-header'); this.btnMenu = this.container.firstElementChild as any; this.btnMenu.classList.add('scrollable', 'scrollable-y'); this.container.append(this.closeBtn); } private async updateButtons(peerIds: PeerId[]) { const promises: Promise[] = peerIds.map(async(sendAsPeerId, idx) => { const textElement = document.createElement('div'); const subtitle = document.createElement('div'); subtitle.classList.add('btn-menu-item-subtitle'); if(sendAsPeerId.isUser()) { subtitle.append(i18n('Chat.SendAs.PersonalAccount')); } else if(sendAsPeerId === this.peerId) { subtitle.append(i18n('VoiceChat.DiscussionGroup')); } else { subtitle.append(await getChatMembersString(sendAsPeerId.toChatId())); } textElement.append( new PeerTitle({peerId: sendAsPeerId}).element, subtitle ); return { onClick: idx ? async() => { const currentPeerId = this.peerId; this.changeSendAsPeerId(sendAsPeerId); const middleware = this.middleware.get(); const executeButtonsUpdate = () => { if(this.sendAsPeerId !== sendAsPeerId || !middleware()) return; const peerIds = this.sendAsPeerIds.slice(); indexOfAndSplice(peerIds, sendAsPeerId); peerIds.unshift(sendAsPeerId); this.updateButtons(peerIds); }; if(rootScope.settings.animationsEnabled) { setTimeout(executeButtonsUpdate, 250); } else { executeButtonsUpdate(); } // return; this.managers.appMessagesManager.saveDefaultSendAs(currentPeerId, sendAsPeerId); } : undefined, textElement }; }); const buttons = await Promise.all(promises); const btnMenu = ButtonMenu(buttons/* , this.listenerSetter */); buttons.forEach((button, idx) => { const peerId = peerIds[idx]; const avatar = new AvatarElement(); avatar.classList.add('avatar-26', 'btn-menu-item-icon'); avatar.updateWithOptions({peerId}); if(!idx) { avatar.classList.add('active'); } button.element.prepend(avatar); }); Array.from(this.btnMenu.children).slice(1).forEach((node) => node.remove()); this.btnMenu.append(...Array.from(btnMenu.children)); } private async updateAvatar(sendAsPeerId: PeerId, skipAnimation?: boolean) { const previousAvatar = this.avatar; if(previousAvatar) { if(previousAvatar.peerId === sendAsPeerId) { return; } } if(!previousAvatar) { skipAnimation = true; } const useRafs = skipAnimation ? 0 : 2; const duration = skipAnimation ? 0 : SEND_AS_ANIMATION_DURATION; const avatar = this.avatar = new AvatarElement(); avatar.classList.add('new-message-send-as-avatar', 'avatar-30'); await avatar.updateWithOptions({ isDialog: false, peerId: sendAsPeerId }); SetTransition(avatar, 'is-visible', true, duration, undefined, useRafs); if(previousAvatar) { SetTransition(previousAvatar, 'is-visible', false, duration, () => { previousAvatar.remove(); }, useRafs); } this.container.append(avatar); } private changeSendAsPeerId(sendAsPeerId: PeerId, skipAnimation?: boolean) { this.sendAsPeerId = sendAsPeerId; this.onChange(sendAsPeerId); return this.updateAvatar(sendAsPeerId, skipAnimation); } private getDefaultSendAs(): Promise> { // return rootScope.myId; return this.managers.acknowledged.appProfileManager.getChannelFull(this.peerId.toChatId()).then((acked) => { return { cached: acked.cached, result: acked.result.then((channelFull) => { return channelFull.default_send_as ? getPeerId(channelFull.default_send_as) : undefined }) }; }); } public async updateManual(skipAnimation?: boolean): Promise<() => void> { const peerId = this.peerId; if(this.updatingPromise || !(await this.managers.appPeersManager.isChannel(peerId))) { return; } const middleware = this.middleware.get(() => { return !this.updatingPromise || this.updatingPromise === updatingPromise; }); const {container} = this; const chatId = peerId.toChatId(); const result = (await modifyAckedPromise(this.getDefaultSendAs())).result; // const result = Promise.resolve(this.getDefaultSendAs()); const wasSkippingAnimation = skipAnimation; if(result instanceof Promise) { skipAnimation = undefined; } const auto = wasSkippingAnimation && !skipAnimation; const updatingPromise = this.updatingPromise = callbackify(result, async(sendAsPeerId) => { if(!middleware() || sendAsPeerId === undefined) return; await this.changeSendAsPeerId(sendAsPeerId, skipAnimation); if(!middleware()) return; this.managers.appChatsManager.getSendAs(chatId).then((peers) => { if(!middleware()) return; const peerIds = peers.map((peer) => getPeerId(peer)); this.sendAsPeerIds = peerIds.slice(); indexOfAndSplice(peerIds, sendAsPeerId); peerIds.unshift(sendAsPeerId); this.updateButtons(peerIds); }); const callback = () => { this.onReady(container, skipAnimation); if(!this.addedListener) { this.listenerSetter.add(rootScope)('peer_full_update', (peerId) => { if(this.peerId === peerId) { this.update(); } }); this.addedListener = true; } }; if(auto) { callback(); return; } return callback; }); updatingPromise.finally(() => { if(this.updatingPromise === updatingPromise) { this.updatingPromise = undefined; } }); if(!auto) { return updatingPromise; } } public update(skipAnimation?: boolean) { return this.updateManual(skipAnimation).then((callback) => callback && callback()); } public setPeerId(peerId?: PeerId) { /* if(this.avatar) { this.avatar.remove(); this.avatar = undefined; } */ this.middleware.clean(); this.updatingPromise = undefined; this.peerId = peerId; } public destroy() { this.container.remove(); this.setPeerId(); this.listenerSetter.removeAll(); } }