From c20cf243dbbcdd84382b2df7dc385059854aa8ff Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 12 Apr 2018 14:20:54 +0400 Subject: [PATCH] Improve phrases and icons in passport. --- .../Resources/icons/passport_authorize.png | Bin 0 -> 362 bytes .../Resources/icons/passport_authorize@2x.png | Bin 0 -> 756 bytes Telegram/Resources/icons/passport_empty.png | Bin 0 -> 346 bytes .../Resources/icons/passport_empty@2x.png | Bin 0 -> 688 bytes Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/passport/passport.style | 7 +- .../passport/passport_encryption.cpp | 6 +- .../passport/passport_form_controller.cpp | 25 +- .../SourceFiles/passport/passport_panel.cpp | 130 ++++++-- .../passport/passport_panel_controller.cpp | 277 ++++++++++++++---- .../passport/passport_panel_controller.h | 6 + .../passport/passport_panel_details_row.h | 3 +- .../passport/passport_panel_edit_contact.cpp | 11 +- .../passport/passport_panel_edit_contact.h | 2 +- .../passport/passport_panel_edit_document.cpp | 2 +- .../passport/passport_panel_edit_document.h | 1 + .../passport/passport_panel_form.cpp | 4 +- Telegram/SourceFiles/ui/widgets/buttons.cpp | 24 +- Telegram/SourceFiles/ui/widgets/widgets.style | 3 + 19 files changed, 394 insertions(+), 109 deletions(-) create mode 100644 Telegram/Resources/icons/passport_authorize.png create mode 100644 Telegram/Resources/icons/passport_authorize@2x.png create mode 100644 Telegram/Resources/icons/passport_empty.png create mode 100644 Telegram/Resources/icons/passport_empty@2x.png diff --git a/Telegram/Resources/icons/passport_authorize.png b/Telegram/Resources/icons/passport_authorize.png new file mode 100644 index 0000000000000000000000000000000000000000..4e8271edc03cbb48924f29d53a3bdea8dc877d9f GIT binary patch literal 362 zcmV-w0hRuVP)M1nsB@KD-8IP2So@0#u!K`0TC~S5CYOP-GRS*Q53~t56>ioIPR&G5*)|5 zRkC3i`b>4=oFk7bgX(PmoL_5Jb@5$n3fAPCSjO$>rS3*16iKK-1#r=?GS|2^H_lBLe7di^V< zl-gx;6qlh@Ro%*L9LL?*>ZUNpP${LgjZVWbV3uY7;X8RsANWQvtgr2xYybcN07*qo IM6N<$f^6-aP5=M^ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/passport_authorize@2x.png b/Telegram/Resources/icons/passport_authorize@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5a4a9704dab4475756f206e67e4b1bf07fee6abe GIT binary patch literal 756 zcmV8fsu2+~p)wnl`e?;!Xl>ZY4ErO#0CAzYZ?zAxaS(01?6oqwR1 z*oC?{T@>NMHO3jo^m@q$vx+C@W5#o492o$@0r2am1-2y-RZSwQn%^p4W|}5Sr4lU5 zLa|uH+1VL#xg0W?3=G4-bUH=9--qKkcz%8sdN+e)dpbEeL8VfGWmzbf%cxW;$mjE5 zj77!{1_R`BIrXBPb6j6vWHcIW z%(-qzFMZq`Ow}i%s)-ckoTJfbpx5gm2m%n1(lMP*;dvg;&(9-eLo4m{^pxJ--jr5+ z7#|-Wba8R9sq)u9;GD-Mxx({2anX9c9;+k~Q4j>;qP<=(c2Ob{Z}{{1Txy%!m9Voy zXw{2IP9_uF-{0fv>I%B9L)Ud!mW9X1M@%LYaoZ5qPW869u1m+q$DvDRnkKofyYtfT zBxt6X$68j)$5Tc3VR)1={WC@m_zg|=EP_`bjO=Y8MD)6AMDbXr9}&cf^bYepO;N1FIubB zgk!4Js%$y{lEpL}4r6Uk(xOBM((qSwIvp|$BQ$|w7(c&-t{9KUba!`0#bS|CsT8Ht zX)2e?^ziUNapB6Udy#DDErC=}#Gf$!_bX0u5zFE2Ek&6ErJzE7U# mMcs`i|B5Il5mikhs+uqRvZa{e$FlkQ)9Emv zh_KmgD9aLnIF3I-JG)01hE!Drz;?TB)bt9rs;Z(WzgOzIZq;>~E(n76bi3USP1C-A zvhVwEQ_?gYW{T%|JfBYh4u=D}u74k!<#PGX;OTVglEHSM>$=?UcK|Mz%kZ!Fe>s?@ s**RLRK+`mdqNwktVe&^Et4810KX(k2@Vfi#SO5S307*qoM6N<$f+>8QHvj+t literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/passport_empty@2x.png b/Telegram/Resources/icons/passport_empty@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..30130da9a0783a0cc5e2f2a0db8b31c1fe90704f GIT binary patch literal 688 zcmV;h0#E&kP)?Gr4gss)}edDjrBg*xK5{!@~oIe1CsOBoYx1BqHqW z?BMC?i9=2%6NEw`@jxPi)9FN~)8UZg@feDthzAl8TrL;7-7be54u|mj{o;W{guT5z z^m;uG+3WS-^ZCRBi3onbAA`YwLq0!0!|is92NDq!MZst^;*fWDcc1Q9>JO`~>vNwo z#tii=W%YbMANu|N+;iyldc|(B$K%1v%L|8leSH=GlDJ&1x!=OkXoNr@V5ZYL-0to! z+U+)ndwY9BFc>u3YYlFDdmE3Bj~s3?nIIevFVej@&f##N)oO7#RaLRSzrSezVz|xC zO*EU$xwu#?X2tH9pDfEVZf|cnoTh0=BodY!9n-*#jSXC1Uvs$GY=(n_1FLZ6fRZGk zR;zJ1UDuIHrL4pm2d=NLqf)7GIK~(`zx80C0MG zx-6V=AQ7QZD16|~&(D{M!&fqqi;D}g+wCOFGL_3^GZmlC8hu~JRn5P9!}_verification.requestId = 0; if (error.type() == qstr("PHONE_CODE_INVALID")) { - verificationError(nonconst, lang(lng_signin_wrong_code)); + verificationError( + nonconst, + lang(lng_signin_wrong_code)); } else { verificationError(nonconst, error.type()); } @@ -558,7 +560,9 @@ void FormController::verify( }).fail([=](const RPCError &error) { nonconst->verification.requestId = 0; if (error.type() == qstr("CODE_INVALID")) { - verificationError(nonconst, lang(lng_signin_wrong_code)); + verificationError( + nonconst, + lang(lng_signin_wrong_code)); } else { verificationError(nonconst, error.type()); } @@ -864,7 +868,8 @@ void FormController::saveEncryptedValue(not_null value) { _secret, value->data.hashInEdit); - const auto selfie = value->selfieInEdit + const auto selfie = (value->selfieInEdit + && !value->selfieInEdit->deleted) ? inputFile(*value->selfieInEdit) : MTPInputSecureFile(); @@ -896,7 +901,7 @@ void FormController::saveEncryptedValue(not_null value) { | (value->filesInEdit.empty() ? MTPDinputSecureValue::Flag(0) : MTPDinputSecureValue::Flag::f_files) - | (value->selfieInEdit + | ((value->selfieInEdit && !value->selfieInEdit->deleted) ? MTPDinputSecureValue::Flag::f_selfie : MTPDinputSecureValue::Flag(0)); Assert(flags != MTPDinputSecureValue::Flags(0)); @@ -953,16 +958,16 @@ void FormController::sendSaveRequest( value->saveRequestId = 0; - const auto &data = result.c_secureValue(); - value->files = data.has_files() - ? parseFiles( - data.vfiles.v, - base::take(value->filesInEdit)) - : std::vector(); + const auto filesInEdit = base::take(value->filesInEdit); auto selfiesInEdit = std::vector(); if (auto selfie = base::take(value->selfieInEdit)) { selfiesInEdit.push_back(std::move(*selfie)); } + + const auto &data = result.c_secureValue(); + value->files = data.has_files() + ? parseFiles(data.vfiles.v, filesInEdit) + : std::vector(); value->selfie = data.has_selfie() ? parseFile(data.vselfie, selfiesInEdit) : base::none; diff --git a/Telegram/SourceFiles/passport/passport_panel.cpp b/Telegram/SourceFiles/passport/passport_panel.cpp index a210b4d15..e57cb640b 100644 --- a/Telegram/SourceFiles/passport/passport_panel.cpp +++ b/Telegram/SourceFiles/passport/passport_panel.cpp @@ -295,7 +295,7 @@ void Panel::focusInEvent(QFocusEvent *e) { } void Panel::initGeometry() { - auto center = Messenger::Instance().getPointForCallPanelCenter(); + const auto center = Messenger::Instance().getPointForCallPanelCenter(); _useTransparency = Platform::TranslucentWindowsSupported(center); setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); _padding = _useTransparency @@ -305,9 +305,14 @@ void Panel::initGeometry() { st::lineWidth, st::lineWidth, st::lineWidth); - auto screen = QApplication::desktop()->screenGeometry(center); - auto rect = QRect(0, 0, st::passportPanelWidth, st::passportPanelHeight); - setGeometry(rect.translated(center - rect.center()).marginsAdded(_padding)); + const auto screen = QApplication::desktop()->screenGeometry(center); + const auto rect = QRect( + 0, + 0, + st::passportPanelWidth, + st::passportPanelHeight); + setGeometry( + rect.translated(center - rect.center()).marginsAdded(_padding)); updateControlsGeometry(); } @@ -368,34 +373,110 @@ void Panel::paintShadowBorder(Painter &p) const { const auto part1 = size / 3; const auto part2 = size - part1; const auto corner = QSize(part1, part1) * factor; + const auto topleft = QRect(QPoint(0, 0), corner); p.drawPixmap(QRect(0, 0, part1, part1), _borderParts, topleft); - const auto topright = QRect(QPoint(part2, 0) * factor, corner); - p.drawPixmap(QRect(width() - part1, 0, part1, part1), _borderParts, topright); - const auto bottomleft = QRect(QPoint(0, part2) * factor, corner); - p.drawPixmap(QRect(0, height() - part1, part1, part1), _borderParts, bottomleft); - const auto bottomright = QRect(QPoint(part2, part2) * factor, corner); - p.drawPixmap(QRect(width() - part1, height() - part1, part1, part1), _borderParts, bottomright); - const auto left = QRect(QPoint(0, part1) * factor, QSize(_padding.left(), part2 - part1) * factor); - p.drawPixmap(QRect(0, part1, _padding.left(), height() - 2 * part1), _borderParts, left); - const auto top = QRect(QPoint(part1, 0) * factor, QSize(part2 - part1, _padding.top() + st::callRadius) * factor); - p.drawPixmap(QRect(part1, 0, width() - 2 * part1, _padding.top() + st::callRadius), _borderParts, top); - const auto right = QRect(QPoint(size - _padding.right(), part1) * factor, QSize(_padding.right(), part2 - part1) * factor); - p.drawPixmap(QRect(width() - _padding.right(), part1, _padding.right(), height() - 2 * part1), _borderParts, right); - const auto bottom = QRect(QPoint(part1, size - _padding.bottom() - st::callRadius) * factor, QSize(part2 - part1, _padding.bottom() + st::callRadius) * factor); - p.drawPixmap(QRect(part1, height() - _padding.bottom() - st::callRadius, width() - 2 * part1, _padding.bottom() + st::callRadius), _borderParts, bottom); - p.fillRect(_padding.left(), _padding.top() + st::callRadius, width() - _padding.left() - _padding.right(), height() - _padding.top() - _padding.bottom() - 2 * st::callRadius, st::windowBg); + const auto topright = QRect(QPoint(part2, 0) * factor, corner); + p.drawPixmap( + QRect(width() - part1, 0, part1, part1), + _borderParts, + topright); + + const auto bottomleft = QRect(QPoint(0, part2) * factor, corner); + p.drawPixmap( + QRect(0, height() - part1, part1, part1), + _borderParts, + bottomleft); + + const auto bottomright = QRect(QPoint(part2, part2) * factor, corner); + p.drawPixmap( + QRect(width() - part1, height() - part1, part1, part1), + _borderParts, + bottomright); + + const auto left = QRect( + QPoint(0, part1) * factor, + QSize(_padding.left(), part2 - part1) * factor); + p.drawPixmap( + QRect(0, part1, _padding.left(), height() - 2 * part1), + _borderParts, + left); + + const auto top = QRect( + QPoint(part1, 0) * factor, + QSize(part2 - part1, _padding.top() + st::callRadius) * factor); + p.drawPixmap( + QRect( + part1, + 0, + width() - 2 * part1, + _padding.top() + st::callRadius), + _borderParts, + top); + + const auto right = QRect( + QPoint(size - _padding.right(), part1) * factor, + QSize(_padding.right(), part2 - part1) * factor); + p.drawPixmap( + QRect( + width() - _padding.right(), + part1, + _padding.right(), + height() - 2 * part1), + _borderParts, + right); + + const auto bottom = QRect( + QPoint(part1, size - _padding.bottom() - st::callRadius) * factor, + QSize(part2 - part1, _padding.bottom() + st::callRadius) * factor); + p.drawPixmap( + QRect( + part1, + height() - _padding.bottom() - st::callRadius, + width() - 2 * part1, + _padding.bottom() + st::callRadius), + _borderParts, + bottom); + + p.fillRect( + _padding.left(), + _padding.top() + st::callRadius, + width() - _padding.left() - _padding.right(), + height() - _padding.top() - _padding.bottom() - 2 * st::callRadius, + st::windowBg); } void Panel::paintOpaqueBorder(Painter &p) const { const auto border = st::windowShadowFgFallback; p.fillRect(0, 0, width(), _padding.top(), border); - p.fillRect(myrtlrect(0, _padding.top(), _padding.left(), height() - _padding.top()), border); - p.fillRect(myrtlrect(width() - _padding.right(), _padding.top(), _padding.right(), height() - _padding.top()), border); - p.fillRect(_padding.left(), height() - _padding.bottom(), width() - _padding.left() - _padding.right(), _padding.bottom(), border); + p.fillRect( + myrtlrect( + 0, + _padding.top(), + _padding.left(), + height() - _padding.top()), + border); + p.fillRect( + myrtlrect( + width() - _padding.right(), + _padding.top(), + _padding.right(), + height() - _padding.top()), + border); + p.fillRect( + _padding.left(), + height() - _padding.bottom(), + width() - _padding.left() - _padding.right(), + _padding.bottom(), + border); - p.fillRect(_padding.left(), _padding.top(), width() - _padding.left() - _padding.right(), height() - _padding.top() - _padding.bottom(), st::windowBg); + p.fillRect( + _padding.left(), + _padding.top(), + width() - _padding.left() - _padding.right(), + height() - _padding.top() - _padding.bottom(), + st::windowBg); } void Panel::closeEvent(QCloseEvent *e) { @@ -423,7 +504,8 @@ void Panel::mouseMoveEvent(QMouseEvent *e) { if (!(e->buttons() & Qt::LeftButton)) { _dragging = false; } else { - move(_dragStartMyPosition + (e->globalPos() - _dragStartMousePosition)); + move(_dragStartMyPosition + + (e->globalPos() - _dragStartMousePosition)); } } } diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 264a15d93..f2f97d358 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "passport/passport_panel_edit_scans.h" #include "passport/passport_panel.h" #include "boxes/confirm_box.h" +#include "ui/countryinput.h" #include "layout.h" namespace Passport { @@ -24,6 +25,19 @@ PanelEditDocument::Scheme GetDocumentScheme( base::optional scansType = base::none) { using Scheme = PanelEditDocument::Scheme; + const auto DontFormat = nullptr; + const auto CountryFormat = [](const QString &value) { + const auto result = CountrySelectBox::NameByISO(value); + return result.isEmpty() ? value : result; + }; + const auto GenderFormat = [](const QString &value) { + if (value == qstr("male")) { + return lang(lng_passport_gender_male); + } else if (value == qstr("female")) { + return lang(lng_passport_gender_female); + } + return value; + }; const auto DontValidate = nullptr; const auto NotEmptyValidate = [](const QString &value) { return !value.isEmpty(); @@ -39,8 +53,8 @@ PanelEditDocument::Scheme GetDocumentScheme( const auto GenderValidate = [](const QString &value) { return value == qstr("male") || value == qstr("female"); }; - const auto CountryValidate = [](const QString &value) { - return QRegularExpression("^[A-Z]{2}$").match(value).hasMatch(); + const auto CountryValidate = [=](const QString &value) { + return !CountryFormat(value).isEmpty(); }; switch (type) { @@ -68,14 +82,16 @@ PanelEditDocument::Scheme GetDocumentScheme( PanelDetailsType::Text, qsl("first_name"), lang(lng_passport_first_name), - NotEmptyValidate + NotEmptyValidate, + DontFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Text, qsl("last_name"), lang(lng_passport_last_name), - DontValidate + DontValidate, + DontFormat, }, { Scheme::ValueType::Fields, @@ -83,6 +99,7 @@ PanelEditDocument::Scheme GetDocumentScheme( qsl("birth_date"), lang(lng_passport_birth_date), DateValidate, + DontFormat, }, { Scheme::ValueType::Fields, @@ -90,6 +107,7 @@ PanelEditDocument::Scheme GetDocumentScheme( qsl("gender"), lang(lng_passport_gender), GenderValidate, + GenderFormat, }, { Scheme::ValueType::Fields, @@ -97,6 +115,7 @@ PanelEditDocument::Scheme GetDocumentScheme( qsl("country_code"), lang(lng_passport_country), CountryValidate, + CountryFormat, }, { Scheme::ValueType::Scans, @@ -104,6 +123,7 @@ PanelEditDocument::Scheme GetDocumentScheme( qsl("document_no"), lang(lng_passport_document_number), NotEmptyValidate, + DontFormat, }, { Scheme::ValueType::Scans, @@ -111,6 +131,7 @@ PanelEditDocument::Scheme GetDocumentScheme( qsl("expiry_date"), lang(lng_passport_expiry_date), DateOrEmptyValidate, + DontFormat, }, }; return result; @@ -131,7 +152,7 @@ PanelEditDocument::Scheme GetDocumentScheme( result.scansHeader = lang(lng_passport_address_agreement); break; default: - Unexpected("scansType in GetDocumentScheme:Identity."); + Unexpected("scansType in GetDocumentScheme:Address."); } } result.rows = { @@ -140,42 +161,48 @@ PanelEditDocument::Scheme GetDocumentScheme( PanelDetailsType::Text, qsl("street_line1"), lang(lng_passport_street), - NotEmptyValidate + NotEmptyValidate, + DontFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Text, qsl("street_line2"), lang(lng_passport_street), - DontValidate + DontValidate, + DontFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Text, qsl("city"), lang(lng_passport_city), - NotEmptyValidate + NotEmptyValidate, + DontFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Text, qsl("state"), lang(lng_passport_state), - DontValidate + DontValidate, + DontFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Country, qsl("country_code"), lang(lng_passport_country), - CountryValidate + CountryValidate, + CountryFormat, }, { Scheme::ValueType::Fields, PanelDetailsType::Text, qsl("post_code"), lang(lng_passport_postcode), - NotEmptyValidate + NotEmptyValidate, + DontFormat, }, }; return result; @@ -197,7 +224,7 @@ PanelEditContact::Scheme GetContactScheme(Scope::Type type) { "^\\d{2,12}$" ).match(value).hasMatch(); }; - result.preprocess = [](const QString &value) { + result.format = [](const QString &value) { return App::formatPhone(value); }; result.postprocess = [](QString value) { @@ -217,7 +244,7 @@ PanelEditContact::Scheme GetContactScheme(Scope::Type type) { const auto dot = value.lastIndexOf('.'); return (at > 0) && (dot > at); }; - result.preprocess = result.postprocess = [](const QString &value) { + result.format = result.postprocess = [](const QString &value) { return value.trimmed(); }; return result; @@ -296,6 +323,158 @@ QString PanelController::privacyPolicyUrl() const { return _form->privacyPolicyUrl(); } +auto PanelController::collectRowInfo(const Scope &scope) const -> Row { + switch (scope.type) { + case Scope::Type::Identity: + if (scope.files.empty()) { + return { + lang(lng_passport_personal_details), + lang(lng_passport_personal_details_enter) + }; + } else if (scope.files.size() == 1) { + switch (scope.files.front()->type) { + case Value::Type::Passport: + return { + lang(lng_passport_identity_passport), + lang(lng_passport_identity_passport_upload) + }; + case Value::Type::IdentityCard: + return { + lang(lng_passport_identity_card), + lang(lng_passport_identity_card_upload) + }; + case Value::Type::DriverLicense: + return { + lang(lng_passport_identity_license), + lang(lng_passport_identity_license_upload) + }; + default: Unexpected("Identity type in collectRowInfo."); + } + } + return { + lang(lng_passport_identity_title), + lang(lng_passport_identity_description) + }; + case Scope::Type::Address: + if (scope.files.empty()) { + return { + lang(lng_passport_address), + lang(lng_passport_address_enter) + }; + } else if (scope.files.size() == 1) { + switch (scope.files.front()->type) { + case Value::Type::BankStatement: + return { + lang(lng_passport_address_statement), + lang(lng_passport_address_statement_upload) + }; + case Value::Type::UtilityBill: + return { + lang(lng_passport_address_bill), + lang(lng_passport_address_bill_upload) + }; + case Value::Type::RentalAgreement: + return { + lang(lng_passport_address_agreement), + lang(lng_passport_address_agreement_upload) + }; + default: Unexpected("Address type in collectRowInfo."); + } + } + return { + lang(lng_passport_address_title), + lang(lng_passport_address_description) + }; + case Scope::Type::Phone: + return { + lang(lng_passport_phone_title), + lang(lng_passport_phone_description) + }; + case Scope::Type::Email: + return { + lang(lng_passport_email_title), + lang(lng_passport_email_description) + }; + default: Unexpected("Scope type in collectRowInfo."); + } +} + +QString PanelController::collectRowReadyString(const Scope &scope) const { + switch (scope.type) { + case Scope::Type::Identity: + case Scope::Type::Address: { + auto list = QStringList(); + const auto &fields = scope.fields->data.parsed.fields; + const auto files = [&]() -> const Value* { + for (const auto &files : scope.files) { + if (!files->files.empty()) { + return files; + } + } + return nullptr; + }(); + if (files && scope.files.size() > 1) { + list.push_back([&] { + switch (files->type) { + case Value::Type::Passport: + return lang(lng_passport_identity_passport); + case Value::Type::DriverLicense: + return lang(lng_passport_identity_license); + case Value::Type::IdentityCard: + return lang(lng_passport_identity_card); + case Value::Type::BankStatement: + return lang(lng_passport_address_statement); + case Value::Type::UtilityBill: + return lang(lng_passport_address_bill); + case Value::Type::RentalAgreement: + return lang(lng_passport_address_agreement); + default: Unexpected("Files type in collectRowReadyString."); + } + }()); + } + if (files + && (files->files.empty() + || (scope.selfieRequired && !files->selfie))) { + return QString(); + } + const auto scheme = GetDocumentScheme(scope.type); + for (const auto &row : scheme.rows) { + const auto format = row.format; + if (row.type == PanelEditDocument::Scheme::ValueType::Fields) { + const auto i = fields.find(row.key); + if (i == end(fields)) { + return QString(); + } else if (row.validate && !row.validate(i->second)) { + return QString(); + } + list.push_back(format ? format(i->second) : i->second); + } else if (!files) { + return QString(); + } else { + const auto i = files->data.parsed.fields.find(row.key); + if (i == end(files->data.parsed.fields)) { + return QString(); + } else if (row.validate && !row.validate(i->second)) { + return QString(); + } + list.push_back(i->second); + } + } + return list.join(", "); + } break; + case Scope::Type::Phone: + case Scope::Type::Email: { + const auto format = GetContactScheme(scope.type).format; + const auto &fields = scope.fields->data.parsed.fields; + const auto i = fields.find("value"); + return (i != end(fields)) + ? (format ? format(i->second) : i->second) + : QString(); + } break; + } + Unexpected("Scope type in collectRowReadyString."); +} + void PanelController::fillRows( base::lambda PanelController::scanUpdated() const { } ScanInfo PanelController::collectScanInfo(const EditFile &file) const { + Expects(_editScope != nullptr); + Expects(_editScopeFilesIndex >= 0); + const auto status = [&] { if (file.fields.accessHash) { if (file.fields.downloadOffset < 0) { @@ -456,11 +618,10 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const { return formatDownloadText(0, file.fields.size); } }(); - auto isSelfie = (_editScope != nullptr) - && (_editScopeFilesIndex >= 0) - && (file.value == _editScope->files[_editScopeFilesIndex]) - && (_editScope->files[_editScopeFilesIndex]->selfieInEdit.has_value()) - && (&file == &*_editScope->files[_editScopeFilesIndex]->selfieInEdit); + const auto &files = _editScope->files; + auto isSelfie = (file.value == files[_editScopeFilesIndex]) + && (files[_editScopeFilesIndex]->selfieInEdit.has_value()) + && (&file == &*files[_editScopeFilesIndex]->selfieInEdit); return { FileKey{ file.fields.id, file.fields.dcId }, status, @@ -508,13 +669,6 @@ int PanelController::findNonEmptyIndex( if (i != end(files)) { return (i - begin(files)); } - // Only an uploaded scan counts as non-empty value. - //const auto j = ranges::find_if(files, [](not_null file) { - // return !file->data.parsed.fields.empty(); - //}); - //if (j != end(files)) { - // return (j - begin(files)); - //} return -1; } @@ -523,17 +677,17 @@ void PanelController::editScope(int index) { Expects(_panel != nullptr); Expects(index >= 0 && index < _scopes.size()); - if (_scopes[index].files.size() > 1) { + if (_scopes[index].files.empty()) { + editScope(index, -1); + } else { const auto filesIndex = findNonEmptyIndex(_scopes[index].files); if (filesIndex >= 0) { editScope(index, filesIndex); - } else { + } else if (_scopes[index].files.size() > 1) { requestScopeFilesType(index); + } else { + editWithUpload(index, 0); } - } else if (_scopes[index].files.empty()) { - editScope(index, -1); - } else { - editWithUpload(index, 0); } } @@ -623,18 +777,19 @@ void PanelController::editScope(int index, int filesIndex) { switch (_editScope->type) { case Scope::Type::Identity: case Scope::Type::Address: { + const auto &files = _editScope->files; auto result = (_editScopeFilesIndex >= 0) ? object_ptr( _panel.get(), this, GetDocumentScheme( _editScope->type, - _editScope->files[_editScopeFilesIndex]->type), + files[_editScopeFilesIndex]->type), _editScope->fields->data.parsedInEdit, - _editScope->files[_editScopeFilesIndex]->data.parsedInEdit, - valueFiles(*_editScope->files[_editScopeFilesIndex]), + files[_editScopeFilesIndex]->data.parsedInEdit, + valueFiles(*files[_editScopeFilesIndex]), (_editScope->selfieRequired - ? valueSelfie(*_editScope->files[_editScopeFilesIndex]) + ? valueSelfie(*files[_editScopeFilesIndex]) : nullptr)) : object_ptr( _panel.get(), diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.h b/Telegram/SourceFiles/passport/passport_panel_controller.h index 49b914800..7d1c8c0bd 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.h +++ b/Telegram/SourceFiles/passport/passport_panel_controller.h @@ -87,6 +87,10 @@ public: rpl::lifetime &lifetime(); private: + struct Row { + QString title; + QString description; + }; void ensurePanelCreated(); void editScope(int index, int filesIndex); @@ -100,6 +104,8 @@ private: void processValueSaveFinished(not_null value); void processVerificationNeeded(not_null value); + Row collectRowInfo(const Scope &scope) const; + QString collectRowReadyString(const Scope &scope) const; ScanInfo collectScanInfo(const EditFile &file) const; QString getDefaultContactValue(Scope::Type type) const; diff --git a/Telegram/SourceFiles/passport/passport_panel_details_row.h b/Telegram/SourceFiles/passport/passport_panel_details_row.h index e9fcef6f9..bd4ff6283 100644 --- a/Telegram/SourceFiles/passport/passport_panel_details_row.h +++ b/Telegram/SourceFiles/passport/passport_panel_details_row.h @@ -40,7 +40,8 @@ protected: void resizeEvent(QResizeEvent *e) override; private: - object_ptr _background = object_ptr(this); + object_ptr _background + = object_ptr(this); }; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp index a65aea64f..24c23f61f 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_contact.cpp @@ -66,7 +66,12 @@ VerifyBox::VerifyBox( rpl::producer call, rpl::producer error) : _title(title) { - setupControls(text, codeLength, submit, std::move(call), std::move(error)); + setupControls( + text, + codeLength, + submit, + std::move(call), + std::move(error)); } void VerifyBox::setupControls( @@ -194,8 +199,8 @@ void PanelEditContact::setupControls( ) | rpl::map([=] { return lng_passport_use_existing( lt_existing, - (_scheme.preprocess - ? _scheme.preprocess(existing) + (_scheme.format + ? _scheme.format(existing) : existing)); }), st::passportUploadButton), diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_contact.h b/Telegram/SourceFiles/passport/passport_panel_edit_contact.h index 8fe06f5a3..f7fd910a4 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_contact.h +++ b/Telegram/SourceFiles/passport/passport_panel_edit_contact.h @@ -36,7 +36,7 @@ public: base::lambda newPlaceholder; QString aboutNew; base::lambda validate; - base::lambda preprocess; + base::lambda format; base::lambda postprocess; }; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp index dc1d28217..013648053 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp @@ -64,7 +64,7 @@ RequestTypeBox::RequestTypeBox( void RequestTypeBox::prepare() { setTitle([=] { return _title; }); - addButton(langFactory(lng_passport_upload_document), [=] { _submit(); }); + addButton(langFactory(lng_passport_upload_document), _submit); addButton(langFactory(lng_cancel), [=] { closeBox(); }); setDimensions(st::boxWidth, _height); } diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.h b/Telegram/SourceFiles/passport/passport_panel_edit_document.h index 8044c53e2..9e5c9f7a0 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.h +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.h @@ -39,6 +39,7 @@ public: QString key; QString label; base::lambda validate; + base::lambda format; }; std::vector rows; QString rowsHeader; diff --git a/Telegram/SourceFiles/passport/passport_panel_form.cpp b/Telegram/SourceFiles/passport/passport_panel_form.cpp index 29f8b862a..1f30ccff6 100644 --- a/Telegram/SourceFiles/passport/passport_panel_form.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_form.cpp @@ -90,7 +90,9 @@ int PanelForm::Row::countAvailableWidth(int newWidth) const { return newWidth - st::passportRowPadding.left() - st::passportRowPadding.right() - - (_ready ? st::passportRowReadyIcon : st::passportRowEmptyIcon).width(); + - (_ready + ? st::passportRowReadyIcon + : st::passportRowEmptyIcon).width(); } int PanelForm::Row::countAvailableWidth() const { diff --git a/Telegram/SourceFiles/ui/widgets/buttons.cpp b/Telegram/SourceFiles/ui/widgets/buttons.cpp index ec9dda8a5..6ba788649 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.cpp +++ b/Telegram/SourceFiles/ui/widgets/buttons.cpp @@ -299,6 +299,9 @@ int RoundButton::contentWidth() const { if (_numbers) { result += (result ? _st.numbersSkip : 0) + _numbers->countWidth(); } + if (!_st.icon.empty() && _st.iconPosition.x() < 0) { + result += _st.icon.width() - _st.iconPosition.x(); + } return result; } @@ -322,11 +325,24 @@ void RoundButton::paintEvent(QPaintEvent *e) { paintRipple(p, rounded.x(), rounded.y(), ms); p.setFont(_st.font); - int textLeft = _st.padding.left() + ((width() - innerWidth - _st.padding.left() - _st.padding.right()) / 2); + const auto textTop = _st.padding.top() + _st.textTop; + auto textLeft = _st.padding.left() + + ((width() + - innerWidth + - _st.padding.left() + - _st.padding.right()) / 2); if (_fullWidthOverride < 0) { textLeft = -_fullWidthOverride / 2; } - int textTop = _st.padding.top() + _st.textTop; + if (!_st.icon.empty() && _st.iconPosition.x() < 0) { + textLeft += _st.icon.width() - _st.iconPosition.x(); + } + const auto iconLeft = (_st.iconPosition.x() >= 0) + ? _st.iconPosition.x() + : (textLeft + _st.iconPosition.x() - _st.icon.width()); + const auto iconTop = (_st.iconPosition.y() >= 0) + ? _st.iconPosition.y() + : (textTop + _st.iconPosition.y()); if (!_text.isEmpty()) { p.setPen((over || down) ? _st.textFgOver : _st.textFg); p.drawTextLeft(textLeft, textTop, width(), _text); @@ -336,7 +352,9 @@ void RoundButton::paintEvent(QPaintEvent *e) { p.setPen((over || down) ? _st.numbersTextFgOver : _st.numbersTextFg); _numbers->paint(p, textLeft, textTop, width()); } - _st.icon.paint(p, QPoint(_st.padding.left(), _st.padding.top()), width()); + if (!_st.icon.empty()) { + _st.icon.paint(p, QPoint(iconLeft, iconTop), width()); + } } QImage RoundButton::prepareRippleMask() const { diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style index f3a510061..a299d55c5 100644 --- a/Telegram/SourceFiles/ui/widgets/widgets.style +++ b/Telegram/SourceFiles/ui/widgets/widgets.style @@ -94,6 +94,7 @@ RoundButton { textTop: pixels; icon: icon; + iconPosition: point; font: font; @@ -584,6 +585,8 @@ defaultActiveButton: RoundButton { textTop: 8px; + iconPosition: point(0px, 0px); + font: semiboldFont; ripple: RippleAnimation(defaultRippleAnimation) {