Load chats in chunks in support mode.

This commit is contained in:
John Preston 2018-11-09 17:54:34 +04:00
parent 2d05281ba9
commit e992702783
6 changed files with 263 additions and 43 deletions

View File

@ -83,6 +83,7 @@ QByteArray AuthSessionSettings::serialize() const {
stream << qint32(_variables.supportSwitch);
stream << qint32(_variables.supportFixChatsOrder ? 1 : 0);
stream << qint32(_variables.supportTemplatesAutocomplete ? 1 : 0);
stream << qint32(_variables.supportChatsTimeSlice.current());
}
return result;
}
@ -113,6 +114,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
qint32 supportSwitch = static_cast<qint32>(_variables.supportSwitch);
qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0;
qint32 supportTemplatesAutocomplete = _variables.supportTemplatesAutocomplete ? 1 : 0;
qint32 supportChatsTimeSlice = _variables.supportChatsTimeSlice.current();
stream >> selectorTab;
stream >> lastSeenWarningSeen;
@ -176,6 +178,9 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
if (!stream.atEnd()) {
stream >> supportTemplatesAutocomplete;
}
if (!stream.atEnd()) {
stream >> supportChatsTimeSlice;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for AuthSessionSettings::constructFromSerialized()"));
@ -243,6 +248,19 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
}
_variables.supportFixChatsOrder = (supportFixChatsOrder == 1);
_variables.supportTemplatesAutocomplete = (supportTemplatesAutocomplete == 1);
_variables.supportChatsTimeSlice = supportChatsTimeSlice;
}
void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
_variables.supportChatsTimeSlice = slice;
}
int AuthSessionSettings::supportChatsTimeSlice() const {
return _variables.supportChatsTimeSlice.current();
}
rpl::producer<int> AuthSessionSettings::supportChatsTimeSliceValue() const {
return _variables.supportChatsTimeSlice.value();
}
void AuthSessionSettings::setTabbedSelectorSectionEnabled(bool enabled) {

View File

@ -102,6 +102,9 @@ public:
bool supportTemplatesAutocomplete() const {
return _variables.supportTemplatesAutocomplete;
}
void setSupportChatsTimeSlice(int slice);
int supportChatsTimeSlice() const;
rpl::producer<int> supportChatsTimeSliceValue() const;
ChatHelpers::SelectorTab selectorTab() const {
return _variables.selectorTab;
@ -220,9 +223,14 @@ private:
= Calls::PeerToPeer();
Ui::InputSubmitSettings sendSubmitWay;
static constexpr auto kDefaultSupportChatsLimitSlice
= 30 * 24 * 60 * 60;
Support::SwitchSettings supportSwitch;
bool supportFixChatsOrder = true;
bool supportTemplatesAutocomplete = true;
rpl::variable<int> supportChatsTimeSlice
= kDefaultSupportChatsLimitSlice;
};
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;

View File

@ -194,10 +194,28 @@ dialogsUpdateButton: FlatButton {
color: activeButtonBgRipple;
}
}
dialogsInstallUpdate: icon {{ "install_update", activeButtonFg }};
dialogsInstallUpdateOver: icon {{ "install_update", activeButtonFgOver }};
dialogsLoadMoreButton: FlatButton(dialogsUpdateButton) {
color: lightButtonFg;
overColor: lightButtonFg;
bgColor: lightButtonBg;
overBgColor: lightButtonBgOver;
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgRipple;
}
height: 36px;
textTop: 9px;
}
dialogsLoadMore: icon {{ "install_update-flip_vertical", lightButtonFg }};
dialogsLoadMoreLoading: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: lightButtonFg;
thickness: 3px;
size: size(12px, 12px);
}
dialogsForwardHeight: 32px;
dialogsForwardTextLeft: 35px;
dialogsForwardTextTop: 6px;

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/effects/radial_animation.h"
#include "lang/lang_keys.h"
#include "application.h"
#include "mainwindow.h"
@ -43,9 +44,16 @@ QString SwitchToChooseFromQuery() {
} // namespace
class DialogsWidget::UpdateButton : public Ui::RippleButton {
class DialogsWidget::BottomButton : public Ui::RippleButton {
public:
UpdateButton(QWidget *parent);
BottomButton(
QWidget *parent,
const QString &text,
const style::FlatButton &st,
const style::icon &icon,
const style::icon &iconOver);
void setText(const QString &text);
protected:
void paintEvent(QPaintEvent *e) override;
@ -53,39 +61,84 @@ protected:
void onStateChanged(State was, StateChangeSource source) override;
private:
void step_radial(TimeMs ms, bool timer);
QString _text;
const style::FlatButton &_st;
const style::icon &_icon;
const style::icon &_iconOver;
std::unique_ptr<Ui::InfiniteRadialAnimation> _loading;
};
DialogsWidget::UpdateButton::UpdateButton(QWidget *parent) : RippleButton(parent, st::dialogsUpdateButton.ripple)
, _text(lang(lng_update_telegram).toUpper())
, _st(st::dialogsUpdateButton) {
DialogsWidget::BottomButton::BottomButton(
QWidget *parent,
const QString &text,
const style::FlatButton &st,
const style::icon &icon,
const style::icon &iconOver)
: RippleButton(parent, st.ripple)
, _text(text.toUpper())
, _st(st)
, _icon(icon)
, _iconOver(iconOver) {
resize(st::columnMinimalWidthLeft, _st.height);
}
void DialogsWidget::UpdateButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
void DialogsWidget::BottomButton::setText(const QString &text) {
_text = text.toUpper();
update();
}
void DialogsWidget::UpdateButton::paintEvent(QPaintEvent *e) {
QPainter p(this);
void DialogsWidget::BottomButton::step_radial(TimeMs ms, bool timer) {
if (timer && !anim::Disabled() && width() < st::columnMinimalWidthLeft) {
update();
}
}
void DialogsWidget::BottomButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
if ((was & StateFlag::Disabled) != (state() & StateFlag::Disabled)) {
_loading = isDisabled()
? std::make_unique<Ui::InfiniteRadialAnimation>(
animation(this, &BottomButton::step_radial),
st::dialogsLoadMoreLoading)
: nullptr;
if (_loading) {
_loading->start();
}
}
update();
}
void DialogsWidget::BottomButton::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto over = isOver() && !isDisabled();
QRect r(0, height() - _st.height, width(), _st.height);
p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor);
p.fillRect(r, over ? _st.overBgColor : _st.bgColor);
paintRipple(p, 0, 0, getms());
if (!isDisabled()) {
paintRipple(p, 0, 0, getms());
}
p.setFont(isOver() ? _st.overFont : _st.font);
p.setFont(over ? _st.overFont : _st.font);
p.setRenderHint(QPainter::TextAntialiasing);
p.setPen(isOver() ? _st.overColor : _st.color);
p.setPen(over ? _st.overColor : _st.color);
if (width() >= st::columnMinimalWidthLeft) {
r.setTop(_st.textTop);
p.drawText(r, _text, style::al_top);
} else if (isDisabled() && _loading) {
_loading->draw(
p,
QPoint(
(width() - st::dialogsLoadMoreLoading.size.width()) / 2,
(height() - st::dialogsLoadMoreLoading.size.height()) / 2),
width());
} else {
(isOver() ? st::dialogsInstallUpdateOver : st::dialogsInstallUpdate).paintInCenter(p, r);
(over ? _iconOver : _icon).paintInCenter(p, r);
}
}
@ -173,6 +226,7 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null<Window::Controller*> cont
updateJumpToDateVisibility(true);
updateSearchFromVisibility(true);
setupConnectingWidget();
setupSupportLoadingLimit();
}
void DialogsWidget::setupConnectingWidget() {
@ -181,13 +235,29 @@ void DialogsWidget::setupConnectingWidget() {
Window::AdaptiveIsOneColumn());
}
void DialogsWidget::setupSupportLoadingLimit() {
if (!Auth().supportMode()) {
return;
}
Auth().settings().supportChatsTimeSliceValue(
) | rpl::start_with_next([=](int seconds) {
_dialogsLoadTill = seconds ? std::max(unixtime() - seconds, 0) : 0;
refreshLoadMoreButton();
}, lifetime());
}
void DialogsWidget::checkUpdateStatus() {
Expects(!Core::UpdaterDisabled());
using Checker = Core::UpdateChecker;
if (Checker().state() == Checker::State::Ready) {
if (_updateTelegram) return;
_updateTelegram.create(this);
_updateTelegram.create(
this,
lang(lng_update_telegram),
st::dialogsUpdateButton,
st::dialogsInstallUpdate,
st::dialogsInstallUpdateOver);
_updateTelegram->show();
_updateTelegram->setClickedCallback([] {
Core::checkReadyUpdate();
@ -369,6 +439,10 @@ void DialogsWidget::dialogsReceived(
_dialogsRequestId = 0;
loadDialogs();
if (!_dialogsRequestId) {
refreshLoadMoreButton();
}
Auth().data().moreChatsLoaded().notify();
if (_dialogsFull && _pinnedDialogsReceived) {
Auth().data().allChatsLoaded().set(true);
@ -425,6 +499,36 @@ void DialogsWidget::updateDialogsOffset(
}
}
void DialogsWidget::refreshLoadMoreButton() {
if (_dialogsFull || !_dialogsLoadTill) {
_loadMoreChats.destroy();
updateControlsGeometry();
return;
}
if (!_loadMoreChats) {
_loadMoreChats.create(
this,
"Load more",
st::dialogsLoadMoreButton,
st::dialogsLoadMore,
st::dialogsLoadMore);
_loadMoreChats->addClickHandler([=] {
if (_loadMoreChats->isDisabled()) {
return;
}
const auto max = Auth().settings().supportChatsTimeSlice();
_dialogsLoadTill = _dialogsOffsetDate
? (_dialogsOffsetDate - max)
: (unixtime() - max);
loadDialogs();
});
updateControlsGeometry();
}
const auto loading = !loadingBlockedByDate();
_loadMoreChats->setDisabled(loading);
_loadMoreChats->setText(loading ? "Loading..." : "Load more");
}
void DialogsWidget::pinnedDialogsReceived(
const MTPmessages_PeerDialogs &result,
mtpRequestId requestId) {
@ -731,11 +835,21 @@ void DialogsWidget::onSearchMore() {
}
}
bool DialogsWidget::loadingBlockedByDate() const {
return !_dialogsFull
&& !_dialogsRequestId
&& (_dialogsLoadTill > 0)
&& (_dialogsOffsetDate > 0)
&& (_dialogsOffsetDate <= _dialogsLoadTill);
}
void DialogsWidget::loadDialogs() {
if (_dialogsRequestId) return;
if (_dialogsFull) {
_inner->addAllSavedPeers();
return;
} else if (loadingBlockedByDate()) {
return;
}
const auto firstLoad = !_dialogsOffsetDate;
@ -759,6 +873,7 @@ void DialogsWidget::loadDialogs() {
if (!_pinnedDialogsReceived) {
loadPinnedDialogs();
}
refreshLoadMoreButton();
}
void DialogsWidget::loadPinnedDialogs() {
@ -1205,11 +1320,19 @@ void DialogsWidget::updateControlsGeometry() {
auto addToScroll = App::main() ? App::main()->contentScrollAddToY() : 0;
auto newScrollTop = _scroll->scrollTop() + addToScroll;
auto scrollHeight = height() - scrollTop;
if (_updateTelegram) {
auto updateHeight = _updateTelegram->height();
_updateTelegram->setGeometry(0, height() - updateHeight, width(), updateHeight);
scrollHeight -= updateHeight;
}
const auto putBottomButton = [&](object_ptr<BottomButton> &button) {
if (button) {
const auto buttonHeight = button->height();
scrollHeight -= buttonHeight;
button->setGeometry(
0,
scrollTop + scrollHeight,
width(),
buttonHeight);
}
};
putBottomButton(_updateTelegram);
putBottomButton(_loadMoreChats);
auto wasScrollHeight = _scroll->height();
_scroll->setGeometry(0, scrollTop, width(), scrollHeight);
if (scrollHeight != wasScrollHeight) {

View File

@ -152,6 +152,7 @@ private:
const QVector<MTPDialog> &dialogs,
const QVector<MTPMessage> &messages);
void setupSupportLoadingLimit();
void setupConnectingWidget();
bool searchForPeersRequired(const QString &query) const;
void setSearchInChat(Dialogs::Key chat, UserData *from = nullptr);
@ -166,6 +167,9 @@ private:
void updateForwardBar();
void checkUpdateStatus();
bool loadingBlockedByDate() const;
void refreshLoadMoreButton();
bool dialogsFailed(const RPCError &error, mtpRequestId req);
bool searchFailed(DialogsSearchRequestType type, const RPCError &error, mtpRequestId req);
bool peopleFailed(const RPCError &error, mtpRequestId req);
@ -175,7 +179,8 @@ private:
QTimer _chooseByDragTimer;
bool _dialogsFull = false;
int32 _dialogsOffsetDate = 0;
TimeId _dialogsLoadTill = 0;
TimeId _dialogsOffsetDate = 0;
MsgId _dialogsOffsetId = 0;
PeerData *_dialogsOffsetPeer = nullptr;
mtpRequestId _dialogsRequestId = 0;
@ -191,8 +196,9 @@ private:
object_ptr<Ui::IconButton> _lockUnlock;
object_ptr<Ui::ScrollArea> _scroll;
QPointer<DialogsInner> _inner;
class UpdateButton;
object_ptr<UpdateButton> _updateTelegram = { nullptr };
class BottomButton;
object_ptr<BottomButton> _updateTelegram = { nullptr };
object_ptr<BottomButton> _loadMoreChats = { nullptr };
base::unique_qptr<Window::ConnectingWidget> _connecting;
Animation _a_show;

View File

@ -908,30 +908,14 @@ void SetupThemeOptions(not_null<Ui::VerticalLayout*> container) {
AddSkip(container);
}
void SetupSupport(not_null<Ui::VerticalLayout*> container) {
AddSkip(container);
AddSubsectionTitle(container, rpl::single(qsl("Support settings")));
AddSkip(container, st::settingsSendTypeSkip);
void SetupSupportSwitchSettings(not_null<Ui::VerticalLayout*> container) {
using SwitchType = Support::SwitchSettings;
const auto skip = st::settingsSendTypeSkip;
auto wrap = object_ptr<Ui::VerticalLayout>(container);
const auto inner = wrap.data();
container->add(
object_ptr<Ui::OverrideMargins>(
container,
std::move(wrap),
QMargins(0, skip, 0, skip)));
const auto group = std::make_shared<Ui::RadioenumGroup<SwitchType>>(
Auth().settings().supportSwitch());
const auto add = [&](SwitchType value, const QString &label) {
inner->add(
container->add(
object_ptr<Ui::Radioenum<SwitchType>>(
inner,
container,
group,
value,
label,
@ -945,6 +929,62 @@ void SetupSupport(not_null<Ui::VerticalLayout*> container) {
Auth().settings().setSupportSwitch(value);
Local::writeUserSettings();
});
}
void SetupSupportChatsLimitSlice(not_null<Ui::VerticalLayout*> container) {
constexpr auto kDayDuration = 24 * 60 * 60;
struct Option {
int days = 0;
QString label;
};
const auto options = std::vector<Option>{
{ 1, "1 day" },
{ 7, "1 week" },
{ 30, "1 month" },
{ 365, "1 year" },
{ 0, "All of them" },
};
const auto current = Auth().settings().supportChatsTimeSlice();
const auto days = current / kDayDuration;
const auto best = ranges::min_element(
options,
std::less<>(),
[&](const Option &option) { return std::abs(option.days - days); });
const auto group = std::make_shared<Ui::RadiobuttonGroup>(best->days);
for (const auto &option : options) {
container->add(
object_ptr<Ui::Radiobutton>(
container,
group,
option.days,
option.label,
st::settingsSendType),
st::settingsSendTypePadding);
}
group->setChangedCallback([=](int days) {
Auth().settings().setSupportChatsTimeSlice(days * kDayDuration);
Local::writeUserSettings();
});
}
void SetupSupport(not_null<Ui::VerticalLayout*> container) {
AddSkip(container);
AddSubsectionTitle(container, rpl::single(qsl("Support settings")));
AddSkip(container, st::settingsSendTypeSkip);
const auto skip = st::settingsSendTypeSkip;
auto wrap = object_ptr<Ui::VerticalLayout>(container);
const auto inner = wrap.data();
container->add(
object_ptr<Ui::OverrideMargins>(
container,
std::move(wrap),
QMargins(0, skip, 0, skip)));
SetupSupportSwitchSettings(inner);
AddSkip(inner, st::settingsCheckboxesSkip);
@ -963,6 +1003,13 @@ void SetupSupport(not_null<Ui::VerticalLayout*> container) {
}, inner->lifetime());
AddSkip(inner, st::settingsCheckboxesSkip);
AddSubsectionTitle(inner, rpl::single(qsl("Load chats for a period")));
SetupSupportChatsLimitSlice(inner);
AddSkip(inner, st::settingsCheckboxesSkip);
AddSkip(inner);
}