Show transfer community button, set 2sv password.

This commit is contained in:
John Preston 2019-06-14 14:01:35 +02:00
parent ca7c50fbcd
commit 0dddb7694f
13 changed files with 341 additions and 140 deletions

View File

@ -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.";

View File

@ -985,3 +985,5 @@ addContactWarningMargin: margins(19px, 10px, 19px, 5px);
blockUserConfirmation: FlatLabel(boxLabel) {
minWidth: 240px;
}
transferCheckWidth: 300px;

View File

@ -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<InformBox>(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<InformBox>(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<ConfirmBox>(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, crl::guard(this, [this] {
save(true);
})));
_replacedBy = getDelegate()->show(
Box<ConfirmBox>(
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());

View File

@ -163,7 +163,7 @@ void Controller::choose(not_null<ChatData*> 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<QPointer<BoxContent>>();

View File

@ -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<GenericBox*> box, not_null<UserData*> 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<GenericBox*> box,
not_null<UserData*> 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<Ui::FlatLabel>(
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<Ui::FlatLabel>(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<Ui::FlatLabel>(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<Ui::SlideWrap<Ui::RpWidget>*> EditAdminBox::setupTransferButton(
bool isGroup) {
const auto wrap = addControl(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
this,
object_ptr<Ui::VerticalLayout>(this)));
const auto container = wrap->entity();
const auto addDivider = [&] {
container->add(
object_ptr<BoxContentDivider>(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()) {

View File

@ -16,6 +16,8 @@ class LinkButton;
class Checkbox;
class Radiobutton;
class RadiobuttonGroup;
template <typename Widget>
class SlideWrap;
} // namespace Ui
class CalendarBox;
@ -77,15 +79,21 @@ private:
static MTPChatAdminRights Defaults(not_null<PeerData*> peer);
void transferOwnership();
bool handleTransferPasswordError(const RPCError &error);
void requestTransferPassword();
bool canSave() const {
return !!_saveCallback;
}
void refreshAboutAddAdminsText(bool canAddAdmins);
bool canTransferOwnership() const;
not_null<Ui::SlideWrap<Ui::RpWidget>*> setupTransferButton(bool isGroup);
const MTPChatAdminRights _oldRights;
Fn<void(MTPChatAdminRights, MTPChatAdminRights)> _saveCallback;
QPointer<Ui::FlatLabel> _aboutAddAdmins;
mtpRequestId _checkTransferRequestId = 0;
};

View File

@ -95,7 +95,7 @@ std::vector<std::pair<ChatRestrictions, LangKey>> 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<PeerData*> peer)

View File

@ -58,3 +58,4 @@ EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions);
ChatAdminRights FullAdminRights(bool isGroup);

View File

@ -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);
});
}

View File

@ -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::PaddingWrap<Ui::FlatLabel>>(
Ui::Text::Link(lang(lng_language_switch_link), _editLink));
const auto content = Ui::CreateChild<Ui::PaddingWrap<Ui::FlatLabel>>(
this,
object_ptr<Ui::FlatLabel>(
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::PaddingWrap<Ui::FlatLabel>>(
Ui::Text::Link(lang(lng_language_not_ready_link), _editLink));
const auto content = Ui::CreateChild<Ui::PaddingWrap<Ui::FlatLabel>>(
this,
object_ptr<Ui::FlatLabel>(
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(); });

View File

@ -238,82 +238,6 @@ void SetupLocalPasscode(not_null<Ui::VerticalLayout*> 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<QPointer<BoxContent>>();
const auto callback = [=] {
Core::UpdateApplication();
if (*box) (*box)->closeBox();
};
*box = Ui::show(Box<ConfirmBox>(
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<PasscodeBox>(
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<PasscodeBox>(
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<Ui::VerticalLayout*> container) {
using namespace rpl::mappers;
using State = Core::CloudPasswordState;
@ -396,7 +320,9 @@ void SetupCloudPassword(not_null<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> 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<not_null<PeerData*>> &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<BoxContent> EditCloudPasswordBox(not_null<AuthSession*> session) {
const auto current = session->api().passwordStateCurrent();
Assert(current.has_value());
auto result = Box<PasscodeBox>(
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<PasscodeBox>(
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<BoxContent> CloudPasswordAppOutdatedBox() {
auto box = std::make_shared<QPointer<BoxContent>>();
const auto callback = [=] {
Core::UpdateApplication();
if (*box) (*box)->closeBox();
};
auto result = Box<ConfirmBox>(
lang(lng_passport_app_out_of_date),
lang(lng_menu_update),
callback);
*box = result.data();
return std::move(result);
}
void AddPrivacyButton(
not_null<Ui::VerticalLayout*> container,
LangKey label,

View File

@ -16,6 +16,11 @@ namespace Settings {
int ExceptionUsersCount(const std::vector<not_null<PeerData*>> &exceptions);
bool CheckEditCloudPassword();
object_ptr<BoxContent> EditCloudPasswordBox(not_null<AuthSession*> session);
void RemoveCloudPassword();
object_ptr<BoxContent> CloudPasswordAppOutdatedBox();
void AddPrivacyButton(
not_null<Ui::VerticalLayout*> container,
LangKey label,

View File

@ -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