diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 8a1a6033c..47f2802e3 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1633,6 +1633,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_passport_country_choose" = "Choose country"; "lng_passport_document_number" = "Document Number"; "lng_passport_expiry_date" = "Expiry date"; +"lng_passport_native_name_title" = "Name in document language"; +"lng_passport_native_name_about" = "Your name in the language of the country ({country}) that issued the document."; "lng_passport_address" = "Address"; "lng_passport_address_enter" = "Enter your address"; "lng_passport_street" = "Street"; diff --git a/Telegram/SourceFiles/passport/passport.style b/Telegram/SourceFiles/passport/passport.style index a10bb7156..e89471071 100644 --- a/Telegram/SourceFiles/passport/passport.style +++ b/Telegram/SourceFiles/passport/passport.style @@ -200,3 +200,6 @@ passportPasswordAbout1Padding: margins(10px, 28px, 10px, 0px); passportPasswordAbout2Padding: margins(10px, 0px, 10px, 28px); passportPasswordIconHeight: 224px; passportPasswordIcon: icon {{ "passport_password_setup", windowSubTextFg }}; + +passportNativeNameAboutMargin: margins(0px, 16px, 0px, 0px); +passportNativeNameHeaderPadding: margins(22px, 28px, 33px, 10px); diff --git a/Telegram/SourceFiles/passport/passport_form_view_controller.cpp b/Telegram/SourceFiles/passport/passport_form_view_controller.cpp index 04c31c2e7..4e75cf3bf 100644 --- a/Telegram/SourceFiles/passport/passport_form_view_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_view_controller.cpp @@ -380,7 +380,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) { scope.details ? scope.details->nativeNames : false); for (const auto &row : scheme.rows) { const auto format = row.format; - if (row.valueClass == EditDocumentScheme::ValueClass::Fields) { + if (row.valueClass != EditDocumentScheme::ValueClass::Scans) { if (!fields) { continue; } diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 9a6677fbc..6fa15c866 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -202,40 +202,35 @@ EditDocumentScheme GetDocumentScheme( Unexpected("scansType in GetDocumentScheme:Identity."); } } - using Validator = EditDocumentScheme::Row::Validator; result.rows = { { ValueClass::Fields, PanelDetailsType::Text, - nativeNames ? qsl("first_name_native") : qsl("first_name"), + qsl("first_name"), lang(lng_passport_first_name), - nativeNames ? Validator(NativeNameValidate) : NameValidate, + NameValidate, DontFormat, kMaxNameSize, }, { ValueClass::Fields, PanelDetailsType::Text, - (nativeNames - ? qsl("middle_name_native") - : qsl("middle_name")), + qsl("middle_name"), lang(lng_passport_middle_name), - (nativeNames - ? Validator(NativeNameOrEmptyValidate) - : NameOrEmptyValidate), + NameOrEmptyValidate, DontFormat, kMaxNameSize, - nativeNames ? qsl("first_name_native") : qsl("first_name"), + qsl("first_name"), }, { ValueClass::Fields, PanelDetailsType::Text, - nativeNames ? qsl("last_name_native") : qsl("last_name"), + qsl("last_name"), lang(lng_passport_last_name), - nativeNames ? Validator(NativeNameValidate) : NameValidate, + NameValidate, DontFormat, kMaxNameSize, - nativeNames ? qsl("first_name_native") : qsl("first_name"), + qsl("first_name"), }, { ValueClass::Fields, @@ -287,6 +282,55 @@ EditDocumentScheme GetDocumentScheme( DontFormat, }, }; + if (nativeNames) { + result.additionalDependencyKey = qsl("residence_country_code"); + result.additionalHeader = lang(lng_passport_native_name_title); + result.additionalDescription = [](const QString &countryCode) { + const auto name = CountrySelectBox::NameByISO(countryCode); + Assert(!name.isEmpty()); + return lng_passport_native_name_about( + lt_country, + name); + }; + result.additionalShown = [](const QString &countryCode) { + return !countryCode.isEmpty(); + }; + using Row = EditDocumentScheme::Row; + auto additional = std::initializer_list{ + { + ValueClass::Additional, + PanelDetailsType::Text, + qsl("first_name_native"), + lang(lng_passport_first_name), + NativeNameValidate, + DontFormat, + kMaxNameSize, + }, + { + ValueClass::Additional, + PanelDetailsType::Text, + qsl("middle_name_native"), + lang(lng_passport_middle_name), + NativeNameOrEmptyValidate, + DontFormat, + kMaxNameSize, + qsl("first_name_native"), + }, + { + ValueClass::Additional, + PanelDetailsType::Text, + qsl("last_name_native"), + lang(lng_passport_last_name), + NativeNameValidate, + DontFormat, + kMaxNameSize, + qsl("first_name_native"), + }, + }; + for (auto &row : additional) { + result.rows.push_back(std::move(row)); + } + } return result; } break; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp index f7551e120..9bfdf7b56 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp @@ -344,22 +344,15 @@ not_null PanelEditDocument::setupContent( std::move(translations))); } - const auto valueOrEmpty = [&]( - const ValueMap &values, - const QString &key) { - const auto &fields = values.fields; - if (const auto i = fields.find(key); i != fields.end()) { - return i->second; - } - return ValueField(); - }; - const auto enumerateRows = [&](auto &&callback) { for (auto i = 0, count = int(_scheme.rows.size()); i != count; ++i) { const auto &row = _scheme.rows[i]; - auto fields = (row.valueClass == Scheme::ValueClass::Fields) - ? data - : scansData; + + Assert(row.valueClass != Scheme::ValueClass::Additional + || !_scheme.additionalDependencyKey.isEmpty()); + auto fields = (row.valueClass == Scheme::ValueClass::Scans) + ? scansData + : data; if (!fields) { continue; } @@ -397,32 +390,58 @@ not_null PanelEditDocument::setupContent( st::passportDetailsHeaderPadding); enumerateRows([&]( int i, - const EditDocumentScheme::Row &row, + const Scheme::Row &row, const ValueMap &fields) { - const auto current = valueOrEmpty(fields, row.key); - const auto [it, ok] = _details.emplace( - i, - inner->add(PanelDetailsRow::Create( - inner, - row.inputType, - _controller, - row.label, - maxLabelWidth, - current.text, - current.error, - row.lengthLimit))); - const bool details = (&fields == data); - it->second->value( - ) | rpl::skip(1) | rpl::start_with_next([=] { - if (details) { - _fieldsChanged = true; - updateCommonError(); - } else { - Assert(_editScans != nullptr); - _editScans->scanFieldsChanged(true); - } - }, it->second->lifetime()); + if (row.valueClass != Scheme::ValueClass::Additional) { + createDetailsRow(inner, i, row, fields, maxLabelWidth); + } }); + if (data && !_scheme.additionalDependencyKey.isEmpty()) { + const auto row = findRow(_scheme.additionalDependencyKey); + const auto wrap = inner->add( + object_ptr>( + inner, + object_ptr(inner))); + const auto added = wrap->entity(); + added->add( + object_ptr( + added, + _scheme.additionalHeader, + Ui::FlatLabel::InitType::Simple, + st::passportFormHeader), + st::passportNativeNameHeaderPadding); + + enumerateRows([&]( + int i, + const Scheme::Row &row, + const ValueMap &fields) { + if (row.valueClass == Scheme::ValueClass::Additional) { + createDetailsRow(added, i, row, fields, maxLabelWidth); + } + }); + + auto description = row->value( + ) | rpl::filter([=](const QString &code) { + return _scheme.additionalShown(code); + }) | rpl::map([=](const QString &code) { + return _scheme.additionalDescription(code); + }); + added->add( + object_ptr( + added, + object_ptr( + added, + std::move(description), + st::boxDividerLabel), + st::passportFormLabelPadding), + st::passportNativeNameAboutMargin); + + wrap->toggleOn(row->value( + ) | rpl::map([=](const QString &code) { + return _scheme.additionalShown(code); + })); + wrap->finishAnimating(); + } inner->add( object_ptr(inner, st::passportDetailsSkip)); @@ -442,6 +461,60 @@ not_null PanelEditDocument::setupContent( return inner; } +void PanelEditDocument::createDetailsRow( + not_null container, + int i, + const Scheme::Row &row, + const ValueMap &fields, + int maxLabelWidth) { + const auto valueOrEmpty = [&]( + const ValueMap &values, + const QString &key) { + const auto &fields = values.fields; + if (const auto i = fields.find(key); i != fields.end()) { + return i->second; + } + return ValueField(); + }; + + const auto current = valueOrEmpty(fields, row.key); + const auto [it, ok] = _details.emplace( + i, + container->add(PanelDetailsRow::Create( + container, + row.inputType, + _controller, + row.label, + maxLabelWidth, + current.text, + current.error, + row.lengthLimit))); + const bool details = (row.valueClass != Scheme::ValueClass::Scans); + it->second->value( + ) | rpl::skip(1) | rpl::start_with_next([=] { + if (details) { + _fieldsChanged = true; + updateCommonError(); + } else { + Assert(_editScans != nullptr); + _editScans->scanFieldsChanged(true); + } + }, it->second->lifetime()); +} + +not_null PanelEditDocument::findRow( + const QString &key) const { + for (auto i = 0, count = int(_scheme.rows.size()); i != count; ++i) { + const auto &row = _scheme.rows[i]; + if (row.key == key) { + const auto it = _details.find(i); + Assert(it != end(_details)); + return it->second.data(); + } + } + Unexpected("Row not found in PanelEditDocument::findRow."); +} + void PanelEditDocument::updateCommonError() { if (_commonError) { _commonError->toggle(!_fieldsChanged, anim::type::normal); @@ -484,9 +557,9 @@ PanelEditDocument::Result PanelEditDocument::collect() const { auto result = Result(); for (const auto [i, field] : _details) { const auto &row = _scheme.rows[i]; - auto &fields = (row.valueClass == Scheme::ValueClass::Fields) - ? result.data - : result.filesData; + auto &fields = (row.valueClass == Scheme::ValueClass::Scans) + ? result.filesData + : result.data; fields.fields[row.key].text = field->valueCurrent(); } return result; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.h b/Telegram/SourceFiles/passport/passport_panel_edit_document.h index c1e23f977..99dde2c9d 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.h +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.h @@ -16,6 +16,7 @@ class FadeShadow; class PlainShadow; class FlatLabel; class RoundButton; +class VerticalLayout; template class SlideWrap; } // namespace Ui @@ -40,6 +41,7 @@ struct ScanListData; struct EditDocumentScheme { enum class ValueClass { Fields, + Additional, Scans, }; struct Row { @@ -59,6 +61,11 @@ struct EditDocumentScheme { QString detailsHeader; QString scansHeader; + QString additionalDependencyKey; + Fn additionalShown; + QString additionalHeader; + Fn additionalDescription; + }; class PanelEditDocument : public Ui::RpWidget { @@ -123,6 +130,14 @@ private: bool validate(); void save(); + void createDetailsRow( + not_null container, + int i, + const Scheme::Row &row, + const ValueMap &fields, + int maxLabelWidth); + not_null findRow(const QString &key) const; + not_null _controller; Scheme _scheme; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp index 22405d5ad..5441076d5 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp @@ -697,7 +697,7 @@ void EditScans::setupSpecialScans(std::map &&files) { inner->add(object_ptr( inner, object_ptr( - _content, + inner, description(type), Ui::FlatLabel::InitType::Simple, st::boxDividerLabel),