Browse Source

Added 'start bot' button

master
morethanwords 2 years ago
parent
commit
a490f29c40
  1. 10
      src/components/chat/bubbles.ts
  2. 24
      src/components/chat/chat.ts
  3. 73
      src/components/chat/input.ts
  4. 4
      src/components/sidebarLeft/index.ts
  5. 2
      src/helpers/dom/toggleDisability.ts
  6. 2
      src/helpers/object.ts
  7. 3
      src/layer.d.ts
  8. 30
      src/lib/appManagers/appImManager.ts
  9. 29
      src/lib/appManagers/appMessagesManager.ts
  10. 1
      src/lib/mtproto/mtproto_config.ts
  11. 3
      src/scripts/in/schema_additional_params.json

10
src/components/chat/bubbles.ts

@ -1953,7 +1953,7 @@ export default class ChatBubbles { @@ -1953,7 +1953,7 @@ export default class ChatBubbles {
this.isTopPaddingSet = false;
}
public setPeer(peerId: PeerId, lastMsgId?: number): {cached?: boolean, promise: Chat['setPeerPromise']} {
public setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string): {cached?: boolean, promise: Chat['setPeerPromise']} {
//console.time('appImManager setPeer');
//console.time('appImManager setPeer pre promise');
////console.time('appImManager: pre render start');
@ -2019,6 +2019,10 @@ export default class ChatBubbles { @@ -2019,6 +2019,10 @@ export default class ChatBubbles {
scrollable.scrollTop = scrollable.scrollHeight;
this.chat.dispatchEvent('setPeer', lastMsgId, true);
}
if(startParam !== undefined) {
this.chat.input.setStartParam(startParam);
}
return null;
}
@ -2095,7 +2099,7 @@ export default class ChatBubbles { @@ -2095,7 +2099,7 @@ export default class ChatBubbles {
if(!samePeer) {
scrollable.container.textContent = '';
//oldChatInner.remove();
this.chat.finishPeerChange(isTarget, isJump, lastMsgId);
this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam);
this.preloader.attach(this.bubblesContainer);
}
}
@ -2110,7 +2114,7 @@ export default class ChatBubbles { @@ -2110,7 +2114,7 @@ export default class ChatBubbles {
if(cached) {
if(!samePeer) {
this.chat.finishPeerChange(isTarget, isJump, lastMsgId); // * костыль
this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam); // * костыль
}
} else {
this.preloader.detach();

24
src/components/chat/chat.ts

@ -34,7 +34,7 @@ import ChatContextMenu from "./contextMenu"; @@ -34,7 +34,7 @@ import ChatContextMenu from "./contextMenu";
import ChatInput from "./input";
import ChatSelection from "./selection";
import ChatTopbar from "./topbar";
import { NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import { BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config";
import SetTransition from "../singleTransition";
import { fastRaf } from "../../helpers/schedulers";
import AppPrivateSearchTab from "../sidebarRight/tabs/search";
@ -109,6 +109,8 @@ export default class Chat extends EventListenerBase<{ @@ -109,6 +109,8 @@ export default class Chat extends EventListenerBase<{
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);
}
@ -255,7 +257,7 @@ export default class Chat extends EventListenerBase<{ @@ -255,7 +257,7 @@ export default class Chat extends EventListenerBase<{
this.selection.cleanup();
}
public setPeer(peerId: PeerId, lastMsgId?: number) {
public setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string) {
if(!peerId) {
this.inited = undefined;
} else if(!this.inited) {
@ -270,7 +272,7 @@ export default class Chat extends EventListenerBase<{ @@ -270,7 +272,7 @@ export default class Chat extends EventListenerBase<{
const samePeer = this.peerId === peerId;
if(!samePeer) {
rootScope.dispatchEvent('peer_changing', this);
this.peerId = peerId;
this.peerId = peerId || NULL_PEER_ID;
} else if(this.setPeerPromise) {
return;
}
@ -306,7 +308,11 @@ export default class Chat extends EventListenerBase<{ @@ -306,7 +308,11 @@ export default class Chat extends EventListenerBase<{
this.peerChanged = samePeer;
const result = this.bubbles.setPeer(peerId, lastMsgId);
if(startParam === undefined && this.isStartButtonNeeded()) {
startParam = BOT_START_PARAM;
}
const result = this.bubbles.setPeer(peerId, lastMsgId, startParam);
if(!result) {
return;
}
@ -361,7 +367,7 @@ export default class Chat extends EventListenerBase<{ @@ -361,7 +367,7 @@ export default class Chat extends EventListenerBase<{
return this.setPeer(this.peerId, messageId);
}
public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {
public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number, startParam?: string) {
if(this.peerChanged) return;
let peerId = this.peerId;
@ -372,7 +378,7 @@ export default class Chat extends EventListenerBase<{ @@ -372,7 +378,7 @@ export default class Chat extends EventListenerBase<{
this.topbar.setPeer(peerId);
this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);
this.bubbles.finishPeerChange();
this.input.finishPeerChange();
this.input.finishPeerChange(startParam);
appSidebarRight.sharedMediaTab.fillProfileElements();
@ -421,4 +427,10 @@ export default class Chat extends EventListenerBase<{ @@ -421,4 +427,10 @@ export default class Chat extends EventListenerBase<{
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;
}
}

73
src/components/chat/input.ts

@ -80,12 +80,13 @@ import { copy } from '../../helpers/object'; @@ -80,12 +80,13 @@ import { copy } from '../../helpers/object';
import PopupPeer from '../popups/peer';
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
import appMediaPlaybackController from '../appMediaPlaybackController';
import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
import { BOT_START_PARAM, NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
import setCaretAt from '../../helpers/dom/setCaretAt';
import CheckboxField from '../checkboxField';
import DropdownHover from '../../helpers/dropdownHover';
import RadioForm from '../radioForm';
import findUpTag from '../../helpers/dom/findUpTag';
import toggleDisability from '../../helpers/dom/toggleDisability';
const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
@ -205,6 +206,7 @@ export default class ChatInput { @@ -205,6 +206,7 @@ export default class ChatInput {
private fakeSelectionWrapper: HTMLDivElement;
private fakeWrapperTo: HTMLElement;
private toggleBotStartBtnDisability: () => void;
// private activeContainer: HTMLElement;
@ -678,6 +680,20 @@ export default class ChatInput { @@ -678,6 +680,20 @@ export default class ChatInput {
if(this.replyToMsgId && msgs.has(this.replyToMsgId)) {
this.clearHelper('reply');
}
/* if(this.chat.isStartButtonNeeded()) {
this.setStartParam(BOT_START_PARAM);
} */
}
});
this.listenerSetter.add(rootScope)('dialogs_multiupdate', (dialogs) => {
if(dialogs[this.chat.peerId]) {
if(this.startParam === BOT_START_PARAM) {
this.setStartParam();
} else { // updateNewMessage comes earlier than dialog appers
this.center(true);
}
}
});
}
@ -794,6 +810,27 @@ export default class ChatInput { @@ -794,6 +810,27 @@ export default class ChatInput {
this.botStartBtn = Button('btn-primary btn-transparent text-bold chat-input-control-button');
this.botStartBtn.append(i18n('BotStart'));
attachClickEvent(this.botStartBtn, () => {
const {startParam} = this;
if(startParam === undefined) {
return;
}
const toggle = this.toggleBotStartBtnDisability = toggleDisability([this.botStartBtn], true);
const peerId = this.chat.peerId;
const middleware = this.chat.bubbles.getMiddleware(() => {
return this.chat.peerId === peerId && this.startParam === startParam && this.toggleBotStartBtnDisability === toggle;
});
this.appMessagesManager.startBot(peerId.toUserId(), undefined, startParam).then(() => {
if(middleware()) {
toggle();
this.toggleBotStartBtnDisability = undefined;
this.setStartParam();
}
});
}, {listenerSetter: this.listenerSetter});
this.controlContainer.append(this.botStartBtn);
}
@ -824,6 +861,10 @@ export default class ChatInput { @@ -824,6 +861,10 @@ export default class ChatInput {
return;
}
if(neededFakeContainer === this.fakeWrapperTo) {
return;
}
/* if(neededFakeContainer === this.botStartContainer && this.fakeWrapperTo === this.fakeSelectionWrapper) {
this.inputContainer.classList.remove('is-centering');
void this.rowsWrapper.offsetLeft; // reflow
@ -882,10 +923,23 @@ export default class ChatInput { @@ -882,10 +923,23 @@ export default class ChatInput {
};
}
public setStartParam(startParam?: string) {
if(this.startParam === startParam) {
return;
}
this.startParam = startParam;
this.center(true);
}
public getNeededFakeContainer() {
if(this.chat.selection.isSelecting) {
return this.fakeSelectionWrapper;
} else if(this.startParam || !this.chat.canSend() || this.chat.type === 'pinned') {
} else if(this.startParam !== undefined ||
!this.chat.canSend() ||
this.chat.type === 'pinned' ||
this.chat.isStartButtonNeeded()
) {
return this.controlContainer;
}
}
@ -1011,6 +1065,12 @@ export default class ChatInput { @@ -1011,6 +1065,12 @@ export default class ChatInput {
cancelSelection();
this.lastTimeType = 0;
this.startParam = undefined;
if(this.toggleBotStartBtnDisability) {
this.toggleBotStartBtnDisability();
this.toggleBotStartBtnDisability = undefined;
}
if(this.messageInput) {
this.clearInput();
@ -1062,7 +1122,7 @@ export default class ChatInput { @@ -1062,7 +1122,7 @@ export default class ChatInput {
return true;
}
public finishPeerChange() {
public finishPeerChange(startParam?: string) {
const peerId = this.chat.peerId;
const {forwardElements, btnScheduled, replyKeyboard, sendMenu, goDownBtn, chatInput} = this;
@ -1110,7 +1170,12 @@ export default class ChatInput { @@ -1110,7 +1170,12 @@ export default class ChatInput {
this.pinnedControlBtn.append(i18n(this.appPeersManager.canPinMessage(this.chat.peerId) ? 'Chat.Input.UnpinAll' : 'Chat.Pinned.DontShow'));
}
this.center();
// * testing
// this.startParam = this.appPeersManager.isBot(peerId) ? '123' : undefined;
this.startParam = startParam;
this.center(false);
}
public updateMessageInput() {

4
src/components/sidebarLeft/index.ts

@ -159,7 +159,9 @@ export class AppSidebarLeft extends SidebarSlider { @@ -159,7 +159,9 @@ export class AppSidebarLeft extends SidebarSlider {
icon: 'help',
text: 'TelegramFeatures',
onClick: () => {
appImManager.openUsername('TelegramTips');
appImManager.openUsername({
userName: 'TelegramTips'
});
}
}, {
icon: 'bug',

2
src/helpers/dom/toggleDisability.ts

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function toggleDisability(elements: HTMLElement[], disable: boolean) {
export default function toggleDisability(elements: HTMLElement[], disable: boolean): () => void {
if(disable) {
elements.forEach(el => el.setAttribute('disabled', 'true'));
} else {

2
src/helpers/object.ts

@ -30,7 +30,7 @@ export function copy<T>(obj: T): T { @@ -30,7 +30,7 @@ export function copy<T>(obj: T): T {
//lastly, handle objects
// @ts-ignore
let clonedObj = new obj.constructor();
for(var prop in obj){
for(var prop in obj) {
if(obj.hasOwnProperty(prop)) {
clonedObj[prop] = copy(obj[prop]);
}

3
src/layer.d.ts vendored

@ -885,7 +885,8 @@ export namespace Message { @@ -885,7 +885,8 @@ export namespace Message {
totalEntities?: MessageEntity[],
reply_to_mid?: number,
savedFrom?: string,
sponsoredMessage?: SponsoredMessage.sponsoredMessage
sponsoredMessage?: SponsoredMessage.sponsoredMessage,
promise?: CancellablePromise<void>
};
export type messageService = {

30
src/lib/appManagers/appImManager.ts

@ -604,7 +604,12 @@ export class AppImManager { @@ -604,7 +604,12 @@ export class AppImManager {
const postId = link.post ? appMessagesIdsManager.generateMessageId(+link.post) : undefined;
const commentId = link.comment ? appMessagesIdsManager.generateMessageId(+link.comment) : undefined;
this.openUsername(link.domain, postId, undefined, commentId);
this.openUsername({
userName: link.domain,
lastMsgId: postId,
commentId,
startParam: link.start
});
break;
}
@ -740,7 +745,10 @@ export class AppImManager { @@ -740,7 +745,10 @@ export class AppImManager {
switch(p[0]) {
case '@': {
this.openUsername(p, postId);
this.openUsername({
userName: p,
lastMsgId: postId
});
break;
}
@ -759,8 +767,15 @@ export class AppImManager { @@ -759,8 +767,15 @@ export class AppImManager {
//location.hash = '';
};
public openUsername(username: string, lastMsgId?: number, threadId?: number, commentId?: number) {
return appUsersManager.resolveUsername(username).then(peer => {
public openUsername(options: {
userName: string,
lastMsgId?: number,
threadId?: number,
commentId?: number,
startParam?: string
}) {
const {userName, lastMsgId, threadId, commentId, startParam} = options;
return appUsersManager.resolveUsername(userName).then(peer => {
const isUser = peer._ === 'user';
const peerId = peer.id.toPeerId(!isUser);
@ -772,7 +787,8 @@ export class AppImManager { @@ -772,7 +787,8 @@ export class AppImManager {
return this.setInnerPeer({
peerId,
lastMsgId
lastMsgId,
startParam: startParam
});
}, (err) => {
if(err.type === 'USERNAME_NOT_OCCUPIED') {
@ -1433,6 +1449,8 @@ export class AppImManager { @@ -1433,6 +1449,8 @@ export class AppImManager {
this.init = null;
}
options.peerId ??= NULL_PEER_ID;
const {peerId, lastMsgId} = options;
const chat = this.chat;
@ -1476,7 +1494,7 @@ export class AppImManager { @@ -1476,7 +1494,7 @@ export class AppImManager {
}
if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) {
const result = chat.setPeer(peerId, lastMsgId);
const result = chat.setPeer(peerId, lastMsgId, options.startParam);
// * wait for cached render
const promise = result?.cached ? result.promise : Promise.resolve();

29
src/lib/appManagers/appMessagesManager.ts

@ -448,7 +448,7 @@ export class AppMessagesManager { @@ -448,7 +448,7 @@ export class AppMessagesManager {
silent: true
}> = {}) {
if(!text.trim()) {
return;
return Promise.resolve();
}
//this.checkSendOptions(options);
@ -552,7 +552,13 @@ export class AppMessagesManager { @@ -552,7 +552,13 @@ export class AppMessagesManager {
//if(is<Updates.updateShortSentMessage>(updates, updates._ === 'updateShortSentMessage')) {
if(updates._ === 'updateShortSentMessage') {
//assumeType<Updates.updateShortSentMessage>(updates);
// * fix copying object with promise
const promise = message.promise;
delete message.promise;
const newMessage = copy(message);
message.promise = promise;
newMessage.date = updates.date;
newMessage.id = updates.id;
newMessage.media = updates.media;
@ -596,8 +602,10 @@ export class AppMessagesManager { @@ -596,8 +602,10 @@ export class AppMessagesManager {
// $timeout(function () {
// ApiUpdatesManager.processUpdateMessage(upd)
// }, 5000)
}, (/* error: any */) => {
message.promise.resolve();
}, (error: any) => {
toggleError(true);
message.promise.reject(error);
}).finally(() => {
if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {
delete this.pendingAfterMsgs[peerId];
@ -610,6 +618,8 @@ export class AppMessagesManager { @@ -610,6 +618,8 @@ export class AppMessagesManager {
threadId: options.threadId,
clearDraft: options.clearDraft
});
return message.promise;
}
public sendFile(peerId: PeerId, file: File | Blob | MyDocument, options: Partial<{
@ -1027,8 +1037,11 @@ export class AppMessagesManager { @@ -1027,8 +1037,11 @@ export class AppMessagesManager {
}
toggleError(true);
throw error;
});
});
sentDeferred.then(message.promise.resolve, message.promise.reject);
}
return {message, promise: sentDeferred};
@ -1120,6 +1133,7 @@ export class AppMessagesManager { @@ -1120,6 +1133,7 @@ export class AppMessagesManager {
const invoke = (multiMedia: InputSingleMedia[]) => {
this.setTyping(peerId, {_: 'sendMessageCancelAction'});
const deferred = deferredPromise<void>();
this.sendSmthLazyLoadQueue.push({
load: () => {
return apiManager.invokeApi('messages.sendMultiMedia', {
@ -1131,11 +1145,15 @@ export class AppMessagesManager { @@ -1131,11 +1145,15 @@ export class AppMessagesManager {
clear_draft: options.clearDraft
}).then((updates) => {
apiUpdatesManager.processUpdateMessage(updates);
deferred.resolve();
}, (error) => {
messages.forEach(message => toggleError(message, true));
deferred.reject(error);
});
}
});
return deferred;
};
const promises: Promise<InputSingleMedia>[] = messages.map((message) => {
@ -1181,8 +1199,8 @@ export class AppMessagesManager { @@ -1181,8 +1199,8 @@ export class AppMessagesManager {
});
});
Promise.all(promises).then(inputs => {
invoke(inputs.filter(Boolean));
return Promise.all(promises).then(inputs => {
return invoke(inputs.filter(Boolean));
});
}
@ -1362,6 +1380,8 @@ export class AppMessagesManager { @@ -1362,6 +1380,8 @@ export class AppMessagesManager {
threadId: options.threadId,
clearDraft: options.clearDraft
});
return message.promise;
}
/* private checkSendOptions(options: Partial<{
@ -1472,6 +1492,7 @@ export class AppMessagesManager { @@ -1472,6 +1492,7 @@ export class AppMessagesManager {
replies: this.generateReplies(peerId),
views: isBroadcast && 1,
pending: true,
promise: options.groupId === undefined ? deferredPromise() : undefined
};
return message;

1
src/lib/mtproto/mtproto_config.ts

@ -14,3 +14,4 @@ export const NULL_PEER_ID: PeerId = 0; @@ -14,3 +14,4 @@ export const NULL_PEER_ID: PeerId = 0;
export const REPLIES_PEER_ID: PeerId = 1271266957;
export const SERVICE_PEER_ID: PeerId = 777000;
export const MUTE_UNTIL = 0x7FFFFFFF;
export const BOT_START_PARAM = '';

3
src/scripts/in/schema_additional_params.json

@ -82,7 +82,8 @@ @@ -82,7 +82,8 @@
{"name": "savedFrom", "type": "string"},
{"name": "sponsored", "type": "true"},
{"name": "local", "type": "true"},
{"name": "sponsoredMessage", "type": "SponsoredMessage.sponsoredMessage"}
{"name": "sponsoredMessage", "type": "SponsoredMessage.sponsoredMessage"},
{"name": "promise", "type": "CancellablePromise<void>"}
]
}, {
"predicate": "messageService",

Loading…
Cancel
Save