diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ad49b37a9..d6d9679da 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -953,6 +953,7 @@ void ApiWrap::requestMoreDialogsIfNeeded() { } } requestContacts(); + _session->data().shortcutMessages().preloadShortcuts(); } void ApiWrap::updateDialogsOffset( @@ -3606,6 +3607,17 @@ void ApiWrap::cancelLocalItem(not_null item) { } } +void ApiWrap::sendShortcutMessages( + not_null peer, + BusinessShortcutId id) { + request(MTPmessages_SendQuickReplyMessages( + peer->input, + MTP_int(id) + )).done([=](const MTPUpdates &result) { + applyUpdates(result); + }).send(); +} + void ApiWrap::sendMessage(MessageToSend &&message) { const auto history = message.action.history; const auto peer = history->peer; diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 615960126..58165adec 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -337,6 +337,9 @@ public: void cancelLocalItem(not_null item); + void sendShortcutMessages( + not_null peer, + BusinessShortcutId id); void sendMessage(MessageToSend &&message); void sendBotStart( not_null bot, diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 382d850e3..1cf45d762 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "chat_helpers/field_autocomplete.h" +#include "data/business/data_shortcut_messages.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_channel.h" @@ -27,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/storage_account.h" #include "core/application.h" #include "core/core_settings.h" +#include "lang/lang_keys.h" #include "lottie/lottie_single_player.h" #include "media/clip/media_clip_reader.h" #include "ui/widgets/popup_menu.h" @@ -636,6 +638,27 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { } } } + const auto shortcuts = _user + ? _user->owner().shortcutMessages().shortcuts().list + : base::flat_map(); + if (!hasUsername && !shortcuts.empty()) { + const auto self = _user->session().user(); + for (const auto &[id, shortcut] : shortcuts) { + if (shortcut.count < 1) { + continue; + } else if (!listAllSuggestions) { + if (!shortcut.name.startsWith(_filter, Qt::CaseInsensitive)) { + continue; + } + } + brows.push_back(BotCommandRow{ + self, + shortcut.name, + tr::lng_forum_messages(tr::now, lt_count, shortcut.count), + self->activeUserpicView() + }); + } + } } rowsUpdated( std::move(mrows), @@ -1247,7 +1270,7 @@ bool FieldAutocomplete::Inner::chooseAtIndex( command, insertUsername ? ('@' + PrimaryUsername(user)) : QString()); - _botCommandChosen.fire({ commandString, method }); + _botCommandChosen.fire({ user, commandString, method }); return true; } } diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h index 2606dc1f2..5c9e291f3 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h @@ -96,6 +96,7 @@ public: ChooseMethod method = ChooseMethod::ByEnter; }; struct BotCommandChosen { + not_null user; QString command; ChooseMethod method = ChooseMethod::ByEnter; }; diff --git a/Telegram/SourceFiles/data/business/data_shortcut_messages.cpp b/Telegram/SourceFiles/data/business/data_shortcut_messages.cpp index e7b4a65a7..df2f5f880 100644 --- a/Telegram/SourceFiles/data/business/data_shortcut_messages.cpp +++ b/Telegram/SourceFiles/data/business/data_shortcut_messages.cpp @@ -497,6 +497,16 @@ Shortcut ShortcutMessages::lookupShortcut(BusinessShortcutId id) const { return i->second; } +BusinessShortcutId ShortcutMessages::lookupShortcutId( + const QString &name) const { + for (const auto &[id, shortcut] : _shortcuts.list) { + if (!shortcut.name.compare(name, Qt::CaseInsensitive)) { + return id; + } + } + return {}; +} + void ShortcutMessages::editShortcut( BusinessShortcutId id, QString name, diff --git a/Telegram/SourceFiles/data/business/data_shortcut_messages.h b/Telegram/SourceFiles/data/business/data_shortcut_messages.h index 57c1205f8..76a1df56d 100644 --- a/Telegram/SourceFiles/data/business/data_shortcut_messages.h +++ b/Telegram/SourceFiles/data/business/data_shortcut_messages.h @@ -78,6 +78,8 @@ public: [[nodiscard]] rpl::producer shortcutIdChanged() const; [[nodiscard]] BusinessShortcutId emplaceShortcut(QString name); [[nodiscard]] Shortcut lookupShortcut(BusinessShortcutId id) const; + [[nodiscard]] BusinessShortcutId lookupShortcutId( + const QString &name) const; void editShortcut( BusinessShortcutId id, QString name, diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b658b8555..043fd7b8c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -52,6 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qt/qt_key_modifiers.h" #include "base/unixtime.h" #include "base/call_delayed.h" +#include "data/business/data_shortcut_messages.h" #include "data/notify/data_notify_settings.h" #include "data/data_changes.h" #include "data/data_drafts.h" @@ -431,7 +432,20 @@ HistoryWidget::HistoryWidget( _fieldAutocomplete->botCommandChosen( ) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) { - insertHashtagOrBotCommand(data.command, data.method); + using Method = FieldAutocomplete::ChooseMethod; + const auto messages = &data.user->owner().shortcutMessages(); + const auto shortcutId = (_peer + && data.user->isSelf() + && data.method != Method::ByTab) + ? messages->lookupShortcutId(data.command.mid(1)) + : BusinessShortcutId(); + if (shortcutId) { + session().api().sendShortcutMessages(_peer, shortcutId); + session().api().finishForwarding(prepareSendAction({})); + setFieldText(_field->getTextWithTagsPart(_field->textCursor().position())); + } else { + insertHashtagOrBotCommand(data.command, data.method); + } }, lifetime()); _fieldAutocomplete->setModerateKeyActivateCallback([=](int key) { @@ -1410,9 +1424,14 @@ AutocompleteQuery HistoryWidget::parseMentionHashtagBotCommandQuery() const { } else if (result.query[0] == '@' && cRecentInlineBots().isEmpty()) { session().local().readRecentHashtagsAndBots(); - } else if (result.query[0] == '/' - && ((_peer->isUser() && !_peer->asUser()->isBot()) || _editMsgId)) { - return AutocompleteQuery(); + } else if (result.query[0] == '/') { + if (_editMsgId) { + return {}; + } else if (_peer->isUser() + && !_peer->asUser()->isBot() + && _peer->owner().shortcutMessages().shortcuts().list.empty()) { + return {}; + } } return result; }