diff --git a/Telegram/SourceFiles/boxes/change_phone_box.cpp b/Telegram/SourceFiles/boxes/change_phone_box.cpp index edf56e2eca..b63d7fba6e 100644 --- a/Telegram/SourceFiles/boxes/change_phone_box.cpp +++ b/Telegram/SourceFiles/boxes/change_phone_box.cpp @@ -129,11 +129,11 @@ private: QString _hash; int _codeLength = 0; int _callTimeout = 0; - object_ptr _code = { nullptr }; + object_ptr _code = { nullptr }; object_ptr> _error = { nullptr }; object_ptr _callLabel = { nullptr }; mtpRequestId _requestId = 0; - SentCodeCall _call; + Ui::SentCodeCall _call; }; @@ -289,7 +289,7 @@ void ChangePhoneBox::EnterCode::prepare() { setDimensions(st::boxWidth, countHeight()); if (_callTimeout > 0) { - _call.setStatus({ SentCodeCall::State::Waiting, _callTimeout }); + _call.setStatus({ Ui::SentCodeCall::State::Waiting, _callTimeout }); updateCall(); } diff --git a/Telegram/SourceFiles/boxes/confirm_phone_box.cpp b/Telegram/SourceFiles/boxes/confirm_phone_box.cpp index 2584c1485e..cf531a1094 100644 --- a/Telegram/SourceFiles/boxes/confirm_phone_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_phone_box.cpp @@ -70,131 +70,6 @@ void ShowPhoneBannedError(const QString &phone) { [=] { SendToBannedHelp(phone); close(); })); } -SentCodeField::SentCodeField( - QWidget *parent, - const style::InputField &st, - rpl::producer placeholder, - const QString &val) -: Ui::InputField(parent, st, std::move(placeholder), val) { - connect(this, &Ui::InputField::changed, [this] { fix(); }); -} - -void SentCodeField::setAutoSubmit(int length, Fn submitCallback) { - _autoSubmitLength = length; - _submitCallback = std::move(submitCallback); -} - -void SentCodeField::setChangedCallback(Fn changedCallback) { - _changedCallback = std::move(changedCallback); -} - -QString SentCodeField::getDigitsOnly() const { - return QString( - getLastText() - ).remove( - QRegularExpression("[^\\d]") - ); -} - -void SentCodeField::fix() { - if (_fixing) return; - - _fixing = true; - auto newText = QString(); - const auto now = getLastText(); - auto oldPos = textCursor().position(); - auto newPos = -1; - auto oldLen = now.size(); - auto digitCount = 0; - for (const auto &ch : now) { - if (ch.isDigit()) { - ++digitCount; - } - } - - if (_autoSubmitLength > 0 && digitCount > _autoSubmitLength) { - digitCount = _autoSubmitLength; - } - auto strict = (_autoSubmitLength > 0) - && (digitCount == _autoSubmitLength); - - newText.reserve(oldLen); - int i = 0; - for (const auto &ch : now) { - if (i++ == oldPos) { - newPos = newText.length(); - } - if (ch.isDigit()) { - if (!digitCount--) { - break; - } - newText += ch; - if (strict && !digitCount) { - break; - } - } else if (ch == '-') { - newText += ch; - } - } - if (newPos < 0) { - newPos = newText.length(); - } - if (newText != now) { - setText(newText); - setCursorPosition(newPos); - } - _fixing = false; - - if (_changedCallback) { - _changedCallback(); - } - if (strict && _submitCallback) { - _submitCallback(); - } -} - -SentCodeCall::SentCodeCall( - FnMut callCallback, - Fn updateCallback) -: _call(std::move(callCallback)) -, _update(std::move(updateCallback)) { - _timer.setCallback([=] { - if (_status.state == State::Waiting) { - if (--_status.timeout <= 0) { - _status.state = State::Calling; - _timer.cancel(); - if (_call) { - _call(); - } - } - } - if (_update) { - _update(); - } - }); -} - -void SentCodeCall::setStatus(const Status &status) { - _status = status; - if (_status.state == State::Waiting) { - _timer.callEach(1000); - } -} - -QString SentCodeCall::getText() const { - switch (_status.state) { - case State::Waiting: { - if (_status.timeout >= 3600) { - return tr::lng_code_call(tr::now, lt_minutes, qsl("%1:%2").arg(_status.timeout / 3600).arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); - } - return tr::lng_code_call(tr::now, lt_minutes, QString::number(_status.timeout / 60), lt_seconds, qsl("%1").arg(_status.timeout % 60, 2, 10, QChar('0'))); - } break; - case State::Calling: return tr::lng_code_calling(tr::now); - case State::Called: return tr::lng_code_called(tr::now); - } - return QString(); -} - void ConfirmPhoneBox::Start( not_null session, const QString &phone, @@ -262,7 +137,7 @@ void ConfirmPhoneBox::sendCodeDone(const MTPauth_SentCode &result) { _phoneHash = qs(data.vphone_code_hash()); if (const auto nextType = data.vnext_type()) { if (nextType->type() == mtpc_auth_codeTypeCall) { - _call.setStatus({ SentCodeCall::State::Waiting, data.vtimeout().value_or(60) }); + _call.setStatus({ Ui::SentCodeCall::State::Waiting, data.vtimeout().value_or(60) }); } } launch(); diff --git a/Telegram/SourceFiles/boxes/confirm_phone_box.h b/Telegram/SourceFiles/boxes/confirm_phone_box.h index 5448a78f82..e5a5c193b7 100644 --- a/Telegram/SourceFiles/boxes/confirm_phone_box.h +++ b/Telegram/SourceFiles/boxes/confirm_phone_box.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" #include "base/timer.h" #include "ui/widgets/input_fields.h" +#include "ui/widgets/sent_code_field.h" #include "mtproto/sender.h" namespace Ui { @@ -23,72 +24,6 @@ class Session; void ShowPhoneBannedError(const QString &phone); -class SentCodeField : public Ui::InputField { -public: - SentCodeField( - QWidget *parent, - const style::InputField &st, - rpl::producer placeholder = nullptr, - const QString &val = QString()); - - void setAutoSubmit(int length, Fn submitCallback); - void setChangedCallback(Fn changedCallback); - QString getDigitsOnly() const; - -private: - void fix(); - - // Flag for not calling onTextChanged() recursively. - bool _fixing = false; - - int _autoSubmitLength = 0; - Fn _submitCallback; - Fn _changedCallback; - -}; - -class SentCodeCall { -public: - SentCodeCall( - FnMut callCallback, - Fn updateCallback); - - enum class State { - Waiting, - Calling, - Called, - Disabled, - }; - struct Status { - Status() { - } - Status(State state, int timeout) : state(state), timeout(timeout) { - } - - State state = State::Disabled; - int timeout = 0; - }; - void setStatus(const Status &status); - - void callDone() { - if (_status.state == State::Calling) { - _status.state = State::Called; - if (_update) { - _update(); - } - } - } - - QString getText() const; - -private: - Status _status; - base::Timer _timer; - FnMut _call; - Fn _update; - -}; - class ConfirmPhoneBox final : public Ui::BoxContent { public: static void Start( @@ -149,9 +84,9 @@ private: mtpRequestId _checkCodeRequestId = 0; object_ptr _about = { nullptr }; - object_ptr _code = { nullptr }; + object_ptr _code = { nullptr }; QString _error; - SentCodeCall _call; + Ui::SentCodeCall _call; }; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 8f3e20fad5..380ef8f800 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/bytes.h" #include "lang/lang_keys.h" #include "boxes/confirm_box.h" -#include "boxes/confirm_phone_box.h" #include "base/unixtime.h" #include "mainwindow.h" #include "apiwrap.h" @@ -24,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/labels.h" +#include "ui/widgets/sent_code_field.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/fade_wrap.h" #include "passport/passport_encryption.h" diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 4569411902..a0140c0222 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -79,7 +79,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/qthelp_regex.h" #include "base/qthelp_url.h" #include "boxes/connection_box.h" -#include "boxes/confirm_phone_box.h" #include "boxes/confirm_box.h" #include "boxes/share_box.h" #include "app.h" diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index eb01b13a84..d92bb829a4 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "core/click_handler_types.h" #include "ui/toast/toast.h" +#include "ui/widgets/sent_code_field.h" #include "main/main_session.h" #include "storage/localimageloader.h" #include "storage/localstorage.h" @@ -2181,11 +2182,11 @@ void FormController::startPhoneVerification(not_null value) { value->verification.codeLength = (type.vlength().v > 0) ? type.vlength().v : -1; - value->verification.call = std::make_unique( + value->verification.call = std::make_unique( [=] { requestPhoneCall(value); }, [=] { _verificationUpdate.fire_copy(value); }); value->verification.call->setStatus( - { SentCodeCall::State::Called, 0 }); + { Ui::SentCodeCall::State::Called, 0 }); if (data.vnext_type()) { LOG(("API Error: next_type is not supported for calls.")); } @@ -2197,11 +2198,11 @@ void FormController::startPhoneVerification(not_null value) { : -1; const auto next = data.vnext_type(); if (next && next->type() == mtpc_auth_codeTypeCall) { - value->verification.call = std::make_unique( + value->verification.call = std::make_unique( [=] { requestPhoneCall(value); }, [=] { _verificationUpdate.fire_copy(value); }); value->verification.call->setStatus({ - SentCodeCall::State::Waiting, + Ui::SentCodeCall::State::Waiting, data.vtimeout().value_or(60) }); } } break; @@ -2235,7 +2236,7 @@ void FormController::requestPhoneCall(not_null value) { Expects(value->verification.call != nullptr); value->verification.call->setStatus( - { SentCodeCall::State::Calling, 0 }); + { Ui::SentCodeCall::State::Calling, 0 }); _api.request(MTPauth_ResendCode( MTP_string(getPhoneFromValue(value)), MTP_string(value->verification.phoneCodeHash) diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h index 580778f9b9..a33e180b21 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_controller.h @@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "mtproto/sender.h" -#include "boxes/confirm_phone_box.h" +#include "base/timer.h" #include "base/weak_ptr.h" #include "core/core_cloud_password.h" @@ -27,6 +27,10 @@ namespace Main { class Session; } // namespace Main +namespace Ui { +class SentCodeCall; +} // namespace Ui + namespace Passport { struct EditDocumentCountry; @@ -184,7 +188,7 @@ struct Verification { mtpRequestId requestId = 0; QString phoneCodeHash; int codeLength = 0; - std::unique_ptr call; + std::unique_ptr call; QString error; diff --git a/Telegram/SourceFiles/passport/passport_form_view_controller.h b/Telegram/SourceFiles/passport/passport_form_view_controller.h index 50d5b04e18..b2a22fbdbc 100644 --- a/Telegram/SourceFiles/passport/passport_form_view_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_view_controller.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "passport/passport_form_controller.h" #include "base/object_ptr.h" +#include "ui/layers/box_content.h" namespace Passport { diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index c0f4d20e77..eadc8e5e76 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" #include "ui/countryinput.h" #include "ui/text/format_values.h" +#include "ui/widgets/sent_code_field.h" #include "core/update_checker.h" #include "countries/countries_instance.h" #include "styles/style_layers.h" diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp index dd09661c33..86729e8cec 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" #include "ui/widgets/box_content_divider.h" +#include "ui/widgets/sent_code_field.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/fade_wrap.h" @@ -61,7 +62,7 @@ private: rpl::producer _title; Fn _submit; - QPointer _code; + QPointer _code; QPointer _content; }; @@ -109,7 +110,7 @@ void VerifyBox::setupControls( st::boxLabel), small); _code = _content->add( - object_ptr( + object_ptr( _content, st::defaultInputField, tr::lng_change_phone_code_title()), @@ -177,9 +178,9 @@ void VerifyBox::setupControls( if (codeLength > 0) { _code->setAutoSubmit(codeLength, _submit); } else { - connect(_code, &SentCodeField::submitted, _submit); + connect(_code, &Ui::SentCodeField::submitted, _submit); } - connect(_code, &SentCodeField::changed, [=] { + connect(_code, &Ui::SentCodeField::changed, [=] { problem->hide(anim::type::normal); }); } diff --git a/Telegram/SourceFiles/ui/widgets/sent_code_field.cpp b/Telegram/SourceFiles/ui/widgets/sent_code_field.cpp new file mode 100644 index 0000000000..e3a76f16e2 --- /dev/null +++ b/Telegram/SourceFiles/ui/widgets/sent_code_field.cpp @@ -0,0 +1,162 @@ +/* +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 "ui/widgets/sent_code_field.h" + +#include "lang/lang_keys.h" + +#include + +namespace Ui { + +SentCodeField::SentCodeField( + QWidget *parent, + const style::InputField &st, + rpl::producer placeholder, + const QString &val) +: Ui::InputField(parent, st, std::move(placeholder), val) { + connect(this, &Ui::InputField::changed, [this] { fix(); }); +} + +void SentCodeField::setAutoSubmit(int length, Fn submitCallback) { + _autoSubmitLength = length; + _submitCallback = std::move(submitCallback); +} + +void SentCodeField::setChangedCallback(Fn changedCallback) { + _changedCallback = std::move(changedCallback); +} + +QString SentCodeField::getDigitsOnly() const { + return QString( + getLastText() + ).remove( + QRegularExpression("[^\\d]") + ); +} + +void SentCodeField::fix() { + if (_fixing) return; + + _fixing = true; + auto newText = QString(); + const auto now = getLastText(); + auto oldPos = textCursor().position(); + auto newPos = -1; + auto oldLen = now.size(); + auto digitCount = 0; + for (const auto &ch : now) { + if (ch.isDigit()) { + ++digitCount; + } + } + + if (_autoSubmitLength > 0 && digitCount > _autoSubmitLength) { + digitCount = _autoSubmitLength; + } + const auto strict = (_autoSubmitLength > 0) + && (digitCount == _autoSubmitLength); + + newText.reserve(oldLen); + int i = 0; + for (const auto &ch : now) { + if (i++ == oldPos) { + newPos = newText.length(); + } + if (ch.isDigit()) { + if (!digitCount--) { + break; + } + newText += ch; + if (strict && !digitCount) { + break; + } + } else if (ch == '-') { + newText += ch; + } + } + if (newPos < 0) { + newPos = newText.length(); + } + if (newText != now) { + setText(newText); + setCursorPosition(newPos); + } + _fixing = false; + + if (_changedCallback) { + _changedCallback(); + } + if (strict && _submitCallback) { + _submitCallback(); + } +} + +SentCodeCall::SentCodeCall( + FnMut callCallback, + Fn updateCallback) +: _call(std::move(callCallback)) +, _update(std::move(updateCallback)) { + _timer.setCallback([=] { + if (_status.state == State::Waiting) { + if (--_status.timeout <= 0) { + _status.state = State::Calling; + _timer.cancel(); + if (_call) { + _call(); + } + } + } + if (_update) { + _update(); + } + }); +} + +void SentCodeCall::setStatus(const Status &status) { + _status = status; + if (_status.state == State::Waiting) { + _timer.callEach(1000); + } +} + +QString SentCodeCall::getText() const { + switch (_status.state) { + case State::Waiting: { + if (_status.timeout >= 3600) { + return tr::lng_code_call( + tr::now, + lt_minutes, + (u"%1:%2"_q) + .arg(_status.timeout / 3600) + .arg((_status.timeout / 60) % 60, 2, 10, QChar('0')), + lt_seconds, + (u"%1"_q).arg(_status.timeout % 60, 2, 10, QChar('0'))); + } + return tr::lng_code_call( + tr::now, + lt_minutes, + QString::number(_status.timeout / 60), + lt_seconds, + (u"%1"_q).arg(_status.timeout % 60, 2, 10, QChar('0'))); + } break; + case State::Calling: return tr::lng_code_calling(tr::now); + case State::Called: return tr::lng_code_called(tr::now); + } + return QString(); +} + +void SentCodeCall::callDone() { + if (_status.state == State::Calling) { + _status.state = State::Called; + if (_update) { + _update(); + } + } +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/sent_code_field.h b/Telegram/SourceFiles/ui/widgets/sent_code_field.h new file mode 100644 index 0000000000..12bbdb34ed --- /dev/null +++ b/Telegram/SourceFiles/ui/widgets/sent_code_field.h @@ -0,0 +1,74 @@ +/* +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 "base/timer.h" +#include "ui/widgets/input_fields.h" + +namespace Ui { + +class SentCodeField final : public Ui::InputField { +public: + SentCodeField( + QWidget *parent, + const style::InputField &st, + rpl::producer placeholder = nullptr, + const QString &val = QString()); + + void setAutoSubmit(int length, Fn submitCallback); + void setChangedCallback(Fn changedCallback); + [[nodiscard]] QString getDigitsOnly() const; + +private: + void fix(); + + // Flag for not calling onTextChanged() recursively. + bool _fixing = false; + + int _autoSubmitLength = 0; + Fn _submitCallback; + Fn _changedCallback; + +}; + +class SentCodeCall final { +public: + SentCodeCall( + FnMut callCallback, + Fn updateCallback); + + enum class State { + Waiting, + Calling, + Called, + Disabled, + }; + struct Status { + Status() { + } + Status(State state, int timeout) : state(state), timeout(timeout) { + } + + State state = State::Disabled; + int timeout = 0; + }; + void setStatus(const Status &status); + + void callDone(); + + [[nodiscard]] QString getText() const; + +private: + Status _status; + base::Timer _timer; + FnMut _call; + Fn _update; + +}; + +} // namespace Ui diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 9113d5531c..e913300d2d 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -177,8 +177,12 @@ PRIVATE ui/text/text_options.h ui/toasts/common_toasts.cpp ui/toasts/common_toasts.h + + ui/widgets/sent_code_field.cpp + ui/widgets/sent_code_field.h ui/widgets/separate_panel.cpp ui/widgets/separate_panel.h + ui/cached_round_corners.cpp ui/cached_round_corners.h ui/grouped_layout.cpp