From 0dddb7694f0da6a0cfe77d01d40701f47c4f929e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 14 Jun 2019 14:01:35 +0200 Subject: [PATCH] Show transfer community button, set 2sv password. --- Telegram/Resources/langs/lang.strings | 14 ++ Telegram/SourceFiles/boxes/boxes.style | 2 + Telegram/SourceFiles/boxes/passcode_box.cpp | 24 ++- .../boxes/peers/edit_linked_chat_box.cpp | 2 +- .../boxes/peers/edit_participant_box.cpp | 176 +++++++++++++++++- .../boxes/peers/edit_participant_box.h | 8 + .../boxes/peers/edit_peer_permissions_box.cpp | 10 +- .../boxes/peers/edit_peer_permissions_box.h | 1 + .../admin_log/history_admin_log_item.cpp | 12 +- .../SourceFiles/lang/lang_cloud_manager.cpp | 50 ++--- .../settings/settings_privacy_security.cpp | 167 +++++++++-------- .../settings/settings_privacy_security.h | 5 + Telegram/SourceFiles/window/layer_widget.cpp | 10 +- 13 files changed, 341 insertions(+), 140 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 071468461b..ff2b34db83 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1651,6 +1651,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_rights_chat_banned_custom" = "Custom"; "lng_rights_chat_banned_custom_date" = "Until {date}"; +"lng_rights_transfer_group" = "Transfer group ownership"; +"lng_rights_transfer_channel" = "Transfer channel ownership"; +"lng_rights_transfer_check" = "Security check"; +"lng_rights_transfer_check_about" = "You can transfer this group to {user} only if you have:"; +"lng_rights_transfer_check_password" = "• Enabled **2-Step Verification** more than **7 days** ago."; +"lng_rights_transfer_check_session" = "• Logged in on this device more than **24 hours** ago."; +"lng_rights_transfer_check_later" = "Please come back later."; +"lng_rights_transfer_set_password" = "Set password"; +"lng_rights_transfer_about" = "This will transfer the full **owner rights** for {group} to {user}."; +"lng_rights_transfer_sure" = "Change owner"; +"lng_rights_transfer_password" = "Please enter your password to complete the transfer."; +"lng_rights_transfer_done_group" = "{user} is now the owner of the group."; +"lng_rights_transfer_done_channel" = "{user} is now the owner of the channel."; + "lng_restricted_send_message" = "The admins of this group restricted you from writing here."; "lng_restricted_send_media" = "The admins of this group restricted you from posting media content here."; "lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here."; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index b39ed0c417..0ccbffa790 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -985,3 +985,5 @@ addContactWarningMargin: margins(19px, 10px, 19px, 5px); blockUserConfirmation: FlatLabel(boxLabel) { minWidth: 240px; } + +transferCheckWidth: 300px; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 4a7a0cadd7..c31f5387d0 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -226,10 +226,17 @@ void PasscodeBox::setInnerFocus() { } void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) { + if (_replacedBy) { + _replacedBy->closeBox(); + } _setRequest = 0; _newPasswordSet.fire_copy(newPasswordBytes); - auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); - getDelegate()->show(Box(text), LayerOption::CloseOther); + const auto weak = make_weak(this); + const auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); + getDelegate()->show(Box(text)); + if (weak) { + closeBox(); + } } void PasscodeBox::closeReplacedBy() { @@ -353,8 +360,7 @@ void PasscodeBox::validateEmail( submit, resend, errors->events(), - resent->events()), - LayerOption::KeepOther); + resent->events())); box->setCloseByOutsideClick(false); box->setCloseByEscape(false); @@ -441,9 +447,12 @@ void PasscodeBox::save(bool force) { } if (!_recoverEmail->isHidden() && email.isEmpty() && !force) { _skipEmailWarning = true; - _replacedBy = getDelegate()->show(Box(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, crl::guard(this, [this] { - save(true); - }))); + _replacedBy = getDelegate()->show( + Box( + lang(lng_cloud_password_about_recover), + lang(lng_cloud_password_skip_email), + st::attentionBoxButton, + crl::guard(this, [this] { save(true); }))); } else if (_newPasscode->isHidden()) { clearCloudPassword(old); } else if (_oldPasscode->isHidden()) { @@ -452,6 +461,7 @@ void PasscodeBox::save(bool force) { changeCloudPassword(old, pwd); } } else { + closeReplacedBy(); const auto weak = make_weak(this); cSetPasscodeBadTries(0); Local::setPasscode(pwd.toUtf8()); diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp index 3ea56878d4..54a0cd401c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp @@ -163,7 +163,7 @@ void Controller::choose(not_null chat) { } text.append("\n\n" + lang(lng_manage_discussion_group_private)); text.append("\n\n"); - text.append(lng_manage_discussion_group_warning__generic( + text.append(lng_manage_discussion_group_warning__rich( lt_visible, Ui::Text::Bold(lang(lng_manage_discussion_group_visible)))); const auto box = std::make_shared>(); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index bdc1f316af..441a4af2d2 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -10,18 +10,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/padding_wrap.h" +#include "ui/wrap/slide_wrap.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" +#include "ui/text/text_utilities.h" #include "ui/text_options.h" #include "ui/special_buttons.h" +#include "info/profile/info_profile_button.h" +#include "settings/settings_privacy_security.h" #include "boxes/calendar_box.h" +#include "boxes/generic_box.h" #include "boxes/peers/edit_peer_permissions_box.h" +#include "boxes/peers/edit_peer_info_box.h" #include "data/data_peer_values.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_user.h" +#include "core/core_cloud_password.h" +#include "apiwrap.h" +#include "auth_session.h" #include "styles/style_boxes.h" +#include "styles/style_info.h" namespace { @@ -29,6 +39,64 @@ constexpr auto kMaxRestrictDelayDays = 366; constexpr auto kSecondsInDay = 24 * 60 * 60; constexpr auto kSecondsInWeek = 7 * kSecondsInDay; +enum class PasswordErrorType { + None, + NoPassword, + Later, +}; + +void SetCloudPassword(not_null box, not_null user) { + user->session().api().reloadPasswordState(); + user->session().api().passwordState( + ) | rpl::start_with_next([=] { + using namespace Settings; + const auto weak = make_weak(box); + if (CheckEditCloudPassword()) { + box->getDelegate()->show( + EditCloudPasswordBox(&user->session())); + } else { + box->getDelegate()->show(CloudPasswordAppOutdatedBox()); + } + if (weak) { + weak->closeBox(); + } + }, box->lifetime()); +} + +void TransferPasswordError( + not_null box, + not_null user, + PasswordErrorType error) { + box->setTitle(langFactory(lng_rights_transfer_check)); + box->setWidth(st::transferCheckWidth); + + auto text = lng_rights_transfer_check_about__rich( + lt_user, + Ui::Text::Bold(user->shortName()) + ).append('\n').append('\n').append( + Ui::Text::RichLangValue(lang(lng_rights_transfer_check_password)) + ).append('\n').append('\n').append( + Ui::Text::RichLangValue(lang(lng_rights_transfer_check_session)) + ); + if (error == PasswordErrorType::Later) { + text.append('\n').append('\n').append( + Ui::Text::RichLangValue(lang(lng_rights_transfer_check_later)) + ); + } + box->addRow(object_ptr( + box, + rpl::single(text), + st::boxLabel)); + if (error == PasswordErrorType::Later) { + box->addButton(langFactory(lng_box_ok), [=] { box->closeBox(); }); + } else { + box->addButton(langFactory(lng_rights_transfer_set_password), [=] { + SetCloudPassword(box, user); + }); + box->addButton(langFactory(lng_cancel), [=] { box->closeBox(); }); + } +} + } // namespace class EditParticipantBox::Inner : public Ui::RpWidget { @@ -244,6 +312,7 @@ void EditAdminBox::prepare() { return result; }(); + const auto isGroup = chat || channel->isMegagroup(); const auto anyoneCanAddMembers = chat ? chat->anyoneCanAddMembers() : channel->anyoneCanAddMembers(); @@ -252,18 +321,31 @@ void EditAdminBox::prepare() { lng_rights_edit_admin_header, prepareFlags, disabledMessages, - peer()->isChat() || peer()->isMegagroup(), + isGroup, anyoneCanAddMembers); addControl(std::move(checkboxes), QMargins()); - _aboutAddAdmins = addControl( - object_ptr(this, st::boxLabel), - st::rightsAboutMargin); - rpl::single( + auto selectedFlags = rpl::single( getChecked() ) | rpl::then(std::move( changes - )) | rpl::map( + )); + if (canTransferOwnership()) { + const auto allFlags = FullAdminRights(isGroup); + setupTransferButton( + isGroup + )->toggleOn(rpl::duplicate( + selectedFlags + ) | rpl::map( + ((_1 & allFlags) == allFlags) + ))->setDuration(0); + } + _aboutAddAdmins = addControl( + object_ptr(this, st::boxLabel), + st::rightsAboutMargin); + std::move( + selectedFlags + ) | rpl::map( (_1 & Flag::f_add_admins) != 0 ) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](bool checked) { @@ -289,6 +371,88 @@ void EditAdminBox::prepare() { } } +bool EditAdminBox::canTransferOwnership() const { + if (user()->isInaccessible() || user()->isBot()) { + return false; + } else if (const auto chat = peer()->asChat()) { + return chat->amCreator(); + } else if (const auto channel = peer()->asChannel()) { + return channel->amCreator(); + } + Unexpected("Chat type in EditAdminBox::canTransferOwnership."); +} + +not_null*> EditAdminBox::setupTransferButton( + bool isGroup) { + const auto wrap = addControl( + object_ptr>( + this, + object_ptr(this))); + + const auto container = wrap->entity(); + const auto addDivider = [&] { + container->add( + object_ptr(container), + { 0, st::infoProfileSkip, 0, st::infoProfileSkip }); + }; + + addDivider(); + container->add(EditPeerInfoBox::CreateButton( + this, + Lang::Viewer(isGroup + ? lng_rights_transfer_group + : lng_rights_transfer_channel), + rpl::single(QString()), + [=] { transferOwnership(); }, + st::peerPermissionsButton)); + addDivider(); + + return wrap; +} + +void EditAdminBox::transferOwnership() { + if (_checkTransferRequestId) { + return; + } + const auto channel = peer()->isChannel() + ? peer()->asChannel()->inputChannel + : MTP_inputChannelEmpty(); + const auto api = &peer()->session().api(); + _checkTransferRequestId = api->request(MTPchannels_EditCreator( + channel, + MTP_inputUserEmpty(), + MTP_inputCheckPasswordEmpty() + )).fail([=](const RPCError &error) { + _checkTransferRequestId = 0; + if (!handleTransferPasswordError(error)) { + requestTransferPassword(); + } + }).send(); +} + +bool EditAdminBox::handleTransferPasswordError(const RPCError &error) { + const auto type = [&] { + const auto &type = error.type(); + if (type == qstr("PASSWORD_MISSING")) { + return PasswordErrorType::NoPassword; + } else if (type.startsWith(qstr("PASSWORD_TOO_FRESH_")) + || type.startsWith(qstr("SESSION_TOO_FRESH_"))) { + return PasswordErrorType::Later; + } + return PasswordErrorType::None; + }(); + if (type == PasswordErrorType::None) { + return false; + } + + getDelegate()->show(Box(TransferPasswordError, user(), type)); + return true; +} + +void EditAdminBox::requestTransferPassword() { + +} + void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) { _aboutAddAdmins->setText([&] { if (!canSave()) { diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h index 34142039a1..987608414a 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h @@ -16,6 +16,8 @@ class LinkButton; class Checkbox; class Radiobutton; class RadiobuttonGroup; +template +class SlideWrap; } // namespace Ui class CalendarBox; @@ -77,15 +79,21 @@ private: static MTPChatAdminRights Defaults(not_null peer); + void transferOwnership(); + bool handleTransferPasswordError(const RPCError &error); + void requestTransferPassword(); bool canSave() const { return !!_saveCallback; } void refreshAboutAddAdminsText(bool canAddAdmins); + bool canTransferOwnership() const; + not_null*> setupTransferButton(bool isGroup); const MTPChatAdminRights _oldRights; Fn _saveCallback; QPointer _aboutAddAdmins; + mtpRequestId _checkTransferRequestId = 0; }; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 485121eb58..d58ac1a239 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -95,7 +95,7 @@ std::vector> RestrictionLabels() { const auto restrictions = Data::ListOfRestrictions(); auto i = 0; for (const auto key : langKeys) { - vector.push_back({restrictions[i++], key}); + vector.emplace_back(restrictions[i++], key); } return vector; } @@ -276,6 +276,14 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) { return restrictions; } +ChatAdminRights FullAdminRights(bool isGroup) { + auto result = ChatAdminRights(); + for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) { + result |= flag; + } + return result; +} + EditPeerPermissionsBox::EditPeerPermissionsBox( QWidget*, not_null peer) diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h index e7e07023ca..5095f3264c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h @@ -58,3 +58,4 @@ EditFlagsControl CreateEditAdminRights( ChatAdminRights DisabledByDefaultRestrictions(not_null peer); ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions); +ChatAdminRights FullAdminRights(bool isGroup); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 500f7c06c0..a25f0341b9 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -133,7 +133,7 @@ TextWithEntities GenerateAdminChangeText( auto newFlags = newRights ? newRights->c_chatAdminRights().vflags.v : MTPDchatAdminRights::Flags(0); auto prevFlags = prevRights ? prevRights->c_chatAdminRights().vflags.v : MTPDchatAdminRights::Flags(0); - auto result = lng_admin_log_promoted__generic(lt_user, user); + auto result = lng_admin_log_promoted__rich(lt_user, user); auto useInviteLinkPhrase = channel->isMegagroup() && channel->anyoneCanAddMembers(); auto invitePhrase = (useInviteLinkPhrase ? lng_admin_log_admin_invite_link : lng_admin_log_admin_invite_users); @@ -201,14 +201,14 @@ TextWithEntities GenerateBannedChangeText( auto newUntil = newRights ? newRights->c_chatBannedRights().vuntil_date.v : TimeId(0); auto indefinitely = ChannelData::IsRestrictedForever(newUntil); if (newFlags & Flag::f_view_messages) { - return lng_admin_log_banned__generic(lt_user, user); + return lng_admin_log_banned__rich(lt_user, user); } auto untilText = indefinitely ? lang(lng_admin_log_restricted_forever) : lng_admin_log_restricted_until( lt_date, langDateTime(ParseDateTime(newUntil))); - auto result = lng_admin_log_restricted__generic( + auto result = lng_admin_log_restricted__rich( lt_user, user, lt_until, @@ -241,7 +241,7 @@ auto GenerateUserString(MTPint userId) { EntityType::Mention, 0, mention.text.size() }); - return lng_admin_log_user_with_username__generic(lt_name, name, lt_mention, mention); + return lng_admin_log_user_with_username__rich(lt_name, name, lt_mention, mention); } auto GenerateParticipantChangeTextInner( @@ -251,7 +251,7 @@ auto GenerateParticipantChangeTextInner( const auto oldType = oldParticipant ? oldParticipant->type() : 0; return participant.match([&](const MTPDchannelParticipantCreator &data) { // No valid string here :( - return lng_admin_log_invited__generic( + return lng_admin_log_invited__rich( lt_user, GenerateUserString(data.vuser_id)); }, [&](const MTPDchannelParticipantAdmin &data) { @@ -285,7 +285,7 @@ auto GenerateParticipantChangeTextInner( nullptr, &oldParticipant->c_channelParticipantBanned().vbanned_rights); } - return lng_admin_log_invited__generic(lt_user, user); + return lng_admin_log_invited__rich(lt_user, user); }); } diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp index 5cd0138040..a4f2b204c9 100644 --- a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/confirm_box.h" #include "ui/wrap/padding_wrap.h" #include "ui/widgets/labels.h" +#include "ui/text/text_utilities.h" #include "lang/lang_file_parser.h" #include "core/file_utilities.h" #include "core/click_handler_types.h" @@ -72,42 +73,23 @@ ConfirmSwitchBox::ConfirmSwitchBox( void ConfirmSwitchBox::prepare() { setTitle(langFactory(lng_language_switch_title)); - auto link = TextWithEntities{ lang(lng_language_switch_link) }; - link.entities.push_back({ - EntityType::CustomUrl, - 0, - link.text.size(), - QString("internal:go_to_translations") }); - auto name = TextWithEntities{ _name }; - name.entities.push_back({ - EntityType::Bold, - 0, - name.text.size() }); - auto percent = TextWithEntities{ QString::number(_percent) }; - percent.entities.push_back({ - EntityType::Bold, - 0, - percent.text.size() }); const auto text = (_official ? lng_language_switch_about_official__rich : lng_language_switch_about_unofficial__rich)( lt_lang_name, - name, + Ui::Text::Bold(_name), lt_percent, - percent, + Ui::Text::Bold(QString::number(_percent)), lt_link, - link); - auto content = Ui::CreateChild>( + Ui::Text::Link(lang(lng_language_switch_link), _editLink)); + const auto content = Ui::CreateChild>( this, object_ptr( this, rpl::single(text), st::boxLabel), QMargins{ st::boxPadding.left(), 0, st::boxPadding.right(), 0 }); - content->entity()->setClickHandlerFilter([=](auto&&...) { - UrlClickHandler::Open(_editLink); - return false; - }); + content->entity()->setLinksTrusted(); addButton(langFactory(lng_language_switch_apply), [=] { const auto apply = _apply; @@ -133,29 +115,19 @@ NotReadyBox::NotReadyBox( void NotReadyBox::prepare() { setTitle(langFactory(lng_language_not_ready_title)); - auto link = TextWithEntities{ lang(lng_language_not_ready_link) }; - link.entities.push_back({ - EntityType::CustomUrl, - 0, - link.text.size(), - QString("internal:go_to_translations") }); - auto name = TextWithEntities{ _name }; - const auto text = lng_language_not_ready_about__generic( + const auto text = lng_language_not_ready_about__rich( lt_lang_name, - name, + TextWithEntities{ _name }, lt_link, - link); - auto content = Ui::CreateChild>( + Ui::Text::Link(lang(lng_language_not_ready_link), _editLink)); + const auto content = Ui::CreateChild>( this, object_ptr( this, rpl::single(text), st::boxLabel), QMargins{ st::boxPadding.left(), 0, st::boxPadding.right(), 0 }); - content->entity()->setClickHandlerFilter([=](auto&&...) { - UrlClickHandler::Open(_editLink); - return false; - }); + content->entity()->setLinksTrusted(); addButton(langFactory(lng_box_ok), [=] { closeBox(); }); diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/settings_privacy_security.cpp index c2693bf3cd..bed65dcd13 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_security.cpp @@ -238,82 +238,6 @@ void SetupLocalPasscode(not_null container) { AddSkip(container); } -bool CheckEditCloudPassword() { - const auto current = Auth().api().passwordStateCurrent(); - Assert(current.has_value()); - if (!current->unknownAlgorithm - && current->newPassword - && current->newSecureSecret) { - return true; - } - auto box = std::make_shared>(); - const auto callback = [=] { - Core::UpdateApplication(); - if (*box) (*box)->closeBox(); - }; - *box = Ui::show(Box( - lang(lng_passport_app_out_of_date), - lang(lng_menu_update), - callback)); - return false; -} - -void EditCloudPassword() { - const auto current = Auth().api().passwordStateCurrent(); - Assert(current.has_value()); - - const auto box = Ui::show(Box( - current->request, - current->newPassword, - current->hasRecovery, - current->notEmptyPassport, - current->hint, - current->newSecureSecret)); - - rpl::merge( - box->newPasswordSet() | rpl::map([] { return rpl::empty_value(); }), - box->passwordReloadNeeded() - ) | rpl::start_with_next([=] { - Auth().api().reloadPasswordState(); - }, box->lifetime()); - - box->clearUnconfirmedPassword( - ) | rpl::start_with_next([=] { - Auth().api().clearUnconfirmedPassword(); - }, box->lifetime()); -} - -void RemoveCloudPassword() { - const auto current = Auth().api().passwordStateCurrent(); - Assert(current.has_value()); - - if (!current->request) { - Auth().api().clearUnconfirmedPassword(); - return; - } - const auto box = Ui::show(Box( - current->request, - current->newPassword, - current->hasRecovery, - current->notEmptyPassport, - current->hint, - current->newSecureSecret, - true)); - - rpl::merge( - box->newPasswordSet( - ) | rpl::map([] { return rpl::empty_value(); }), - box->passwordReloadNeeded() - ) | rpl::start_with_next([=] { - Auth().api().reloadPasswordState(); - }, box->lifetime()); - - box->clearUnconfirmedPassword( - ) | rpl::start_with_next([=] { - Auth().api().clearUnconfirmedPassword(); - }, box->lifetime()); -} - void SetupCloudPassword(not_null container) { using namespace rpl::mappers; using State = Core::CloudPasswordState; @@ -396,7 +320,9 @@ void SetupCloudPassword(not_null container) { ))->setDuration(0); change->entity()->addClickHandler([] { if (CheckEditCloudPassword()) { - EditCloudPassword(); + Ui::show(EditCloudPasswordBox(&Auth())); + } else { + Ui::show(CloudPasswordAppOutdatedBox()); } }); @@ -437,6 +363,8 @@ void SetupCloudPassword(not_null container) { const auto remove = [] { if (CheckEditCloudPassword()) { RemoveCloudPassword(); + } else { + Ui::show(CloudPasswordAppOutdatedBox()); } }; const auto disable = container->add( @@ -537,6 +465,91 @@ int ExceptionUsersCount(const std::vector> &exceptions) { return ranges::accumulate(exceptions, 0, add); } +bool CheckEditCloudPassword() { + const auto current = Auth().api().passwordStateCurrent(); + Assert(current.has_value()); + + if (!current->unknownAlgorithm + && current->newPassword + && current->newSecureSecret) { + return true; + } + return false; +} + +object_ptr EditCloudPasswordBox(not_null session) { + const auto current = session->api().passwordStateCurrent(); + Assert(current.has_value()); + + auto result = Box( + current->request, + current->newPassword, + current->hasRecovery, + current->notEmptyPassport, + current->hint, + current->newSecureSecret); + const auto box = result.data(); + + rpl::merge( + box->newPasswordSet() | rpl::map([] { return rpl::empty_value(); }), + box->passwordReloadNeeded() + ) | rpl::start_with_next([=] { + session->api().reloadPasswordState(); + }, box->lifetime()); + + box->clearUnconfirmedPassword( + ) | rpl::start_with_next([=] { + session->api().clearUnconfirmedPassword(); + }, box->lifetime()); + + return std::move(result); +} + +void RemoveCloudPassword() { + const auto current = Auth().api().passwordStateCurrent(); + Assert(current.has_value()); + + if (!current->request) { + Auth().api().clearUnconfirmedPassword(); + return; + } + const auto box = Ui::show(Box( + current->request, + current->newPassword, + current->hasRecovery, + current->notEmptyPassport, + current->hint, + current->newSecureSecret, + true)); + + rpl::merge( + box->newPasswordSet( + ) | rpl::map([] { return rpl::empty_value(); }), + box->passwordReloadNeeded() + ) | rpl::start_with_next([=] { + Auth().api().reloadPasswordState(); + }, box->lifetime()); + + box->clearUnconfirmedPassword( + ) | rpl::start_with_next([=] { + Auth().api().clearUnconfirmedPassword(); + }, box->lifetime()); +} + +object_ptr CloudPasswordAppOutdatedBox() { + auto box = std::make_shared>(); + const auto callback = [=] { + Core::UpdateApplication(); + if (*box) (*box)->closeBox(); + }; + auto result = Box( + lang(lng_passport_app_out_of_date), + lang(lng_menu_update), + callback); + *box = result.data(); + return std::move(result); +} + void AddPrivacyButton( not_null container, LangKey label, diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.h b/Telegram/SourceFiles/settings/settings_privacy_security.h index c6a7c8578e..724c14f534 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.h +++ b/Telegram/SourceFiles/settings/settings_privacy_security.h @@ -16,6 +16,11 @@ namespace Settings { int ExceptionUsersCount(const std::vector> &exceptions); +bool CheckEditCloudPassword(); +object_ptr EditCloudPasswordBox(not_null session); +void RemoveCloudPassword(); +object_ptr CloudPasswordAppOutdatedBox(); + void AddPrivacyButton( not_null container, LangKey label, diff --git a/Telegram/SourceFiles/window/layer_widget.cpp b/Telegram/SourceFiles/window/layer_widget.cpp index f07806867a..aad6772c97 100644 --- a/Telegram/SourceFiles/window/layer_widget.cpp +++ b/Telegram/SourceFiles/window/layer_widget.cpp @@ -552,8 +552,6 @@ void LayerStackWidget::startAnimation( ClearOld clearOldWidgets, Action action, anim::type animated) { - if (App::quitting()) return; - if (animated == anim::type::instant) { setupNewWidgets(); clearOldWidgets(); @@ -845,7 +843,13 @@ void LayerStackWidget::sendFakeMouseEvent() { sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton); } -LayerStackWidget::~LayerStackWidget() = default; +LayerStackWidget::~LayerStackWidget() { + // Some layer destructors call back into LayerStackWidget. + while (!_layers.empty() || !_closingLayers.empty()) { + hideAll(anim::type::instant); + clearClosingLayers(); + } +} } // namespace Window