From d82381881a2619c497034ed6d7c5278fd39a0bf7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 26 May 2023 20:30:02 +0400 Subject: [PATCH] Allow sending stickers / GIFs in story replies. --- .../SourceFiles/boxes/premium_preview_box.cpp | 4 +- .../SourceFiles/boxes/premium_preview_box.h | 2 +- .../stories/media_stories_controller.cpp | 2 +- .../media/stories/media_stories_reply.cpp | 116 ++++++++++++++++-- .../media/stories/media_stories_reply.h | 24 ++++ .../SourceFiles/window/section_widget.cpp | 8 +- Telegram/SourceFiles/window/section_widget.h | 7 ++ 7 files changed, 147 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.cpp b/Telegram/SourceFiles/boxes/premium_preview_box.cpp index d63288a01..20581a726 100644 --- a/Telegram/SourceFiles/boxes/premium_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/premium_preview_box.cpp @@ -1192,9 +1192,9 @@ void Show( } // namespace void ShowStickerPreviewBox( - not_null controller, + std::shared_ptr show, not_null document) { - Show(controller->uiShow(), Descriptor{ + Show(std::move(show), Descriptor{ .section = PremiumPreview::Stickers, .requestedSticker = document, }); diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.h b/Telegram/SourceFiles/boxes/premium_preview_box.h index 30fb8f866..51f9bcfbd 100644 --- a/Telegram/SourceFiles/boxes/premium_preview_box.h +++ b/Telegram/SourceFiles/boxes/premium_preview_box.h @@ -34,7 +34,7 @@ class Session; } // namespace Main void ShowStickerPreviewBox( - not_null controller, + std::shared_ptr show, not_null document); void DoubledLimitsPreviewBox( diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index bbd787d91..0edb1baec 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -345,7 +345,7 @@ std::shared_ptr Controller::uiShow() const { } auto Controller::stickerOrEmojiChosen() const -->rpl::producer { +-> rpl::producer { return _delegate->storiesStickerOrEmojiChosen(); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp index b11228f46..105f61def 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/stories/media_stories_reply.h" #include "api/api_common.h" +#include "api/api_sending.h" #include "apiwrap.h" #include "base/call_delayed.h" #include "boxes/premium_limits_box.h" @@ -28,8 +29,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/stories/media_stories_controller.h" #include "menu/menu_send.h" #include "storage/localimageloader.h" +#include "storage/storage_account.h" #include "storage/storage_media_prepare.h" #include "ui/chat/attach/attach_prepare.h" +#include "window/section_widget.h" #include "styles/style_boxes.h" // sendMediaPreviewSize. #include "styles/style_chat_helpers.h" #include "styles/style_media_view.h" @@ -134,6 +137,96 @@ void ReplyArea::sendVoice(VoiceToSend &&data) { finishSending(); } +bool ReplyArea::sendExistingDocument( + not_null document, + Api::SendOptions options, + std::optional localId) { + Expects(_data.user != nullptr); + + const auto show = _controller->uiShow(); + const auto error = Data::RestrictionError( + _data.user, + ChatRestriction::SendStickers); + if (error) { + show->showToast(*error); + return false; + } else if (Window::ShowSendPremiumError(show, document)) { + return false; + } + + Api::SendExistingDocument( + Api::MessageToSend(prepareSendAction(options)), + document, + localId); + + _controls->cancelReplyMessage(); + finishSending(); + return true; +} + +void ReplyArea::sendExistingPhoto(not_null photo) { + sendExistingPhoto(photo, {}); +} + +bool ReplyArea::sendExistingPhoto( + not_null photo, + Api::SendOptions options) { + Expects(_data.user != nullptr); + + const auto show = _controller->uiShow(); + const auto error = Data::RestrictionError( + _data.user, + ChatRestriction::SendPhotos); + if (error) { + show->showToast(*error); + return false; + } + + Api::SendExistingPhoto( + Api::MessageToSend(prepareSendAction(options)), + photo); + + _controls->cancelReplyMessage(); + finishSending(); + return true; +} + +void ReplyArea::sendInlineResult( + not_null result, + not_null bot) { + const auto errorText = result->getErrorOnSend(history()); + if (!errorText.isEmpty()) { + _controller->uiShow()->showToast(errorText); + return; + } + sendInlineResult(result, bot, {}, std::nullopt); +} + +void ReplyArea::sendInlineResult( + not_null result, + not_null bot, + Api::SendOptions options, + std::optional localMessageId) { + auto action = prepareSendAction(options); + action.generateLocal = true; + session().api().sendInlineResult(bot, result, action, localMessageId); + + _controls->clear(); + + auto &bots = cRefRecentInlineBots(); + const auto index = bots.indexOf(bot); + if (index) { + if (index > 0) { + bots.removeAt(index); + } else if (bots.size() >= RecentInlineBotsLimit) { + bots.resize(RecentInlineBotsLimit - 1); + } + bots.push_front(bot); + bot->session().local().writeRecentHashtagsAndBots(); + } + finishSending(); +} + void ReplyArea::finishSending() { _controls->hidePanelsAnimated(); _controller->wrap()->setFocus(); @@ -188,12 +281,17 @@ bool ReplyArea::showSendingFilesError( return true; } +not_null ReplyArea::history() const { + Expects(_data.user != nullptr); + + return _data.user->owner().history(_data.user); +} + Api::SendAction ReplyArea::prepareSendAction( Api::SendOptions options) const { Expects(_data.user != nullptr); - const auto history = _data.user->owner().history(_data.user); - auto result = Api::SendAction(history, options); + auto result = Api::SendAction(history(), options); result.options.sendAs = _controls->sendAsPeer(); result.replyTo.storyId = { .peer = _data.user->id, .story = _data.id }; return result; @@ -402,23 +500,19 @@ void ReplyArea::initActions() { _controls->fileChosen( ) | rpl::start_with_next([=](ChatHelpers::FileChosen data) { _controller->uiShow()->hideLayer(); - //controller()->sendingAnimation().appendSending( - // data.messageSendingFrom); - //const auto localId = data.messageSendingFrom.localId; - //sendExistingDocument(data.document, data.options, localId); + const auto localId = data.messageSendingFrom.localId; + sendExistingDocument(data.document, data.options, localId); }, _lifetime); _controls->photoChosen( ) | rpl::start_with_next([=](ChatHelpers::PhotoChosen chosen) { - //sendExistingPhoto(chosen.photo, chosen.options); + sendExistingPhoto(chosen.photo, chosen.options); }, _lifetime); _controls->inlineResultChosen( ) | rpl::start_with_next([=](ChatHelpers::InlineChosen chosen) { - //controller()->sendingAnimation().appendSending( - // chosen.messageSendingFrom); - //const auto localId = chosen.messageSendingFrom.localId; - //sendInlineResult(chosen.result, chosen.bot, chosen.options, localId); + const auto localId = chosen.messageSendingFrom.localId; + sendInlineResult(chosen.result, chosen.bot, chosen.options, localId); }, _lifetime); _controls->setMimeDataHook([=]( diff --git a/Telegram/SourceFiles/media/stories/media_stories_reply.h b/Telegram/SourceFiles/media/stories/media_stories_reply.h index c7ea6f88c..d9683521e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reply.h +++ b/Telegram/SourceFiles/media/stories/media_stories_reply.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/weak_ptr.h" +class History; enum class SendMediaType; namespace Api { @@ -24,6 +25,10 @@ namespace HistoryView::Controls { struct VoiceToSend; } // namespace HistoryView::Controls +namespace InlineBots { +class Result; +} // namespace InlineBots + namespace Main { class Session; } // namespace Main @@ -58,6 +63,7 @@ private: using VoiceToSend = HistoryView::Controls::VoiceToSend; [[nodiscard]] Main::Session &session() const; + [[nodiscard]] not_null history() const; bool confirmSendingFiles(const QStringList &files); bool confirmSendingFiles(not_null data); @@ -90,6 +96,24 @@ private: bool ctrlShiftEnter); void finishSending(); + void sendExistingDocument(not_null document); + bool sendExistingDocument( + not_null document, + Api::SendOptions options, + std::optional localId); + void sendExistingPhoto(not_null photo); + bool sendExistingPhoto( + not_null photo, + Api::SendOptions options); + void sendInlineResult( + not_null result, + not_null bot); + void sendInlineResult( + not_null result, + not_null bot, + Api::SendOptions options, + std::optional localMessageId); + void initGeometry(); void initActions(); diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index bdc5fc849..d08a28c59 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -457,11 +457,17 @@ auto ChatThemeValueFromPeer( bool ShowSendPremiumError( not_null controller, not_null document) { + return ShowSendPremiumError(controller->uiShow(), document); +} + +bool ShowSendPremiumError( + std::shared_ptr show, + not_null document) { if (!document->isPremiumSticker() || document->session().premium()) { return false; } - ShowStickerPreviewBox(controller, document); + ShowStickerPreviewBox(std::move(show), document); return true; } diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index 89be8819c..d8cfda814 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -16,6 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class PeerData; +namespace ChatHelpers { +class Show; +} // namespace ChatHelpers + namespace Data { struct ReactionId; class ForumTopic; @@ -238,6 +242,9 @@ private: [[nodiscard]] bool ShowSendPremiumError( not_null controller, not_null document); +[[nodiscard]] bool ShowSendPremiumError( + std::shared_ptr show, + not_null document); [[nodiscard]] bool ShowReactPremiumError( not_null controller,