Implement keyboard navigation for recent peers.

This commit is contained in:
John Preston 2024-04-12 16:30:46 +04:00
parent 051ca51d3b
commit 19f5d95a3c
5 changed files with 110 additions and 72 deletions

View File

@ -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);
}

View File

@ -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<Ui::SlideWrap<>> Suggestions::setupRecentPeers(
}, lifetime);
auto content = object_ptr<PeerListContent>(_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<Ui::SlideWrap<>>(this, std::move(content));

View File

@ -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<not_null<PeerData*>> 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<TopPeersStrip*> _topPeers;
rpl::variable<int> _recentCount;
Fn<bool()> _recentPeersChoose;
Fn<JumpResult(Qt::Key, int)> _recentSelectJump;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recentPeers;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyRecent;

View File

@ -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());

View File

@ -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();