diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index bece81b64..76db78597 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -53,6 +53,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace ChatHelpers { namespace { [[nodiscard]] QString PrimaryUsername(not_null user) { @@ -60,6 +61,18 @@ namespace { return usernames.empty() ? user->username() : usernames.front(); } +template +inline int indexOfInFirstN(const T &v, const U &elem, int last) { + for (auto b = v.cbegin(), i = b, e = b + std::max(int(v.size()), last) + ; i != e + ; ++i) { + if (i->user == elem) { + return (i - b); + } + } + return -1; +} + } // namespace class FieldAutocomplete::Inner final : public Ui::RpWidget { @@ -70,7 +83,7 @@ public: }; Inner( - std::shared_ptr show, + std::shared_ptr show, const style::EmojiPan &st, not_null parent, not_null mrows, @@ -127,7 +140,7 @@ private: Media::Clip::Notification notification, not_null document); - const std::shared_ptr _show; + const std::shared_ptr _show; const not_null _session; const style::EmojiPan &_st; const not_null _parent; @@ -197,7 +210,7 @@ FieldAutocomplete::FieldAutocomplete( FieldAutocomplete::FieldAutocomplete( QWidget *parent, - std::shared_ptr show, + std::shared_ptr show, const style::EmojiPan *stOverride) : RpWidget(parent) , _show(std::move(show)) @@ -235,7 +248,7 @@ FieldAutocomplete::FieldAutocomplete( }), lifetime()); } -std::shared_ptr FieldAutocomplete::uiShow() const { +std::shared_ptr FieldAutocomplete::uiShow() const { return _show; } @@ -373,18 +386,6 @@ bool FieldAutocomplete::clearFilteredBotCommands() { return true; } -namespace { -template -inline int indexOfInFirstN(const T &v, const U &elem, int last) { - for (auto b = v.cbegin(), i = b, e = b + std::max(int(v.size()), last); i != e; ++i) { - if (i->user == elem) { - return (i - b); - } - } - return -1; -} -} - FieldAutocomplete::StickerRows FieldAutocomplete::getStickerSuggestions() { const auto data = &_session->data().stickers(); const auto list = data->getListByEmoji({ _emoji }, _stickersSeed); @@ -871,7 +872,7 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) { } FieldAutocomplete::Inner::Inner( - std::shared_ptr show, + std::shared_ptr show, const style::EmojiPan &st, not_null parent, not_null mrows, @@ -963,8 +964,8 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) { media->checkStickerSmall(); const auto paused = _show->paused( - ChatHelpers::PauseReason::TabbedPanel); - const auto size = ChatHelpers::ComputeStickerSize( + PauseReason::TabbedPanel); + const auto size = ComputeStickerSize( document, stickerBoundingBox()); const auto ppos = pos + QPoint( @@ -989,7 +990,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) { } else if (const auto image = media->getStickerSmall()) { p.drawPixmapLeft(ppos, width(), image->pix(size)); } else { - ChatHelpers::PaintStickerThumbnailPath( + PaintStickerThumbnailPath( p, media.get(), QRect(ppos, size), @@ -1250,7 +1251,7 @@ bool FieldAutocomplete::Inner::chooseAtIndex( const auto bounding = selectedRect(index); auto contentRect = QRect( QPoint(), - ChatHelpers::ComputeStickerSize( + ComputeStickerSize( document, stickerBoundingBox())); contentRect.moveCenter(bounding.center()); @@ -1464,9 +1465,9 @@ auto FieldAutocomplete::Inner::getLottieRenderer() void FieldAutocomplete::Inner::setupLottie(StickerSuggestion &suggestion) { const auto document = suggestion.document; - suggestion.lottie = ChatHelpers::LottiePlayerFromDocument( + suggestion.lottie = LottiePlayerFromDocument( suggestion.documentMedia.get(), - ChatHelpers::StickerLottieSize::InlineResults, + StickerLottieSize::InlineResults, stickerBoundingBox() * style::DevicePixelRatio(), Lottie::Quality::Default, getLottieRenderer()); @@ -1534,7 +1535,7 @@ void FieldAutocomplete::Inner::clipCallback( } else if (i->webm->state() == State::Error) { i->webm.setBad(); } else if (i->webm->ready() && !i->webm->started()) { - const auto size = ChatHelpers::ComputeStickerSize( + const auto size = ComputeStickerSize( i->document, stickerBoundingBox()); i->webm->start({ .frame = size, .keepAlpha = true }); @@ -1632,3 +1633,5 @@ auto FieldAutocomplete::Inner::scrollToRequested() const -> rpl::producer { return _scrollToRequested.events(); } + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h index d95b7e394..b13659709 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h @@ -46,9 +46,15 @@ struct Details; } // namespace SendMenu namespace ChatHelpers { + struct FileChosen; class Show; -} // namespace ChatHelpers + +enum class FieldAutocompleteChooseMethod { + ByEnter, + ByTab, + ByClick, +}; class FieldAutocomplete final : public Ui::RpWidget { public: @@ -57,11 +63,11 @@ public: not_null controller); FieldAutocomplete( QWidget *parent, - std::shared_ptr show, + std::shared_ptr show, const style::EmojiPan *stOverride = nullptr); ~FieldAutocomplete(); - [[nodiscard]] std::shared_ptr uiShow() const; + [[nodiscard]] std::shared_ptr uiShow() const; bool clearFilteredBotCommands(); void showFiltered( @@ -81,11 +87,7 @@ public: bool eventFilter(QObject *obj, QEvent *e) override; - enum class ChooseMethod { - ByEnter, - ByTab, - ByClick, - }; + using ChooseMethod = FieldAutocompleteChooseMethod; struct MentionChosen { not_null user; QString mention; @@ -100,7 +102,7 @@ public: QString command; ChooseMethod method = ChooseMethod::ByEnter; }; - using StickerChosen = ChatHelpers::FileChosen; + using StickerChosen = FileChosen; enum class Type { Mentions, Hashtags, @@ -157,7 +159,7 @@ private: void recount(bool resetScroll = false); StickerRows getStickerSuggestions(); - const std::shared_ptr _show; + const std::shared_ptr _show; const not_null _session; const style::EmojiPan &_st; QPixmap _cache; @@ -193,3 +195,5 @@ private: Fn _moderateKeyActivateCallback; }; + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d857f252d..90c0fb7df 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -118,6 +118,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_media.h" #include "profile/profile_block_group_members.h" #include "core/click_handler_types.h" +#include "chat_helpers/field_autocomplete.h" #include "chat_helpers/tabbed_panel.h" #include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_section.h" @@ -473,7 +474,8 @@ HistoryWidget::HistoryWidget( }, lifetime()); _fieldAutocomplete->mentionChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::MentionChosen data) { auto replacement = QString(); auto entityTag = QString(); if (data.mention.isEmpty()) { @@ -489,13 +491,15 @@ HistoryWidget::HistoryWidget( }, lifetime()); _fieldAutocomplete->hashtagChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::HashtagChosen data) { insertHashtagOrBotCommand(data.hashtag, data.method); }, lifetime()); _fieldAutocomplete->botCommandChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) { - using Method = FieldAutocomplete::ChooseMethod; + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::BotCommandChosen data) { + using Method = ChatHelpers::FieldAutocompleteChooseMethod; const auto messages = &data.user->owner().shortcutMessages(); const auto shortcut = data.user->isSelf(); const auto command = data.command.mid(1); @@ -528,11 +532,11 @@ HistoryWidget::HistoryWidget( }); _fieldAutocomplete->choosingProcesses( - ) | rpl::start_with_next([=](FieldAutocomplete::Type type) { + ) | rpl::start_with_next([=](ChatHelpers::FieldAutocomplete::Type type) { if (!_history) { return; } - if (type == FieldAutocomplete::Type::Stickers) { + if (type == ChatHelpers::FieldAutocomplete::Type::Stickers) { session().sendProgressManager().update( _history, Api::SendProgressType::ChooseSticker); @@ -1488,13 +1492,14 @@ void HistoryWidget::start() { void HistoryWidget::insertHashtagOrBotCommand( QString str, - FieldAutocomplete::ChooseMethod method) { + ChatHelpers::FieldAutocompleteChooseMethod method) { if (!_peer) { return; } // Send bot command at once, if it was not inserted by pressing Tab. - if (str.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) { + using Method = ChatHelpers::FieldAutocompleteChooseMethod; + if (str.at(0) == '/' && method != Method::ByTab) { sendBotCommand({ _peer, str, FullMsgId(), replyTo() }); session().api().finishForwarding(prepareSendAction({})); setFieldText(_field->getTextWithTagsPart(_field->textCursor().position())); @@ -6935,7 +6940,8 @@ void HistoryWidget::fieldTabbed() { if (_supportAutocomplete) { _supportAutocomplete->activate(_field.data()); } else if (!_fieldAutocomplete->isHidden()) { - _fieldAutocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab); + _fieldAutocomplete->chooseSelected( + ChatHelpers::FieldAutocomplete::ChooseMethod::ByTab); } } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 362dccb79..1f0851431 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_view_highlight_manager.h" #include "history/history_view_top_toast.h" #include "history/history.h" -#include "chat_helpers/field_autocomplete.h" #include "chat_helpers/field_characters_count_manager.h" #include "window/section_widget.h" #include "ui/widgets/fields/input_field.h" @@ -84,6 +83,8 @@ class SessionController; namespace ChatHelpers { class TabbedPanel; class TabbedSelector; +class FieldAutocomplete; +enum class FieldAutocompleteChooseMethod; } // namespace ChatHelpers namespace HistoryView { @@ -368,7 +369,7 @@ private: void insertHashtagOrBotCommand( QString str, - FieldAutocomplete::ChooseMethod method); + ChatHelpers::FieldAutocompleteChooseMethod method); void cancelInlineBot(); void saveDraft(bool delayed = false); void saveCloudDraft(); @@ -739,7 +740,7 @@ private: HistoryView::CornerButtons _cornerButtons; - const object_ptr _fieldAutocomplete; + const object_ptr _fieldAutocomplete; object_ptr _supportAutocomplete; UserData *_inlineBot = nullptr; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 11ab5d49e..b0d17ff9c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -859,7 +859,7 @@ ComposeControls::ComposeControls( _wrap.get(), st::historyBotCommandStart) : nullptr) -, _autocomplete(std::make_unique( +, _autocomplete(std::make_unique( parent, _show, &_st.tabbed)) @@ -1701,9 +1701,10 @@ void ComposeControls::updateSubmitSettings() { void ComposeControls::initAutocomplete() { const auto insertHashtagOrBotCommand = [=]( const QString &string, - FieldAutocomplete::ChooseMethod method) { + ChatHelpers::FieldAutocompleteChooseMethod method) { // Send bot command at once, if it was not inserted by pressing Tab. - if (string.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) { + using Method = ChatHelpers::FieldAutocompleteChooseMethod; + if (string.at(0) == '/' && method != Method::ByTab) { _sendCommandRequests.fire_copy(string); setText( _field->getTextWithTagsPart(_field->textCursor().position())); @@ -1713,7 +1714,8 @@ void ComposeControls::initAutocomplete() { }; _autocomplete->mentionChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::MentionChosen data) { const auto user = data.user; if (data.mention.isEmpty()) { _field->insertTag( @@ -1725,17 +1727,20 @@ void ComposeControls::initAutocomplete() { }, _autocomplete->lifetime()); _autocomplete->hashtagChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::HashtagChosen data) { insertHashtagOrBotCommand(data.hashtag, data.method); }, _autocomplete->lifetime()); _autocomplete->botCommandChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::BotCommandChosen data) { insertHashtagOrBotCommand(data.command, data.method); }, _autocomplete->lifetime()); _autocomplete->stickerChosen( - ) | rpl::start_with_next([=](FieldAutocomplete::StickerChosen data) { + ) | rpl::start_with_next([=]( + ChatHelpers::FieldAutocomplete::StickerChosen data) { if (!_showSlowmodeError || !_showSlowmodeError()) { setText({}); } @@ -1747,8 +1752,8 @@ void ComposeControls::initAutocomplete() { }, _autocomplete->lifetime()); _autocomplete->choosingProcesses( - ) | rpl::start_with_next([=](FieldAutocomplete::Type type) { - if (type == FieldAutocomplete::Type::Stickers) { + ) | rpl::start_with_next([=](ChatHelpers::FieldAutocomplete::Type type) { + if (type == ChatHelpers::FieldAutocomplete::Type::Stickers) { _sendActionUpdates.fire({ .type = Api::SendProgressType::ChooseSticker, }); @@ -2125,7 +2130,8 @@ void ComposeControls::cancelForward() { void ComposeControls::fieldTabbed() { if (!_autocomplete->isHidden()) { - _autocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab); + _autocomplete->chooseSelected( + ChatHelpers::FieldAutocomplete::ChooseMethod::ByTab); } } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index fb373a0f7..6950111cc 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -21,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class History; class DocumentData; -class FieldAutocomplete; class Image; namespace style { @@ -39,6 +38,7 @@ struct FileChosen; struct PhotoChosen; class Show; enum class PauseReason; +class FieldAutocomplete; } // namespace ChatHelpers namespace Data { @@ -391,7 +391,7 @@ private: std::unique_ptr _inlineResults; std::unique_ptr _tabbedPanel; std::unique_ptr _attachBotsMenu; - std::unique_ptr _autocomplete; + std::unique_ptr _autocomplete; friend class FieldHeader; const std::unique_ptr _header;