diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7d6c592f29..a391f36440 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1524,6 +1524,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_terms_agree" = "Agree & Continue"; "lng_terms_decline" = "Decline"; "lng_terms_signup_sorry" = "We're very sorry, but this means you can't sign up for Telegram.\n\nUnlike others, we don't use your data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a feature-rich cloud service. You can adjust how we use your data in Privacy & Security settings.\n\nBut if you're generally not OK with Telegram's modest needs, it won't be possible for us to provide this service."; +"lng_terms_update_sorry" = "We're very sorry, but this means we must part ways here. Unlike others, we don't use your data for ad targeting or other commercial purposes. Telegram only stores the information it needs to function as a feature-rich cloud service. You can adjust how we use your data in Privacy & Security settings.\n\nBut if you're generally not OK with Telegram's modest needs, it won't be possible for us to provide this service. You can deactivate your account now — or look around some more and deactivate it later if you feel you're not happy with the way we use your data. How does that sound?"; +"lng_terms_decline_and_delete" = "Decline & Delete"; +"lng_terms_back" = "Back"; +"lng_terms_delete_warning" = "Warning, this will irreversibly delete your Telegram account along with all the data you store in the Telegram cloud.\n\nWe will provide a tool to download your data before June, 23 – so you may want to wait a little before deleting."; +"lng_terms_delete_now" = "Delete now"; +"lng_terms_agree_to_proceed" = "Please agree and proceed to {bot}."; "lng_date_input_day" = "Day"; "lng_date_input_month" = "Month"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 6608f80aae..3c0cf83468 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "auth_session.h" #include "boxes/confirm_box.h" #include "window/notifications_manager.h" +#include "window/window_lock_widgets.h" #include "window/window_controller.h" #include "chat_helpers/message_field.h" #include "chat_helpers/stickers.h" @@ -249,6 +250,62 @@ void ApiWrap::requestDeepLinkInfo( }).send(); } +void ApiWrap::requestTermsUpdate() { + if (_termsUpdateRequestId) { + return; + } + const auto now = getms(true); + if (_termsUpdateSendAt && now < _termsUpdateSendAt) { + App::CallDelayed(_termsUpdateSendAt - now, _session, [=] { + requestTermsUpdate(); + }); + return; + } + + constexpr auto kTermsUpdateTimeoutMin = 10 * TimeMs(1000); + constexpr auto kTermsUpdateTimeoutMax = 86400 * TimeMs(1000); + + _termsUpdateRequestId = request(MTPhelp_GetTermsOfServiceUpdate( + )).done([=](const MTPhelp_TermsOfServiceUpdate &result) { + _termsUpdateRequestId = 0; + + const auto requestNext = [&](auto &&data) { + _termsUpdateSendAt = getms(true) + snap( + TimeMs(data.vexpires.v - unixtime()), + kTermsUpdateTimeoutMin, + kTermsUpdateTimeoutMax); + requestTermsUpdate(); + }; + switch (result.type()) { + case mtpc_help_termsOfServiceUpdateEmpty: { + const auto &data = result.c_help_termsOfServiceUpdateEmpty(); + requestNext(data); + } break; + case mtpc_help_termsOfServiceUpdate: { + const auto &data = result.c_help_termsOfServiceUpdate(); + const auto &terms = data.vterms_of_service; + const auto &fields = terms.c_help_termsOfService(); + Messenger::Instance().lockByTerms( + Window::TermsLock::FromMTP(fields)); + requestNext(data); + } break; + default: Unexpected("Type in requestTermsUpdate()."); + } + }).fail([=](const RPCError &error) { + _termsUpdateRequestId = 0; + _termsUpdateSendAt = getms(true) + kTermsUpdateTimeoutMin; + requestTermsUpdate(); + }).send(); +} + +void ApiWrap::acceptTerms(bytes::const_span id) { + request(MTPhelp_AcceptTermsOfService( + MTP_dataJSON(MTP_bytes(id)) + )).done([=](const MTPBool &result) { + requestTermsUpdate(); + }).send(); +} + void ApiWrap::applyUpdates( const MTPUpdates &updates, uint64 sentMessageRandomId) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 01d4f0e435..8bcf553802 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -97,6 +97,8 @@ public: void requestDeepLinkInfo( const QString &path, Fn callback); + void requestTermsUpdate(); + void acceptTerms(bytes::const_span termsId); void requestChannelMembersForAdd( not_null channel, @@ -583,4 +585,7 @@ private: mtpRequestId _deepLinkInfoRequestId = 0; + TimeMs _termsUpdateSendAt = 0; + mtpRequestId _termsUpdateRequestId = 0; + }; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 43446958dc..dd9c3b9127 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -140,13 +140,6 @@ namespace App { return nullptr; } - bool passcoded() { - if (auto window = wnd()) { - return window->passcodeWidget(); - } - return false; - } - namespace { // we should get a full restriction in "{fulltype}: {reason}" format and we // need to find a "-all" tag in {fulltype}, otherwise ignore this restriction diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 021a3e5828..9c0827b6d6 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -66,7 +66,6 @@ enum RoundCorners { namespace App { MainWindow *wnd(); MainWidget *main(); - bool passcoded(); QString formatPhone(QString phone); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 067c64e1b0..9191487007 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -66,7 +66,8 @@ QString _escapeFrom7bit(const QString &str) { bool StartUrlRequiresActivate(const QString &url) { const auto urlTrimmed = url.trimmed(); - if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive) || App::passcoded()) { + if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive) + || Messenger::Instance().locked()) { return true; } const auto command = urlTrimmed.midRef(qstr("tg://").size()); diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index 8ce8b33c1e..1fda773cf6 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -281,14 +281,19 @@ AuthSession::AuthSession(UserId userId) _saveDataTimer.setCallback([=] { Local::writeUserSettings(); }); - subscribe(Messenger::Instance().passcodedChanged(), [=] { + Messenger::Instance().passcodeLockChanges( + ) | rpl::start_with_next([=] { _shouldLockAt = 0; + }, _lifetime); + Messenger::Instance().lockChanges( + ) | rpl::start_with_next([=] { notifications().updateAll(); - }); + }, _lifetime); subscribe(Global::RefConnectionTypeChanged(), [=] { _api->refreshProxyPromotion(); }); _api->refreshProxyPromotion(); + _api->requestTermsUpdate(); Window::Theme::Background()->start(); } @@ -327,7 +332,10 @@ void AuthSession::saveSettingsDelayed(TimeMs delay) { } void AuthSession::checkAutoLock() { - if (!Global::LocalPasscode() || App::passcoded()) return; + if (!Global::LocalPasscode() + || Messenger::Instance().passcodeLocked()) { + return; + } Messenger::Instance().checkLocalTime(); auto now = getms(true); @@ -336,7 +344,7 @@ void AuthSession::checkAutoLock() { auto notPlayingVideoForMs = now - settings().lastTimeVideoPlayedAt(); auto checkTimeMs = qMin(idleForMs, notPlayingVideoForMs); if (checkTimeMs >= shouldLockInMs || (_shouldLockAt > 0 && now > _shouldLockAt + kAutoLockTimeoutLateMs)) { - Messenger::Instance().setupPasscode(); + Messenger::Instance().lockByPasscode(); } else { _shouldLockAt = now + (shouldLockInMs - checkTimeMs); _autoLockTimer.callOnce(shouldLockInMs - checkTimeMs); diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 9bafa7d219..00a7df15f4 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -785,3 +785,9 @@ proxyAboutPadding: margins(22px, 7px, 22px, 14px); proxyAboutSponsorPadding: margins(22px, 7px, 22px, 0px); markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px); + +termsContent: FlatLabel(defaultFlatLabel) { + minWidth: 285px; +} +termsPadding: margins(23px, 4px, 16px, 16px); +termsAgePadding: margins(23px, 16px, 16px, 0px); diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index e22dccd87e..0a355b0ab0 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -44,6 +44,7 @@ public: } void addItem(not_null item) { Expects(canAddItem(item)); + _items.push_back(item); ranges::sort(_items, [](not_null a, auto b) { return (a->id > b->id); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index dd3e54f998..b2fc6578ff 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -140,7 +140,7 @@ DialogsWidget::DialogsWidget(QWidget *parent, not_null cont subscribe(Global::RefLocalPasscodeChanged(), [this] { updateLockUnlockVisibility(); }); _lockUnlock->setClickedCallback([this] { _lockUnlock->setIconOverride(&st::dialogsUnlockIcon, &st::dialogsUnlockIconOver); - Messenger::Instance().setupPasscode(); + Messenger::Instance().lockByPasscode(); _lockUnlock->setIconOverride(nullptr); }); _mainMenuToggle->setClickedCallback([this] { showMainMenu(); }); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 12658c91b9..ade50f2632 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -46,8 +46,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "application.h" #include "mainwidget.h" #include "mainwindow.h" -#include "passcodewidget.h" -#include "mainwindow.h" #include "storage/localimageloader.h" #include "storage/localstorage.h" #include "storage/file_upload.h" @@ -55,6 +53,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/media_audio.h" #include "media/media_audio_capture.h" #include "media/player/media_player_instance.h" +#include "messenger.h" #include "apiwrap.h" #include "history/view/history_view_top_bar_widget.h" #include "observer_peer.h" @@ -6472,8 +6471,13 @@ void HistoryWidget::updateTopBarSelection() { _topBar->showSelected(selectedState); updateControlsVisibility(); updateHistoryGeometry(); - if (!Ui::isLayerShown() && !App::passcoded()) { - if (_nonEmptySelection || (_list && _list->wasSelectedText()) || _recording || isBotStart() || isBlocked() || !_canSendMessages) { + if (!Ui::isLayerShown() && !Messenger::Instance().locked()) { + if (_nonEmptySelection + || (_list && _list->wasSelectedText()) + || _recording + || isBotStart() + || isBlocked() + || !_canSendMessages) { _list->setFocus(); } else { _field->setFocus(); diff --git a/Telegram/SourceFiles/intro/intro.style b/Telegram/SourceFiles/intro/intro.style index 9b321e99ef..19535cd8f6 100644 --- a/Telegram/SourceFiles/intro/intro.style +++ b/Telegram/SourceFiles/intro/intro.style @@ -129,11 +129,6 @@ introTermsLabel: FlatLabel(defaultFlatLabel) { align: align(top); } introTermsBottom: 20px; -introTermsContent: FlatLabel(defaultFlatLabel) { - minWidth: 285px; -} -introTermsPadding: margins(23px, 0px, 16px, 0px); -introTermsAgePadding: margins(23px, 8px, 16px, 8px); introCountryIcon: icon {{ "intro_country_dropdown", menuIconFg }}; introCountryIconPosition: point(8px, 37px); diff --git a/Telegram/SourceFiles/intro/introsignup.cpp b/Telegram/SourceFiles/intro/introsignup.cpp index 4dd855cb51..16492d0ae4 100644 --- a/Telegram/SourceFiles/intro/introsignup.cpp +++ b/Telegram/SourceFiles/intro/introsignup.cpp @@ -217,8 +217,8 @@ void SignupWidget::submit() { rpcFail(&SignupWidget::nameSubmitFail)); }; if (_termsAccepted - || getData()->termsText.text.isEmpty() - || !getData()->termsPopup) { + || getData()->termsLock.text.text.isEmpty() + || !getData()->termsLock.popup) { send(); } else { acceptTerms(crl::guard(this, [=] { diff --git a/Telegram/SourceFiles/intro/introwidget.cpp b/Telegram/SourceFiles/intro/introwidget.cpp index 17287a0bb1..b5a8c8dc15 100644 --- a/Telegram/SourceFiles/intro/introwidget.cpp +++ b/Telegram/SourceFiles/intro/introwidget.cpp @@ -24,13 +24,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" -#include "ui/widgets/checkbox.h" #include "ui/wrap/fade_wrap.h" -#include "ui/wrap/vertical_layout.h" #include "ui/effects/slide_animation.h" #include "core/update_checker.h" #include "window/window_slide_animation.h" #include "window/window_connecting_widget.h" +#include "window/window_lock_widgets.h" #include "styles/style_boxes.h" #include "styles/style_intro.h" #include "styles/style_window.h" @@ -43,114 +42,6 @@ namespace { constexpr str_const kDefaultCountry = "US"; -class TermsBox : public BoxContent { -public: - TermsBox( - QWidget*, - const TextWithEntities &text, - Fn agree, - Fn cancel, - int age = 0); - - rpl::producer<> agreeClicks() const; - rpl::producer<> cancelClicks() const; - -protected: - void prepare() override; - - void keyPressEvent(QKeyEvent *e) override; - -private: - TextWithEntities _text; - Fn _agree; - Fn _cancel; - int _age = 0; - rpl::event_stream<> _agreeClicks; - rpl::event_stream<> _cancelClicks; - -}; - -TermsBox::TermsBox( - QWidget*, - const TextWithEntities &text, - Fn agree, - Fn cancel, - int age) -: _text(text) -, _agree(agree) -, _cancel(cancel) -, _age(age) { -} - -rpl::producer<> TermsBox::agreeClicks() const { - return _agreeClicks.events(); -} - -rpl::producer<> TermsBox::cancelClicks() const { - return _cancelClicks.events(); -} - -void TermsBox::prepare() { - setTitle(langFactory(lng_terms_header)); - - const auto content = Ui::CreateChild(this); - content->add( - object_ptr ( - this, - rpl::single(_text), - st::introTermsContent), - st::introTermsPadding); - const auto age = (_age > 0) - ? content->add( - object_ptr( - this, - lng_terms_age(lt_count, _age)), - st::introTermsAgePadding) - : nullptr; - - const auto refreshButtons = [=] { - clearButtons(); - if (age && !age->checked()) { - addButton(langFactory(lng_cancel), [=] { closeBox(); }); - } else { - addButton(_agree, [=] {})->clicks( - ) | rpl::filter([=] { - if (age && !age->checked()) { - return false; - } - return true; - }) | rpl::start_to_stream(_agreeClicks, lifetime()); - - if (_cancel) { - addButton(_cancel, [=] {})->clicks( - ) | rpl::start_to_stream(_cancelClicks, lifetime()); - } - } - }; - if (age) { - base::ObservableViewer( - age->checkedChanged - ) | rpl::start_with_next([=] { - refreshButtons(); - }, lifetime()); - } - refreshButtons(); - - content->resizeToWidth(st::boxWideWidth); - content->heightValue( - ) | rpl::start_with_next([=](int height) { - setDimensions(st::boxWideWidth, height); - }, content->lifetime()); -} - -void TermsBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - _agreeClicks.fire({}); - } else { - BoxContent::keyPressEvent(e); - } -} - } // namespace Widget::Widget(QWidget *parent) : RpWidget(parent) @@ -412,7 +303,7 @@ void Widget::showResetButton() { } void Widget::showTerms() { - if (getData()->termsText.text.isEmpty()) { + if (getData()->termsLock.text.text.isEmpty()) { _terms.destroy(); } else if (!_terms) { auto entity = object_ptr( @@ -498,15 +389,22 @@ void Widget::getNearestDC() { } void Widget::showTerms(Fn callback) { - if (getData()->termsText.text.isEmpty()) { + if (getData()->termsLock.text.text.isEmpty()) { return; } const auto weak = make_weak(this); - const auto box = Ui::show(Box( - getData()->termsText, - langFactory(callback ? lng_terms_agree : lng_box_ok), - callback ? langFactory(lng_terms_decline) : nullptr, - getData()->termsAge)); + const auto box = Ui::show(callback + ? Box( + getData()->termsLock, + langFactory(lng_terms_agree), + langFactory(lng_terms_decline)) + : Box( + getData()->termsLock.text, + langFactory(lng_box_ok), + nullptr)); + + box->setCloseByEscape(false); + box->setCloseByOutsideClick(false); box->agreeClicks( ) | rpl::start_with_next([=] { @@ -520,7 +418,7 @@ void Widget::showTerms(Fn callback) { box->cancelClicks( ) | rpl::start_with_next([=] { - const auto box = Ui::show(Box( + const auto box = Ui::show(Box( TextWithEntities{ lang(lng_terms_signup_sorry) }, langFactory(lng_intro_finish), langFactory(lng_terms_decline))); @@ -836,16 +734,9 @@ bool Widget::Step::paintAnimated(Painter &p, QRect clip) { void Widget::Step::fillSentCodeData(const MTPDauth_sentCode &data) { if (data.has_terms_of_service()) { const auto &terms = data.vterms_of_service.c_help_termsOfService(); - getData()->termsText = TextWithEntities{ - TextUtilities::Clean(qs(terms.vtext)), - TextUtilities::EntitiesFromMTP(terms.ventities.v) }; - getData()->termsPopup = terms.is_popup(); - getData()->termsAge = terms.has_min_age_confirm() - ? terms.vmin_age_confirm.v - : 0; + getData()->termsLock = Window::TermsLock::FromMTP(terms); } else { - getData()->termsText = TextWithEntities(); - getData()->termsAge = 0; + getData()->termsLock = Window::TermsLock(); } const auto &type = data.vtype; diff --git a/Telegram/SourceFiles/intro/introwidget.h b/Telegram/SourceFiles/intro/introwidget.h index 9de0d94437..ef58c1fec3 100644 --- a/Telegram/SourceFiles/intro/introwidget.h +++ b/Telegram/SourceFiles/intro/introwidget.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/sender.h" #include "ui/rp_widget.h" +#include "window/window_lock_widgets.h" namespace Ui { class IconButton; @@ -78,9 +79,7 @@ public: QString pwdHint; bool pwdNotEmptyPassport = false; - TextWithEntities termsText; - bool termsPopup = false; - int termsAge = 0; + Window::TermsLock termsLock; base::Observable updated; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 1db6ae7fef..74d5144c20 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -872,7 +872,7 @@ void MainWidget::noHider(HistoryHider *destroyed) { } void MainWidget::hiderLayer(object_ptr h) { - if (App::passcoded()) { + if (Messenger::Instance().locked()) { return; } @@ -2082,7 +2082,7 @@ void MainWidget::ui_showPeerHistory( auto animatedShow = [&] { if (_a_show.animating() - || App::passcoded() + || Messenger::Instance().locked() || (params.animated == anim::type::instant)) { return false; } @@ -2411,7 +2411,7 @@ void MainWidget::showNewSection( auto animatedShow = [&] { if (_a_show.animating() - || App::passcoded() + || Messenger::Instance().locked() || (params.animated == anim::type::instant) || memento.instant()) { return false; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 732733d82f..57cb367aa9 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -21,8 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "shortcuts.h" #include "messenger.h" +#include "auth_session.h" #include "application.h" -#include "passcodewidget.h" #include "intro/introwidget.h" #include "mainwidget.h" #include "boxes/confirm_box.h" @@ -38,8 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/notifications_manager.h" #include "window/themes/window_theme.h" #include "window/themes/window_theme_warning.h" +#include "window/window_lock_widgets.h" #include "window/window_main_menu.h" -#include "auth_session.h" #include "window/window_controller.h" namespace { @@ -82,7 +82,10 @@ MainWindow::MainWindow() { subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &data) { themeUpdated(data); }); - subscribe(Messenger::Instance().passcodedChanged(), [this] { updateGlobalMenu(); }); + Messenger::Instance().lockChanges( + ) | rpl::start_with_next([=] { + updateGlobalMenu(); + }, lifetime()); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); @@ -126,7 +129,7 @@ void MainWindow::firstShow() { void MainWindow::clearWidgetsHook() { auto wasMain = (_main != nullptr); - _passcode.destroyDelayed(); + _passcodeLock.destroy(); _main.destroy(); _intro.destroy(); if (wasMain) { @@ -135,23 +138,43 @@ void MainWindow::clearWidgetsHook() { } QPixmap MainWindow::grabInner() { - QPixmap result; if (_intro) { - result = Ui::GrabWidget(_intro); - } else if (_passcode) { - result = Ui::GrabWidget(_passcode); + return Ui::GrabWidget(_intro); + } else if (_passcodeLock) { + return Ui::GrabWidget(_passcodeLock); } else if (_main) { - result = Ui::GrabWidget(_main); + return Ui::GrabWidget(_main); } - return result; + return {}; } -void MainWindow::clearPasscode() { - if (!_passcode) return; +void MainWindow::setupPasscodeLock() { + auto animated = (_main || _intro); + auto bg = animated ? grabInner() : QPixmap(); + _passcodeLock.create(bodyWidget()); + updateControlsGeometry(); + + Messenger::Instance().hideMediaView(); + Ui::hideSettingsAndLayer(anim::type::instant); + if (_main) { + _main->hide(); + } + if (_intro) { + _intro->hide(); + } + if (animated) { + _passcodeLock->showAnimated(bg); + } else { + setInnerFocus(); + } +} + +void MainWindow::clearPasscodeLock() { + if (!_passcodeLock) return; auto bg = grabInner(); - _passcode.destroy(); + _passcodeLock.destroy(); if (_intro) { _intro->showAnimated(bg, true); } else { @@ -161,23 +184,6 @@ void MainWindow::clearPasscode() { } } -void MainWindow::setupPasscode() { - auto animated = (_main || _intro); - auto bg = animated ? grabInner() : QPixmap(); - _passcode.create(bodyWidget()); - updateControlsGeometry(); - - if (_main) _main->hide(); - Messenger::Instance().hideMediaView(); - Ui::hideSettingsAndLayer(anim::type::instant); - if (_intro) _intro->hide(); - if (animated) { - _passcode->showAnimated(bg); - } else { - setInnerFocus(); - } -} - void MainWindow::setupIntro() { if (_intro && !_intro->isHidden() && !_main) { return; @@ -185,7 +191,7 @@ void MainWindow::setupIntro() { Ui::hideSettingsAndLayer(anim::type::instant); - auto animated = (_main || _passcode); + auto animated = (_main || _passcodeLock); auto bg = animated ? grabInner() : QPixmap(); clearWidgets(); @@ -267,7 +273,7 @@ void MainWindow::sendServiceHistoryRequest() { } void MainWindow::setupMain(const MTPUser *self) { - auto animated = (_intro || _passcode); + auto animated = (_intro || _passcodeLock); auto bg = animated ? grabInner() : QPixmap(); clearWidgets(); @@ -297,7 +303,7 @@ void MainWindow::showSettings() { void MainWindow::showSpecialLayer( object_ptr layer, anim::type animated) { - if (_passcode) return; + if (_passcodeLock) return; if (layer) { ensureLayerCreated(); @@ -317,7 +323,7 @@ bool MainWindow::showSectionInExistingLayer( } void MainWindow::showMainMenu() { - if (_passcode) return; + if (_passcodeLock) return; if (isHidden()) showFromTray(); @@ -360,10 +366,6 @@ MainWidget *MainWindow::mainWidget() { return _main; } -PasscodeWidget *MainWindow::passcodeWidget() { - return _passcode; -} - void MainWindow::ui_showBox( object_ptr box, LayerOptions options, @@ -481,8 +483,8 @@ void MainWindow::setInnerFocus() { _testingThemeWarning->setFocus(); } else if (_layer && _layer->canSetFocus()) { _layer->setInnerFocus(); - } else if (_passcode) { - _passcode->setInnerFocus(); + } else if (_passcodeLock) { + _passcodeLock->setInnerFocus(); } else if (_main) { _main->setInnerFocus(); } else if (_intro) { @@ -700,7 +702,7 @@ bool MainWindow::skipTrayClick() const { } void MainWindow::toggleDisplayNotifyFromTray() { - if (App::passcoded()) { + if (Messenger::Instance().locked()) { if (!isActive()) showFromTray(); Ui::show(Box(lang(lng_passcode_need_unblock))); return; @@ -749,7 +751,7 @@ void MainWindow::updateControlsGeometry() { Platform::MainWindow::updateControlsGeometry(); auto body = bodyWidget()->rect(); - if (_passcode) _passcode->setGeometry(body); + if (_passcodeLock) _passcodeLock->setGeometry(body); if (_main) _main->setGeometry(body); if (_intro) _intro->setGeometry(body); if (_layer) _layer->setGeometry(body); @@ -911,7 +913,9 @@ QImage MainWindow::iconWithCounter(int size, int count, style::color bg, style:: } void MainWindow::sendPaths() { - if (App::passcoded()) return; + if (Messenger::Instance().locked()) { + return; + } Messenger::Instance().hideMediaView(); Ui::hideSettingsAndLayer(anim::type::instant); if (_main) { diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 5f46065f5f..c9c6d721b4 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_main_window.h" #include "core/single_timer.h" -class PasscodeWidget; class MainWidget; class BoxContent; @@ -28,6 +27,7 @@ class LayerWidget; class LayerStackWidget; class SectionMemento; struct SectionShow; +class PasscodeLockWidget; namespace Theme { struct BackgroundUpdate; class WarningWidget; @@ -49,8 +49,8 @@ public: void firstShow(); - void setupPasscode(); - void clearPasscode(); + void setupPasscodeLock(); + void clearPasscodeLock(); void setupIntro(); void setupMain(const MTPUser *user = nullptr); void serviceNotification(const TextWithEntities &message, const MTPMessageMedia &media = MTP_messageMediaEmpty(), int32 date = 0, bool force = false); @@ -62,7 +62,6 @@ public: } MainWidget *mainWidget(); - PasscodeWidget *passcodeWidget(); bool doWeReadServerHistory(); bool doWeReadMentions(); @@ -173,7 +172,7 @@ private: mtpRequestId _serviceHistoryRequest = 0; TimeMs _lastTrayClickTime = 0; - object_ptr _passcode = { nullptr }; + object_ptr _passcodeLock = { nullptr }; object_ptr _intro = { nullptr }; object_ptr _main = { nullptr }; object_ptr _layer = { nullptr }; diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 06e5771782..13b084a19a 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/media_audio_track.h" #include "window/notifications_manager.h" #include "window/themes/window_theme.h" +#include "window/window_lock_widgets.h" #include "history/history_location_manager.h" #include "ui/widgets/tooltip.h" #include "ui/text_options.h" @@ -160,7 +161,7 @@ Messenger::Messenger(not_null launcher) DEBUG_LOG(("Application Info: showing.")); if (state == Local::ReadMapPassNeeded) { - setupPasscode(); + lockByPasscode(); } else { if (AuthSession::Exists()) { _window->setupMain(); @@ -788,11 +789,14 @@ void Messenger::onSwitchTestMode() { void Messenger::authSessionCreate(UserId userId) { Expects(_mtproto != nullptr); + _authSession = std::make_unique(userId); authSessionChanged().notify(true); } void Messenger::authSessionDestroy() { + unlockTerms(); + _uploaderSubscription = rpl::lifetime(); _authSession.reset(); _private->storedAuthSession.reset(); @@ -839,7 +843,7 @@ QString Messenger::createInternalLinkFull(const QString &query) const { } void Messenger::checkStartUrl() { - if (!cStartUrl().isEmpty() && !App::passcoded()) { + if (!cStartUrl().isEmpty() && !locked()) { auto url = cStartUrl(); cSetStartUrl(QString()); if (!openLocalUrl(url)) { @@ -852,10 +856,11 @@ bool Messenger::openLocalUrl(const QString &url) { auto urlTrimmed = url.trimmed(); if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192); - if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive) || App::passcoded()) { + const auto protocol = qstr("tg://"); + if (!urlTrimmed.startsWith(protocol, Qt::CaseInsensitive) || locked()) { return false; } - auto command = urlTrimmed.midRef(qstr("tg://").size()); + auto command = urlTrimmed.midRef(protocol.size()); const auto showPassportForm = [](const QMap ¶ms) { const auto botId = params.value("bot_id", QString()).toInt(); @@ -1026,15 +1031,75 @@ void Messenger::uploadProfilePhoto(QImage &&tosend, const PeerId &peerId) { Auth().uploader().uploadMedia(newId, ready); } -void Messenger::setupPasscode() { - _window->setupPasscode(); - _passcodedChanged.notify(); +void Messenger::lockByPasscode() { + _passcodeLock = true; + _window->setupPasscodeLock(); } -void Messenger::clearPasscode() { +void Messenger::unlockPasscode() { cSetPasscodeBadTries(0); - _window->clearPasscode(); - _passcodedChanged.notify(); + _window->clearPasscodeLock(); + _passcodeLock = false; +} + +bool Messenger::passcodeLocked() const { + return _passcodeLock.current(); +} + +rpl::producer Messenger::passcodeLockChanges() const { + return _passcodeLock.changes(); +} + +rpl::producer Messenger::passcodeLockValue() const { + return _passcodeLock.value(); +} + +void Messenger::lockByTerms(const Window::TermsLock &data) { + if (!_termsLock || *_termsLock != data) { + _termsLock = std::make_unique(data); + _termsLockChanges.fire(true); + } +} + +void Messenger::unlockTerms() { + if (_termsLock) { + _termsLock = nullptr; + _termsLockChanges.fire(false); + } +} + +base::optional Messenger::termsLocked() const { + return _termsLock ? base::make_optional(*_termsLock) : base::none; +} + +rpl::producer Messenger::termsLockChanges() const { + return _termsLockChanges.events(); +} + +rpl::producer Messenger::termsLockValue() const { + return rpl::single( + _termsLock != nullptr + ) | rpl::then(termsLockChanges()); +} + +void Messenger::termsDeleteNow() { + MTP::send(MTPaccount_DeleteAccount(MTP_string("Decline ToS update"))); +} + +bool Messenger::locked() const { + return passcodeLocked() || termsLocked(); +} + +rpl::producer Messenger::lockChanges() const { + return lockValue() | rpl::skip(1); +} + +rpl::producer Messenger::lockValue() const { + using namespace rpl::mappers; + return rpl::combine( + passcodeLockValue(), + termsLockValue(), + _1 || _2); } Messenger::~Messenger() { diff --git a/Telegram/SourceFiles/messenger.h b/Telegram/SourceFiles/messenger.h index 101569f686..6acab14f5c 100644 --- a/Telegram/SourceFiles/messenger.h +++ b/Telegram/SourceFiles/messenger.h @@ -23,6 +23,10 @@ namespace Core { class Launcher; } // namespace Core +namespace Window { +struct TermsLock; +} // namespace Window + namespace App { void quit(); } // namespace App @@ -168,11 +172,22 @@ public: void forceLogOut(const TextWithEntities &explanation); void checkLocalTime(); - void setupPasscode(); - void clearPasscode(); - base::Observable &passcodedChanged() { - return _passcodedChanged; - } + void lockByPasscode(); + void unlockPasscode(); + [[nodiscard]] bool passcodeLocked() const; + rpl::producer passcodeLockChanges() const; + rpl::producer passcodeLockValue() const; + + void lockByTerms(const Window::TermsLock &data); + void unlockTerms(); + [[nodiscard]] base::optional termsLocked() const; + rpl::producer termsLockChanges() const; + rpl::producer termsLockValue() const; + void termsDeleteNow(); + + [[nodiscard]] bool locked() const; + rpl::producer lockChanges() const; + rpl::producer lockValue() const; void registerLeaveSubscription(QWidget *widget); void unregisterLeaveSubscription(QWidget *widget); @@ -253,6 +268,10 @@ private: QImage _logo; QImage _logoNoMargin; + rpl::variable _passcodeLock; + rpl::event_stream _termsLockChanges; + std::unique_ptr _termsLock; + base::DelayedCallTimer _callDelayedTimer; struct LeaveSubscription { diff --git a/Telegram/SourceFiles/mtproto/special_config_request.cpp b/Telegram/SourceFiles/mtproto/special_config_request.cpp index 4b95aa5cba..d5c0be016d 100644 --- a/Telegram/SourceFiles/mtproto/special_config_request.cpp +++ b/Telegram/SourceFiles/mtproto/special_config_request.cpp @@ -161,7 +161,9 @@ void ServiceWebRequest::destroy() { } ServiceWebRequest::~ServiceWebRequest() { - destroy(); + if (reply) { + reply->deleteLater(); + } } SpecialConfigRequest::SpecialConfigRequest( diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp deleted file mode 100644 index e60c23aca1..0000000000 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "passcodewidget.h" - -#include "lang/lang_keys.h" -#include "storage/localstorage.h" -#include "mainwindow.h" -#include "messenger.h" -#include "ui/text/text.h" -#include "ui/widgets/buttons.h" -#include "ui/widgets/input_fields.h" -#include "styles/style_boxes.h" -#include "window/window_slide_animation.h" -#include "window/window_controller.h" -#include "auth_session.h" - -PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent) -, _passcode(this, st::passcodeInput, langFactory(lng_passcode_ph)) -, _submit(this, langFactory(lng_passcode_submit), st::passcodeSubmit) -, _logout(this, lang(lng_passcode_logout)) { - connect(_passcode, &Ui::MaskedInputField::changed, [=] { changed(); }); - connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); }); - - _submit->setClickedCallback([=] { submit(); }); - _logout->setClickedCallback([] { App::wnd()->onLogout(); }); - - show(); -} - -void PasscodeWidget::submit() { - if (_passcode->text().isEmpty()) { - _passcode->showError(); - return; - } - if (!passcodeCanTry()) { - _error = lang(lng_flood_error); - _passcode->showError(); - update(); - return; - } - - if (App::main()) { - if (Local::checkPasscode(_passcode->text().toUtf8())) { - Messenger::Instance().clearPasscode(); // Destroys this widget. - return; - } else { - cSetPasscodeBadTries(cPasscodeBadTries() + 1); - cSetPasscodeLastTry(getms(true)); - error(); - return; - } - } else { - if (Local::readMap(_passcode->text().toUtf8()) != Local::ReadMapPassNeeded) { - cSetPasscodeBadTries(0); - - Messenger::Instance().startMtp(); - if (AuthSession::Exists()) { - App::wnd()->setupMain(); - } else { - App::wnd()->setupIntro(); - } - } else { - cSetPasscodeBadTries(cPasscodeBadTries() + 1); - cSetPasscodeLastTry(getms(true)); - error(); - return; - } - } -} - -void PasscodeWidget::error() { - _error = lang(lng_passcode_wrong); - _passcode->selectAll(); - _passcode->showError(); - update(); -} - -void PasscodeWidget::changed() { - if (!_error.isEmpty()) { - _error = QString(); - update(); - } -} - -void PasscodeWidget::showAnimated(const QPixmap &bgAnimCache, bool back) { - _showBack = back; - (_showBack ? _cacheOver : _cacheUnder) = bgAnimCache; - - _a_show.finish(); - - showAll(); - setInnerFocus(); - _passcode->finishAnimating(); - (_showBack ? _cacheUnder : _cacheOver) = Ui::GrabWidget(this); - hideAll(); - - _a_show.start( - [this] { animationCallback(); }, - 0., - 1., - st::slideDuration, - Window::SlideAnimation::transition()); - show(); -} - -void PasscodeWidget::animationCallback() { - update(); - if (!_a_show.animating()) { - showAll(); - if (App::wnd()) App::wnd()->setInnerFocus(); - - Ui::showChatsList(); - - _cacheUnder = _cacheOver = QPixmap(); - } -} - -void PasscodeWidget::showAll() { - _passcode->show(); - _submit->show(); - _logout->show(); -} - -void PasscodeWidget::hideAll() { - _passcode->hide(); - _submit->hide(); - _logout->hide(); -} - -void PasscodeWidget::paintEvent(QPaintEvent *e) { - bool trivial = (rect() == e->rect()); - setMouseTracking(true); - - Painter p(this); - if (!trivial) { - p.setClipRect(e->rect()); - } - - auto progress = _a_show.current(getms(), 1.); - if (_a_show.animating()) { - auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress); - auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress); - auto shadow = _showBack ? (1. - progress) : progress; - if (coordOver > 0) { - p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * cRetinaFactor(), 0, coordOver * cRetinaFactor(), height() * cRetinaFactor())); - p.setOpacity(shadow); - p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg); - p.setOpacity(1); - } - p.drawPixmap(coordOver, 0, _cacheOver); - p.setOpacity(shadow); - st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height())); - } else { - p.fillRect(rect(), st::windowBg); - - p.setFont(st::passcodeHeaderFont); - p.setPen(st::windowFg); - p.drawText(QRect(0, _passcode->y() - st::passcodeHeaderHeight, width(), st::passcodeHeaderHeight), lang(lng_passcode_enter), style::al_center); - - if (!_error.isEmpty()) { - p.setFont(st::boxTextFont); - p.setPen(st::boxTextFgError); - p.drawText(QRect(0, _passcode->y() + _passcode->height(), width(), st::passcodeSubmitSkip), _error, style::al_center); - } - } -} - -void PasscodeWidget::resizeEvent(QResizeEvent *e) { - _passcode->move((width() - _passcode->width()) / 2, (height() / 3)); - _submit->move(_passcode->x(), _passcode->y() + _passcode->height() + st::passcodeSubmitSkip); - _logout->move(_passcode->x() + (_passcode->width() - _logout->width()) / 2, _submit->y() + _submit->height() + st::linkFont->ascent); -} - -void PasscodeWidget::setInnerFocus() { - if (auto controller = App::wnd()->controller()) { - controller->dialogsListFocused().set(false, true); - } - _passcode->setFocusFast(); -} diff --git a/Telegram/SourceFiles/passcodewidget.h b/Telegram/SourceFiles/passcodewidget.h deleted file mode 100644 index e6f1d5c82b..0000000000 --- a/Telegram/SourceFiles/passcodewidget.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -namespace Ui { -class PasswordInput; -class LinkButton; -class RoundButton; -} // namespace Ui - -class PasscodeWidget : public TWidget { -public: - PasscodeWidget(QWidget *parent); - - void setInnerFocus(); - - void showAnimated(const QPixmap &bgAnimCache, bool back = false); - -protected: - void paintEvent(QPaintEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - -private: - void animationCallback(); - void changed(); - void submit(); - void error(); - - void showAll(); - void hideAll(); - - Animation _a_show; - bool _showBack = false; - QPixmap _cacheUnder, _cacheOver; - - object_ptr _passcode; - object_ptr _submit; - object_ptr _logout; - QString _error; - -}; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index ea895dd1c0..69e4b6cd38 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "mainwidget.h" #include "application.h" +#include "messenger.h" #include "history/history.h" #include "history/history_widget.h" #include "history/history_inner_widget.h" @@ -675,7 +676,7 @@ void MainWindow::updateGlobalMenuHook() { if (!App::wnd() || !positionInited()) return; auto focused = QApplication::focusWidget(); - bool isLogged = !!App::self(), canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false; + bool canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false; auto clipboardHasText = _private->clipboardHasText(); if (auto edit = qobject_cast(focused)) { canCut = canCopy = canDelete = edit->hasSelectedText(); @@ -694,7 +695,10 @@ void MainWindow::updateGlobalMenuHook() { canDelete = list->canDeleteSelected(); } App::wnd()->updateIsActive(0); - _forceDisabled(psLogout, !isLogged && !App::passcoded()); + const auto logged = !!App::self(); + const auto locked = !Messenger::Instance().locked(); + const auto inactive = !logged || locked; + _forceDisabled(psLogout, !logged && !locked); _forceDisabled(psUndo, !canUndo); _forceDisabled(psRedo, !canRedo); _forceDisabled(psCut, !canCut); @@ -702,10 +706,10 @@ void MainWindow::updateGlobalMenuHook() { _forceDisabled(psPaste, !canPaste); _forceDisabled(psDelete, !canDelete); _forceDisabled(psSelectAll, !canSelectAll); - _forceDisabled(psContacts, !isLogged || App::passcoded()); - _forceDisabled(psAddContact, !isLogged || App::passcoded()); - _forceDisabled(psNewGroup, !isLogged || App::passcoded()); - _forceDisabled(psNewChannel, !isLogged || App::passcoded()); + _forceDisabled(psContacts, inactive); + _forceDisabled(psAddContact, inactive); + _forceDisabled(psNewGroup, inactive); + _forceDisabled(psNewChannel, inactive); _forceDisabled(psShowTelegram, App::wnd()->isActive()); } diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index c549f061f5..ddc90bbed9 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -13,7 +13,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_widget.h" #include "core/crash_reports.h" #include "storage/localstorage.h" -#include "passcodewidget.h" #include "mainwindow.h" #include "history/history_location_manager.h" #include "platform/mac/mac_utilities.h" diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 8495050ef8..d74481ef68 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -800,10 +800,14 @@ void MainWindow::psFirstShow() { setWindowState(Qt::WindowMaximized); } - if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized() && !App::passcoded()) || cStartInTray()) { + if (cStartInTray() + || (cLaunchMode() == LaunchModeAutoStart + && cStartMinimized() + && !Messenger::Instance().passcodeLocked())) { DEBUG_LOG(("Window Pos: First show, setting minimized after.")); setWindowState(Qt::WindowMinimized); - if (Global::WorkMode().value() == dbiwmTrayOnly || Global::WorkMode().value() == dbiwmWindowAndTray) { + if (Global::WorkMode().value() == dbiwmTrayOnly + || Global::WorkMode().value() == dbiwmWindowAndTray) { hide(); } else { show(); diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index e49048f6e6..e25838e62b 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -17,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "history/history_location_manager.h" #include "storage/localstorage.h" -#include "passcodewidget.h" #include "core/crash_reports.h" #include diff --git a/Telegram/SourceFiles/shortcuts.cpp b/Telegram/SourceFiles/shortcuts.cpp index 13f8bbbc90..34b62ea5d8 100644 --- a/Telegram/SourceFiles/shortcuts.cpp +++ b/Telegram/SourceFiles/shortcuts.cpp @@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "shortcuts.h" #include "mainwindow.h" -#include "passcodewidget.h" #include "mainwidget.h" #include "messenger.h" #include "media/player/media_player_instance.h" @@ -20,8 +19,9 @@ namespace ShortcutCommands { using Handler = bool(*)(); bool lock_telegram() { - if (!App::passcoded() && Global::LocalPasscode()) { - Messenger::Instance().setupPasscode(); + if (!Messenger::Instance().passcodeLocked() + && Global::LocalPasscode()) { + Messenger::Instance().lockByPasscode(); return true; } return false; diff --git a/Telegram/SourceFiles/ui/widgets/popup_menu.cpp b/Telegram/SourceFiles/ui/widgets/popup_menu.cpp index e808d1367a..b56767f647 100644 --- a/Telegram/SourceFiles/ui/widgets/popup_menu.cpp +++ b/Telegram/SourceFiles/ui/widgets/popup_menu.cpp @@ -16,14 +16,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { -PopupMenu::PopupMenu(QWidget*, const style::PopupMenu &st) : TWidget(nullptr) -, _st(st) +PopupMenu::PopupMenu(QWidget*, const style::PopupMenu &st) +: _st(st) , _menu(this, _st.menu) { init(); } -PopupMenu::PopupMenu(QWidget*, QMenu *menu, const style::PopupMenu &st) : TWidget(nullptr) -, _st(st) +PopupMenu::PopupMenu(QWidget*, QMenu *menu, const style::PopupMenu &st) +: _st(st) , _menu(this, menu, _st.menu) { init(); @@ -36,11 +36,14 @@ PopupMenu::PopupMenu(QWidget*, QMenu *menu, const style::PopupMenu &st) : TWidge } void PopupMenu::init() { - subscribe(Messenger::Instance().passcodedChanged(), [this] { - if (App::passcoded()) { - hideMenu(true); - } - }); + using namespace rpl::mappers; + + rpl::merge( + Messenger::Instance().passcodeLockChanges(), + Messenger::Instance().termsLockChanges() + ) | rpl::start_with_next([=] { + hideMenu(true); + }, lifetime()); _menu->setResizedCallback([this] { handleMenuResize(); }); _menu->setActivatedCallback([this](QAction *action, int actionTop, TriggeredSource source) { diff --git a/Telegram/SourceFiles/ui/widgets/popup_menu.h b/Telegram/SourceFiles/ui/widgets/popup_menu.h index 0b9a6c7652..99da81690b 100644 --- a/Telegram/SourceFiles/ui/widgets/popup_menu.h +++ b/Telegram/SourceFiles/ui/widgets/popup_menu.h @@ -8,12 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "styles/style_widgets.h" +#include "ui/rp_widget.h" #include "ui/widgets/menu.h" #include "ui/effects/panel_animation.h" namespace Ui { -class PopupMenu : public TWidget, private base::Subscriber { +class PopupMenu : public Ui::RpWidget, private base::Subscriber { public: PopupMenu(QWidget*, const style::PopupMenu &st = st::defaultPopupMenu); PopupMenu(QWidget*, QMenu *menu, const style::PopupMenu &st = st::defaultPopupMenu); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 8298c687b2..cf6ecf3de3 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -8,14 +8,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/main_window.h" #include "storage/localstorage.h" -#include "styles/style_window.h" #include "platform/platform_window_title.h" #include "history/history.h" #include "window/themes/window_theme.h" #include "window/window_controller.h" +#include "window/window_lock_widgets.h" +#include "boxes/confirm_box.h" +#include "core/click_handler_types.h" +#include "lang/lang_keys.h" #include "mediaview.h" +#include "auth_session.h" +#include "apiwrap.h" #include "messenger.h" #include "mainwindow.h" +#include "styles/style_window.h" +#include "styles/style_boxes.h" namespace Window { @@ -64,10 +71,94 @@ MainWindow::MainWindow() subscribe(Messenger::Instance().authSessionChanged(), [this] { checkAuthSession(); }); checkAuthSession(); + Messenger::Instance().termsLockValue( + ) | rpl::start_with_next([=] { + checkLockByTerms(); + }, lifetime()); + _isActiveTimer.setCallback([this] { updateIsActive(0); }); _inactivePressTimer.setCallback([this] { setInactivePress(false); }); } +void MainWindow::checkLockByTerms() { + const auto data = Messenger::Instance().termsLocked(); + if (!data || !AuthSession::Exists()) { + if (_termsBox) { + _termsBox->closeBox(); + } + return; + } + Ui::hideSettingsAndLayer(anim::type::instant); + const auto box = Ui::show(Box( + *data, + langFactory(lng_terms_agree), + langFactory(lng_terms_decline))); + + box->setCloseByEscape(false); + box->setCloseByOutsideClick(false); + + const auto id = data->id; + box->agreeClicks( + ) | rpl::start_with_next([=] { + const auto mention = box ? box->lastClickedMention() : QString(); + if (AuthSession::Exists()) { + Auth().api().acceptTerms(id); + if (!mention.isEmpty()) { + MentionClickHandler(mention).onClick(Qt::LeftButton); + } + } + Messenger::Instance().unlockTerms(); + }, box->lifetime()); + + box->cancelClicks( + ) | rpl::start_with_next([=] { + showTermsDecline(); + }, box->lifetime()); + + connect(box, &QObject::destroyed, [=] { + crl::on_main(this, [=] { checkLockByTerms(); }); + }); + + _termsBox = box; +} + +void MainWindow::showTermsDecline() { + const auto box = Ui::show( + Box( + TextWithEntities{ lang(lng_terms_update_sorry) }, + langFactory(lng_terms_decline_and_delete), + langFactory(lng_terms_back), + true), + LayerOption::KeepOther); + + box->agreeClicks( + ) | rpl::start_with_next([=] { + if (box) { + box->closeBox(); + } + showTermsDelete(); + }, box->lifetime()); + + box->cancelClicks( + ) | rpl::start_with_next([=] { + if (box) { + box->closeBox(); + } + }, box->lifetime()); +} + +void MainWindow::showTermsDelete() { + const auto box = std::make_shared>(); + *box = Ui::show( + Box( + lang(lng_terms_delete_warning), + lang(lng_terms_delete_now), + st::attentionBoxButton, + [=] { Messenger::Instance().termsDeleteNow(); }, + [=] { if (*box) (*box)->closeBox(); }), + LayerOption::KeepOther); +} + bool MainWindow::hideNoQuit() { if (App::quitting()) { return false; @@ -238,7 +329,7 @@ rpl::producer<> MainWindow::leaveEvents() const { return _leaveEvents.events(); } -void MainWindow::leaveEvent(QEvent *e) { +void MainWindow::leaveEventHook(QEvent *e) { _leaveEvents.fire({}); } diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 1fec65f06b..1c8834840c 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -7,22 +7,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include #include "window/window_title.h" +#include "ui/rp_widget.h" #include "base/timer.h" +class BoxContent; class MediaView; namespace Window { class Controller; class TitleWidget; +struct TermsLock; QImage LoadLogo(); QImage LoadLogoNoMargin(); QIcon CreateIcon(); -class MainWindow : public QWidget, protected base::Subscriber { +class MainWindow : public Ui::RpWidget, protected base::Subscriber { Q_OBJECT public: @@ -89,7 +91,7 @@ public slots: protected: void resizeEvent(QResizeEvent *e) override; - void leaveEvent(QEvent *e) override; + void leaveEventHook(QEvent *e) override; void savePosition(Qt::WindowState state = Qt::WindowActive); void handleStateChanged(Qt::WindowState state); @@ -149,6 +151,9 @@ private: void initSize(); bool computeIsActive() const; + void checkLockByTerms(); + void showTermsDecline(); + void showTermsDelete(); base::Timer _positionUpdatedTimer; bool _positionInited = false; @@ -157,6 +162,7 @@ private: object_ptr _title = { nullptr }; object_ptr _body; object_ptr _rightColumn = { nullptr }; + QPointer _termsBox; QIcon _icon; QString _titleText; diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 7a6ab813bd..d82d2d0d01 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_controller.h" #include "mainwindow.h" #include "mainwidget.h" +#include "messenger.h" #include "apiwrap.h" #include "auth_session.h" @@ -380,7 +381,8 @@ void System::updateAll() { } Manager::DisplayOptions Manager::getNotificationOptions(HistoryItem *item) { - auto hideEverything = (App::passcoded() || Global::ScreenIsLocked()); + const auto hideEverything = Messenger::Instance().locked() + || Global::ScreenIsLocked(); DisplayOptions result; result.hideNameAndPhoto = hideEverything || (Global::NotifyView() > dbinvShowName); @@ -395,7 +397,7 @@ void Manager::notificationActivated(PeerId peerId, MsgId msgId) { auto history = App::history(peerId); window->showFromTray(); window->reActivateWindow(); - if (App::passcoded()) { + if (Messenger::Instance().locked()) { window->setInnerFocus(); system()->clearAll(); } else { diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index ec634a61ec..ffd5131717 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -727,7 +727,10 @@ bool Notification::unlinkItem(HistoryItem *deleted) { } bool Notification::canReply() const { - return !_hideReplyButton && (_item != nullptr) && !App::passcoded() && (Global::NotifyView() <= dbinvShowPreview); + return !_hideReplyButton + && (_item != nullptr) + && !Messenger::Instance().locked() + && (Global::NotifyView() <= dbinvShowPreview); } void Notification::unlinkHistoryInManager() { diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp new file mode 100644 index 0000000000..8222c784e5 --- /dev/null +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -0,0 +1,357 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "window/window_lock_widgets.h" + +#include "lang/lang_keys.h" +#include "storage/localstorage.h" +#include "mainwindow.h" +#include "messenger.h" +#include "ui/text/text.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/input_fields.h" +#include "ui/widgets/labels.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/toast/toast.h" +#include "styles/style_boxes.h" +#include "window/window_slide_animation.h" +#include "window/window_controller.h" +#include "auth_session.h" + +namespace Window { + +LockWidget::LockWidget(QWidget *parent) : RpWidget(parent) { + show(); +} + +void LockWidget::setInnerFocus() { + if (const auto controller = App::wnd()->controller()) { + controller->dialogsListFocused().set(false, true); + } + setFocus(); +} + +void LockWidget::showAnimated(const QPixmap &bgAnimCache, bool back) { + _showBack = back; + (_showBack ? _cacheOver : _cacheUnder) = bgAnimCache; + + _a_show.finish(); + + showChildren(); + setInnerFocus(); + (_showBack ? _cacheUnder : _cacheOver) = Ui::GrabWidget(this); + hideChildren(); + + _a_show.start( + [this] { animationCallback(); }, + 0., + 1., + st::slideDuration, + Window::SlideAnimation::transition()); + show(); +} + +void LockWidget::animationCallback() { + update(); + if (!_a_show.animating()) { + showChildren(); + if (App::wnd()) App::wnd()->setInnerFocus(); + + Ui::showChatsList(); + + _cacheUnder = _cacheOver = QPixmap(); + } +} + +void LockWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto progress = _a_show.current(getms(), 1.); + if (_a_show.animating()) { + auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress); + auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress); + auto shadow = _showBack ? (1. - progress) : progress; + if (coordOver > 0) { + p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * cRetinaFactor(), 0, coordOver * cRetinaFactor(), height() * cRetinaFactor())); + p.setOpacity(shadow); + p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg); + p.setOpacity(1); + } + p.drawPixmap(coordOver, 0, _cacheOver); + p.setOpacity(shadow); + st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height())); + } else { + paintContent(p); + } +} + +void LockWidget::paintContent(Painter &p) { + p.fillRect(rect(), st::windowBg); +} + +PasscodeLockWidget::PasscodeLockWidget(QWidget *parent) +: LockWidget(parent) +, _passcode(this, st::passcodeInput, langFactory(lng_passcode_ph)) +, _submit(this, langFactory(lng_passcode_submit), st::passcodeSubmit) +, _logout(this, lang(lng_passcode_logout)) { + connect(_passcode, &Ui::MaskedInputField::changed, [=] { changed(); }); + connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); }); + + _submit->setClickedCallback([=] { submit(); }); + _logout->setClickedCallback([] { App::wnd()->onLogout(); }); +} + +void PasscodeLockWidget::paintContent(Painter &p) { + LockWidget::paintContent(p); + + p.setFont(st::passcodeHeaderFont); + p.setPen(st::windowFg); + p.drawText(QRect(0, _passcode->y() - st::passcodeHeaderHeight, width(), st::passcodeHeaderHeight), lang(lng_passcode_enter), style::al_center); + + if (!_error.isEmpty()) { + p.setFont(st::boxTextFont); + p.setPen(st::boxTextFgError); + p.drawText(QRect(0, _passcode->y() + _passcode->height(), width(), st::passcodeSubmitSkip), _error, style::al_center); + } +} + +void PasscodeLockWidget::submit() { + if (_passcode->text().isEmpty()) { + _passcode->showError(); + return; + } + if (!passcodeCanTry()) { + _error = lang(lng_flood_error); + _passcode->showError(); + update(); + return; + } + + if (App::main()) { + if (Local::checkPasscode(_passcode->text().toUtf8())) { + Messenger::Instance().unlockPasscode(); // Destroys this widget. + return; + } else { + cSetPasscodeBadTries(cPasscodeBadTries() + 1); + cSetPasscodeLastTry(getms(true)); + error(); + return; + } + } else { + if (Local::readMap(_passcode->text().toUtf8()) != Local::ReadMapPassNeeded) { + cSetPasscodeBadTries(0); + + Messenger::Instance().startMtp(); + + // Destroys this widget. + if (AuthSession::Exists()) { + App::wnd()->setupMain(); + } else { + App::wnd()->setupIntro(); + } + } else { + cSetPasscodeBadTries(cPasscodeBadTries() + 1); + cSetPasscodeLastTry(getms(true)); + error(); + return; + } + } +} + +void PasscodeLockWidget::error() { + _error = lang(lng_passcode_wrong); + _passcode->selectAll(); + _passcode->showError(); + update(); +} + +void PasscodeLockWidget::changed() { + if (!_error.isEmpty()) { + _error = QString(); + update(); + } +} + +void PasscodeLockWidget::resizeEvent(QResizeEvent *e) { + _passcode->move((width() - _passcode->width()) / 2, (height() / 3)); + _submit->move(_passcode->x(), _passcode->y() + _passcode->height() + st::passcodeSubmitSkip); + _logout->move(_passcode->x() + (_passcode->width() - _logout->width()) / 2, _submit->y() + _submit->height() + st::linkFont->ascent); +} + +void PasscodeLockWidget::setInnerFocus() { + LockWidget::setInnerFocus(); + _passcode->setFocusFast(); +} + +TermsLock TermsLock::FromMTP(const MTPDhelp_termsOfService &data) { + return { + bytes::make_vector(data.vid.c_dataJSON().vdata.v), + TextWithEntities { + TextUtilities::Clean(qs(data.vtext)), + TextUtilities::EntitiesFromMTP(data.ventities.v) }, + (data.has_min_age_confirm() + ? base::make_optional(data.vmin_age_confirm.v) + : base::none), + data.is_popup() + }; +} + +TermsBox::TermsBox( + QWidget*, + const TermsLock &data, + Fn agree, + Fn cancel) +: _data(data) +, _agree(agree) +, _cancel(cancel) { +} + +TermsBox::TermsBox( + QWidget*, + const TextWithEntities &text, + Fn agree, + Fn cancel, + bool attentionAgree) +: _data{ {}, text, base::none, false } +, _agree(agree) +, _cancel(cancel) +, _attentionAgree(attentionAgree) { +} + +rpl::producer<> TermsBox::agreeClicks() const { + return _agreeClicks.events(); +} + +rpl::producer<> TermsBox::cancelClicks() const { + return _cancelClicks.events(); +} + +void TermsBox::prepare() { + setTitle(langFactory(lng_terms_header)); + + auto check = std::make_unique(st::defaultCheck, false); + const auto ageCheck = check.get(); + const auto age = _data.minAge + ? Ui::CreateChild>( + this, + object_ptr( + this, + lng_terms_age(lt_count, *_data.minAge), + st::defaultCheckbox, + std::move(check)), + st::termsAgePadding) + : nullptr; + if (age) { + age->resizeToNaturalWidth(st::boxWideWidth); + } + + const auto content = setInnerWidget( + object_ptr>( + this, + object_ptr ( + this, + rpl::single(_data.text), + st::termsContent), + st::termsPadding), + 0, + age ? age->height() : 0); + content->entity()->setClickHandlerHook([=]( + const ClickHandlerPtr &handler, + Qt::MouseButton button) { + const auto link = handler + ? handler->copyToClipboardText() + : QString(); + if (TextUtilities::RegExpMention().match(link).hasMatch()) { + _lastClickedMention = link; + Ui::Toast::Show(lng_terms_agree_to_proceed(lt_bot, link)); + return false; + } + return true; + }); + + const auto errorAnimationCallback = [=] { + // lambda 'this' gets deleted in _ageErrorAnimation.current() call. + const auto check = ageCheck; + const auto error = _ageErrorAnimation.current( + _ageErrorShown ? 1. : 0.); + if (error == 0.) { + check->setUntoggledOverride(base::none); + } else { + const auto color = anim::color( + st::defaultCheck.untoggledFg, + st::boxTextFgError, + error); + check->setUntoggledOverride(color); + } + }; + const auto toggleAgeError = [=](bool shown) { + if (_ageErrorShown != shown) { + _ageErrorShown = shown; + _ageErrorAnimation.start( + [=] { errorAnimationCallback(); }, + _ageErrorShown ? 0. : 1., + _ageErrorShown ? 1. : 0., + st::defaultCheck.duration); + } + }; + + const auto &agreeStyle = _attentionAgree + ? st::attentionBoxButton + : st::defaultBoxButton; + addButton(_agree, [=] {}, agreeStyle)->clicks( + ) | rpl::filter([=] { + if (age && !age->entity()->checked()) { + toggleAgeError(true); + return false; + } + return true; + }) | rpl::start_to_stream(_agreeClicks, lifetime()); + + if (_cancel) { + addButton(_cancel, [=] {})->clicks( + ) | rpl::start_to_stream(_cancelClicks, lifetime()); + } + + if (age) { + base::ObservableViewer( + age->entity()->checkedChanged + ) | rpl::start_with_next([=] { + toggleAgeError(false); + }, lifetime()); + + heightValue( + ) | rpl::start_with_next([=](int height) { + age->moveToLeft(0, height - age->height()); + }, age->lifetime()); + } + + content->resizeToWidth(st::boxWideWidth); + + using namespace rpl::mappers; + rpl::combine( + content->heightValue(), + age ? age->heightValue() : rpl::single(0), + _1 + _2 + ) | rpl::start_with_next([=](int height) { + setDimensions(st::boxWideWidth, height); + }, content->lifetime()); +} + +void TermsBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + _agreeClicks.fire({}); + } else { + BoxContent::keyPressEvent(e); + } +} + +QString TermsBox::lastClickedMention() const { + return _lastClickedMention; +} + +} // namespace Window diff --git a/Telegram/SourceFiles/window/window_lock_widgets.h b/Telegram/SourceFiles/window/window_lock_widgets.h new file mode 100644 index 0000000000..f04e64debc --- /dev/null +++ b/Telegram/SourceFiles/window/window_lock_widgets.h @@ -0,0 +1,120 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/rp_widget.h" +#include "boxes/abstract_box.h" +#include "base/bytes.h" + +namespace Ui { +class PasswordInput; +class LinkButton; +class RoundButton; +class CheckView; +} // namespace Ui + +namespace Window { + +class LockWidget : public Ui::RpWidget { +public: + LockWidget(QWidget *parent); + + virtual void setInnerFocus(); + + void showAnimated(const QPixmap &bgAnimCache, bool back = false); + +protected: + void paintEvent(QPaintEvent *e) override; + virtual void paintContent(Painter &p); + +private: + void animationCallback(); + + Animation _a_show; + bool _showBack = false; + QPixmap _cacheUnder, _cacheOver; + +}; + +class PasscodeLockWidget : public LockWidget { +public: + PasscodeLockWidget(QWidget *parent); + + void setInnerFocus() override; + +protected: + void resizeEvent(QResizeEvent *e) override; + +private: + void paintContent(Painter &p) override; + void changed(); + void submit(); + void error(); + + object_ptr _passcode; + object_ptr _submit; + object_ptr _logout; + QString _error; + +}; + +struct TermsLock { + bytes::vector id; + TextWithEntities text; + base::optional minAge; + bool popup = false; + + inline bool operator==(const TermsLock &other) const { + return (id == other.id); + } + inline bool operator!=(const TermsLock &other) const { + return !(*this == other); + } + + static TermsLock FromMTP(const MTPDhelp_termsOfService &data); + +}; + +class TermsBox : public BoxContent { +public: + TermsBox( + QWidget*, + const TermsLock &data, + Fn agree, + Fn cancel); + TermsBox( + QWidget*, + const TextWithEntities &text, + Fn agree, + Fn cancel, + bool attentionAgree = false); + + rpl::producer<> agreeClicks() const; + rpl::producer<> cancelClicks() const; + QString lastClickedMention() const; + +protected: + void prepare() override; + + void keyPressEvent(QKeyEvent *e) override; + +private: + TermsLock _data; + Fn _agree; + Fn _cancel; + rpl::event_stream<> _agreeClicks; + rpl::event_stream<> _cancelClicks; + QString _lastClickedMention; + bool _attentionAgree = false; + + bool _ageErrorShown = false; + Animation _ageErrorAnimation; + +}; + +} // namespace Window diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index e21be3b601..b980b4cdae 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -729,6 +729,8 @@ <(src_loc)/window/window_connecting_widget.h <(src_loc)/window/window_controller.cpp <(src_loc)/window/window_controller.h +<(src_loc)/window/window_lock_widgets.cpp +<(src_loc)/window/window_lock_widgets.h <(src_loc)/window/window_main_menu.cpp <(src_loc)/window/window_main_menu.h <(src_loc)/window/window_peer_menu.cpp @@ -773,8 +775,6 @@ <(src_loc)/messenger.h <(src_loc)/observer_peer.cpp <(src_loc)/observer_peer.h -<(src_loc)/passcodewidget.cpp -<(src_loc)/passcodewidget.h <(src_loc)/qt_static_plugins.cpp <(src_loc)/settings.cpp <(src_loc)/settings.h