mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-22 09:07:05 +02:00
Implement nice stories list scrolling.
This commit is contained in:
parent
1d27c8c940
commit
16128d61c0
8 changed files with 248 additions and 29 deletions
|
@ -142,7 +142,7 @@ InnerWidget::InnerWidget(
|
||||||
, _stories(std::make_unique<Stories::List>(
|
, _stories(std::make_unique<Stories::List>(
|
||||||
this,
|
this,
|
||||||
Stories::ContentForSession(&controller->session()),
|
Stories::ContentForSession(&controller->session()),
|
||||||
[=] { return st::dialogsStoriesFull.height - _visibleTop; }))
|
[=] { return _stories->height() - _visibleTop; }))
|
||||||
, _shownList(controller->session().data().chatsList()->indexed())
|
, _shownList(controller->session().data().chatsList()->indexed())
|
||||||
, _st(&st::defaultDialogRow)
|
, _st(&st::defaultDialogRow)
|
||||||
, _pinnedShiftAnimation([=](crl::time now) {
|
, _pinnedShiftAnimation([=](crl::time now) {
|
||||||
|
@ -323,6 +323,18 @@ InnerWidget::InnerWidget(
|
||||||
switchToFilter(filterId);
|
switchToFilter(filterId);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
_stories->heightValue(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return (_viewportHeight > 0) && (defaultScrollTop() > _visibleTop);
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
jumpToTop();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_stories->entered(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
clearSelection();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
handleChatListEntryRefreshes();
|
handleChatListEntryRefreshes();
|
||||||
|
|
||||||
refreshWithCollapsedRows(true);
|
refreshWithCollapsedRows(true);
|
||||||
|
@ -428,6 +440,16 @@ int InnerWidget::dialogsOffset() const {
|
||||||
- skipTopHeight();
|
- skipTopHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> InnerWidget::scrollToVeryTopRequests() const {
|
||||||
|
return _stories->expandRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
int InnerWidget::defaultScrollTop() const {
|
||||||
|
return storiesShown()
|
||||||
|
? std::max(_stories->height() - st::dialogsStories.height, 0)
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
int InnerWidget::fixedOnTopCount() const {
|
int InnerWidget::fixedOnTopCount() const {
|
||||||
auto result = 0;
|
auto result = 0;
|
||||||
for (const auto &row : *_shownList) {
|
for (const auto &row : *_shownList) {
|
||||||
|
@ -1699,6 +1721,15 @@ void InnerWidget::mousePressReleased(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setViewportHeight(int viewportHeight) {
|
||||||
|
if (_viewportHeight != viewportHeight) {
|
||||||
|
_viewportHeight = viewportHeight;
|
||||||
|
if (height() < defaultScrollTop() + viewportHeight) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::setCollapsedPressed(int pressed) {
|
void InnerWidget::setCollapsedPressed(int pressed) {
|
||||||
if (_collapsedPressed != pressed) {
|
if (_collapsedPressed != pressed) {
|
||||||
if (_collapsedPressed >= 0) {
|
if (_collapsedPressed >= 0) {
|
||||||
|
@ -2745,10 +2776,13 @@ void InnerWidget::refresh(bool toTop) {
|
||||||
h = searchedOffset() + (_searchResults.size() * _st->height);
|
h = searchedOffset() + (_searchResults.size() * _st->height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (const auto storiesSkip = defaultScrollTop()) {
|
||||||
|
accumulate_max(h, storiesSkip + _viewportHeight);
|
||||||
|
}
|
||||||
resize(width(), h);
|
resize(width(), h);
|
||||||
if (toTop) {
|
if (toTop) {
|
||||||
stopReorderPinned();
|
stopReorderPinned();
|
||||||
_mustScrollTo.fire({ 0, 0 });
|
jumpToTop();
|
||||||
preloadRowsData();
|
preloadRowsData();
|
||||||
}
|
}
|
||||||
_controller->setDialogsListDisplayForced(
|
_controller->setDialogsListDisplayForced(
|
||||||
|
@ -3226,7 +3260,7 @@ void InnerWidget::switchToFilter(FilterId filterId) {
|
||||||
filterId = 0;
|
filterId = 0;
|
||||||
}
|
}
|
||||||
if (_filterId == filterId) {
|
if (_filterId == filterId) {
|
||||||
_mustScrollTo.fire({ 0, 0 });
|
jumpToTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveChatsFilterScrollState(_filterId);
|
saveChatsFilterScrollState(_filterId);
|
||||||
|
@ -3251,6 +3285,11 @@ void InnerWidget::switchToFilter(FilterId filterId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::jumpToTop() {
|
||||||
|
const auto to = defaultScrollTop();
|
||||||
|
_mustScrollTo.fire({ to, -1 });
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::saveChatsFilterScrollState(FilterId filterId) {
|
void InnerWidget::saveChatsFilterScrollState(FilterId filterId) {
|
||||||
_chatsFilterScrollStates[filterId] = -y();
|
_chatsFilterScrollStates[filterId] = -y();
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,10 @@ public:
|
||||||
const QVector<MTPPeer> &my,
|
const QVector<MTPPeer> &my,
|
||||||
const QVector<MTPPeer> &result);
|
const QVector<MTPPeer> &result);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<> scrollToVeryTopRequests() const;
|
||||||
|
[[nodiscard]] int defaultScrollTop() const;
|
||||||
|
void setViewportHeight(int viewportHeight);
|
||||||
|
|
||||||
[[nodiscard]] FilterId filterId() const;
|
[[nodiscard]] FilterId filterId() const;
|
||||||
|
|
||||||
void clearSelection();
|
void clearSelection();
|
||||||
|
@ -279,6 +283,7 @@ private:
|
||||||
|
|
||||||
int defaultRowTop(not_null<Row*> row) const;
|
int defaultRowTop(not_null<Row*> row) const;
|
||||||
void setupOnlineStatusCheck();
|
void setupOnlineStatusCheck();
|
||||||
|
void jumpToTop();
|
||||||
|
|
||||||
void updateRowCornerStatusShown(not_null<History*> history);
|
void updateRowCornerStatusShown(not_null<History*> history);
|
||||||
void repaintDialogRowCornerStatus(not_null<History*> history);
|
void repaintDialogRowCornerStatus(not_null<History*> history);
|
||||||
|
@ -402,6 +407,7 @@ private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
|
||||||
const std::unique_ptr<Stories::List> _stories;
|
const std::unique_ptr<Stories::List> _stories;
|
||||||
|
int _viewportHeight = 0;
|
||||||
|
|
||||||
not_null<IndexedList*> _shownList;
|
not_null<IndexedList*> _shownList;
|
||||||
FilterId _filterId = 0;
|
FilterId _filterId = 0;
|
||||||
|
|
|
@ -260,6 +260,11 @@ Widget::Widget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
_inner->scrollToVeryTopRequests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
scrollToDefaultChecked(true);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_inner->mustScrollTo(
|
_inner->mustScrollTo(
|
||||||
) | rpl::start_with_next([=](const Ui::ScrollToRequest &data) {
|
) | rpl::start_with_next([=](const Ui::ScrollToRequest &data) {
|
||||||
if (_scroll) {
|
if (_scroll) {
|
||||||
|
@ -527,13 +532,15 @@ void Widget::setGeometryWithTopMoved(
|
||||||
_topDelta = 0;
|
_topDelta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::setupScrollUpButton() {
|
void Widget::scrollToDefaultChecked(bool verytop) {
|
||||||
_scrollToTop->setClickedCallback([=] {
|
|
||||||
if (_scrollToAnimation.animating()) {
|
if (_scrollToAnimation.animating()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scrollToTop();
|
scrollToDefault(verytop);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
void Widget::setupScrollUpButton() {
|
||||||
|
_scrollToTop->setClickedCallback([=] { scrollToDefaultChecked(); });
|
||||||
base::install_event_filter(_scrollToTop, [=](not_null<QEvent*> event) {
|
base::install_event_filter(_scrollToTop, [=](not_null<QEvent*> event) {
|
||||||
if (event->type() != QEvent::Wheel) {
|
if (event->type() != QEvent::Wheel) {
|
||||||
return base::EventFilterResult::Continue;
|
return base::EventFilterResult::Continue;
|
||||||
|
@ -1111,10 +1118,13 @@ void Widget::jumpToTop(bool belowPinned) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::scrollToTop() {
|
void Widget::scrollToDefault(bool verytop) {
|
||||||
_scrollToAnimation.stop();
|
_scrollToAnimation.stop();
|
||||||
auto scrollTop = _scroll->scrollTop();
|
auto scrollTop = _scroll->scrollTop();
|
||||||
const auto scrollTo = 0;
|
const auto scrollTo = verytop ? 0 : _inner->defaultScrollTop();
|
||||||
|
if (scrollTop <= scrollTo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto maxAnimatedDelta = _scroll->height();
|
const auto maxAnimatedDelta = _scroll->height();
|
||||||
if (scrollTo + maxAnimatedDelta < scrollTop) {
|
if (scrollTo + maxAnimatedDelta < scrollTop) {
|
||||||
scrollTop = scrollTo + maxAnimatedDelta;
|
scrollTop = scrollTo + maxAnimatedDelta;
|
||||||
|
@ -2494,7 +2504,11 @@ void Widget::updateControlsGeometry() {
|
||||||
}
|
}
|
||||||
auto scrollTop = forumReportTop
|
auto scrollTop = forumReportTop
|
||||||
+ (_forumReportBar ? _forumReportBar->bar().height() : 0);
|
+ (_forumReportBar ? _forumReportBar->bar().height() : 0);
|
||||||
auto newScrollTop = _scroll->scrollTop() + _topDelta;
|
const auto wasScrollTop = _scroll->scrollTop();
|
||||||
|
const auto newScrollTop = (_topDelta < 0
|
||||||
|
&& wasScrollTop <= _inner->defaultScrollTop())
|
||||||
|
? wasScrollTop
|
||||||
|
: (wasScrollTop + _topDelta);
|
||||||
auto scrollHeight = height() - scrollTop;
|
auto scrollHeight = height() - scrollTop;
|
||||||
const auto putBottomButton = [&](auto &button) {
|
const auto putBottomButton = [&](auto &button) {
|
||||||
if (button && !button->isHidden()) {
|
if (button && !button->isHidden()) {
|
||||||
|
@ -2518,13 +2532,22 @@ void Widget::updateControlsGeometry() {
|
||||||
|
|
||||||
const auto scrollw = _childList ? _narrowWidth : barw;
|
const auto scrollw = _childList ? _narrowWidth : barw;
|
||||||
const auto wasScrollHeight = _scroll->height();
|
const auto wasScrollHeight = _scroll->height();
|
||||||
|
if (scrollHeight >= wasScrollHeight) {
|
||||||
|
_inner->setViewportHeight(scrollHeight);
|
||||||
|
}
|
||||||
_scroll->setGeometry(0, scrollTop, scrollw, scrollHeight);
|
_scroll->setGeometry(0, scrollTop, scrollw, scrollHeight);
|
||||||
|
if (scrollHeight < wasScrollHeight) {
|
||||||
|
_inner->setViewportHeight(scrollHeight);
|
||||||
|
}
|
||||||
_inner->resize(scrollw, _inner->height());
|
_inner->resize(scrollw, _inner->height());
|
||||||
_inner->setNarrowRatio(narrowRatio);
|
_inner->setNarrowRatio(narrowRatio);
|
||||||
if (scrollHeight != wasScrollHeight) {
|
if (scrollHeight != wasScrollHeight) {
|
||||||
controller()->floatPlayerAreaUpdated();
|
controller()->floatPlayerAreaUpdated();
|
||||||
}
|
}
|
||||||
if (_topDelta) {
|
const auto startWithTop = _inner->defaultScrollTop();
|
||||||
|
if (wasScrollHeight < startWithTop && scrollHeight >= startWithTop) {
|
||||||
|
_scroll->scrollToY(startWithTop);
|
||||||
|
} else if (newScrollTop != wasScrollTop) {
|
||||||
_scroll->scrollToY(newScrollTop);
|
_scroll->scrollToY(newScrollTop);
|
||||||
} else {
|
} else {
|
||||||
listScrollUpdated();
|
listScrollUpdated();
|
||||||
|
|
|
@ -209,7 +209,8 @@ private:
|
||||||
mtpRequestId requestId);
|
mtpRequestId requestId);
|
||||||
void peopleFailed(const MTP::Error &error, mtpRequestId requestId);
|
void peopleFailed(const MTP::Error &error, mtpRequestId requestId);
|
||||||
|
|
||||||
void scrollToTop();
|
void scrollToDefault(bool verytop = false);
|
||||||
|
void scrollToDefaultChecked(bool verytop = false);
|
||||||
void setupScrollUpButton();
|
void setupScrollUpButton();
|
||||||
void updateScrollUpVisibility();
|
void updateScrollUpVisibility();
|
||||||
void startScrollUpButtonAnimation(bool shown);
|
void startScrollUpButtonAnimation(bool shown);
|
||||||
|
|
|
@ -173,10 +173,12 @@ rpl::producer<Content> ContentForSession(not_null<Main::Session*> session) {
|
||||||
#if 0 // #TODO stories testing
|
#if 0 // #TODO stories testing
|
||||||
stories->allChanged()
|
stories->allChanged()
|
||||||
#endif
|
#endif
|
||||||
|
rpl::merge(
|
||||||
session->data().chatsListChanges(
|
session->data().chatsListChanges(
|
||||||
) | rpl::filter(
|
) | rpl::filter(
|
||||||
rpl::mappers::_1 == nullptr
|
rpl::mappers::_1 == nullptr
|
||||||
) | rpl::to_empty
|
) | rpl::to_empty,
|
||||||
|
session->data().unreadBadgeChanges())
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
consumer.put_next(state->next());
|
consumer.put_next(state->next());
|
||||||
}, result);
|
}, result);
|
||||||
|
|
|
@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
namespace Dialogs::Stories {
|
namespace Dialogs::Stories {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -24,19 +26,31 @@ List::List(
|
||||||
Fn<int()> shownHeight)
|
Fn<int()> shownHeight)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _shownHeight(shownHeight) {
|
, _shownHeight(shownHeight) {
|
||||||
resize(0, st::dialogsStoriesFull.height);
|
setCursor(style::cur_default);
|
||||||
|
|
||||||
std::move(content) | rpl::start_with_next([=](Content &&content) {
|
std::move(content) | rpl::start_with_next([=](Content &&content) {
|
||||||
showContent(std::move(content));
|
showContent(std::move(content));
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
_shownAnimation.stop();
|
||||||
|
resize(0, _items.empty() ? 0 : st::dialogsStoriesFull.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::showContent(Content &&content) {
|
void List::showContent(Content &&content) {
|
||||||
if (_content == content) {
|
if (_content == content) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (content.users.empty()) {
|
||||||
|
_hidingItems = base::take(_items);
|
||||||
|
if (!_hidingItems.empty()) {
|
||||||
|
toggleAnimated(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto hidden = _content.users.empty();
|
||||||
_content = std::move(content);
|
_content = std::move(content);
|
||||||
auto items = base::take(_items);
|
auto items = base::take(_items.empty() ? _hidingItems : _items);
|
||||||
|
_hidingItems.clear();
|
||||||
_items.reserve(_content.users.size());
|
_items.reserve(_content.users.size());
|
||||||
for (const auto &user : _content.users) {
|
for (const auto &user : _content.users) {
|
||||||
const auto i = ranges::find(items, user.id, [](const Item &item) {
|
const auto i = ranges::find(items, user.id, [](const Item &item) {
|
||||||
|
@ -53,10 +67,39 @@ void List::showContent(Content &&content) {
|
||||||
item.user.name = user.name;
|
item.user.name = user.name;
|
||||||
item.nameCache = QImage();
|
item.nameCache = QImage();
|
||||||
}
|
}
|
||||||
|
item.user.unread = user.unread;
|
||||||
} else {
|
} else {
|
||||||
_items.emplace_back(Item{ .user = user });
|
_items.emplace_back(Item{ .user = user });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateScrollMax();
|
||||||
|
update();
|
||||||
|
if (hidden) {
|
||||||
|
toggleAnimated(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::toggleAnimated(bool shown) {
|
||||||
|
_shownAnimation.start(
|
||||||
|
[=] { updateHeight(); },
|
||||||
|
shown ? 0. : 1.,
|
||||||
|
shown ? 1. : 0.,
|
||||||
|
st::slideWrapDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::updateHeight() {
|
||||||
|
const auto shown = _shownAnimation.value(_items.empty() ? 0. : 1.);
|
||||||
|
resize(
|
||||||
|
width(),
|
||||||
|
anim::interpolate(0, st::dialogsStoriesFull.height, shown));
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::updateScrollMax() {
|
||||||
|
const auto &full = st::dialogsStoriesFull;
|
||||||
|
const auto singleFull = full.photoLeft * 2 + full.photo;
|
||||||
|
const auto widthFull = full.left + int(_items.size()) * singleFull;
|
||||||
|
_scrollLeftMax = std::max(widthFull - width(), 0);
|
||||||
|
_scrollLeft = std::clamp(_scrollLeft, 0, _scrollLeftMax);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +111,18 @@ rpl::producer<> List::expandRequests() const {
|
||||||
return _expandRequests.events();
|
return _expandRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> List::entered() const {
|
||||||
|
return _entered.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::enterEventHook(QEnterEvent *e) {
|
||||||
|
_entered.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::resizeEvent(QResizeEvent *e) {
|
||||||
|
updateScrollMax();
|
||||||
|
}
|
||||||
|
|
||||||
void List::paintEvent(QPaintEvent *e) {
|
void List::paintEvent(QPaintEvent *e) {
|
||||||
const auto &st = st::dialogsStories;
|
const auto &st = st::dialogsStories;
|
||||||
const auto &full = st::dialogsStoriesFull;
|
const auto &full = st::dialogsStoriesFull;
|
||||||
|
@ -96,7 +151,7 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
const auto startIndexFull = std::max(-leftFull, 0) / singleFull;
|
const auto startIndexFull = std::max(-leftFull, 0) / singleFull;
|
||||||
const auto cellLeftFull = leftFull + (startIndexFull * singleFull);
|
const auto cellLeftFull = leftFull + (startIndexFull * singleFull);
|
||||||
const auto endIndexFull = std::min(
|
const auto endIndexFull = std::min(
|
||||||
(width() - cellLeftFull + singleFull - 1) / singleFull,
|
(width() - leftFull + singleFull - 1) / singleFull,
|
||||||
itemsCount);
|
itemsCount);
|
||||||
const auto startIndexSmall = 0;
|
const auto startIndexSmall = 0;
|
||||||
const auto endIndexSmall = std::min(kSmallUserpicsShown, itemsCount);
|
const auto endIndexSmall = std::min(kSmallUserpicsShown, itemsCount);
|
||||||
|
@ -265,19 +320,92 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::wheelEvent(QWheelEvent *e) {
|
void List::wheelEvent(QWheelEvent *e) {
|
||||||
|
const auto horizontal = (e->angleDelta().x() != 0);
|
||||||
|
if (!horizontal) {
|
||||||
|
e->ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto delta = horizontal
|
||||||
|
? ((style::RightToLeft() ? -1 : 1) * (e->pixelDelta().x()
|
||||||
|
? e->pixelDelta().x()
|
||||||
|
: e->angleDelta().x()))
|
||||||
|
: (e->pixelDelta().y()
|
||||||
|
? e->pixelDelta().y()
|
||||||
|
: e->angleDelta().y());
|
||||||
|
|
||||||
}
|
const auto now = _scrollLeft;
|
||||||
|
const auto used = now - delta;
|
||||||
void List::mouseMoveEvent(QMouseEvent *e) {
|
const auto next = std::clamp(used, 0, _scrollLeftMax);
|
||||||
|
if (next != now) {
|
||||||
|
_expandRequests.fire({});
|
||||||
|
_scrollLeft = next;
|
||||||
|
//updateSelected();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
e->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::mousePressEvent(QMouseEvent *e) {
|
void List::mousePressEvent(QMouseEvent *e) {
|
||||||
|
if (e->button() != Qt::LeftButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_mouseDownPosition = _lastMousePosition = e->globalPos();
|
||||||
|
//updateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
_lastMousePosition = e->globalPos();
|
||||||
|
//updateSelected();
|
||||||
|
|
||||||
|
if (!_dragging && _mouseDownPosition) {
|
||||||
|
if ((_lastMousePosition - *_mouseDownPosition).manhattanLength()
|
||||||
|
>= QApplication::startDragDistance()) {
|
||||||
|
if (_shownHeight() < st::dialogsStoriesFull.height) {
|
||||||
|
_expandRequests.fire({});
|
||||||
|
}
|
||||||
|
_dragging = true;
|
||||||
|
_startDraggingLeft = _scrollLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkDragging();
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::checkDragging() {
|
||||||
|
if (_dragging) {
|
||||||
|
const auto sign = (style::RightToLeft() ? -1 : 1);
|
||||||
|
const auto newLeft = std::clamp(
|
||||||
|
(sign * (_mouseDownPosition->x() - _lastMousePosition.x())
|
||||||
|
+ _startDraggingLeft),
|
||||||
|
0,
|
||||||
|
_scrollLeftMax);
|
||||||
|
if (newLeft != _scrollLeft) {
|
||||||
|
_scrollLeft = newLeft;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::mouseReleaseEvent(QMouseEvent *e) {
|
void List::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
_lastMousePosition = e->globalPos();
|
||||||
|
const auto guard = gsl::finally([&] {
|
||||||
|
_mouseDownPosition = std::nullopt;
|
||||||
|
});
|
||||||
|
|
||||||
|
//const auto wasDown = std::exchange(_pressed, SpecialOver::None);
|
||||||
|
if (finishDragging()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//updateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool List::finishDragging() {
|
||||||
|
if (!_dragging) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
checkDragging();
|
||||||
|
_dragging = false;
|
||||||
|
//updateSelected();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dialogs::Stories
|
} // namespace Dialogs::Stories
|
||||||
|
|
|
@ -46,30 +46,48 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
||||||
[[nodiscard]] rpl::producer<> expandRequests() const;
|
[[nodiscard]] rpl::producer<> expandRequests() const;
|
||||||
|
[[nodiscard]] rpl::producer<> entered() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Item {
|
struct Item {
|
||||||
User user;
|
User user;
|
||||||
QImage frameSmall;
|
|
||||||
QImage frameFull;
|
|
||||||
QImage nameCache;
|
QImage nameCache;
|
||||||
QColor nameCacheColor;
|
QColor nameCacheColor;
|
||||||
bool subscribed = false;
|
bool subscribed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void showContent(Content &&content);
|
void showContent(Content &&content);
|
||||||
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void wheelEvent(QWheelEvent *e) override;
|
void wheelEvent(QWheelEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
void updateScrollMax();
|
||||||
|
void checkDragging();
|
||||||
|
bool finishDragging();
|
||||||
|
|
||||||
|
void updateHeight();
|
||||||
|
void toggleAnimated(bool shown);
|
||||||
|
|
||||||
Content _content;
|
Content _content;
|
||||||
std::vector<Item> _items;
|
std::vector<Item> _items;
|
||||||
|
std::vector<Item> _hidingItems;
|
||||||
Fn<int()> _shownHeight = 0;
|
Fn<int()> _shownHeight = 0;
|
||||||
rpl::event_stream<uint64> _clicks;
|
rpl::event_stream<uint64> _clicks;
|
||||||
rpl::event_stream<> _expandRequests;
|
rpl::event_stream<> _expandRequests;
|
||||||
|
rpl::event_stream<> _entered;
|
||||||
|
|
||||||
|
Ui::Animations::Simple _shownAnimation;
|
||||||
|
|
||||||
|
QPoint _lastMousePosition;
|
||||||
|
std::optional<QPoint> _mouseDownPosition;
|
||||||
|
int _startDraggingLeft = 0;
|
||||||
int _scrollLeft = 0;
|
int _scrollLeft = 0;
|
||||||
|
int _scrollLeftMax = 0;
|
||||||
|
bool _dragging = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1141,7 +1141,9 @@ void SessionController::openFolder(not_null<Data::Folder*> folder) {
|
||||||
if (_openedFolder.current() != folder) {
|
if (_openedFolder.current() != folder) {
|
||||||
resetFakeUnreadWhileOpened();
|
resetFakeUnreadWhileOpened();
|
||||||
}
|
}
|
||||||
|
if (activeChatsFilterCurrent() != 0) {
|
||||||
setActiveChatsFilter(0);
|
setActiveChatsFilter(0);
|
||||||
|
}
|
||||||
closeForum();
|
closeForum();
|
||||||
_openedFolder = folder.get();
|
_openedFolder = folder.get();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue