Fix drag-n-drop to frequent/recent contacts.

This commit is contained in:
John Preston 2024-05-19 12:05:01 +04:00
parent ba8bb2d50f
commit 1c6f45d8d3
7 changed files with 129 additions and 11 deletions

View file

@ -2125,6 +2125,16 @@ bool PeerListContent::submitted() {
return false;
}
PeerListRowId PeerListContent::updateFromParentDrag(QPoint globalPosition) {
selectByMouse(globalPosition);
const auto row = getRow(_selected.index);
return row ? row->id() : 0;
}
void PeerListContent::dragLeft() {
clearSelection();
}
void PeerListContent::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {

View file

@ -625,6 +625,9 @@ public:
void searchQueryChanged(QString query);
bool submitted();
PeerListRowId updateFromParentDrag(QPoint globalPosition);
void dragLeft();
// Interface for the controller.
void appendRow(std::unique_ptr<PeerListRow> row);
void appendSearchRow(std::unique_ptr<PeerListRow> row);

View file

@ -2543,15 +2543,18 @@ void Widget::dragMoveEvent(QDragMoveEvent *e) {
} else {
_chooseByDragTimer.callOnce(ChoosePeerByDragTimeout);
}
if (_inner->updateFromParentDrag(mapToGlobal(e->pos()))) {
e->setDropAction(Qt::CopyAction);
} else {
e->setDropAction(Qt::IgnoreAction);
}
const auto global = mapToGlobal(e->pos());
const auto thread = _suggestions
? _suggestions->updateFromParentDrag(global)
: _inner->updateFromParentDrag(global);
e->setDropAction(thread ? Qt::CopyAction : Qt::IgnoreAction);
} else {
if (_dragForward) {
updateDragInScroll(false);
}
if (_suggestions) {
_suggestions->dragLeft();
}
_inner->dragLeft();
e->setDropAction(Qt::IgnoreAction);
}
@ -2564,6 +2567,9 @@ void Widget::dragLeaveEvent(QDragLeaveEvent *e) {
} else {
_chooseByDragTimer.cancel();
}
if (_suggestions) {
_suggestions->dragLeft();
}
_inner->dragLeft();
e->accept();
}
@ -2582,8 +2588,11 @@ void Widget::updateDragInScroll(bool inScroll) {
void Widget::dropEvent(QDropEvent *e) {
_chooseByDragTimer.cancel();
if (_scroll->geometry().contains(e->pos())) {
const auto point = mapToGlobal(e->pos());
if (const auto thread = _inner->updateFromParentDrag(point)) {
const auto globalPosition = mapToGlobal(e->pos());
const auto thread = _suggestions
? _suggestions->updateFromParentDrag(globalPosition)
: _inner->updateFromParentDrag(globalPosition);
if (thread) {
e->setDropAction(Qt::CopyAction);
e->accept();
controller()->content()->filesOrForwardDrop(

View file

@ -1121,6 +1121,39 @@ void Suggestions::chooseRow() {
}
}
Data::Thread *Suggestions::updateFromParentDrag(QPoint globalPosition) {
return (_tab.current() == Tab::Chats)
? updateFromChatsDrag(globalPosition)
: updateFromChannelsDrag(globalPosition);
}
Data::Thread *Suggestions::updateFromChatsDrag(QPoint globalPosition) {
if (const auto top = _topPeers->updateFromParentDrag(globalPosition)) {
return _controller->session().data().history(PeerId(top));
}
return fromListId(_recentUpdateFromParentDrag(globalPosition));
}
Data::Thread *Suggestions::updateFromChannelsDrag(QPoint globalPosition) {
if (const auto id = _myChannelsUpdateFromParentDrag(globalPosition)) {
return fromListId(id);
}
return fromListId(_recommendationsUpdateFromParentDrag(globalPosition));
}
Data::Thread *Suggestions::fromListId(uint64 peerListRowId) {
return peerListRowId
? _controller->session().data().history(PeerId(peerListRowId)).get()
: nullptr;
}
void Suggestions::dragLeft() {
_topPeers->dragLeft();
_recentDragLeft();
_myChannelsDragLeft();
_recommendationsDragLeft();
}
void Suggestions::show(anim::type animated, Fn<void()> finish) {
RpWidget::show();
@ -1304,6 +1337,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupRecentPeers(
}
return JumpResult::NotApplied;
};
_recentUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_recentDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _topPeersWrap->toggled() ? _topPeers->height() : 0;
@ -1438,6 +1477,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupMyChannels() {
}
return JumpResult::NotApplied;
};
_myChannelsUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_myChannelsDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
_channelsScroll->scrollToY(request.ymin, request.ymax);
@ -1499,6 +1544,12 @@ object_ptr<Ui::SlideWrap<>> Suggestions::setupRecommendations() {
}
return JumpResult::NotApplied;
};
_recommendationsUpdateFromParentDrag = [=](QPoint globalPosition) {
return raw->updateFromParentDrag(globalPosition);
};
_recommendationsDragLeft = [=] {
raw->dragLeft();
};
raw->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
const auto add = _myChannels->toggled() ? _myChannels->height() : 0;

View file

@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h"
#include "ui/rp_widget.h"
namespace Data {
class Thread;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
@ -46,6 +50,9 @@ public:
void selectJump(Qt::Key direction, int pageSize = 0);
void chooseRow();
[[nodiscard]] Data::Thread *updateFromParentDrag(QPoint globalPosition);
void dragLeft();
void show(anim::type animated, Fn<void()> finish);
void hide(anim::type animated, Fn<void()> finish);
[[nodiscard]] float64 shownOpacity() const;
@ -90,6 +97,11 @@ private:
void selectJumpChats(Qt::Key direction, int pageSize);
void selectJumpChannels(Qt::Key direction, int pageSize);
[[nodiscard]] Data::Thread *updateFromChatsDrag(QPoint globalPosition);
[[nodiscard]] Data::Thread *updateFromChannelsDrag(
QPoint globalPosition);
[[nodiscard]] Data::Thread *fromListId(uint64 peerListRowId);
[[nodiscard]] object_ptr<Ui::SlideWrap<Ui::RpWidget>> setupRecentPeers(
RecentPeersList recentPeers);
[[nodiscard]] object_ptr<Ui::SlideWrap<Ui::RpWidget>> setupEmptyRecent();
@ -121,6 +133,8 @@ private:
rpl::variable<int> _recentCount;
Fn<bool()> _recentPeersChoose;
Fn<JumpResult(Qt::Key, int)> _recentSelectJump;
Fn<uint64(QPoint)> _recentUpdateFromParentDrag;
Fn<void()> _recentDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recentPeers;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyRecent;
@ -130,11 +144,15 @@ private:
rpl::variable<int> _myChannelsCount;
Fn<bool()> _myChannelsChoose;
Fn<JumpResult(Qt::Key, int)> _myChannelsSelectJump;
Fn<uint64(QPoint)> _myChannelsUpdateFromParentDrag;
Fn<void()> _myChannelsDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _myChannels;
rpl::variable<int> _recommendationsCount;
Fn<bool()> _recommendationsChoose;
Fn<JumpResult(Qt::Key, int)> _recommendationsSelectJump;
Fn<uint64(QPoint)> _recommendationsUpdateFromParentDrag;
Fn<void()> _recommendationsDragLeft;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _recommendations;
const not_null<Ui::SlideWrap<Ui::RpWidget>*> _emptyChannels;

View file

@ -248,7 +248,7 @@ void TopPeersStrip::stripWheelEvent(QWheelEvent *e) {
void TopPeersStrip::stripLeaveEvent(QEvent *e) {
if (!_selectionByKeyboard) {
setSelected(-1);
clearSelection();
}
if (!_dragging) {
_lastMousePosition = std::nullopt;
@ -299,9 +299,7 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
&& (_lastMousePosition == e->globalPos())) {
return;
}
_lastMousePosition = e->globalPos();
_selectionByKeyboard = false;
updateSelected();
selectByMouse(e->globalPos());
if (!_dragging && _mouseDownPosition) {
if ((*_lastMousePosition - *_mouseDownPosition).manhattanLength()
@ -315,6 +313,12 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) {
checkDragging();
}
void TopPeersStrip::selectByMouse(QPoint globalPosition) {
_lastMousePosition = globalPosition;
_selectionByKeyboard = false;
updateSelected();
}
void TopPeersStrip::checkDragging() {
if (_dragging && !_expandAnimation.animating()) {
const auto sign = (style::RightToLeft() ? -1 : 1);
@ -551,6 +555,20 @@ bool TopPeersStrip::chooseRow() {
return false;
}
uint64 TopPeersStrip::updateFromParentDrag(QPoint globalPosition) {
if (!rect().contains(mapFromGlobal(globalPosition))) {
dragLeft();
return 0;
}
selectByMouse(globalPosition);
return (_selected >= 0) ? _entries[_selected].id : 0;
}
void TopPeersStrip::dragLeft() {
clearSelection();
}
void TopPeersStrip::apply(const TopPeersList &list) {
if (_hiddenLocally) {
return;
@ -908,6 +926,10 @@ void TopPeersStrip::setSelected(int selected) {
}
}
void TopPeersStrip::clearSelection() {
setSelected(-1);
}
void TopPeersStrip::scrollToSelected() {
if (_selected < 0) {
return;

View file

@ -62,6 +62,9 @@ public:
void deselectByKeyboard();
bool chooseRow();
uint64 updateFromParentDrag(QPoint globalPosition);
void dragLeft();
[[nodiscard]] auto verticalScrollEvents() const
-> rpl::producer<not_null<QWheelEvent*>>;
@ -92,6 +95,8 @@ private:
void subscribeUserpic(Entry &entry);
void unsubscribeUserpics(bool all = false);
void paintUserpic(Painter &p, int x, int y, int index, bool selected);
void clearSelection();
void selectByMouse(QPoint globalPosition);
[[nodiscard]] QRect outer() const;
[[nodiscard]] QRect innerRounded() const;