From cf566586642f3d9c19f043da244e0da34aeb05fd Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 9 Aug 2020 17:13:24 +0300 Subject: [PATCH] Slightly refactored FieldAutocomplete. --- .../chat_helpers/field_autocomplete.cpp | 106 ++++++++++++++---- .../chat_helpers/field_autocomplete.h | 61 +++++++--- .../SourceFiles/history/history_widget.cpp | 38 +++++-- Telegram/SourceFiles/history/history_widget.h | 2 - 4 files changed, 155 insertions(+), 52 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 1c9e792a5d..847fb71356 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -45,8 +45,10 @@ FieldAutocomplete::FieldAutocomplete( , _scroll(this, st::mentionScroll) { _scroll->setGeometry(rect()); + using Inner = internal::FieldAutocompleteInner; + _inner = _scroll->setOwnedWidget( - object_ptr( + object_ptr( _controller, this, &_mrows, @@ -55,18 +57,41 @@ FieldAutocomplete::FieldAutocomplete( &_srows)); _inner->setGeometry(rect()); - connect(_inner, SIGNAL(mentionChosen(not_null,FieldAutocomplete::ChooseMethod)), this, SIGNAL(mentionChosen(not_null,FieldAutocomplete::ChooseMethod))); - connect(_inner, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod))); - connect(_inner, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod))); - connect(_inner, SIGNAL(stickerChosen(not_null,FieldAutocomplete::ChooseMethod)), this, SIGNAL(stickerChosen(not_null,FieldAutocomplete::ChooseMethod))); - connect(_inner, SIGNAL(mustScrollTo(int, int)), _scroll, SLOT(scrollToY(int, int))); + _inner->scrollToRequested( + ) | rpl::start_with_next([=](Inner::ScrollTo data) { + _scroll->scrollToY(data.top, data.bottom); + }, lifetime()); _scroll->show(); _inner->show(); hide(); - connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged())); + connect( + _scroll, + &Ui::ScrollArea::geometryChanged, + _inner, + &Inner::onParentGeometryChanged); +} + +auto FieldAutocomplete::mentionChosen() const +-> rpl::producer { + return _inner->mentionChosen(); +} + +auto FieldAutocomplete::hashtagChosen() const +-> rpl::producer { + return _inner->hashtagChosen(); +} + +auto FieldAutocomplete::botCommandChosen() const +-> rpl::producer { + return _inner->botCommandChosen(); +} + +auto FieldAutocomplete::stickerChosen() const +-> rpl::producer { + return _inner->stickerChosen(); } FieldAutocomplete::~FieldAutocomplete() = default; @@ -583,9 +608,10 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) { && ((key >= Qt::Key_1 && key <= Qt::Key_9) || key == Qt::Key_Q || key == Qt::Key_W)) { - bool handled = false; - emit moderateKeyActivate(key, &handled); - return handled; + + return _moderateKeyActivateCallback + ? _moderateKeyActivateCallback(key) + : false; } } } @@ -878,29 +904,37 @@ bool FieldAutocompleteInner::moveSel(int key) { bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const { if (!_srows->empty()) { if (_sel >= 0 && _sel < _srows->size()) { - emit stickerChosen((*_srows)[_sel].document, method); + _stickerChosen.fire({ (*_srows)[_sel].document, method }); return true; } } else if (!_mrows->empty()) { if (_sel >= 0 && _sel < _mrows->size()) { - emit mentionChosen(_mrows->at(_sel).user, method); + _mentionChosen.fire({ _mrows->at(_sel).user, method }); return true; } } else if (!_hrows->empty()) { if (_sel >= 0 && _sel < _hrows->size()) { - emit hashtagChosen('#' + _hrows->at(_sel), method); + _hashtagChosen.fire({ '#' + _hrows->at(_sel), method }); return true; } } else if (!_brows->empty()) { if (_sel >= 0 && _sel < _brows->size()) { const auto user = _brows->at(_sel).user; const auto command = _brows->at(_sel).command; - int32 botStatus = _parent->chat() ? _parent->chat()->botStatus : ((_parent->channel() && _parent->channel()->isMegagroup()) ? _parent->channel()->mgInfo->botStatus : -1); - if (botStatus == 0 || botStatus == 2 || _parent->filter().indexOf('@') > 0) { - emit botCommandChosen('/' + command->command + '@' + user->username, method); - } else { - emit botCommandChosen('/' + command->command, method); - } + const auto botStatus = _parent->chat() + ? _parent->chat()->botStatus + : ((_parent->channel() && _parent->channel()->isMegagroup()) + ? _parent->channel()->mgInfo->botStatus + : -1); + + const auto insertUsername = (botStatus == 0 + || botStatus == 2 + || _parent->filter().indexOf('@') > 0); + const auto commandString = QString("/%1%2") + .arg(command->command) + .arg(insertUsername ? ('@' + user->username) : QString()); + + _botCommandChosen.fire({ commandString, method }); return true; } } @@ -1000,10 +1034,15 @@ void FieldAutocompleteInner::setSel(int sel, bool scroll) { if (scroll && _sel >= 0) { if (_srows->empty()) { - emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight); + _scrollToRequested.fire({ + _sel * st::mentionHeight, + (_sel + 1) * st::mentionHeight }); } else { int32 row = _sel / _stickersPerRow; - emit mustScrollTo(st::stickerPanPadding + row * st::stickerPanSize.height(), st::stickerPanPadding + (row + 1) * st::stickerPanSize.height()); + const auto padding = st::stickerPanPadding; + _scrollToRequested.fire({ + padding + row * st::stickerPanSize.height(), + padding + (row + 1) * st::stickerPanSize.height() }); } } } @@ -1131,4 +1170,29 @@ void FieldAutocompleteInner::showPreview() { } } +auto FieldAutocompleteInner::mentionChosen() const +-> rpl::producer { + return _mentionChosen.events(); +} + +auto FieldAutocompleteInner::hashtagChosen() const +-> rpl::producer { + return _hashtagChosen.events(); +} + +auto FieldAutocompleteInner::botCommandChosen() const +-> rpl::producer { + return _botCommandChosen.events(); +} + +auto FieldAutocompleteInner::stickerChosen() const +-> rpl::producer { + return _stickerChosen.events(); +} + +auto FieldAutocompleteInner::scrollToRequested() const +-> rpl::producer { + return _scrollToRequested.events(); +} + } // namespace internal diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h index 94a7578f4c..5a0ea82b35 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h @@ -59,7 +59,6 @@ class FieldAutocompleteInner; } // namespace internal class FieldAutocomplete final : public Ui::RpWidget { - Q_OBJECT public: FieldAutocomplete( @@ -90,6 +89,23 @@ public: ByTab, ByClick, }; + struct MentionChosen { + not_null user; + ChooseMethod method; + }; + struct HashtagChosen { + QString hashtag; + ChooseMethod method; + }; + struct BotCommandChosen { + QString command; + ChooseMethod method; + }; + struct StickerChosen { + not_null sticker; + ChooseMethod method; + }; + bool chooseSelected(ChooseMethod method) const; bool stickersShown() const { @@ -102,15 +118,16 @@ public: return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); } + void setModerateKeyActivateCallback(Fn callback) { + _moderateKeyActivateCallback = std::move(callback); + } + void hideFast(); -signals: - void mentionChosen(not_null user, FieldAutocomplete::ChooseMethod method) const; - void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; - void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; - void stickerChosen(not_null sticker, FieldAutocomplete::ChooseMethod method) const; - - void moderateKeyActivate(int key, bool *outHandled) const; + rpl::producer mentionChosen() const; + rpl::producer hashtagChosen() const; + rpl::producer botCommandChosen() const; + rpl::producer stickerChosen() const; public slots: void showAnimated(); @@ -160,11 +177,12 @@ private: QRect _boundings; bool _addInlineBots; - int32 _width, _height; bool _hiding = false; Ui::Animations::Simple _a_opacity; + Fn _moderateKeyActivateCallback; + friend class internal::FieldAutocompleteInner; }; @@ -174,9 +192,13 @@ namespace internal { class FieldAutocompleteInner final : public Ui::RpWidget , private base::Subscriber { - Q_OBJECT public: + struct ScrollTo { + int top; + int bottom; + }; + FieldAutocompleteInner( not_null controller, not_null parent, @@ -192,14 +214,13 @@ public: void setRecentInlineBotsInRows(int32 bots); void rowsUpdated(); -signals: - void mentionChosen(not_null user, FieldAutocomplete::ChooseMethod method) const; - void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; - void botCommandChosen(QString command, FieldAutocomplete::ChooseMethod method) const; - void stickerChosen(not_null sticker, FieldAutocomplete::ChooseMethod method) const; - void mustScrollTo(int scrollToTop, int scrollToBottom); + rpl::producer mentionChosen() const; + rpl::producer hashtagChosen() const; + rpl::producer + botCommandChosen() const; + rpl::producer stickerChosen() const; + rpl::producer scrollToRequested() const; -public slots: void onParentGeometryChanged(); private: @@ -242,6 +263,12 @@ private: bool _previewShown = false; + rpl::event_stream _mentionChosen; + rpl::event_stream _hashtagChosen; + rpl::event_stream _botCommandChosen; + rpl::event_stream _stickerChosen; + rpl::event_stream _scrollToRequested; + base::Timer _previewTimer; }; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 13df5ea959..07447e41ff 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -382,15 +382,33 @@ HistoryWidget::HistoryWidget( InitMessageField(controller, _field); _fieldAutocomplete->hide(); - connect(_fieldAutocomplete, &FieldAutocomplete::mentionChosen, this, [=](not_null user) { - onMentionInsert(user); + + _fieldAutocomplete->mentionChosen( + ) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) { + onMentionInsert(data.user); + }, lifetime()); + + _fieldAutocomplete->hashtagChosen( + ) | rpl::start_with_next([=](FieldAutocomplete::HashtagChosen data) { + onHashtagOrBotCommandInsert(data.hashtag, data.method); + }, lifetime()); + + _fieldAutocomplete->botCommandChosen( + ) | rpl::start_with_next([=](FieldAutocomplete::BotCommandChosen data) { + onHashtagOrBotCommandInsert(data.command, data.method); + }, lifetime()); + + _fieldAutocomplete->stickerChosen( + ) | rpl::start_with_next([=](FieldAutocomplete::StickerChosen data) { + sendExistingDocument(data.sticker, Api::SendOptions()); + }, lifetime()); + + _fieldAutocomplete->setModerateKeyActivateCallback([=](int key) { + return _keyboard->isHidden() + ? false + : _keyboard->moderateKeyActivate(key); }); - connect(_fieldAutocomplete, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod))); - connect(_fieldAutocomplete, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod))); - connect(_fieldAutocomplete, &FieldAutocomplete::stickerChosen, this, [=](not_null document) { - sendExistingDocument(document, Api::SendOptions()); - }); - connect(_fieldAutocomplete, SIGNAL(moderateKeyActivate(int,bool*)), this, SLOT(onModerateKeyActivate(int,bool*))); + if (_supportAutocomplete) { supportInitAutocomplete(); } @@ -3921,10 +3939,6 @@ void HistoryWidget::onMembersDropdownShow() { _membersDropdown->otherEnter(); } -void HistoryWidget::onModerateKeyActivate(int index, bool *outHandled) { - *outHandled = _keyboard->isHidden() ? false : _keyboard->moderateKeyActivate(index); -} - bool HistoryWidget::pushTabbedSelectorToThirdSection( not_null peer, const Window::SectionShow ¶ms) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index c73ec6cb7c..a2d4fd2b93 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -325,8 +325,6 @@ private slots: void onInlineBotCancel(); void onMembersDropdownShow(); - void onModerateKeyActivate(int index, bool *outHandled); - private: using TabbedPanel = ChatHelpers::TabbedPanel; using TabbedSelector = ChatHelpers::TabbedSelector;