Allow editing sessions auto-termination period.

This commit is contained in:
John Preston 2021-11-26 00:52:06 +04:00
parent fe4bb19358
commit f3e1aef264
9 changed files with 143 additions and 23 deletions

View file

@ -695,6 +695,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_destroy_if" = "If away for..."; "lng_settings_destroy_if" = "If away for...";
"lng_settings_change_phone" = "Change phone number"; "lng_settings_change_phone" = "Change phone number";
"lng_settings_terminate_title" = "Terminate old sessions";
"lng_settings_terminate_if" = "If inactive for...";
"lng_settings_reset" = "Terminate all other sessions"; "lng_settings_reset" = "Terminate all other sessions";
"lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?"; "lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?";
"lng_settings_reset_one_sure" = "Do you want to terminate this session?"; "lng_settings_reset_one_sure" = "Do you want to terminate this session?";
@ -816,6 +818,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_self_destruct_title" = "Account self-destruction"; "lng_self_destruct_title" = "Account self-destruction";
"lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts."; "lng_self_destruct_description" = "If you don't come online at least once within this period, your account will be deleted along with all groups, messages and contacts.";
"lng_self_destruct_sessions_title" = "Session termination";
"lng_self_destruct_sessions_description" = "If you don't come online from a specific session at least once within this period, it will be terminated.";
"lng_self_destruct_weeks#one" = "{count} week";
"lng_self_destruct_weeks#other" = "{count} weeks";
"lng_self_destruct_months#one" = "{count} month"; "lng_self_destruct_months#one" = "{count} month";
"lng_self_destruct_months#other" = "{count} months"; "lng_self_destruct_months#other" = "{count} months";
"lng_self_destruct_years#one" = "{count} year"; "lng_self_destruct_years#one" = "{count} year";

View file

@ -119,6 +119,7 @@ void Authorizations::reload() {
_requestId = 0; _requestId = 0;
_lastReceived = crl::now(); _lastReceived = crl::now();
result.match([&](const MTPDaccount_authorizations &auths) { result.match([&](const MTPDaccount_authorizations &auths) {
_ttlDays = auths.vauthorization_ttl_days().v;
_list = ( _list = (
auths.vauthorizations().v auths.vauthorizations().v
) | ranges::views::transform([](const MTPAuthorization &d) { ) | ranges::views::transform([](const MTPAuthorization &d) {
@ -184,6 +185,22 @@ rpl::producer<int> Authorizations::totalChanges() const {
_listChanges.events() | rpl::map([=] { return total(); })); _listChanges.events() | rpl::map([=] { return total(); }));
} }
void Authorizations::updateTTL(int days) {
_api.request(_ttlRequestId).cancel();
_ttlRequestId = _api.request(MTPaccount_SetAuthorizationTTL(
MTP_int(days)
)).done([=](const MTPBool &result) {
_ttlRequestId = 0;
}).fail([=](const MTP::Error &result) {
_ttlRequestId = 0;
}).send();
_ttlDays = days;
}
rpl::producer<int> Authorizations::ttlDays() const {
return _ttlDays.value() | rpl::filter(rpl::mappers::_1 != 0);
}
int Authorizations::total() const { int Authorizations::total() const {
return ranges::count_if( return ranges::count_if(
_list, _list,

View file

@ -40,6 +40,9 @@ public:
[[nodiscard]] int total() const; [[nodiscard]] int total() const;
[[nodiscard]] rpl::producer<int> totalChanges() const; [[nodiscard]] rpl::producer<int> totalChanges() const;
void updateTTL(int days);
[[nodiscard]] rpl::producer<int> ttlDays() const;
private: private:
MTP::Sender _api; MTP::Sender _api;
mtpRequestId _requestId = 0; mtpRequestId _requestId = 0;
@ -47,6 +50,9 @@ private:
List _list; List _list;
rpl::event_stream<> _listChanges; rpl::event_stream<> _listChanges;
mtpRequestId _ttlRequestId = 0;
rpl::variable<int> _ttlDays = 0;
crl::time _lastReceived = 0; crl::time _lastReceived = 0;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -12,16 +12,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "api/api_self_destruct.h" #include "api/api_self_destruct.h"
#include "api/api_authorizations.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
namespace {
using Type = SelfDestructionBox::Type;
[[nodiscard]] std::vector<int> Values(Type type) {
switch (type) {
case Type::Account: return { 30, 90, 180, 365 };
case Type::Sessions: return { 7, 30, 90, 180 };
}
Unexpected("SelfDestructionBox::Type in Values.");
}
} // namespace
SelfDestructionBox::SelfDestructionBox( SelfDestructionBox::SelfDestructionBox(
QWidget*, QWidget*,
not_null<Main::Session*> session, not_null<Main::Session*> session,
Type type,
rpl::producer<int> preloaded) rpl::producer<int> preloaded)
: _session(session) : _type(type)
, _ttlValues{ 30, 90, 180, 365 } , _session(session)
, _ttlValues(Values(type))
, _loading( , _loading(
this, this,
tr::lng_contacts_loading(tr::now), tr::lng_contacts_loading(tr::now),
@ -57,7 +74,9 @@ void SelfDestructionBox::showContent() {
auto y = st::boxOptionListPadding.top(); auto y = st::boxOptionListPadding.top();
_description.create( _description.create(
this, this,
tr::lng_self_destruct_description(tr::now), (_type == Type::Account
? tr::lng_self_destruct_description(tr::now)
: tr::lng_self_destruct_sessions_description(tr::now)),
st::boxLabel); st::boxLabel);
_description->moveToLeft(st::boxPadding.left(), y); _description->moveToLeft(st::boxPadding.left(), y);
y += _description->height() + st::boxMediumSkip; y += _description->height() + st::boxMediumSkip;
@ -76,24 +95,46 @@ void SelfDestructionBox::showContent() {
clearButtons(); clearButtons();
addButton(tr::lng_settings_save(), [=] { addButton(tr::lng_settings_save(), [=] {
_session->api().selfDestruct().update(_ttlGroup->value()); switch (_type) {
case Type::Account:
_session->api().selfDestruct().update(_ttlGroup->value());
break;
case Type::Sessions:
_session->api().authorizations().updateTTL(_ttlGroup->value());
break;
}
closeBox(); closeBox();
}); });
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });
} }
QString SelfDestructionBox::DaysLabel(int days) { QString SelfDestructionBox::DaysLabel(int days) {
return (days > 364) return !days
? QString()
: (days > 364)
? tr::lng_self_destruct_years(tr::now, lt_count, days / 365) ? tr::lng_self_destruct_years(tr::now, lt_count, days / 365)
: tr::lng_self_destruct_months(tr::now, lt_count, qMax(days / 30, 1)); : (days > 25)
? tr::lng_self_destruct_months(
tr::now,
lt_count,
qMax(days / 30, 1))
: tr::lng_self_destruct_weeks(
tr::now,
lt_count,
qMax(days / 7, 1));
} }
void SelfDestructionBox::prepare() { void SelfDestructionBox::prepare() {
setTitle(tr::lng_self_destruct_title()); setTitle((_type == Type::Account
? tr::lng_self_destruct_title()
: tr::lng_self_destruct_sessions_title()));
auto fake = object_ptr<Ui::FlatLabel>( auto fake = object_ptr<Ui::FlatLabel>(
this, this,
tr::lng_self_destruct_description(tr::now), (_type == Type::Account
? tr::lng_self_destruct_description(tr::now)
: tr::lng_self_destruct_sessions_description(tr::now)),
st::boxLabel); st::boxLabel);
const auto boxHeight = st::boxOptionListPadding.top() const auto boxHeight = st::boxOptionListPadding.top()
+ fake->height() + st::boxMediumSkip + fake->height() + st::boxMediumSkip

View file

@ -22,9 +22,14 @@ class Session;
class SelfDestructionBox : public Ui::BoxContent { class SelfDestructionBox : public Ui::BoxContent {
public: public:
enum class Type {
Account,
Sessions,
};
SelfDestructionBox( SelfDestructionBox(
QWidget*, QWidget*,
not_null<Main::Session*> session, not_null<Main::Session*> session,
Type type,
rpl::producer<int> preloaded); rpl::producer<int> preloaded);
static QString DaysLabel(int days); static QString DaysLabel(int days);
@ -36,6 +41,7 @@ private:
void gotCurrent(int days); void gotCurrent(int days);
void showContent(); void showContent();
const Type _type;
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
bool _prepared = false; bool _prepared = false;
std::vector<int> _ttlValues; std::vector<int> _ttlValues;

View file

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/algorithm.h" #include "base/algorithm.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "boxes/self_destruction_box.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -77,7 +78,9 @@ void RenameBox(not_null<Ui::GenericBox*> box) {
class SessionsContent : public Ui::RpWidget { class SessionsContent : public Ui::RpWidget {
public: public:
SessionsContent(QWidget*, not_null<Main::Session*> session); SessionsContent(
QWidget*,
not_null<Window::SessionController*> controller);
void setupContent(); void setupContent();
@ -165,7 +168,10 @@ private:
class SessionsContent::Inner : public Ui::RpWidget { class SessionsContent::Inner : public Ui::RpWidget {
public: public:
Inner(QWidget *parent); Inner(
QWidget *parent,
not_null<Window::SessionController*> controller,
rpl::producer<int> ttlDays);
void showData(const Full &data); void showData(const Full &data);
rpl::producer<uint64> terminateOne() const; rpl::producer<uint64> terminateOne() const;
@ -177,16 +183,20 @@ public:
private: private:
void setupContent(); void setupContent();
const not_null<Window::SessionController*> _controller;
QPointer<List> _current; QPointer<List> _current;
QPointer<Ui::SettingsButton> _terminateAll; QPointer<Ui::SettingsButton> _terminateAll;
QPointer<List> _incomplete; QPointer<List> _incomplete;
QPointer<List> _list; QPointer<List> _list;
rpl::variable<int> _ttlDays;
}; };
SessionsContent::SessionsContent(QWidget*, not_null<Main::Session*> session) SessionsContent::SessionsContent(
: _authorizations(&session->api().authorizations()) QWidget*,
, _inner(this) not_null<Window::SessionController*> controller)
: _authorizations(&controller->session().api().authorizations())
, _inner(this, controller, _authorizations->ttlDays())
, _shortPollTimer([=] { shortPollSessions(); }) { , _shortPollTimer([=] { shortPollSessions(); }) {
} }
@ -347,8 +357,13 @@ void SessionsContent::terminateAll() {
terminate(std::move(callback), tr::lng_settings_reset_sure(tr::now)); terminate(std::move(callback), tr::lng_settings_reset_sure(tr::now));
} }
SessionsContent::Inner::Inner(QWidget *parent) SessionsContent::Inner::Inner(
: RpWidget(parent) { QWidget *parent,
not_null<Window::SessionController*> controller,
rpl::producer<int> ttlDays)
: RpWidget(parent)
, _controller(controller)
, _ttlDays(std::move(ttlDays)) {
setupContent(); setupContent();
} }
@ -415,6 +430,31 @@ void SessionsContent::Inner::setupContent() {
_list = listInner->add(object_ptr<List>(listInner)); _list = listInner->add(object_ptr<List>(listInner));
AddSkip(listInner); AddSkip(listInner);
const auto ttlWrap = content->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
content,
object_ptr<Ui::VerticalLayout>(content)))->setDuration(0);
const auto ttlInner = ttlWrap->entity();
AddDivider(ttlInner);
AddSkip(ttlInner);
AddSubsectionTitle(ttlInner, tr::lng_settings_terminate_title());
AddButtonWithLabel(
ttlInner,
tr::lng_settings_terminate_if(),
_ttlDays.value(
) | rpl::map(SelfDestructionBox::DaysLabel),
st::settingsButton
)->addClickHandler([=] {
_controller->show(Box<SelfDestructionBox>(
&_controller->session(),
SelfDestructionBox::Type::Sessions,
_ttlDays.value()));
});
AddSkip(ttlInner);
const auto placeholder = content->add( const auto placeholder = content->add(
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>( object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
content, content,
@ -431,6 +471,7 @@ void SessionsContent::Inner::setupContent() {
(_1 + _2) > 0)); (_1 + _2) > 0));
incompleteWrap->toggleOn(_incomplete->itemsCount() | rpl::map(_1 > 0)); incompleteWrap->toggleOn(_incomplete->itemsCount() | rpl::map(_1 > 0));
listWrap->toggleOn(_list->itemsCount() | rpl::map(_1 > 0)); listWrap->toggleOn(_list->itemsCount() | rpl::map(_1 > 0));
ttlWrap->toggleOn(_list->itemsCount() | rpl::map(_1 > 0));
placeholder->toggleOn(_list->itemsCount() | rpl::map(_1 == 0)); placeholder->toggleOn(_list->itemsCount() | rpl::map(_1 == 0));
Ui::ResizeFitChild(this, content); Ui::ResizeFitChild(this, content);
@ -592,8 +633,10 @@ void SessionsContent::List::paintEvent(QPaintEvent *e) {
} }
} }
SessionsBox::SessionsBox(QWidget*, not_null<Main::Session*> session) SessionsBox::SessionsBox(
: _session(session) { QWidget*,
not_null<Window::SessionController*> controller)
: _controller(controller) {
} }
void SessionsBox::prepare() { void SessionsBox::prepare() {
@ -604,7 +647,7 @@ void SessionsBox::prepare() {
const auto w = st::boxWideWidth; const auto w = st::boxWideWidth;
const auto content = setInnerWidget( const auto content = setInnerWidget(
object_ptr<SessionsContent>(this, _session), object_ptr<SessionsContent>(this, _controller),
st::sessionsScroll); st::sessionsScroll);
content->resize(w, st::noContactsHeight); content->resize(w, st::noContactsHeight);
content->setupContent(); content->setupContent();
@ -624,7 +667,7 @@ Sessions::Sessions(
void Sessions::setupContent(not_null<Window::SessionController*> controller) { void Sessions::setupContent(not_null<Window::SessionController*> controller) {
const auto container = Ui::CreateChild<Ui::VerticalLayout>(this); const auto container = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto content = container->add( const auto content = container->add(
object_ptr<SessionsContent>(container, &controller->session())); object_ptr<SessionsContent>(container, controller));
content->setupContent(); content->setupContent();
Ui::ResizeFitChild(this, container); Ui::ResizeFitChild(this, container);

View file

@ -31,12 +31,12 @@ private:
class SessionsBox : public Ui::BoxContent { class SessionsBox : public Ui::BoxContent {
public: public:
SessionsBox(QWidget*, not_null<Main::Session*> session); SessionsBox(QWidget*, not_null<Window::SessionController*> controller);
protected: protected:
void prepare() override; void prepare() override;
private: private:
const not_null<Main::Session*> _session; const not_null<Window::SessionController*> _controller;
}; };

View file

@ -379,7 +379,7 @@ bool ResolveSettings(
} }
if (section == qstr("devices")) { if (section == qstr("devices")) {
controller->session().api().authorizations().reload(); controller->session().api().authorizations().reload();
controller->show(Box<SessionsBox>(&controller->session())); controller->show(Box<SessionsBox>(controller));
return true; return true;
} else if (section == qstr("language")) { } else if (section == qstr("language")) {
ShowLanguagesBox(); ShowLanguagesBox();

View file

@ -693,6 +693,7 @@ void SetupSelfDestruction(
)->addClickHandler([=] { )->addClickHandler([=] {
controller->show(Box<SelfDestructionBox>( controller->show(Box<SelfDestructionBox>(
session, session,
SelfDestructionBox::Type::Account,
session->api().selfDestruct().days())); session->api().selfDestruct().days()));
}); });
@ -800,7 +801,7 @@ void SetupSessionsList(
std::move(count), std::move(count),
st::settingsButton st::settingsButton
)->addClickHandler([=] { )->addClickHandler([=] {
controller->show(Box<SessionsBox>(&controller->session())); controller->show(Box<SessionsBox>(controller));
}); });
AddSkip(container, st::settingsPrivacySecurityPadding); AddSkip(container, st::settingsPrivacySecurityPadding);
AddDividerText(container, tr::lng_settings_sessions_about()); AddDividerText(container, tr::lng_settings_sessions_about());