Replaced boxes for local passcode settings with section.

This commit is contained in:
23rd 2022-05-04 23:03:42 +03:00
parent c27db754a7
commit 376b592e5a
6 changed files with 357 additions and 68 deletions

View File

@ -490,7 +490,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_forwards_privacy" = "Forwarded messages";
"lng_settings_profile_photo_privacy" = "Profile photo";
"lng_settings_sessions_about" = "Control your sessions on other devices.";
"lng_settings_passcode_disable" = "Disable passcode";
"lng_settings_passcode_disable" = "Disable Passcode";
"lng_settings_passcode_disable_sure" = "Are you sure you want to disable passcode?";
"lng_settings_password_disable" = "Disable cloud password";
"lng_settings_password_abort" = "Abort two-step verification setup";
"lng_settings_password_reenter_email" = "Re-enter recovery email";
@ -634,7 +635,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_passcode_remove_button" = "Remove";
"lng_passcode_turn_on" = "Turn on local passcode";
"lng_passcode_change" = "Change local passcode";
"lng_passcode_change" = "Change Passcode";
"lng_passcode_create" = "Local passcode";
"lng_passcode_remove" = "Remove local passcode";
"lng_passcode_turn_off" = "Turn off";

View File

@ -153,7 +153,7 @@ settingLocalPasscodeError: FlatLabel(changePhoneError) {
}
settingLocalPasscodeDescriptionBottomSkip: 15px;
settingLocalPasscodeIconPadding: margins(0px, 19px, 0px, 5px);
settingLocalPasscodeButtonPadding: margins(0px, 19px, 0px, 15px);
settingLocalPasscodeButtonPadding: margins(0px, 19px, 0px, 35px);
settingsInfoPhotoHeight: 161px;
settingsInfoPhotoSize: 100px;

View File

@ -7,20 +7,88 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/settings_local_passcode.h"
#include "base/platform/base_platform_last_input.h"
#include "base/timer.h"
#include "boxes/auto_lock_box.h"
#include "core/application.h"
#include "lang/lang_keys.h"
#include "lottie/lottie_icon.h"
#include "main/main_domain.h"
#include "main/main_session.h"
#include "storage/storage_domain.h"
#include "ui/boxes/confirm_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
#include "styles/style_settings.h"
#include "styles/style_boxes.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
namespace Settings {
namespace {
constexpr auto kTimerCheck = crl::time(1000 * 60);
constexpr auto kAutoCloseTimeout = crl::time(1000 * 60 * 10);
void SetPasscode(
not_null<Window::SessionController*> controller,
const QString &pass) {
cSetPasscodeBadTries(0);
controller->session().domain().local().setPasscode(pass.toUtf8());
Core::App().localPasscodeChanged();
}
void SetupAutoCloseTimer(rpl::lifetime &lifetime, Fn<void()> callback) {
const auto timer = lifetime.make_state<base::Timer>([=] {
const auto idle = crl::now() - Core::App().lastNonIdleTime();
if (idle >= kAutoCloseTimeout) {
callback();
}
});
timer->callEach(kTimerCheck);
}
class Divider : public Ui::BoxContentDivider {
public:
using Ui::BoxContentDivider::BoxContentDivider;
void skipEdge(Qt::Edge edge, bool skip);
protected:
void paintEvent(QPaintEvent *e) override;
private:
Qt::Edges _skipEdges;
};
void Divider::skipEdge(Qt::Edge edge, bool skip) {
const auto was = _skipEdges;
if (skip) {
_skipEdges |= edge;
} else {
_skipEdges &= ~edge;
}
if (was != _skipEdges) {
update();
}
}
void Divider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), Ui::BoxContentDivider::color());
if (!(_skipEdges & Qt::TopEdge)) {
Ui::BoxContentDivider::paintTop(p);
}
if (!(_skipEdges & Qt::BottomEdge)) {
Ui::BoxContentDivider::paintBottom(p);
}
}
} // namespace
namespace details {
LocalPasscodeEnter::LocalPasscodeEnter(
@ -39,6 +107,7 @@ void LocalPasscodeEnter::setupContent() {
const auto isCreate = (enterType() == EnterType::Create);
const auto isCheck = (enterType() == EnterType::Check);
[[maybe_unused]] const auto isChange = (enterType() == EnterType::Change);
auto icon = CreateLottieIcon(
content,
@ -56,6 +125,10 @@ void LocalPasscodeEnter::setupContent() {
animate(anim::repeat::once);
}, content->lifetime());
if (isChange) {
SetupAutoCloseTimer(content->lifetime(), [=] { _showBack.fire({}); });
}
AddSkip(content);
content->add(
@ -126,9 +199,7 @@ void LocalPasscodeEnter::setupContent() {
const auto reenterPasscode = isCheck
? (Ui::PasswordInput*)(nullptr)
: addField(tr::lng_passcode_confirm_new());
const auto reenterError = isCheck
? (Ui::FlatLabel*)(nullptr)
: addError(reenterPasscode);
const auto error = addError(isCheck ? newPasscode : reenterPasscode);
const auto button = content->add(
object_ptr<Ui::CenterWrap<Ui::RoundButton>>(
@ -148,7 +219,7 @@ void LocalPasscodeEnter::setupContent() {
const auto reenterText = reenterPasscode
? reenterPasscode->text()
: QString();
if (isCreate) {
if (isCreate || isChange) {
if (newText.isEmpty()) {
newPasscode->setFocus();
newPasscode->showError();
@ -159,14 +230,64 @@ void LocalPasscodeEnter::setupContent() {
reenterPasscode->setFocus();
reenterPasscode->showError();
reenterPasscode->selectAll();
reenterError->show();
reenterError->setText(tr::lng_passcode_differ(tr::now));
error->show();
error->setText(tr::lng_passcode_differ(tr::now));
} else {
// showOther
if (isChange) {
const auto &domain = _controller->session().domain();
if (domain.local().checkPasscode(newText.toUtf8())) {
newPasscode->setFocus();
newPasscode->showError();
newPasscode->selectAll();
error->show();
error->setText(tr::lng_passcode_is_same(tr::now));
return;
}
}
SetPasscode(_controller, newText);
if (isCreate) {
_showOther.fire(LocalPasscodeManage::Id());
} else if (isChange) {
_showBack.fire({});
}
}
} else if (isCheck) {
if (!passcodeCanTry()) {
newPasscode->setFocus();
newPasscode->showError();
error->show();
error->setText(tr::lng_flood_error(tr::now));
return;
}
const auto &domain = _controller->session().domain();
if (domain.local().checkPasscode(newText.toUtf8())) {
cSetPasscodeBadTries(0);
_showOther.fire(LocalPasscodeManage::Id());
} else {
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
cSetPasscodeLastTry(crl::now());
newPasscode->selectAll();
newPasscode->setFocus();
newPasscode->showError();
error->show();
error->setText(tr::lng_passcode_wrong(tr::now));
}
}
});
const auto submit = [=] {
if (!reenterPasscode || reenterPasscode->hasFocus()) {
button->clicked({}, Qt::LeftButton);
} else {
reenterPasscode->setFocus();
}
};
connect(newPasscode, &Ui::MaskedInputField::submitted, submit);
if (reenterPasscode) {
connect(reenterPasscode, &Ui::MaskedInputField::submitted, submit);
}
_setInnerFocus.events(
) | rpl::start_with_next([=] {
if (newPasscode->text().isEmpty()) {
@ -189,7 +310,185 @@ void LocalPasscodeEnter::setInnerFocus() {
_setInnerFocus.fire({});
}
rpl::producer<Type> LocalPasscodeEnter::sectionShowOther() {
return _showOther.events();
}
rpl::producer<> LocalPasscodeEnter::sectionShowBack() {
return _showBack.events();
}
LocalPasscodeEnter::~LocalPasscodeEnter() = default;
} // namespace details
LocalPasscodeManage::LocalPasscodeManage(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent)
, _controller(controller) {
setupContent();
}
rpl::producer<QString> LocalPasscodeManage::title() {
return tr::lng_settings_passcode_title();
}
rpl::producer<std::vector<Type>> LocalPasscodeManage::removeFromStack() {
return rpl::single(std::vector<Type>{
LocalPasscodeManage::Id(),
LocalPasscodeCreate::Id(),
LocalPasscodeCheck::Id(),
LocalPasscodeChange::Id(),
});
}
void LocalPasscodeManage::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
struct State {
rpl::event_stream<> autoLockBoxClosing;
};
const auto state = content->lifetime().make_state<State>();
SetupAutoCloseTimer(content->lifetime(), [=] { _showBack.fire({}); });
AddSkip(content);
AddButton(
content,
tr::lng_passcode_change(),
st::settingsButton,
{ &st::settingsIconLock, kIconLightBlue }
)->addClickHandler([=] {
_showOther.fire(LocalPasscodeChange::Id());
});
auto autolockLabel = state->autoLockBoxClosing.events_starting_with(
{}
) | rpl::map([] {
const auto autolock = Core::App().settings().autoLock();
const auto hours = autolock / 3600;
const auto minutes = (autolock - (hours * 3600)) / 60;
return (hours && minutes)
? tr::lng_passcode_autolock_hours_minutes(
tr::now,
lt_hours_count,
QString::number(hours),
lt_minutes_count,
QString::number(minutes))
: minutes
? tr::lng_minutes(tr::now, lt_count, minutes)
: tr::lng_hours(tr::now, lt_count, hours);
});
AddButtonWithLabel(
content,
(base::Platform::LastUserInputTimeSupported()
? tr::lng_passcode_autolock_away
: tr::lng_passcode_autolock_inactive)(),
std::move(autolockLabel),
st::settingsButton,
{ &st::settingsIconTimer, kIconGreen }
)->addClickHandler([=] {
const auto box = _controller->show(Box<AutoLockBox>());
box->boxClosing(
) | rpl::start_to_stream(state->autoLockBoxClosing, box->lifetime());
});
AddSkip(content);
const auto divider = Ui::CreateChild<Divider>(this);
divider->lower();
const auto about = content->add(
object_ptr<Ui::PaddingWrap<>>(
content,
object_ptr<Ui::FlatLabel>(
content,
rpl::combine(
tr::lng_passcode_about1(),
tr::lng_passcode_about3()
) | rpl::map([](const QString &s1, const QString &s2) {
return s1 + "\n\n" + s2;
}),
st::boxDividerLabel),
st::settingsDividerLabelPadding));
about->geometryValue(
) | rpl::start_with_next([=](const QRect &r) {
divider->setGeometry(r);
}, divider->lifetime());
_isBottomFillerShown.value(
) | rpl::start_with_next([=](bool shown) {
divider->skipEdge(Qt::BottomEdge, shown);
}, divider->lifetime());
Ui::ResizeFitChild(this, content);
}
QPointer<Ui::RpWidget> LocalPasscodeManage::createPinnedToBottom(
not_null<Ui::RpWidget*> parent) {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(parent.get());
AddSkip(content);
AddButton(
content,
tr::lng_settings_passcode_disable(),
st::settingsAttentionButton
)->addClickHandler([=] {
_controller->show(
Ui::MakeConfirmBox({
.text = tr::lng_settings_passcode_disable_sure(),
.confirmed = [=](Fn<void()> &&close) {
SetPasscode(_controller, QString());
close();
_showBack.fire({});
},
.confirmText = tr::lng_settings_auto_night_disable(),
.confirmStyle = &st::attentionBoxButton,
}));
});
const auto divider = Ui::CreateChild<Divider>(parent.get());
divider->skipEdge(Qt::TopEdge, true);
rpl::combine(
geometryValue(),
parent->geometryValue(),
content->geometryValue()
) | rpl::start_with_next([=](
const QRect &r,
const QRect &parentRect,
const QRect &bottomRect) {
const auto top = r.y() + r.height();
divider->setGeometry(
0,
top,
r.width(),
parentRect.height() - top - bottomRect.height());
}, divider->lifetime());
divider->show();
_isBottomFillerShown = divider->geometryValue(
) | rpl::map([](const QRect &r) {
return r.height() > 0;
});
return Ui::MakeWeak(not_null<Ui::RpWidget*>{ content });
}
void LocalPasscodeManage::showFinished() {
_showFinished.fire({});
}
rpl::producer<Type> LocalPasscodeManage::sectionShowOther() {
return _showOther.events();
}
rpl::producer<> LocalPasscodeManage::sectionShowBack() {
return _showBack.events();
}
LocalPasscodeManage::~LocalPasscodeManage() = default;
} // namespace Settings

View File

@ -27,6 +27,8 @@ public:
void showFinished() override;
void setInnerFocus() override;
[[nodiscard]] rpl::producer<Type> sectionShowOther() override;
[[nodiscard]] rpl::producer<> sectionShowBack() override;
[[nodiscard]] rpl::producer<QString> title() override;
@ -41,6 +43,8 @@ private:
rpl::event_stream<> _showFinished;
rpl::event_stream<> _setInnerFocus;
rpl::event_stream<Type> _showOther;
rpl::event_stream<> _showBack;
};
@ -104,5 +108,36 @@ public:
};
class LocalPasscodeManage : public Section<LocalPasscodeManage> {
public:
LocalPasscodeManage(
QWidget *parent,
not_null<Window::SessionController*> controller);
~LocalPasscodeManage();
[[nodiscard]] rpl::producer<QString> title() override;
void showFinished() override;
[[nodiscard]] rpl::producer<Type> sectionShowOther() override;
[[nodiscard]] rpl::producer<> sectionShowBack() override;
[[nodiscard]] rpl::producer<std::vector<Type>> removeFromStack() override;
[[nodiscard]] QPointer<Ui::RpWidget> createPinnedToBottom(
not_null<Ui::RpWidget*> parent) override;
private:
void setupContent();
const not_null<Window::SessionController*> _controller;
rpl::variable<bool> _isBottomFillerShown;
rpl::event_stream<> _showFinished;
rpl::event_stream<Type> _showOther;
rpl::event_stream<> _showBack;
};
} // namespace Settings

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_global_privacy.h"
#include "settings/settings_blocked_peers.h"
#include "settings/settings_common.h"
#include "settings/settings_local_passcode.h"
#include "settings/settings_privacy_controllers.h"
#include "base/timer_rpl.h"
#include "base/unixtime.h"
@ -223,7 +224,8 @@ void SetupArchiveAndMute(
void SetupLocalPasscode(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
not_null<Ui::VerticalLayout*> container,
Fn<void(Type)> showOther) {
AddSkip(container);
AddDivider(container);
AddSkip(container);
@ -237,7 +239,7 @@ void SetupLocalPasscode(
auto text = rpl::combine(
tr::lng_passcode_change(),
tr::lng_passcode_turn_on(),
base::duplicate(has),
std::move(has),
[](const QString &change, const QString &create, bool has) {
return has ? change : create;
});
@ -247,60 +249,12 @@ void SetupLocalPasscode(
st::settingsButton,
{ &st::settingsIconLock, kIconGreen }
)->addClickHandler([=] {
controller->show(Box<PasscodeBox>(&controller->session(), false));
if (controller->session().domain().local().hasLocalPasscode()) {
showOther(LocalPasscodeCheck::Id());
} else {
showOther(LocalPasscodeCreate::Id());
}
});
const auto wrap = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto inner = wrap->entity();
AddButton(
inner,
tr::lng_settings_passcode_disable(),
st::settingsButton,
{ &st::settingsIconMinus, kIconRed }
)->addClickHandler([=] {
controller->show(Box<PasscodeBox>(&controller->session(), true));
});
const auto autoLockBoxClosing =
container->lifetime().make_state<rpl::event_stream<>>();
const auto label = base::Platform::LastUserInputTimeSupported()
? tr::lng_passcode_autolock_away
: tr::lng_passcode_autolock_inactive;
auto value = autoLockBoxClosing->events_starting_with(
{}
) | rpl::map([] {
const auto autolock = Core::App().settings().autoLock();
const auto hours = autolock / 3600;
const auto minutes = (autolock - (hours * 3600)) / 60;
return (hours && minutes)
? tr::lng_passcode_autolock_hours_minutes(
tr::now,
lt_hours_count,
QString::number(hours),
lt_minutes_count,
QString::number(minutes))
: minutes
? tr::lng_minutes(tr::now, lt_count, minutes)
: tr::lng_hours(tr::now, lt_count, hours);
});
AddButtonWithLabel(
inner,
label(),
std::move(value),
st::settingsButton,
{ &st::settingsIconTimer, kIconGreen }
)->addClickHandler([=] {
const auto box = controller->show(Box<AutoLockBox>());
box->boxClosing(
) | rpl::start_to_stream(*autoLockBoxClosing, box->lifetime());
});
wrap->toggleOn(base::duplicate(has));
}
void SetupCloudPassword(
@ -826,7 +780,7 @@ void SetupSecurity(
container,
rpl::duplicate(updateTrigger),
showOther);
SetupLocalPasscode(controller, container);
SetupLocalPasscode(controller, container, showOther);
SetupCloudPassword(controller, container);
}

@ -1 +1 @@
Subproject commit 9b6e11db62810626a56431cdc8eeb771817f6560
Subproject commit 83553d08264effc9909e6674fa19c9d8d74a71de