diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7d6c592f2..a391f3644 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 6608f80aa..3c0cf8346 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 01d4f0e43..8bcf55380 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 43446958d..dd9c3b912 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 021a3e582..9c0827b6d 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 067c64e1b..919148700 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 8ce8b33c1..1fda773cf 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 9bafa7d21..00a7df15f 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 e22dccd87..0a355b0ab 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 dd3e54f99..b2fc6578f 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 12658c91b..ade50f263 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 9b321e99e..19535cd8f 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 4dd855cb5..16492d0ae 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 17287a0bb..b5a8c8dc1 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 9de0d9443..ef58c1fec 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 1db6ae7fe..74d5144c2 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 732733d82..57cb367aa 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 5f46065f5..c9c6d721b 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 06e577178..13b084a19 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 101569f68..6acab14f5 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 4b95aa5cb..d5c0be016 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 e60c23aca..000000000 --- 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 e6f1d5c82..000000000 --- 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 ea895dd1c..69e4b6cd3 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 c549f061f..ddc90bbed 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 8495050ef..d74481ef6 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 e49048f6e..e25838e62 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 13f8bbbc9..34b62ea5d 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 e808d1367..b56767f64 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 0b9a6c765..99da81690 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 8298c687b..cf6ecf3de 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 1fec65f06..1c8834840 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 7a6ab813b..d82d2d0d0 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 ec634a61e..ffd513171 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 000000000..8222c784e --- /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 000000000..f04e64deb --- /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 e21be3b60..b980b4cda 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