Support touchscreen pinned chats reordering.

This commit is contained in:
John Preston 2024-05-30 23:22:03 +04:00
parent 4df5372dab
commit 4953246c5d
3 changed files with 90 additions and 28 deletions

View file

@ -79,6 +79,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_window.h" #include "styles/style_window.h"
#include "styles/style_menu_icons.h" #include "styles/style_menu_icons.h"
#include <QtWidgets/QApplication>
namespace Dialogs { namespace Dialogs {
namespace { namespace {
@ -1316,7 +1318,7 @@ void InnerWidget::paintSearchInTopic(
} }
void InnerWidget::mouseMoveEvent(QMouseEvent *e) { void InnerWidget::mouseMoveEvent(QMouseEvent *e) {
if (_chatPreviewTouchGlobal) { if (_chatPreviewTouchGlobal || _touchDragStartGlobal) {
return; return;
} }
const auto globalPosition = e->globalPos(); const auto globalPosition = e->globalPos();
@ -1336,7 +1338,6 @@ void InnerWidget::mouseMoveEvent(QMouseEvent *e) {
void InnerWidget::cancelChatPreview() { void InnerWidget::cancelChatPreview() {
_chatPreviewTimer.cancel(); _chatPreviewTimer.cancel();
_chatPreviewWillBeFor = {}; _chatPreviewWillBeFor = {};
_chatPreviewTouchLocal = {};
_chatPreviewTouchGlobal = {}; _chatPreviewTouchGlobal = {};
} }
@ -1622,8 +1623,14 @@ void InnerWidget::checkReorderPinnedStart(QPoint localPosition) {
< style::ConvertScale(kStartReorderThreshold)) { < style::ConvertScale(kStartReorderThreshold)) {
return; return;
} }
cancelChatPreview();
_dragging = _pressed; _dragging = _pressed;
startReorderPinned(localPosition);
}
void InnerWidget::startReorderPinned(QPoint localPosition) {
Expects(_dragging != nullptr);
cancelChatPreview();
if (updateReorderIndexGetCount() < 2) { if (updateReorderIndexGetCount() < 2) {
_dragging = nullptr; _dragging = nullptr;
} else { } else {
@ -1682,6 +1689,7 @@ void InnerWidget::finishReorderPinned() {
if (wasDragging) { if (wasDragging) {
savePinnedOrder(); savePinnedOrder();
_dragging = nullptr; _dragging = nullptr;
_touchDragStartGlobal = {};
} }
_draggingIndex = -1; _draggingIndex = -1;
@ -1694,6 +1702,22 @@ void InnerWidget::finishReorderPinned() {
} }
} }
bool InnerWidget::finishReorderOnRelease() {
if (!_dragging) {
return false;
}
updateReorderIndexGetCount();
if (_draggingIndex >= 0) {
_pinnedRows[_draggingIndex].yadd.start(0.);
_pinnedRows[_draggingIndex].animStartTime = crl::now();
if (!_pinnedShiftAnimation.animating()) {
_pinnedShiftAnimation.start();
}
}
finishReorderPinned();
return true;
}
void InnerWidget::stopReorderPinned() { void InnerWidget::stopReorderPinned() {
_pinnedShiftAnimation.stop(); _pinnedShiftAnimation.stop();
finishReorderPinned(); finishReorderPinned();
@ -1845,18 +1869,7 @@ void InnerWidget::mousePressReleased(
_chatPreviewTimer.cancel(); _chatPreviewTimer.cancel();
_pressButton = Qt::NoButton; _pressButton = Qt::NoButton;
auto wasDragging = (_dragging != nullptr); const auto wasDragging = finishReorderOnRelease();
if (wasDragging) {
updateReorderIndexGetCount();
if (_draggingIndex >= 0) {
_pinnedRows[_draggingIndex].yadd.start(0.);
_pinnedRows[_draggingIndex].animStartTime = crl::now();
if (!_pinnedShiftAnimation.animating()) {
_pinnedShiftAnimation.start();
}
}
finishReorderPinned();
}
auto collapsedPressed = _collapsedPressed; auto collapsedPressed = _collapsedPressed;
setCollapsedPressed(-1); setCollapsedPressed(-1);
@ -2547,14 +2560,14 @@ void InnerWidget::parentGeometryChanged() {
} }
} }
void InnerWidget::processTouchEvent(not_null<QTouchEvent*> e) { bool InnerWidget::processTouchEvent(not_null<QTouchEvent*> e) {
const auto point = e->touchPoints().empty() const auto point = e->touchPoints().empty()
? std::optional<QPoint>() ? std::optional<QPoint>()
: e->touchPoints().front().screenPos().toPoint(); : e->touchPoints().front().screenPos().toPoint();
switch (e->type()) { switch (e->type()) {
case QEvent::TouchBegin: { case QEvent::TouchBegin: {
if (!point) { if (!point) {
return; return false;
} }
selectByMouse(*point); selectByMouse(*point);
const auto onlyUserpic = true; const auto onlyUserpic = true;
@ -2562,24 +2575,69 @@ void InnerWidget::processTouchEvent(not_null<QTouchEvent*> e) {
_chatPreviewTouchGlobal = point; _chatPreviewTouchGlobal = point;
_chatPreviewWillBeFor = computeChatPreviewRow(); _chatPreviewWillBeFor = computeChatPreviewRow();
_chatPreviewTimer.callOnce(kChatPreviewDelay); _chatPreviewTimer.callOnce(kChatPreviewDelay);
} else if (!_dragging) {
_touchDragStartGlobal = point;
_touchDragPinnedTimer.callOnce(QApplication::startDragTime());
} }
} break; } break;
case QEvent::TouchUpdate: { case QEvent::TouchUpdate: {
if (!_chatPreviewTouchGlobal || !point) { if (!point) {
return; return false;
} }
const auto delta = (*_chatPreviewTouchGlobal - *point); if (_chatPreviewTouchGlobal) {
if (delta.manhattanLength() > _st->photoSize) { const auto delta = (*_chatPreviewTouchGlobal - *point);
cancelChatPreview(); if (delta.manhattanLength() > _st->photoSize) {
cancelChatPreview();
}
}
if (_touchDragStartGlobal && _dragging) {
updateReorderPinned(mapFromGlobal(*point));
return _dragging != nullptr;
} else if (_touchDragStartGlobal) {
const auto delta = (*_touchDragStartGlobal - *point);
if (delta.manhattanLength() > QApplication::startDragDistance()) {
if (_touchDragPinnedTimer.isActive()) {
_touchDragPinnedTimer.cancel();
_touchDragStartGlobal = {};
_touchDragNowGlobal = {};
} else {
dragPinnedFromTouch();
}
} else {
_touchDragNowGlobal = point;
}
} }
} break; } break;
case QEvent::TouchEnd: case QEvent::TouchEnd:
case QEvent::TouchCancel: if (_chatPreviewTouchGlobal) { case QEvent::TouchCancel: {
cancelChatPreview(); if (_chatPreviewTouchGlobal) {
cancelChatPreview();
}
if (_touchDragStartGlobal) {
_touchDragStartGlobal = {};
return finishReorderOnRelease();
}
} break; } break;
} }
return false;
}
void InnerWidget::dragPinnedFromTouch() {
Expects(_touchDragStartGlobal.has_value());
const auto global = *_touchDragStartGlobal;
_touchDragPinnedTimer.cancel();
selectByMouse(global);
if (!_selected || _dragging || _state != WidgetState::Default) {
return;
}
_dragStart = mapFromGlobal(global);
_dragging = _selected;
const auto now = mapFromGlobal(_touchDragNowGlobal.value_or(global));
startReorderPinned(now);
updateReorderPinned(now);
} }
void InnerWidget::applySearchState(SearchState state) { void InnerWidget::applySearchState(SearchState state) {

View file

@ -174,7 +174,7 @@ public:
void parentGeometryChanged(); void parentGeometryChanged();
void processTouchEvent(not_null<QTouchEvent*> e); bool processTouchEvent(not_null<QTouchEvent*> e);
[[nodiscard]] rpl::producer<> touchCancelRequests() const { [[nodiscard]] rpl::producer<> touchCancelRequests() const {
return _touchCancelRequests.events(); return _touchCancelRequests.events();
} }
@ -404,15 +404,18 @@ private:
[[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const; [[nodiscard]] const std::vector<Key> &pinnedChatsOrder() const;
void checkReorderPinnedStart(QPoint localPosition); void checkReorderPinnedStart(QPoint localPosition);
void startReorderPinned(QPoint localPosition);
int updateReorderIndexGetCount(); int updateReorderIndexGetCount();
bool updateReorderPinned(QPoint localPosition); bool updateReorderPinned(QPoint localPosition);
void finishReorderPinned(); void finishReorderPinned();
bool finishReorderOnRelease();
void stopReorderPinned(); void stopReorderPinned();
int countPinnedIndex(Row *ofRow); int countPinnedIndex(Row *ofRow);
void savePinnedOrder(); void savePinnedOrder();
bool pinnedShiftAnimationCallback(crl::time now); bool pinnedShiftAnimationCallback(crl::time now);
void handleChatListEntryRefreshes(); void handleChatListEntryRefreshes();
void moveCancelSearchButtons(); void moveCancelSearchButtons();
void dragPinnedFromTouch();
void saveChatsFilterScrollState(FilterId filterId); void saveChatsFilterScrollState(FilterId filterId);
void restoreChatsFilterScrollState(FilterId filterId); void restoreChatsFilterScrollState(FilterId filterId);
@ -525,8 +528,10 @@ private:
base::Timer _chatPreviewTimer; base::Timer _chatPreviewTimer;
Key _chatPreviewWillBeFor; Key _chatPreviewWillBeFor;
Key _chatPreviewKey; Key _chatPreviewKey;
std::optional<QPoint> _chatPreviewTouchLocal;
std::optional<QPoint> _chatPreviewTouchGlobal; std::optional<QPoint> _chatPreviewTouchGlobal;
base::Timer _touchDragPinnedTimer;
std::optional<QPoint> _touchDragStartGlobal;
std::optional<QPoint> _touchDragNowGlobal;
rpl::event_stream<> _touchCancelRequests; rpl::event_stream<> _touchCancelRequests;
rpl::variable<ChildListShown> _childListShown; rpl::variable<ChildListShown> _childListShown;

View file

@ -658,8 +658,7 @@ void Widget::setupScrollUpButton() {
void Widget::setupTouchChatPreview() { void Widget::setupTouchChatPreview() {
_scroll->setCustomTouchProcess([=](not_null<QTouchEvent*> e) { _scroll->setCustomTouchProcess([=](not_null<QTouchEvent*> e) {
_inner->processTouchEvent(e); return _inner->processTouchEvent(e);
return false;
}); });
_inner->touchCancelRequests() | rpl::start_with_next([=] { _inner->touchCancelRequests() | rpl::start_with_next([=] {
QTouchEvent ev(QEvent::TouchCancel); QTouchEvent ev(QEvent::TouchCancel);