Allow collapsing expanded poll results.

This commit is contained in:
John Preston 2020-01-16 17:11:48 +03:00
parent e6c005dcba
commit ac650b08fd
4 changed files with 107 additions and 8 deletions

View File

@ -2204,6 +2204,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_polls_quiz_results_title" = "Quiz results"; "lng_polls_quiz_results_title" = "Quiz results";
"lng_polls_show_more#one" = "Show {count} more voter"; "lng_polls_show_more#one" = "Show {count} more voter";
"lng_polls_show_more#other" = "Show {count} more voters"; "lng_polls_show_more#other" = "Show {count} more voters";
"lng_polls_votes_collapse" = "Collapse";
"lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM."; "lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM.";
"lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}."; "lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}.";

View File

@ -165,9 +165,11 @@ public:
void loadMoreRows() override; void loadMoreRows() override;
void allowLoadMore(); void allowLoadMore();
void collapse();
[[nodiscard]] auto showPeerInfoRequests() const [[nodiscard]] auto showPeerInfoRequests() const
-> rpl::producer<not_null<PeerData*>>; -> rpl::producer<not_null<PeerData*>>;
[[nodiscard]] rpl::producer<int> scrollToRequests() const;
[[nodiscard]] rpl::producer<int> count() const; [[nodiscard]] rpl::producer<int> count() const;
[[nodiscard]] rpl::producer<int> fullCount() const; [[nodiscard]] rpl::producer<int> fullCount() const;
[[nodiscard]] rpl::producer<int> loadMoreCount() const; [[nodiscard]] rpl::producer<int> loadMoreCount() const;
@ -178,6 +180,8 @@ public:
std::unique_ptr<PeerListRow> createRestoredRow( std::unique_ptr<PeerListRow> createRestoredRow(
not_null<PeerData*> peer) override; not_null<PeerData*> peer) override;
void scrollTo(int y);
private: private:
struct SavedState : SavedStateBase { struct SavedState : SavedStateBase {
QString offset; QString offset;
@ -191,6 +195,8 @@ private:
bool appendRow(not_null<UserData*> user); bool appendRow(not_null<UserData*> user);
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const; std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
void addPreloaded(); void addPreloaded();
bool addPreloadedPage();
void preloadedAdded();
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
const not_null<PollData*> _poll; const not_null<PollData*> _poll;
@ -208,6 +214,7 @@ private:
rpl::variable<int> _leftToLoad; rpl::variable<int> _leftToLoad;
rpl::event_stream<not_null<PeerData*>> _showPeerInfoRequests; rpl::event_stream<not_null<PeerData*>> _showPeerInfoRequests;
rpl::event_stream<int> _scrollToRequests;
}; };
@ -280,15 +287,15 @@ void ListController::loadMoreRows() {
} }
return data.vcount().v; return data.vcount().v;
}); });
_count = delegate()->peerListFullRowsCount();
if (_offset.isEmpty()) { if (_offset.isEmpty()) {
addPreloaded(); addPreloaded();
_fullCount = delegate()->peerListFullRowsCount(); _fullCount = delegate()->peerListFullRowsCount();
_leftToLoad = 0; _leftToLoad = 0;
} else { } else {
delegate()->peerListRefreshRows(); _count = delegate()->peerListFullRowsCount();
_fullCount = count; _fullCount = count;
_leftToLoad = count - delegate()->peerListFullRowsCount(); _leftToLoad = count - delegate()->peerListFullRowsCount();
delegate()->peerListRefreshRows();
} }
_loadRequestId = 0; _loadRequestId = 0;
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
@ -297,16 +304,58 @@ void ListController::loadMoreRows() {
} }
void ListController::allowLoadMore() { void ListController::allowLoadMore() {
_loadForOffset = _offset; if (!addPreloadedPage()) {
addPreloaded(); _loadForOffset = _offset;
loadMoreRows(); addPreloaded();
loadMoreRows();
}
}
void ListController::collapse() {
const auto count = delegate()->peerListFullRowsCount();
if (count <= kFirstPage) {
return;
}
const auto remove = count - (kFirstPage - kLeavePreloaded);
ranges::action::reverse(_preloaded);
_preloaded.reserve(_preloaded.size() + remove);
for (auto i = 0; i != remove; ++i) {
const auto row = delegate()->peerListRowAt(count - i - 1);
_preloaded.push_back(row->peer()->asUser());
delegate()->peerListRemoveRow(row);
}
ranges::action::reverse(_preloaded);
delegate()->peerListRefreshRows();
const auto now = count - remove;
_count = now;
_leftToLoad = _fullCount.current() - now;
} }
void ListController::addPreloaded() { void ListController::addPreloaded() {
for (const auto user : base::take(_preloaded)) { for (const auto user : base::take(_preloaded)) {
appendRow(user); appendRow(user);
} }
_leftToLoad = _fullCount.current() - delegate()->peerListFullRowsCount(); preloadedAdded();
}
bool ListController::addPreloadedPage() {
if (_preloaded.size() < kPerPage + kLeavePreloaded) {
return false;
}
const auto from = begin(_preloaded);
const auto till = from + kPerPage;
for (auto i = from; i != till; ++i) {
appendRow(*i);
}
_preloaded.erase(from, till);
preloadedAdded();
return true;
}
void ListController::preloadedAdded() {
_count = delegate()->peerListFullRowsCount();
_leftToLoad = _fullCount.current() - _count.current();
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
@ -315,6 +364,10 @@ auto ListController::showPeerInfoRequests() const
return _showPeerInfoRequests.events(); return _showPeerInfoRequests.events();
} }
rpl::producer<int> ListController::scrollToRequests() const {
return _scrollToRequests.events();
}
rpl::producer<int> ListController::count() const { rpl::producer<int> ListController::count() const {
return _count.value(); return _count.value();
} }
@ -399,6 +452,10 @@ std::unique_ptr<PeerListRow> ListController::createRow(
return row; return row;
} }
void ListController::scrollTo(int y) {
_scrollToRequests.fire_copy(y);
}
ListController *CreateAnswerRows( ListController *CreateAnswerRows(
not_null<Ui::VerticalLayout*> container, not_null<Ui::VerticalLayout*> container,
rpl::producer<int> visibleTop, rpl::producer<int> visibleTop,
@ -479,6 +536,23 @@ ListController *CreateAnswerRows(
lt_count_decimal, lt_count_decimal,
controller->fullCount() | rpl::map(_1 + 0.)), controller->fullCount() | rpl::map(_1 + 0.)),
st::pollResultsVotesCount); st::pollResultsVotesCount);
const auto collapse = Ui::CreateChild<Ui::LinkButton>(
header,
tr::lng_polls_votes_collapse(tr::now),
st::defaultLinkButton);
collapse->setClickedCallback([=] {
controller->scrollTo(headerWrap->y());
controller->collapse();
});
rpl::combine(
controller->fullCount(),
controller->count()
) | rpl::start_with_next([=](int fullCount, int count) {
const auto many = (fullCount > kFirstPage)
&& (count > kFirstPage - kLeavePreloaded);
collapse->setVisible(many);
votes->setVisible(!many);
}, collapse->lifetime());
headerWrap->widthValue( headerWrap->widthValue(
) | rpl::start_with_next([=](int width) { ) | rpl::start_with_next([=](int width) {
@ -487,6 +561,10 @@ ListController *CreateAnswerRows(
st::pollResultsHeaderPadding.right(), st::pollResultsHeaderPadding.right(),
st::pollResultsHeaderPadding.top(), st::pollResultsHeaderPadding.top(),
width); width);
collapse->moveToRight(
st::pollResultsHeaderPadding.right(),
st::pollResultsHeaderPadding.top(),
width);
}, header->lifetime()); }, header->lifetime());
header->heightValue( header->heightValue(
@ -520,7 +598,9 @@ ListController *CreateAnswerRows(
std::move(visibleTop), std::move(visibleTop),
headerWrap->geometryValue(), headerWrap->geometryValue(),
more->topValue() more->topValue()
) | rpl::start_with_next([=]( ) | rpl::filter([=](int, QRect headerRect, int moreTop) {
return moreTop >= headerRect.y() + headerRect.height();
}) | rpl::start_with_next([=](
int visibleTop, int visibleTop,
QRect headerRect, QRect headerRect,
int moreTop) { int moreTop) {
@ -612,6 +692,10 @@ void InnerWidget::setupContent() {
) | rpl::start_to_stream( ) | rpl::start_to_stream(
_showPeerInfoRequests, _showPeerInfoRequests,
lifetime()); lifetime());
controller->scrollToRequests(
) | rpl::start_with_next([=](int y) {
_scrollToRequests.fire({ y, -1 });
}, lifetime());
_sections.emplace(answer.option, controller); _sections.emplace(answer.option, controller);
} }
@ -626,6 +710,10 @@ void InnerWidget::setupContent() {
}, _content->lifetime()); }, _content->lifetime());
} }
rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {
return _scrollToRequests.events();
}
auto InnerWidget::showPeerInfoRequests() const auto InnerWidget::showPeerInfoRequests() const
-> rpl::producer<not_null<PeerData*>> { -> rpl::producer<not_null<PeerData*>> {
return _showPeerInfoRequests.events(); return _showPeerInfoRequests.events();

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/widgets/scroll_area.h"
#include "base/object_ptr.h" #include "base/object_ptr.h"
namespace Ui { namespace Ui {
@ -38,6 +39,9 @@ public:
return _contextId; return _contextId;
} }
[[nodiscard]] auto scrollToRequests() const
-> rpl::producer<Ui::ScrollToRequest>;
[[nodiscard]] auto showPeerInfoRequests() const [[nodiscard]] auto showPeerInfoRequests() const
-> rpl::producer<not_null<PeerData*>>; -> rpl::producer<not_null<PeerData*>>;
@ -58,9 +62,11 @@ private:
not_null<PollData*> _poll; not_null<PollData*> _poll;
FullMsgId _contextId; FullMsgId _contextId;
object_ptr<Ui::VerticalLayout> _content; object_ptr<Ui::VerticalLayout> _content;
base::flat_map<QByteArray, not_null<ListController*>> _sections;
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
rpl::event_stream<not_null<PeerData*>> _showPeerInfoRequests; rpl::event_stream<not_null<PeerData*>> _showPeerInfoRequests;
rpl::variable<int> _visibleTop = 0; rpl::variable<int> _visibleTop = 0;
base::flat_map<QByteArray, not_null<ListController*>> _sections;
}; };

View File

@ -55,6 +55,10 @@ Widget::Widget(QWidget *parent, not_null<Controller*> controller)
) | rpl::start_with_next([=](not_null<PeerData*> peer) { ) | rpl::start_with_next([=](not_null<PeerData*> peer) {
controller->showPeerInfo(peer); controller->showPeerInfo(peer);
}, _inner->lifetime()); }, _inner->lifetime());
_inner->scrollToRequests(
) | rpl::start_with_next([=](const Ui::ScrollToRequest &request) {
scrollTo(request);
}, _inner->lifetime());
controller->setCanSaveChanges(rpl::single(false)); controller->setCanSaveChanges(rpl::single(false));
} }