From 051ca51d3b7a401aa5991e3994d079f2408bccda Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 12 Apr 2024 15:37:14 +0400 Subject: [PATCH] Allow clearing search results. --- .../SourceFiles/dialogs/dialogs_widget.cpp | 8 +- Telegram/SourceFiles/dialogs/dialogs_widget.h | 1 + .../dialogs/ui/dialogs_suggestions.cpp | 137 ++++++++++++++---- Telegram/SourceFiles/mainwidget.cpp | 23 ++- Telegram/SourceFiles/mainwidget.h | 8 +- 5 files changed, 141 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index e5746bc5c..90adb1f50 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1453,13 +1453,19 @@ void Widget::setInnerFocus() { } else if ((_openedFolder || _openedForum) && _subsectionTopBar->searchSetFocus()) { return; - } else if (!_search->getLastText().isEmpty() || _searchInChat) { + } else if (!_search->getLastText().isEmpty() + || _searchInChat + || _searchHasFocus) { _search->setFocus(); } else { setFocus(); } } +bool Widget::searchHasFocus() const { + return _searchHasFocus; +} + void Widget::jumpToTop(bool belowPinned) { if (session().supportMode()) { return; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 6ebd6ab50..b0f892e2d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -100,6 +100,7 @@ public: const Window::SectionShow ¶ms); void searchInChat(Key chat); void setInnerFocus(); + [[nodiscard]] bool searchHasFocus() const; void jumpToTop(bool belowPinned = false); void raiseWithTooltip(); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index 6a7dde299..bcc90575a 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -21,9 +21,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "settings/settings_common.h" #include "ui/boxes/confirm_box.h" +#include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/buttons.h" #include "ui/widgets/elastic_scroll.h" #include "ui/widgets/labels.h" +#include "ui/widgets/popup_menu.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" #include "ui/delayed_activation.h" @@ -70,10 +72,12 @@ private: }; -class RecentsController final : public PeerListController { +class RecentsController final + : public PeerListController + , public base::has_weak_ptr { public: RecentsController( - not_null session, + not_null window, RecentPeersList list); [[nodiscard]] rpl::producer count() const { @@ -95,8 +99,9 @@ public: private: void setupDivider(); void subscribeToEvents(); + [[nodiscard]] Fn removeAllCallback(); - const not_null _session; + const not_null _window; RecentPeersList _recent; rpl::variable _count; base::unique_qptr _menu; @@ -105,14 +110,33 @@ private: }; -void FillTopPeerMenu( +struct EntryMenuDescriptor { + not_null controller; + not_null peer; + QString removeOneText; + Fn removeOne; + QString removeAllText; + QString removeAllConfirm; + Fn removeAll; +}; + +[[nodiscard]] Fn RemoveAllConfirm( not_null controller, - const ShowTopPeerMenuRequest &request, - Fn)> remove, - Fn hideAll) { - const auto owner = &controller->session().data(); - const auto peer = owner->peer(PeerId(request.id)); - const auto &add = request.callback; + QString removeAllConfirm, + Fn removeAll) { + return [=] { + controller->show(Ui::MakeConfirmBox({ + .text = removeAllConfirm, + .confirmed = [=](Fn close) { removeAll(); close(); } + })); + }; +} + +void FillEntryMenu( + const Ui::Menu::MenuCallback &add, + EntryMenuDescriptor &&descriptor) { + const auto peer = descriptor.peer; + const auto controller = descriptor.controller; const auto group = peer->isMegagroup(); const auto channel = peer->isChannel(); @@ -143,21 +167,18 @@ void FillTopPeerMenu( add({ .separatorSt = &st::expandedMenuSeparator }); add({ - .text = tr::lng_recent_remove(tr::now), - .handler = [=] { remove(peer); }, + .text = descriptor.removeOneText, + .handler = descriptor.removeOne, .icon = &st::menuIconDeleteAttention, .isAttention = true, }); - const auto hideAllConfirmed = [=] { - controller->show(Ui::MakeConfirmBox({ - .text = tr::lng_recent_hide_sure(), - .confirmed = [=](Fn close) { hideAll(); close(); } - })); - }; add({ - .text = tr::lng_recent_hide_top(tr::now).replace('&', u"&&"_q), - .handler = hideAllConfirmed, + .text = descriptor.removeAllText, + .handler = RemoveAllConfirm( + descriptor.controller, + descriptor.removeAllConfirm, + descriptor.removeAll), .icon = &st::menuIconCancelAttention, .isAttention = true, }); @@ -257,9 +278,9 @@ QPoint RecentRow::computeNamePosition(const style::PeerListItem &st) const { } RecentsController::RecentsController( - not_null session, + not_null window, RecentPeersList list) -: _session(session) +: _window(window) , _recent(std::move(list)) { } @@ -279,14 +300,55 @@ void RecentsController::rowClicked(not_null row) { _chosen.fire(row->peer()); } +Fn RecentsController::removeAllCallback() { + const auto weak = base::make_weak(this); + const auto session = &_window->session(); + return crl::guard(session, [=] { + if (weak) { + _count = 0; + while (delegate()->peerListFullRowsCount() > 0) { + delegate()->peerListRemoveRow(delegate()->peerListRowAt(0)); + } + delegate()->peerListRefreshRows(); + } + session->recentPeers().clear(); + }); +} + base::unique_qptr RecentsController::rowContextMenu( QWidget *parent, not_null row) { - return nullptr; + auto result = base::make_unique_q( + parent, + st::popupMenuWithIcons); + const auto peer = row->peer(); + const auto weak = base::make_weak(this); + const auto session = &_window->session(); + const auto removeOne = crl::guard(session, [=] { + if (weak) { + const auto rowId = peer->id.value; + if (const auto row = delegate()->peerListFindRow(rowId)) { + _count = std::max(0, _count.current() - 1); + delegate()->peerListRemoveRow(row); + delegate()->peerListRefreshRows(); + } + } + session->recentPeers().remove(peer); + }); + FillEntryMenu(Ui::Menu::CreateAddActionCallback(result), { + .controller = _window, + .peer = peer, + .removeOneText = tr::lng_recent_remove(tr::now), + .removeOne = removeOne, + .removeAllText = tr::lng_recent_clear_all(tr::now), + .removeAllConfirm = tr::lng_recent_clear_sure(tr::now), + .removeAll = removeAllCallback(), + }); + return result; } Main::Session &RecentsController::session() const { - return *_session; + return _window->session(); } QString RecentsController::savedMessagesChatStatus() const { @@ -306,6 +368,10 @@ void RecentsController::setupDivider() { raw, tr::lng_recent_clear(tr::now), st::searchedBarLink); + clear->setClickedCallback(RemoveAllConfirm( + _window, + tr::lng_recent_clear_sure(tr::now), + removeAllCallback())); rpl::combine( raw->sizeValue(), clear->widthValue() @@ -325,7 +391,7 @@ void RecentsController::setupDivider() { void RecentsController::subscribeToEvents() { using Flag = Data::PeerUpdate::Flag; - _session->changes().peerUpdates( + session().changes().peerUpdates( Flag::Notifications | Flag::OnlineStatus ) | rpl::start_with_next([=](const Data::PeerUpdate &update) { @@ -349,7 +415,7 @@ void RecentsController::subscribeToEvents() { } }, _lifetime); - _session->data().unreadBadgeChanges( + session().data().unreadBadgeChanges( ) | rpl::start_with_next([=] { for (auto i = 0; i != _count.current(); ++i) { const auto row = delegate()->peerListRowAt(i); @@ -395,20 +461,31 @@ Suggestions::Suggestions( _topPeers->showMenuRequests( ) | rpl::start_with_next([=](const ShowTopPeerMenuRequest &request) { const auto weak = Ui::MakeWeak(this); - const auto remove = [=](not_null peer) { + const auto owner = &controller->session().data(); + const auto peer = owner->peer(PeerId(request.id)); + const auto removeOne = [=] { peer->session().topPeers().remove(peer); if (weak) { _topPeers->removeLocally(peer->id.value); } }; const auto session = &controller->session(); - const auto hideAll = crl::guard(session, [=] { + const auto removeAll = crl::guard(session, [=] { session->topPeers().toggleDisabled(true); if (weak) { _topPeers->removeLocally(); } }); - FillTopPeerMenu(controller, request, remove, hideAll); + FillEntryMenu(request.callback, { + .controller = controller, + .peer = peer, + .removeOneText = tr::lng_recent_remove(tr::now), + .removeOne = removeOne, + .removeAllText = tr::lng_recent_hide_top( + tr::now).replace('&', u"&&"_q), + .removeAllConfirm = tr::lng_recent_hide_sure(tr::now), + .removeAll = removeAll, + }); }, _topPeers->lifetime()); } @@ -469,7 +546,7 @@ object_ptr> Suggestions::setupRecentPeers( PeerListContentDelegateSimple >(); const auto controller = lifetime.make_state( - &window->session(), + window, std::move(recentPeers)); controller->setStyleOverrides(&st::recentPeersList); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index debb7490f..23d3bca8d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1167,7 +1167,9 @@ Image *MainWidget::newBackgroundThumb() { } void MainWidget::setInnerFocus() { - if (_hider || !_history->peer()) { + if (_dialogs && _dialogs->searchHasFocus()) { + _dialogs->setInnerFocus(); + } else if (_hider || !_history->peer()) { if (!_hider && _mainSection) { _mainSection->setInnerFocus(); } else if (!_hider && _thirdSection) { @@ -2620,12 +2622,29 @@ void MainWidget::returnTabbedSelector() { } } +bool MainWidget::relevantForDialogsFocus(not_null widget) const { + if (!_dialogs || widget->window() != window()) { + return false; + } + while (true) { + if (widget.get() == this) { + return true; + } + const auto parent = widget->parentWidget(); + if (!parent) { + return false; + } + widget = parent; + } + Unexpected("Should never be here."); +} + bool MainWidget::eventFilter(QObject *o, QEvent *e) { const auto widget = o->isWidgetType() ? static_cast(o) : nullptr; if (e->type() == QEvent::FocusIn) { - if (widget && _dialogs && widget->window() == window()) { + if (widget && relevantForDialogsFocus(widget)) { _dialogs->updateHasFocus(widget); } } else if (e->type() == QEvent::MouseButtonPress) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 809086765..aab9239ef 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -108,7 +108,7 @@ class ItemBase; } // namespace Layout } // namespace InlineBots -class MainWidget +class MainWidget final : public Ui::RpWidget , private Media::Player::FloatDelegate { public: @@ -236,12 +236,14 @@ public: void dialogsCancelled(); -protected: +private: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; bool eventFilter(QObject *o, QEvent *e) override; -private: + [[nodiscard]] bool relevantForDialogsFocus( + not_null widget) const; + void showFinished(); void handleAdaptiveLayoutUpdate(); void updateWindowAdaptiveLayout();