From f3e1aef264c2164365a12ab8fb77b8127f30a6bd Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 26 Nov 2021 00:52:06 +0400 Subject: [PATCH] Allow editing sessions auto-termination period. --- Telegram/Resources/langs/lang.strings | 6 ++ .../SourceFiles/api/api_authorizations.cpp | 17 +++++ Telegram/SourceFiles/api/api_authorizations.h | 6 ++ .../boxes/self_destruction_box.cpp | 57 +++++++++++++--- .../SourceFiles/boxes/self_destruction_box.h | 6 ++ Telegram/SourceFiles/boxes/sessions_box.cpp | 65 +++++++++++++++---- Telegram/SourceFiles/boxes/sessions_box.h | 4 +- .../SourceFiles/core/local_url_handlers.cpp | 2 +- .../settings/settings_privacy_security.cpp | 3 +- 9 files changed, 143 insertions(+), 23 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1b5a92b5b2..016a4ed1c8 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -695,6 +695,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_destroy_if" = "If away for..."; "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_sure" = "Are you sure you want to terminate\nall other sessions?"; "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_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#other" = "{count} months"; "lng_self_destruct_years#one" = "{count} year"; diff --git a/Telegram/SourceFiles/api/api_authorizations.cpp b/Telegram/SourceFiles/api/api_authorizations.cpp index c645cb8cd5..ce609661fa 100644 --- a/Telegram/SourceFiles/api/api_authorizations.cpp +++ b/Telegram/SourceFiles/api/api_authorizations.cpp @@ -119,6 +119,7 @@ void Authorizations::reload() { _requestId = 0; _lastReceived = crl::now(); result.match([&](const MTPDaccount_authorizations &auths) { + _ttlDays = auths.vauthorization_ttl_days().v; _list = ( auths.vauthorizations().v ) | ranges::views::transform([](const MTPAuthorization &d) { @@ -184,6 +185,22 @@ rpl::producer Authorizations::totalChanges() const { _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 Authorizations::ttlDays() const { + return _ttlDays.value() | rpl::filter(rpl::mappers::_1 != 0); +} + int Authorizations::total() const { return ranges::count_if( _list, diff --git a/Telegram/SourceFiles/api/api_authorizations.h b/Telegram/SourceFiles/api/api_authorizations.h index d84de71157..9110c0650c 100644 --- a/Telegram/SourceFiles/api/api_authorizations.h +++ b/Telegram/SourceFiles/api/api_authorizations.h @@ -40,6 +40,9 @@ public: [[nodiscard]] int total() const; [[nodiscard]] rpl::producer totalChanges() const; + void updateTTL(int days); + [[nodiscard]] rpl::producer ttlDays() const; + private: MTP::Sender _api; mtpRequestId _requestId = 0; @@ -47,6 +50,9 @@ private: List _list; rpl::event_stream<> _listChanges; + mtpRequestId _ttlRequestId = 0; + rpl::variable _ttlDays = 0; + crl::time _lastReceived = 0; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/boxes/self_destruction_box.cpp b/Telegram/SourceFiles/boxes/self_destruction_box.cpp index 9a167f6c42..2d4b947484 100644 --- a/Telegram/SourceFiles/boxes/self_destruction_box.cpp +++ b/Telegram/SourceFiles/boxes/self_destruction_box.cpp @@ -12,16 +12,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "apiwrap.h" #include "api/api_self_destruct.h" +#include "api/api_authorizations.h" #include "main/main_session.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" +namespace { + +using Type = SelfDestructionBox::Type; + +[[nodiscard]] std::vector 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( QWidget*, not_null session, + Type type, rpl::producer preloaded) -: _session(session) -, _ttlValues{ 30, 90, 180, 365 } +: _type(type) +, _session(session) +, _ttlValues(Values(type)) , _loading( this, tr::lng_contacts_loading(tr::now), @@ -57,7 +74,9 @@ void SelfDestructionBox::showContent() { auto y = st::boxOptionListPadding.top(); _description.create( 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); _description->moveToLeft(st::boxPadding.left(), y); y += _description->height() + st::boxMediumSkip; @@ -76,24 +95,46 @@ void SelfDestructionBox::showContent() { clearButtons(); 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(); }); addButton(tr::lng_cancel(), [=] { closeBox(); }); } 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_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() { - 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( 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); const auto boxHeight = st::boxOptionListPadding.top() + fake->height() + st::boxMediumSkip diff --git a/Telegram/SourceFiles/boxes/self_destruction_box.h b/Telegram/SourceFiles/boxes/self_destruction_box.h index 95f7928c87..228953aa66 100644 --- a/Telegram/SourceFiles/boxes/self_destruction_box.h +++ b/Telegram/SourceFiles/boxes/self_destruction_box.h @@ -22,9 +22,14 @@ class Session; class SelfDestructionBox : public Ui::BoxContent { public: + enum class Type { + Account, + Sessions, + }; SelfDestructionBox( QWidget*, not_null session, + Type type, rpl::producer preloaded); static QString DaysLabel(int days); @@ -36,6 +41,7 @@ private: void gotCurrent(int days); void showContent(); + const Type _type; const not_null _session; bool _prepared = false; std::vector _ttlValues; diff --git a/Telegram/SourceFiles/boxes/sessions_box.cpp b/Telegram/SourceFiles/boxes/sessions_box.cpp index 6a94829b27..c4868bd89e 100644 --- a/Telegram/SourceFiles/boxes/sessions_box.cpp +++ b/Telegram/SourceFiles/boxes/sessions_box.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "base/algorithm.h" #include "base/platform/base_platform_info.h" +#include "boxes/self_destruction_box.h" #include "ui/boxes/confirm_box.h" #include "lang/lang_keys.h" #include "main/main_session.h" @@ -77,7 +78,9 @@ void RenameBox(not_null box) { class SessionsContent : public Ui::RpWidget { public: - SessionsContent(QWidget*, not_null session); + SessionsContent( + QWidget*, + not_null controller); void setupContent(); @@ -165,7 +168,10 @@ private: class SessionsContent::Inner : public Ui::RpWidget { public: - Inner(QWidget *parent); + Inner( + QWidget *parent, + not_null controller, + rpl::producer ttlDays); void showData(const Full &data); rpl::producer terminateOne() const; @@ -177,16 +183,20 @@ public: private: void setupContent(); + const not_null _controller; QPointer _current; QPointer _terminateAll; QPointer _incomplete; QPointer _list; + rpl::variable _ttlDays; }; -SessionsContent::SessionsContent(QWidget*, not_null session) -: _authorizations(&session->api().authorizations()) -, _inner(this) +SessionsContent::SessionsContent( + QWidget*, + not_null controller) +: _authorizations(&controller->session().api().authorizations()) +, _inner(this, controller, _authorizations->ttlDays()) , _shortPollTimer([=] { shortPollSessions(); }) { } @@ -347,8 +357,13 @@ void SessionsContent::terminateAll() { terminate(std::move(callback), tr::lng_settings_reset_sure(tr::now)); } -SessionsContent::Inner::Inner(QWidget *parent) -: RpWidget(parent) { +SessionsContent::Inner::Inner( + QWidget *parent, + not_null controller, + rpl::producer ttlDays) +: RpWidget(parent) +, _controller(controller) +, _ttlDays(std::move(ttlDays)) { setupContent(); } @@ -415,6 +430,31 @@ void SessionsContent::Inner::setupContent() { _list = listInner->add(object_ptr(listInner)); AddSkip(listInner); + const auto ttlWrap = content->add( + object_ptr>( + content, + object_ptr(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( + &_controller->session(), + SelfDestructionBox::Type::Sessions, + _ttlDays.value())); + }); + + AddSkip(ttlInner); + const auto placeholder = content->add( object_ptr>( content, @@ -431,6 +471,7 @@ void SessionsContent::Inner::setupContent() { (_1 + _2) > 0)); incompleteWrap->toggleOn(_incomplete->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)); Ui::ResizeFitChild(this, content); @@ -592,8 +633,10 @@ void SessionsContent::List::paintEvent(QPaintEvent *e) { } } -SessionsBox::SessionsBox(QWidget*, not_null session) -: _session(session) { +SessionsBox::SessionsBox( + QWidget*, + not_null controller) +: _controller(controller) { } void SessionsBox::prepare() { @@ -604,7 +647,7 @@ void SessionsBox::prepare() { const auto w = st::boxWideWidth; const auto content = setInnerWidget( - object_ptr(this, _session), + object_ptr(this, _controller), st::sessionsScroll); content->resize(w, st::noContactsHeight); content->setupContent(); @@ -624,7 +667,7 @@ Sessions::Sessions( void Sessions::setupContent(not_null controller) { const auto container = Ui::CreateChild(this); const auto content = container->add( - object_ptr(container, &controller->session())); + object_ptr(container, controller)); content->setupContent(); Ui::ResizeFitChild(this, container); diff --git a/Telegram/SourceFiles/boxes/sessions_box.h b/Telegram/SourceFiles/boxes/sessions_box.h index bbde054117..ac66540155 100644 --- a/Telegram/SourceFiles/boxes/sessions_box.h +++ b/Telegram/SourceFiles/boxes/sessions_box.h @@ -31,12 +31,12 @@ private: class SessionsBox : public Ui::BoxContent { public: - SessionsBox(QWidget*, not_null session); + SessionsBox(QWidget*, not_null controller); protected: void prepare() override; private: - const not_null _session; + const not_null _controller; }; diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index e45295f4e3..59d8c1bfbc 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -379,7 +379,7 @@ bool ResolveSettings( } if (section == qstr("devices")) { controller->session().api().authorizations().reload(); - controller->show(Box(&controller->session())); + controller->show(Box(controller)); return true; } else if (section == qstr("language")) { ShowLanguagesBox(); diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/settings_privacy_security.cpp index b288a0079e..049ea5c487 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_security.cpp @@ -693,6 +693,7 @@ void SetupSelfDestruction( )->addClickHandler([=] { controller->show(Box( session, + SelfDestructionBox::Type::Account, session->api().selfDestruct().days())); }); @@ -800,7 +801,7 @@ void SetupSessionsList( std::move(count), st::settingsButton )->addClickHandler([=] { - controller->show(Box(&controller->session())); + controller->show(Box(controller)); }); AddSkip(container, st::settingsPrivacySecurityPadding); AddDividerText(container, tr::lng_settings_sessions_about());