588 lines
20 KiB
TypeScript
588 lines
20 KiB
TypeScript
/*
|
|
* https://github.com/morethanwords/tweb
|
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
*/
|
|
|
|
import type { AppNotificationsManager } from "../../lib/appManagers/appNotificationsManager";
|
|
import type { AppChatsManager, ChatRights } from "../../lib/appManagers/appChatsManager";
|
|
import type { AppDocsManager } from "../../lib/appManagers/appDocsManager";
|
|
import type { AppImManager } from "../../lib/appManagers/appImManager";
|
|
import type { AppInlineBotsManager } from "../../lib/appManagers/appInlineBotsManager";
|
|
import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManager";
|
|
import type { AppPeersManager } from "../../lib/appManagers/appPeersManager";
|
|
import type { AppPhotosManager } from "../../lib/appManagers/appPhotosManager";
|
|
import type { AppPollsManager } from "../../lib/appManagers/appPollsManager";
|
|
import type { AppProfileManager } from "../../lib/appManagers/appProfileManager";
|
|
import type { AppStickersManager } from "../../lib/appManagers/appStickersManager";
|
|
import type { AppUsersManager } from "../../lib/appManagers/appUsersManager";
|
|
import type { AppWebPagesManager } from "../../lib/appManagers/appWebPagesManager";
|
|
import type { ApiManagerProxy } from "../../lib/mtproto/mtprotoworker";
|
|
import type { AppDraftsManager } from "../../lib/appManagers/appDraftsManager";
|
|
import type { AppEmojiManager } from "../../lib/appManagers/appEmojiManager";
|
|
import type { ServerTimeManager } from "../../lib/mtproto/serverTimeManager";
|
|
import type { AppMessagesIdsManager } from "../../lib/appManagers/appMessagesIdsManager";
|
|
import type { AppGroupCallsManager } from "../../lib/appManagers/appGroupCallsManager";
|
|
import type { AppReactionsManager } from "../../lib/appManagers/appReactionsManager";
|
|
import type stateStorage from '../../lib/stateStorage';
|
|
import EventListenerBase from "../../helpers/eventListenerBase";
|
|
import { logger, LogTypes } from "../../lib/logger";
|
|
import rootScope from "../../lib/rootScope";
|
|
import appSidebarRight from "../sidebarRight";
|
|
import ChatBubbles from "./bubbles";
|
|
import ChatContextMenu from "./contextMenu";
|
|
import ChatInput from "./input";
|
|
import ChatSelection from "./selection";
|
|
import ChatTopbar from "./topbar";
|
|
import { BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
|
|
import SetTransition from "../singleTransition";
|
|
import AppPrivateSearchTab from "../sidebarRight/tabs/search";
|
|
import renderImageFromUrl, { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
|
import mediaSizes from "../../helpers/mediaSizes";
|
|
import ChatSearch from "./search";
|
|
import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
|
|
import getAutoDownloadSettingsByPeerId, { ChatAutoDownloadSettings } from "../../helpers/autoDownload";
|
|
import ChatBackgroundGradientRenderer from "./gradientRenderer";
|
|
import ChatBackgroundPatternRenderer from "./patternRenderer";
|
|
import pause from "../../helpers/schedulers/pause";
|
|
|
|
export type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';
|
|
|
|
export default class Chat extends EventListenerBase<{
|
|
setPeer: (mid: number, isTopMessage: boolean) => void
|
|
}> {
|
|
public container: HTMLElement;
|
|
public backgroundEl: HTMLElement;
|
|
|
|
public topbar: ChatTopbar;
|
|
public bubbles: ChatBubbles;
|
|
public input: ChatInput;
|
|
public selection: ChatSelection;
|
|
public contextMenu: ChatContextMenu;
|
|
public search: ChatSearch;
|
|
|
|
public wasAlreadyUsed: boolean;
|
|
// public initPeerId = 0;
|
|
public peerId: PeerId;
|
|
public threadId: number;
|
|
public setPeerPromise: Promise<void>;
|
|
public peerChanged: boolean;
|
|
|
|
public log: ReturnType<typeof logger>;
|
|
|
|
public type: ChatType;
|
|
|
|
public noForwards: boolean;
|
|
|
|
public inited: boolean;
|
|
|
|
public isRestricted: boolean;
|
|
public autoDownload: ChatAutoDownloadSettings;
|
|
|
|
public gradientRenderer: ChatBackgroundGradientRenderer;
|
|
public patternRenderer: ChatBackgroundPatternRenderer;
|
|
public gradientCanvas: HTMLCanvasElement;
|
|
public patternCanvas: HTMLCanvasElement;
|
|
public backgroundTempId: number;
|
|
public setBackgroundPromise: Promise<void>;
|
|
// public renderDarkPattern: () => Promise<void>;
|
|
|
|
constructor(
|
|
public appImManager: AppImManager,
|
|
public appChatsManager: AppChatsManager,
|
|
public appDocsManager: AppDocsManager,
|
|
public appInlineBotsManager: AppInlineBotsManager,
|
|
public appMessagesManager: AppMessagesManager,
|
|
public appPeersManager: AppPeersManager,
|
|
public appPhotosManager: AppPhotosManager,
|
|
public appProfileManager: AppProfileManager,
|
|
public appStickersManager: AppStickersManager,
|
|
public appUsersManager: AppUsersManager,
|
|
public appWebPagesManager: AppWebPagesManager,
|
|
public appPollsManager: AppPollsManager,
|
|
public apiManager: ApiManagerProxy,
|
|
public appDraftsManager: AppDraftsManager,
|
|
public serverTimeManager: ServerTimeManager,
|
|
public storage: typeof stateStorage,
|
|
public appNotificationsManager: AppNotificationsManager,
|
|
public appEmojiManager: AppEmojiManager,
|
|
public appMessagesIdsManager: AppMessagesIdsManager,
|
|
public appGroupCallsManager: AppGroupCallsManager,
|
|
public appReactionsManager: AppReactionsManager
|
|
) {
|
|
super();
|
|
|
|
this.type = 'chat';
|
|
|
|
this.container = document.createElement('div');
|
|
this.container.classList.add('chat', 'tabs-tab');
|
|
|
|
this.backgroundEl = document.createElement('div');
|
|
this.backgroundEl.classList.add('chat-background');
|
|
|
|
// * constructor end
|
|
|
|
this.log = logger('CHAT', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);
|
|
//this.log.error('Chat construction');
|
|
|
|
this.peerId = NULL_PEER_ID;
|
|
|
|
this.container.append(this.backgroundEl);
|
|
this.appImManager.chatsContainer.append(this.container);
|
|
|
|
this.backgroundTempId = 0;
|
|
}
|
|
|
|
public setBackground(url: string, skipAnimation?: boolean): Promise<void> {
|
|
const theme = rootScope.getTheme();
|
|
|
|
let item: HTMLElement;
|
|
const isColorBackground = !!theme.background.color && !theme.background.slug && !theme.background.intensity;
|
|
if(
|
|
isColorBackground &&
|
|
document.documentElement.style.cursor === 'grabbing' &&
|
|
this.gradientRenderer &&
|
|
!this.patternRenderer
|
|
) {
|
|
this.gradientCanvas.dataset.colors = theme.background.color;
|
|
this.gradientRenderer.init(this.gradientCanvas);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
const tempId = ++this.backgroundTempId;
|
|
|
|
const previousGradientRenderer = this.gradientRenderer;
|
|
const previousPatternRenderer = this.patternRenderer;
|
|
const previousGradientCanvas = this.gradientCanvas;
|
|
const previousPatternCanvas = this.patternCanvas;
|
|
|
|
this.gradientRenderer =
|
|
this.patternRenderer =
|
|
this.gradientCanvas =
|
|
this.patternCanvas =
|
|
// this.renderDarkPattern =
|
|
undefined;
|
|
|
|
const intensity = theme.background.intensity && theme.background.intensity / 100;
|
|
const isDarkPattern = !!intensity && intensity < 0;
|
|
|
|
let patternRenderer: ChatBackgroundPatternRenderer;
|
|
let patternCanvas = item?.firstElementChild as HTMLCanvasElement;
|
|
let gradientCanvas: HTMLCanvasElement;
|
|
if(!item) {
|
|
item = document.createElement('div');
|
|
item.classList.add('chat-background-item');
|
|
|
|
if(url) {
|
|
if(intensity) {
|
|
item.classList.add('is-pattern');
|
|
|
|
const rect = this.appImManager.chatsContainer.getBoundingClientRect();
|
|
patternRenderer = this.patternRenderer = ChatBackgroundPatternRenderer.getInstance({
|
|
url,
|
|
width: rect.width,
|
|
height: rect.height,
|
|
mask: isDarkPattern
|
|
});
|
|
|
|
patternCanvas = this.patternCanvas = patternRenderer.createCanvas();
|
|
patternCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-pattern-canvas');
|
|
|
|
if(isDarkPattern) {
|
|
item.classList.add('is-dark');
|
|
}
|
|
|
|
// if(isDarkPattern) {
|
|
// this.renderDarkPattern = () => {
|
|
// return patternRenderer.exportCanvasPatternToImage(patternCanvas).then(url => {
|
|
// if(this.backgroundTempId !== tempId) {
|
|
// return;
|
|
// }
|
|
|
|
// gradientCanvas.style.webkitMaskImage = `url(${url})`;
|
|
// });
|
|
// };
|
|
// }
|
|
} else if(theme.background.slug) {
|
|
item.classList.add('is-image');
|
|
}
|
|
} else if(theme.background.color) {
|
|
item.classList.add('is-color');
|
|
}
|
|
}
|
|
|
|
let gradientRenderer: ChatBackgroundGradientRenderer;
|
|
const color = theme.background.color;
|
|
if(color) {
|
|
// if(color.includes(',')) {
|
|
const {canvas, gradientRenderer: _gradientRenderer} = ChatBackgroundGradientRenderer.create(color);
|
|
gradientRenderer = this.gradientRenderer = _gradientRenderer;
|
|
gradientCanvas = this.gradientCanvas = canvas;
|
|
gradientCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-color-canvas');
|
|
|
|
if(rootScope.settings.animationsEnabled) {
|
|
gradientRenderer.scrollAnimate(true);
|
|
}
|
|
// } else {
|
|
// item.style.backgroundColor = color;
|
|
// item.style.backgroundImage = 'none';
|
|
// }
|
|
}
|
|
|
|
if(patternRenderer) {
|
|
const setOpacityTo = isDarkPattern ? gradientCanvas : patternCanvas;
|
|
setOpacityTo.style.setProperty('--opacity-max', '' + Math.abs(intensity));
|
|
}
|
|
|
|
const promise = new Promise<void>((resolve) => {
|
|
const cb = () => {
|
|
if(this.backgroundTempId !== tempId) {
|
|
if(patternRenderer) {
|
|
patternRenderer.cleanup(patternCanvas);
|
|
}
|
|
|
|
if(gradientRenderer) {
|
|
gradientRenderer.cleanup();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
const prev = this.backgroundEl.lastElementChild as HTMLElement;
|
|
|
|
if(prev === item) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
const append = [
|
|
gradientCanvas,
|
|
// isDarkPattern && this.renderDarkPattern ? undefined : patternCanvas
|
|
patternCanvas
|
|
].filter(Boolean);
|
|
if(append.length) {
|
|
item.append(...append);
|
|
}
|
|
|
|
this.backgroundEl.append(item);
|
|
|
|
SetTransition(item, 'is-visible', true, !skipAnimation ? 200 : 0, prev ? () => {
|
|
if(previousPatternRenderer) {
|
|
previousPatternRenderer.cleanup(previousPatternCanvas);
|
|
}
|
|
|
|
if(previousGradientRenderer) {
|
|
previousGradientRenderer.cleanup();
|
|
}
|
|
|
|
prev.remove();
|
|
} : null, 2);
|
|
|
|
resolve();
|
|
};
|
|
|
|
if(patternRenderer) {
|
|
const renderPatternPromise = patternRenderer.renderToCanvas(patternCanvas);
|
|
renderPatternPromise.then(() => {
|
|
if(this.backgroundTempId !== tempId) {
|
|
return;
|
|
}
|
|
|
|
let promise: Promise<any>;
|
|
// if(isDarkPattern && this.renderDarkPattern) {
|
|
// promise = this.renderDarkPattern();
|
|
// } else {
|
|
promise = Promise.resolve();
|
|
// }
|
|
|
|
promise.then(cb);
|
|
});
|
|
} else if(url) {
|
|
renderImageFromUrl(item, url, cb);
|
|
} else {
|
|
cb();
|
|
}
|
|
});
|
|
|
|
return this.setBackgroundPromise = Promise.race([
|
|
pause(500),
|
|
promise
|
|
]);
|
|
}
|
|
|
|
public setType(type: ChatType) {
|
|
this.type = type;
|
|
|
|
if(this.type === 'scheduled') {
|
|
this.getMessagesStorage = () => this.appMessagesManager.getScheduledMessagesStorage(this.peerId);
|
|
//this.getMessage = (mid) => this.appMessagesManager.getMessageFromStorage(this.appMessagesManager.getScheduledMessagesStorage(this.peerId), mid);
|
|
}
|
|
}
|
|
|
|
public init(/* peerId: PeerId */) {
|
|
// this.initPeerId = peerId;
|
|
|
|
this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager, this.appProfileManager, this.appUsersManager, this.appGroupCallsManager);
|
|
this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager, this.appDraftsManager, this.appMessagesIdsManager, this.appChatsManager, this.appReactionsManager, this.appWebPagesManager);
|
|
this.input = new ChatInput(this, this.appMessagesManager, this.appMessagesIdsManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager, this.appInlineBotsManager, this.appProfileManager);
|
|
this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);
|
|
this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager, this.appMessagesIdsManager, this.appReactionsManager);
|
|
|
|
if(this.type === 'chat') {
|
|
this.topbar.constructUtils();
|
|
this.topbar.constructPeerHelpers();
|
|
} else if(this.type === 'pinned') {
|
|
this.topbar.constructPinnedHelpers();
|
|
} else if(this.type === 'discussion') {
|
|
this.topbar.constructUtils();
|
|
this.topbar.constructDiscussionHelpers();
|
|
}
|
|
|
|
this.topbar.construct();
|
|
this.input.construct();
|
|
|
|
if(this.type === 'chat') { // * гений в деле, разный порядок из-за разной последовательности действий
|
|
this.bubbles.constructPeerHelpers();
|
|
this.input.constructPeerHelpers();
|
|
} else if(this.type === 'pinned') {
|
|
this.bubbles.constructPinnedHelpers();
|
|
this.input.constructPinnedHelpers();
|
|
} else if(this.type === 'scheduled') {
|
|
this.bubbles.constructScheduledHelpers();
|
|
this.input.constructPeerHelpers();
|
|
} else if(this.type === 'discussion') {
|
|
this.bubbles.constructPeerHelpers();
|
|
this.input.constructPeerHelpers();
|
|
}
|
|
|
|
if(this.type !== 'scheduled' && !IS_TOUCH_SUPPORTED) {
|
|
this.bubbles.setReactionsHoverListeners();
|
|
}
|
|
|
|
this.container.classList.add('type-' + this.type);
|
|
this.container.append(this.topbar.container, this.bubbles.bubblesContainer, this.input.chatInput);
|
|
|
|
this.bubbles.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {
|
|
if(this.peerId === migrateFrom) {
|
|
this.setPeer(migrateTo);
|
|
}
|
|
});
|
|
|
|
this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => {
|
|
if(e.peerId === this.peerId) {
|
|
this.appImManager.setPeer();
|
|
}
|
|
});
|
|
}
|
|
|
|
public beforeDestroy() {
|
|
this.bubbles.cleanup();
|
|
}
|
|
|
|
private cleanupBackground() {
|
|
++this.backgroundTempId;
|
|
if(this.patternRenderer) {
|
|
this.patternRenderer.cleanup(this.patternCanvas);
|
|
this.patternRenderer = undefined;
|
|
}
|
|
|
|
if(this.gradientRenderer) {
|
|
this.gradientRenderer.cleanup();
|
|
this.gradientRenderer = undefined;
|
|
}
|
|
}
|
|
|
|
public destroy() {
|
|
//const perf = performance.now();
|
|
|
|
this.topbar.destroy();
|
|
this.bubbles.destroy();
|
|
this.input.destroy();
|
|
this.contextMenu && this.contextMenu.destroy();
|
|
|
|
this.cleanupBackground();
|
|
|
|
delete this.topbar;
|
|
delete this.bubbles;
|
|
delete this.input;
|
|
delete this.selection;
|
|
delete this.contextMenu;
|
|
|
|
this.container.remove();
|
|
|
|
//this.log.error('Chat destroy time:', performance.now() - perf);
|
|
}
|
|
|
|
public cleanup(helperToo = true) {
|
|
this.input.cleanup(helperToo);
|
|
this.selection.cleanup();
|
|
}
|
|
|
|
public setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string) {
|
|
if(!peerId) {
|
|
this.inited = undefined;
|
|
} else if(!this.inited) {
|
|
if(this.init) {
|
|
this.init(/* peerId */);
|
|
this.init = null;
|
|
}
|
|
|
|
this.inited = true;
|
|
}
|
|
|
|
const samePeer = this.peerId === peerId;
|
|
if(!samePeer) {
|
|
rootScope.dispatchEvent('peer_changing', this);
|
|
this.peerId = peerId || NULL_PEER_ID;
|
|
} else if(this.setPeerPromise) {
|
|
return;
|
|
}
|
|
|
|
//console.time('appImManager setPeer');
|
|
//console.time('appImManager setPeer pre promise');
|
|
////console.time('appImManager: pre render start');
|
|
if(!peerId) {
|
|
appSidebarRight.toggleSidebar(false);
|
|
this.cleanup(true);
|
|
this.topbar.setPeer(peerId);
|
|
this.bubbles.setPeer(peerId);
|
|
rootScope.dispatchEvent('peer_changed', peerId);
|
|
|
|
return;
|
|
}
|
|
|
|
// set new
|
|
if(!samePeer) {
|
|
const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);
|
|
if(searchTab) {
|
|
searchTab.close();
|
|
}
|
|
|
|
this.noForwards = this.appPeersManager.noForwards(peerId);
|
|
this.isRestricted = this.appPeersManager.isRestricted(peerId);
|
|
this.container.classList.toggle('no-forwards', this.noForwards);
|
|
|
|
appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);
|
|
this.input.clearHelper(); // костыль
|
|
this.selection.cleanup(); // TODO: REFACTOR !!!!!!
|
|
this.setAutoDownloadMedia();
|
|
}
|
|
|
|
this.peerChanged = samePeer;
|
|
|
|
if(startParam === undefined && this.isStartButtonNeeded()) {
|
|
startParam = BOT_START_PARAM;
|
|
}
|
|
|
|
const result = this.bubbles.setPeer(peerId, lastMsgId, startParam);
|
|
if(!result) {
|
|
return;
|
|
}
|
|
|
|
const {promise} = result;
|
|
|
|
//console.timeEnd('appImManager setPeer pre promise');
|
|
|
|
const setPeerPromise = this.setPeerPromise = promise.finally(() => {
|
|
if(this.setPeerPromise === setPeerPromise) {
|
|
this.setPeerPromise = null;
|
|
}
|
|
});
|
|
|
|
if(!samePeer) {
|
|
appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);
|
|
appSidebarRight.sharedMediaTab.loadSidebarMedia(true);
|
|
}
|
|
/* this.setPeerPromise.then(() => {
|
|
appSidebarRight.sharedMediaTab.loadSidebarMedia(false);
|
|
}); */
|
|
|
|
return result;
|
|
}
|
|
|
|
public setAutoDownloadMedia() {
|
|
this.autoDownload = getAutoDownloadSettingsByPeerId(this.peerId);
|
|
}
|
|
|
|
public setMessageId(messageId?: number) {
|
|
return this.setPeer(this.peerId, messageId);
|
|
}
|
|
|
|
public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number, startParam?: string) {
|
|
if(this.peerChanged) return;
|
|
|
|
let peerId = this.peerId;
|
|
this.peerChanged = true;
|
|
|
|
this.cleanup(false);
|
|
|
|
this.topbar.setPeer(peerId);
|
|
this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);
|
|
this.bubbles.finishPeerChange();
|
|
this.input.finishPeerChange(startParam);
|
|
|
|
appSidebarRight.sharedMediaTab.fillProfileElements();
|
|
|
|
this.log.setPrefix('CHAT-' + peerId + '-' + this.type);
|
|
|
|
rootScope.dispatchEvent('peer_changed', peerId);
|
|
this.wasAlreadyUsed = true;
|
|
}
|
|
|
|
public getMessagesStorage() {
|
|
return this.appMessagesManager.getMessagesStorage(this.peerId);
|
|
}
|
|
|
|
public getMessage(mid: number) {
|
|
return this.appMessagesManager.getMessageFromStorage(this.getMessagesStorage(), mid);
|
|
//return this.appMessagesManager.getMessageByPeer(this.peerId, mid);
|
|
}
|
|
|
|
public getMidsByMid(mid: number) {
|
|
return this.appMessagesManager.getMidsByMessage(this.getMessage(mid));
|
|
}
|
|
|
|
public isAnyGroup() {
|
|
return this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || this.appPeersManager.isAnyGroup(this.peerId);
|
|
}
|
|
|
|
public initSearch(query?: string) {
|
|
if(!this.peerId) return;
|
|
|
|
if(mediaSizes.isMobile) {
|
|
if(!this.search) {
|
|
this.search = new ChatSearch(this.topbar, this, query);
|
|
} else {
|
|
this.search.setQuery(query);
|
|
}
|
|
} else {
|
|
let tab = appSidebarRight.getTab(AppPrivateSearchTab);
|
|
if(!tab) {
|
|
tab = new AppPrivateSearchTab(appSidebarRight);
|
|
}
|
|
|
|
tab.open(this.peerId, this.threadId, this.bubbles.onDatePick, query);
|
|
}
|
|
}
|
|
|
|
public canSend(action?: ChatRights) {
|
|
return this.appMessagesManager.canSendToPeer(this.peerId, this.threadId, action);
|
|
}
|
|
|
|
public isStartButtonNeeded() {
|
|
return this.appPeersManager.isBot(this.peerId) &&
|
|
!this.appMessagesManager.getDialogOnly(this.peerId) &&
|
|
!this.appMessagesManager.getHistoryStorage(this.peerId).history.length;
|
|
}
|
|
|
|
public getMessageSendingParams() {
|
|
return {
|
|
threadId: this.threadId,
|
|
replyToMsgId: this.input.replyToMsgId,
|
|
scheduleDate: this.input.scheduleDate,
|
|
sendSilent: this.input.sendSilent,
|
|
sendAsPeerId: this.input.sendAsPeerId
|
|
};
|
|
}
|
|
}
|