From 19f5d95a3c52897064088d7b30b8662ee266507c Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 12 Apr 2024 16:30:46 +0400 Subject: [PATCH] Implement keyboard navigation for recent peers. --- .../SourceFiles/dialogs/dialogs_widget.cpp | 25 ++--- .../dialogs/ui/dialogs_suggestions.cpp | 103 +++++++++++++----- .../dialogs/ui/dialogs_suggestions.h | 13 ++- .../dialogs/ui/top_peers_strip.cpp | 37 +++---- .../SourceFiles/dialogs/ui/top_peers_strip.h | 4 +- 5 files changed, 110 insertions(+), 72 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 90adb1f50..e2c43a20a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -3165,32 +3165,25 @@ void Widget::keyPressEvent(QKeyEvent *e) { //} } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { submit(); + } else if (_suggestions + && (e->key() == Qt::Key_Down + || e->key() == Qt::Key_Up + || e->key() == Qt::Key_Left + || e->key() == Qt::Key_Right)) { + _suggestions->selectJump(Qt::Key(e->key())); } else if (e->key() == Qt::Key_Down) { - if (_suggestions) { - _suggestions->selectSkip(1); - } else { - _inner->selectSkip(1); - } + _inner->selectSkip(1); } else if (e->key() == Qt::Key_Up) { - if (_suggestions) { - _suggestions->selectSkip(-1); - } else { - _inner->selectSkip(-1); - } _inner->selectSkip(-1); - } else if (e->key() == Qt::Key_Left && _suggestions) { - _suggestions->selectLeft(); - } else if (e->key() == Qt::Key_Right && _suggestions) { - _suggestions->selectRight(); } else if (e->key() == Qt::Key_PageDown) { if (_suggestions) { - _suggestions->selectSkipPage(_scroll->height(), 1); + _suggestions->selectJump(Qt::Key_Down, _scroll->height()); } else { _inner->selectSkipPage(_scroll->height(), 1); } } else if (e->key() == Qt::Key_PageUp) { if (_suggestions) { - _suggestions->selectSkipPage(_scroll->height(), -1); + _suggestions->selectJump(Qt::Key_Up, _scroll->height()); } else { _inner->selectSkipPage(_scroll->height(), -1); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index bcc90575a..b3af39435 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -491,43 +491,60 @@ Suggestions::Suggestions( Suggestions::~Suggestions() = default; -void Suggestions::selectSkip(int delta) { - if (!delta) { - return; - } else if (delta > 0) { - const auto hasRecent = false; - if (hasRecent && (_topPeers->selectedByKeyboard() || delta > 1)) { +void Suggestions::selectJump(Qt::Key direction, int pageSize) { + const auto recentHasSelection = [=] { + return _recentSelectJump(Qt::Key(), 0) == JumpResult::Applied; + }; + if (pageSize) { + if (direction == Qt::Key_Down || direction == Qt::Key_Up) { _topPeers->deselectByKeyboard(); + if (!recentHasSelection()) { + if (direction == Qt::Key_Down) { + _recentSelectJump(direction, 0); + } else { + return; + } + } + if (_recentSelectJump(direction, pageSize) == JumpResult::AppliedAndOut) { + if (direction == Qt::Key_Up) { + _scroll->scrollTo(0); + } + } + } + } else if (direction == Qt::Key_Up) { + if (_recentSelectJump(direction, pageSize) + == JumpResult::AppliedAndOut) { + _topPeers->selectByKeyboard(Qt::Key()); + _scroll->scrollTo(0); } else { - _topPeers->selectByKeyboard(0); - } - } else { - if (_topPeers->selectedByKeyboard()) { _topPeers->deselectByKeyboard(); } - } -} - -void Suggestions::selectSkipPage(int height, int direction) { - if (_topPeers->selectedByKeyboard()) { - _topPeers->deselectByKeyboard(); + } else if (direction == Qt::Key_Down) { + if (_topPeers->selectedByKeyboard()) { + if (_recentCount.current() > 0) { + _topPeers->deselectByKeyboard(); + _recentSelectJump(direction, pageSize); + } + } else if (!_topPeersWrap->toggled() || recentHasSelection()) { + _recentSelectJump(direction, pageSize); + } else { + _topPeers->selectByKeyboard(Qt::Key()); + _scroll->scrollTo(0); + } + } else if (direction == Qt::Key_Left || direction == Qt::Key_Right) { + if (!recentHasSelection()) { + _topPeers->selectByKeyboard(direction); + _scroll->scrollTo(0); + } } } void Suggestions::chooseRow() { - if (_topPeers->chooseRow()) { - return; + if (!_topPeers->chooseRow()) { + _recentPeersChoose(); } } -void Suggestions::selectLeft() { - _topPeers->selectLeft(); -} - -void Suggestions::selectRight() { - _topPeers->selectRight(); -} - void Suggestions::paintEvent(QPaintEvent *e) { QPainter(this).fillRect(e->rect(), st::windowBg); } @@ -559,7 +576,39 @@ object_ptr> Suggestions::setupRecentPeers( }, lifetime); auto content = object_ptr(_content, controller); - delegate->setContent(content); + + const auto raw = content.data(); + _recentPeersChoose = [=] { + return raw->submitted(); + }; + _recentSelectJump = [raw](Qt::Key direction, int pageSize) { + const auto had = raw->hasSelection(); + if (direction == Qt::Key()) { + return had ? JumpResult::Applied : JumpResult::NotApplied; + } else if (direction == Qt::Key_Up && !had) { + return JumpResult::NotApplied; + } else if (direction == Qt::Key_Down || direction == Qt::Key_Up) { + const auto delta = (direction == Qt::Key_Down) ? 1 : -1; + if (pageSize > 0) { + raw->selectSkipPage(pageSize, delta); + } else { + raw->selectSkip(delta); + } + return raw->hasSelection() + ? JumpResult::Applied + : had + ? JumpResult::AppliedAndOut + : JumpResult::NotApplied; + } + return JumpResult::NotApplied; + }; + raw->scrollToRequests( + ) | rpl::start_with_next([this](Ui::ScrollToRequest request) { + const auto add = _topPeersWrap->toggled() ? _topPeers->height() : 0; + _scroll->scrollToY(request.ymin + add, request.ymax + add); + }, lifetime); + + delegate->setContent(raw); controller->setDelegate(delegate); return object_ptr>(this, std::move(content)); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h index 3ddd00f72..b960eddaf 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h @@ -41,10 +41,7 @@ public: RecentPeersList recentPeers); ~Suggestions(); - void selectSkip(int delta); - void selectSkipPage(int height, int direction); - void selectLeft(); - void selectRight(); + void selectJump(Qt::Key direction, int pageSize = 0); void chooseRow(); [[nodiscard]] rpl::producer> topPeerChosen() const { @@ -55,6 +52,12 @@ public: } private: + enum class JumpResult { + NotApplied, + Applied, + AppliedAndOut, + }; + void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; @@ -70,6 +73,8 @@ private: const not_null _topPeers; rpl::variable _recentCount; + Fn _recentPeersChoose; + Fn _recentSelectJump; const not_null*> _recentPeers; const not_null*> _emptyRecent; diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp index 3f5104547..4797b7abb 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp @@ -282,20 +282,29 @@ bool TopPeersStrip::selectedByKeyboard() const { return _selectionByKeyboard && _selected >= 0; } -void TopPeersStrip::selectByKeyboard(int delta) { +void TopPeersStrip::selectByKeyboard(Qt::Key direction) { if (_entries.empty()) { return; } - _selectionByKeyboard = true; - if (!delta) { + if (direction == Qt::Key()) { + _selectionByKeyboard = true; if (_selected < 0) { setSelected(0); scrollToSelected(); } - return; + } else if (direction == Qt::Key_Left) { + if (_selected > 0) { + _selectionByKeyboard = true; + setSelected(_selected - 1); + scrollToSelected(); + } + } else if (direction == Qt::Key_Right) { + if (_selected + 1 < _entries.size()) { + _selectionByKeyboard = true; + setSelected(_selected + 1); + scrollToSelected(); + } } - setSelected(std::clamp(_selected + delta, 0, int(_entries.size()) - 1)); - scrollToSelected(); } void TopPeersStrip::deselectByKeyboard() { @@ -305,22 +314,6 @@ void TopPeersStrip::deselectByKeyboard() { } } -void TopPeersStrip::selectLeft() { - if (_selected > 0) { - _selectionByKeyboard = true; - setSelected(_selected - 1); - scrollToSelected(); - } -} - -void TopPeersStrip::selectRight() { - if (_selected + 1 < _entries.size()) { - _selectionByKeyboard = true; - setSelected(_selected + 1); - scrollToSelected(); - } -} - bool TopPeersStrip::chooseRow() { if (_selected >= 0) { Assert(_selected < _entries.size()); diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h index 84584e56d..c3330e40d 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h @@ -53,9 +53,7 @@ public: void removeLocally(uint64 id = 0); [[nodiscard]] bool selectedByKeyboard() const; - void selectByKeyboard(int delta); - void selectLeft(); - void selectRight(); + void selectByKeyboard(Qt::Key direction); void deselectByKeyboard(); bool chooseRow();