Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
9.8 KiB
300 lines
9.8 KiB
/* |
|
* 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<ChatSendAs['updateManual']>; |
|
private middleware: ReturnType<typeof getMiddleware>; |
|
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<ButtonMenuItemOptions>[] = 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<AckedResult<PeerId>> { |
|
// 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((sendAsPeers) => { |
|
if(!middleware()) return; |
|
|
|
const peers = sendAsPeers.filter((sendAsPeer) => !sendAsPeer.pFlags.premium_required).map((sendAsPeer) => sendAsPeer.peer); |
|
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(); |
|
} |
|
}
|
|
|