diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f13454d7d..2489020b8 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2228,6 +2228,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_replies_message_placeholder" = "Add a Quick Reply"; "lng_replies_delete_sure" = "Are you sure you want to delete this quick reply with all its messages?"; "lng_replies_error_occupied" = "This shortcut is already used."; +"lng_replies_edit_button" = "Edit Quick Replies"; "lng_greeting_title" = "Greeting Message"; "lng_greeting_about" = "Greet customers when they message you the first time or after a period of no activity."; diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 08b5abf14..d5aba296b 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -641,7 +641,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { const auto shortcuts = (_user && !_user->isBot()) ? _user->owner().shortcutMessages().shortcuts().list : base::flat_map(); - if (!hasUsername && !shortcuts.empty()) { + if (!hasUsername && brows.empty() && !shortcuts.empty()) { const auto self = _user->session().user(); for (const auto &[id, shortcut] : shortcuts) { if (shortcut.count < 1) { @@ -658,6 +658,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { self->activeUserpicView() }); } + if (!brows.empty()) { + brows.insert(begin(brows), BotCommandRow{ self }); // Edit. + } } } rowsUpdated( @@ -1096,6 +1099,15 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) { } else { auto &row = _brows->at(i); const auto user = row.user; + if (user->isSelf() && row.command.isEmpty()) { + p.setPen(st::windowActiveTextFg); + p.setFont(st::semiboldFont); + p.drawText( + QRect(0, i * st::mentionHeight, width(), st::mentionHeight), + tr::lng_replies_edit_button(tr::now), + style::al_center); + continue; + } auto toHighlight = row.command; int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : ((_parent->channel() && _parent->channel()->isMegagroup()) ? _parent->channel()->mgInfo->botStatus : -1); @@ -1163,7 +1175,13 @@ void FieldAutocomplete::Inner::clearSel(bool hidden) { _overDelete = false; _mouseSelection = false; _lastMousePosition = std::nullopt; - setSel((_mrows->empty() && _brows->empty() && _hrows->empty()) ? -1 : 0); + setSel((_mrows->empty() && _brows->empty() && _hrows->empty()) + ? -1 + : (_brows->size() > 1 + && _brows->front().user->isSelf() + && _brows->front().command.isEmpty()) + ? 1 + : 0); if (hidden) { _down = -1; _previewShown = false; @@ -1269,7 +1287,6 @@ bool FieldAutocomplete::Inner::chooseAtIndex( const auto commandString = QString("/%1%2").arg( command, insertUsername ? ('@' + PrimaryUsername(user)) : QString()); - _botCommandChosen.fire({ user, commandString, method }); return true; } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 3b6ab5dd5..8a5fd3dfa 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -123,6 +123,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "mainwidget.h" #include "mainwindow.h" +#include "settings/business/settings_quick_replies.h" #include "storage/localimageloader.h" #include "storage/storage_account.h" #include "storage/file_upload.h" @@ -378,6 +379,11 @@ HistoryWidget::HistoryWidget( checkFieldAutocomplete(); }, Qt::QueuedConnection); + controller->session().data().shortcutMessages().shortcutsChanged( + ) | rpl::start_with_next([=] { + checkFieldAutocomplete(); + }, lifetime()); + _fieldBarCancel->hide(); _topBar->hide(); @@ -435,12 +441,15 @@ HistoryWidget::HistoryWidget( ) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) { 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)) + const auto shortcut = data.user->isSelf(); + const auto command = data.command.mid(1); + const auto byTab = (data.method == Method::ByTab); + const auto shortcutId = (_peer && shortcut && !byTab) + ? messages->lookupShortcutId(command) : BusinessShortcutId(); - if (!shortcutId) { + if (shortcut && command.isEmpty()) { + controller->showSettings(Settings::QuickRepliesId()); + } else if (!shortcutId) { insertHashtagOrBotCommand(data.command, data.method); } else if (!_peer->session().premium()) { ShowPremiumPreviewToBuy( diff --git a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp index d45d94750..cc55987cb 100644 --- a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp +++ b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "settings/business/settings_quick_replies.h" +#include "boxes/premium_preview_box.h" #include "core/application.h" #include "data/business/data_shortcut_messages.h" #include "data/data_session.h" @@ -96,6 +97,12 @@ void QuickReplies::setupContent( )); add->setClickedCallback([=] { + if (!controller->session().premium()) { + ShowPremiumPreviewToBuy( + controller, + PremiumFeature::QuickReplies); + return; + } const auto submit = [=](QString name, Fn close) { const auto id = messages->emplaceShortcut(name); showOther(ShortcutMessagesId(id)); diff --git a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp index 91ba0c63f..2e1f577ca 100644 --- a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp +++ b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "boxes/delete_messages_box.h" #include "boxes/premium_limits_box.h" +#include "boxes/premium_preview_box.h" #include "boxes/send_files_box.h" #include "chat_helpers/tabbed_selector.h" #include "core/file_utilities.h" @@ -253,6 +254,7 @@ private: void showAtEnd(); void finishSending(); void refreshEmptyText(); + bool showPremiumRequired() const; const not_null _controller; const not_null _session; @@ -508,6 +510,12 @@ void ShortcutMessages::fillTopBarMenu( const auto messages = &owner->shortcutMessages(); addAction(tr::lng_context_edit_shortcut(tr::now), [=] { + if (!_controller->session().premium()) { + ShowPremiumPreviewToBuy( + _controller, + PremiumFeature::QuickReplies); + return; + } const auto submit = [=](QString name, Fn close) { const auto id = _shortcutId.current(); const auto error = [=](QString text) { @@ -773,6 +781,7 @@ QPointer ShortcutMessages::createPinnedToBottom( _composeControls = std::make_unique( dynamic_cast(_scroll->parentWidget()), ComposeControlsDescriptor{ + .stOverride = &st::repliesComposeControls, .show = _controller->uiShow(), .unavailableEmojiPasted = [=](not_null emoji) { listShowPremiumToast(emoji); @@ -1127,6 +1136,9 @@ bool ShortcutMessages::showSendingFilesError( bool ShortcutMessages::showSendingFilesError( const Ui::PreparedList &list, std::optional compress) const { + if (showPremiumRequired()) { + return true; + } const auto text = [&] { using Error = Ui::PreparedList::Error; switch (list.error) { @@ -1171,6 +1183,9 @@ void ShortcutMessages::send() { } void ShortcutMessages::sendVoice(ComposeControls::VoiceToSend &&data) { + if (showPremiumRequired()) { + return; + } auto action = prepareSendAction(data.options); _session->api().sendVoiceMessage( data.bytes, @@ -1184,6 +1199,9 @@ void ShortcutMessages::sendVoice(ComposeControls::VoiceToSend &&data) { } void ShortcutMessages::send(Api::SendOptions options) { + if (showPremiumRequired()) { + return; + } _cornerButtons.clearReplyReturns(); auto message = Api::MessageToSend(prepareSendAction(options)); @@ -1409,6 +1427,9 @@ void ShortcutMessages::sendingFilesConfirmed( void ShortcutMessages::chooseAttach( std::optional overrideSendImagesAsPhotos) { + if (showPremiumRequired()) { + return; + } _choosingAttach = false; const auto filter = (overrideSendImagesAsPhotos == true) @@ -1472,6 +1493,10 @@ bool ShortcutMessages::sendExistingDocument( not_null document, Api::SendOptions options, std::optional localId) { + if (showPremiumRequired()) { + return false; + } + Api::SendExistingDocument( Api::MessageToSend(prepareSendAction(options)), document, @@ -1489,6 +1514,9 @@ void ShortcutMessages::sendExistingPhoto(not_null photo) { bool ShortcutMessages::sendExistingPhoto( not_null photo, Api::SendOptions options) { + if (showPremiumRequired()) { + return false; + } Api::SendExistingPhoto( Api::MessageToSend(prepareSendAction(options)), photo); @@ -1501,6 +1529,9 @@ bool ShortcutMessages::sendExistingPhoto( void ShortcutMessages::sendInlineResult( not_null result, not_null bot) { + if (showPremiumRequired()) { + return; + } const auto errorText = result->getErrorOnSend(_history); if (!errorText.isEmpty()) { _controller->showToast(errorText); @@ -1520,6 +1551,9 @@ void ShortcutMessages::sendInlineResult( not_null bot, Api::SendOptions options, std::optional localMessageId) { + if (showPremiumRequired()) { + return; + } auto action = prepareSendAction(options); action.generateLocal = true; _session->api().sendInlineResult(bot, result, action, localMessageId); @@ -1564,6 +1598,14 @@ FullReplyTo ShortcutMessages::replyTo() const { return _composeControls->replyingToMessage(); } +bool ShortcutMessages::showPremiumRequired() const { + if (!_controller->session().premium()) { + ShowPremiumPreviewToBuy(_controller, PremiumFeature::QuickReplies); + return true; + } + return false; +} + } // namespace Type ShortcutMessagesId(int shortcutId) { diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index b4217d85b..655ea9896 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1050,6 +1050,9 @@ awayEmptyIcon: icon{{ "chat/large_away", msgServiceFg }}; repliesEmptyWidth: 264px; repliesEmptySkip: 16px; repliesEmptyPadding: margins(10px, 20px, 10px, 16px); +repliesComposeControls: ComposeControls(defaultComposeControls) { + tabbedHeightMin: 220px; +} boostMessageIcon: icon {{ "stories/boost_mini", windowFg }}; boostMessageIconPadding: margins(0px, 2px, 0px, 0px);