mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-20 02:10:24 +00:00
Improve native name phrases in passport.
Also auto-save *_name to *_name_latin for english countries.
This commit is contained in:
parent
5b88f4d3d2
commit
b8b5ab6378
55
Telegram/Resources/langs/cloud_lang.strings
Normal file
55
Telegram/Resources/langs/cloud_lang.strings
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
"cloud_lng_passport_in_ar" = "Arabic";
|
||||
"cloud_lng_passport_in_az" = "Azerbaijani";
|
||||
"cloud_lng_passport_in_bg" = "Bulgarian";
|
||||
"cloud_lng_passport_in_bn" = "Bangla";
|
||||
"cloud_lng_passport_in_cs" = "Czech";
|
||||
"cloud_lng_passport_in_da" = "Danish";
|
||||
"cloud_lng_passport_in_de" = "German";
|
||||
"cloud_lng_passport_in_dv" = "Divehi";
|
||||
"cloud_lng_passport_in_dz" = "Dzongkha";
|
||||
"cloud_lng_passport_in_el" = "Greek";
|
||||
"cloud_lng_passport_in_en" = "English";
|
||||
"cloud_lng_passport_in_es" = "Spanish";
|
||||
"cloud_lng_passport_in_et" = "Estonian";
|
||||
"cloud_lng_passport_in_fa" = "Persian";
|
||||
"cloud_lng_passport_in_fr" = "French";
|
||||
"cloud_lng_passport_in_he" = "Hebrew";
|
||||
"cloud_lng_passport_in_hr" = "Croatian";
|
||||
"cloud_lng_passport_in_hu" = "Hungarian";
|
||||
"cloud_lng_passport_in_hy" = "Armenian";
|
||||
"cloud_lng_passport_in_id" = "Indonesian";
|
||||
"cloud_lng_passport_in_is" = "Icelandic";
|
||||
"cloud_lng_passport_in_it" = "Italian";
|
||||
"cloud_lng_passport_in_ja" = "Japanese";
|
||||
"cloud_lng_passport_in_ka" = "Georgian";
|
||||
"cloud_lng_passport_in_km" = "Khmer";
|
||||
"cloud_lng_passport_in_ko" = "Korean";
|
||||
"cloud_lng_passport_in_lo" = "Lao";
|
||||
"cloud_lng_passport_in_lt" = "Lithuanian";
|
||||
"cloud_lng_passport_in_lv" = "Latvian";
|
||||
"cloud_lng_passport_in_mk" = "Macedonian";
|
||||
"cloud_lng_passport_in_mn" = "Mongolian";
|
||||
"cloud_lng_passport_in_ms" = "Malay";
|
||||
"cloud_lng_passport_in_my" = "Burmese";
|
||||
"cloud_lng_passport_in_ne" = "Nepali";
|
||||
"cloud_lng_passport_in_nl" = "Dutch";
|
||||
"cloud_lng_passport_in_pl" = "Polish";
|
||||
"cloud_lng_passport_in_pt" = "Portuguese";
|
||||
"cloud_lng_passport_in_ro" = "Romanian";
|
||||
"cloud_lng_passport_in_ru" = "Russian";
|
||||
"cloud_lng_passport_in_sk" = "Slovak";
|
||||
"cloud_lng_passport_in_sl" = "Slovenian";
|
||||
"cloud_lng_passport_in_th" = "Thai";
|
||||
"cloud_lng_passport_in_tk" = "Turkmen";
|
||||
"cloud_lng_passport_in_tr" = "Turkish";
|
||||
"cloud_lng_passport_in_uk" = "Ukrainian";
|
||||
"cloud_lng_passport_in_uz" = "Uzbek";
|
||||
"cloud_lng_passport_in_vi" = "Vietnamese";
|
@ -1553,7 +1553,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passport_password_wrong" = "The password you entered is not valid.";
|
||||
"lng_passport_header" = "Requested information";
|
||||
"lng_passport_identity_title" = "Identity document";
|
||||
"lng_passport_identity_description" = "Upload a scan of your passport or another ID";
|
||||
"lng_passport_identity_description" = "Upload proof of your identity";
|
||||
"lng_passport_identity_passport" = "Passport";
|
||||
"lng_passport_identity_passport_upload" = "Upload a scan of your passport";
|
||||
"lng_passport_identity_card" = "Identity card";
|
||||
@ -1632,6 +1632,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"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_native_name_language" = "Your name in {language}";
|
||||
"lng_passport_native_name_language_about" = "Your name in the language of the country that issued the document.";
|
||||
"lng_passport_address" = "Address";
|
||||
"lng_passport_address_enter" = "Please provide your address";
|
||||
"lng_passport_street" = "Street";
|
||||
|
@ -19,7 +19,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Lang {
|
||||
|
||||
CloudManager::CloudManager(Instance &langpack, not_null<MTP::Instance*> mtproto) : MTP::Sender()
|
||||
CloudManager::CloudManager(
|
||||
Instance &langpack,
|
||||
not_null<MTP::Instance*> mtproto)
|
||||
: MTP::Sender()
|
||||
, _langpack(langpack) {
|
||||
requestLangPackDifference();
|
||||
}
|
||||
|
@ -433,7 +433,8 @@ void Instance::applyDifference(const MTPDlangPackDifference &difference) {
|
||||
_updated.notify();
|
||||
}
|
||||
|
||||
std::map<LangKey, QString> Instance::ParseStrings(const MTPVector<MTPLangPackString> &strings) {
|
||||
std::map<LangKey, QString> Instance::ParseStrings(
|
||||
const MTPVector<MTPLangPackString> &strings) {
|
||||
auto result = std::map<LangKey, QString>();
|
||||
for (auto &mtpString : strings.v) {
|
||||
HandleString(mtpString, [&result](auto &&key, auto &&value) {
|
||||
@ -449,10 +450,16 @@ std::map<LangKey, QString> Instance::ParseStrings(const MTPVector<MTPLangPackStr
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
LangKey Instance::ParseKeyValue(const QByteArray &key, const QByteArray &value, Result &result) {
|
||||
LangKey Instance::ParseKeyValue(
|
||||
const QByteArray &key,
|
||||
const QByteArray &value,
|
||||
Result &result) {
|
||||
auto keyIndex = GetKeyIndex(QLatin1String(key));
|
||||
if (keyIndex == kLangKeysCount) {
|
||||
LOG(("Lang Error: Unknown key '%1'").arg(QString::fromLatin1(key)));
|
||||
if (!key.startsWith("cloud_")) {
|
||||
LOG(("Lang Warning: Unknown key '%1'"
|
||||
).arg(QString::fromLatin1(key)));
|
||||
}
|
||||
return kLangKeysCount;
|
||||
}
|
||||
|
||||
@ -464,6 +471,13 @@ LangKey Instance::ParseKeyValue(const QByteArray &key, const QByteArray &value,
|
||||
return kLangKeysCount;
|
||||
}
|
||||
|
||||
QString Instance::getNonDefaultValue(const QByteArray &key) const {
|
||||
const auto i = _nonDefaultValues.find(key);
|
||||
return (i != end(_nonDefaultValues))
|
||||
? QString::fromUtf8(i->second)
|
||||
: QString();
|
||||
}
|
||||
|
||||
void Instance::applyValue(const QByteArray &key, const QByteArray &value) {
|
||||
_nonDefaultValues[key] = value;
|
||||
auto index = ParseKeyValue(key, value, _values);
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
|
||||
return _values[key];
|
||||
}
|
||||
QString getNonDefaultValue(const QByteArray &key) const;
|
||||
bool isNonDefaultPlural(LangKey key) const {
|
||||
Expects(key >= 0 && key < kLangKeysCount);
|
||||
Expects(_nonDefaultSet.size() == kLangKeysCount);
|
||||
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "passport/passport_encryption.h"
|
||||
#include "passport/passport_panel_controller.h"
|
||||
#include "passport/passport_panel_edit_document.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/passcode_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@ -34,6 +35,8 @@ constexpr auto kTranslationScansLimit = 20;
|
||||
constexpr auto kShortPollTimeout = TimeMs(3000);
|
||||
constexpr auto kRememberCredentialsDelay = TimeMs(1800 * 1000);
|
||||
|
||||
Config GlobalConfig;
|
||||
|
||||
bool ForwardServiceErrorRequired(const QString &error) {
|
||||
return (error == qstr("BOT_INVALID"))
|
||||
|| (error == qstr("PUBLIC_KEY_REQUIRED"))
|
||||
@ -228,6 +231,44 @@ QString ValidateUrl(const QString &url) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Config &ConfigInstance() {
|
||||
return GlobalConfig;
|
||||
}
|
||||
|
||||
Config ParseConfig(const MTPhelp_PassportConfig &data) {
|
||||
return data.match([](const MTPDhelp_passportConfig &data) {
|
||||
auto result = Config();
|
||||
result.hash = data.vhash.v;
|
||||
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
||||
const auto document = QJsonDocument::fromJson(
|
||||
data.vcountries_langs.c_dataJSON().vdata.v,
|
||||
&error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
LOG(("API Error: Failed to parse passport config, error: %1."
|
||||
).arg(error.errorString()));
|
||||
return result;
|
||||
} else if (!document.isObject()) {
|
||||
LOG(("API Error: Not an object received in passport config."));
|
||||
return result;
|
||||
}
|
||||
const auto object = document.object();
|
||||
for (auto i = object.constBegin(); i != object.constEnd(); ++i) {
|
||||
const auto countryCode = i.key();
|
||||
const auto language = i.value();
|
||||
if (!language.isString()) {
|
||||
LOG(("API Error: Not a string in passport config item."));
|
||||
continue;
|
||||
}
|
||||
result.languagesByCountryCode.emplace(
|
||||
countryCode,
|
||||
language.toString());
|
||||
}
|
||||
return result;
|
||||
}, [](const MTPDhelp_passportConfigNotModified &data) {
|
||||
return ConfigInstance();
|
||||
});
|
||||
}
|
||||
|
||||
QString NonceNameByScope(const QString &scope) {
|
||||
if (scope.startsWith('{') && scope.endsWith('}')) {
|
||||
return qsl("nonce");
|
||||
@ -579,6 +620,7 @@ FormController::FormController(
|
||||
void FormController::show() {
|
||||
requestForm();
|
||||
requestPassword();
|
||||
requestConfig();
|
||||
}
|
||||
|
||||
UserData *FormController::bot() const {
|
||||
@ -1082,6 +1124,7 @@ void FormController::decryptValues() {
|
||||
decryptValue(value);
|
||||
}
|
||||
fillErrors();
|
||||
fillNativeFromFallback();
|
||||
}
|
||||
|
||||
void FormController::fillErrors() {
|
||||
@ -1178,6 +1221,42 @@ void FormController::fillErrors() {
|
||||
}
|
||||
}
|
||||
|
||||
void FormController::fillNativeFromFallback() {
|
||||
const auto i = _form.values.find(Value::Type::PersonalDetails);
|
||||
if (i == end(_form.values) || !i->second.nativeNames) {
|
||||
return;
|
||||
}
|
||||
const auto scheme = GetDocumentScheme(
|
||||
Scope::Type::PersonalDetails,
|
||||
base::none,
|
||||
true);
|
||||
auto changed = false;
|
||||
auto values = i->second.data.parsed;
|
||||
using Scheme = EditDocumentScheme;
|
||||
for (const auto &row : scheme.rows) {
|
||||
if (row.valueClass == Scheme::ValueClass::Additional) {
|
||||
auto &field = values.fields[row.key];
|
||||
if (!field.text.isEmpty() || !field.error.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto i = values.fields.find(row.additionalFallbackKey);
|
||||
const auto value = (i == end(values.fields))
|
||||
? QString()
|
||||
: i->second.text;
|
||||
if (row.error(value).has_value()) {
|
||||
return;
|
||||
} else if (field.text != value) {
|
||||
field.text = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
startValueEdit(&i->second);
|
||||
saveValueEdit(&i->second, std::move(values));
|
||||
}
|
||||
}
|
||||
|
||||
void FormController::decryptValue(Value &value) const {
|
||||
Expects(!_secret.empty());
|
||||
|
||||
@ -2375,11 +2454,29 @@ auto FormController::findFile(const FileKey &key)
|
||||
void FormController::formDone(const MTPaccount_AuthorizationForm &result) {
|
||||
if (!parseForm(result)) {
|
||||
_view->showCriticalError(lang(lng_passport_form_error));
|
||||
} else if (!_passwordRequestId) {
|
||||
} else {
|
||||
showForm();
|
||||
}
|
||||
}
|
||||
|
||||
void FormController::requestConfig() {
|
||||
const auto i = _form.values.find(Value::Type::PersonalDetails);
|
||||
if (i == end(_form.values) || !i->second.nativeNames) {
|
||||
return;
|
||||
}
|
||||
const auto hash = ConfigInstance().hash;
|
||||
_configRequestId = request(MTPhelp_GetPassportConfig(
|
||||
MTP_int(hash)
|
||||
)).done([=](const MTPhelp_PassportConfig &result) {
|
||||
_configRequestId = 0;
|
||||
ConfigInstance() = ParseConfig(result);
|
||||
showForm();
|
||||
}).fail([=](const RPCError &error) {
|
||||
_configRequestId = 0;
|
||||
showForm();
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
||||
Expects(result.type() == mtpc_account_authorizationForm);
|
||||
|
||||
@ -2458,7 +2555,7 @@ void FormController::passwordDone(const MTPaccount_Password &result) {
|
||||
Expects(result.type() == mtpc_account_password);
|
||||
|
||||
const auto changed = applyPassword(result.c_account_password());
|
||||
if (changed && !_formRequestId) {
|
||||
if (changed) {
|
||||
showForm();
|
||||
}
|
||||
shortPollEmailConfirmation();
|
||||
@ -2473,7 +2570,9 @@ void FormController::shortPollEmailConfirmation() {
|
||||
}
|
||||
|
||||
void FormController::showForm() {
|
||||
if (!_bot) {
|
||||
if (_formRequestId || _passwordRequestId || _configRequestId) {
|
||||
return;
|
||||
} else if (!_bot) {
|
||||
formFail(Lang::Hard::NoAuthorizationBot());
|
||||
return;
|
||||
}
|
||||
|
@ -25,6 +25,13 @@ class Controller;
|
||||
|
||||
namespace Passport {
|
||||
|
||||
struct Config {
|
||||
int32 hash = 0;
|
||||
std::map<QString, QString> languagesByCountryCode;
|
||||
};
|
||||
Config &ConfigInstance();
|
||||
Config ParseConfig(const MTPhelp_PassportConfig &data);
|
||||
|
||||
struct SavedCredentials {
|
||||
bytes::vector hashForAuth;
|
||||
bytes::vector hashForSecret;
|
||||
@ -387,6 +394,7 @@ private:
|
||||
|
||||
void requestForm();
|
||||
void requestPassword();
|
||||
void requestConfig();
|
||||
|
||||
void formDone(const MTPaccount_AuthorizationForm &result);
|
||||
void formFail(const QString &error);
|
||||
@ -436,6 +444,7 @@ private:
|
||||
bool validateValueSecrets(Value &value) const;
|
||||
void resetValue(Value &value) const;
|
||||
void fillErrors();
|
||||
void fillNativeFromFallback();
|
||||
|
||||
void loadFile(File &file);
|
||||
void fileLoadDone(FileKey key, const QByteArray &bytes);
|
||||
@ -505,6 +514,7 @@ private:
|
||||
mtpRequestId _formRequestId = 0;
|
||||
mtpRequestId _passwordRequestId = 0;
|
||||
mtpRequestId _passwordCheckRequestId = 0;
|
||||
mtpRequestId _configRequestId = 0;
|
||||
|
||||
PasswordSettings _password;
|
||||
TimeMs _lastSrpIdInvalidTime = 0;
|
||||
|
@ -32,6 +32,7 @@ constexpr auto kMaxStreetSize = 64;
|
||||
constexpr auto kMinCitySize = 2;
|
||||
constexpr auto kMaxCitySize = 64;
|
||||
constexpr auto kMaxPostcodeSize = 10;
|
||||
const auto kLanguageNamePrefix = "cloud_lng_passport_in_";
|
||||
|
||||
ScanInfo CollectScanInfo(const EditFile &file) {
|
||||
const auto status = [&] {
|
||||
@ -282,8 +283,33 @@ EditDocumentScheme GetDocumentScheme(
|
||||
};
|
||||
if (nativeNames) {
|
||||
result.additionalDependencyKey = qsl("residence_country_code");
|
||||
result.additionalHeader = lang(lng_passport_native_name_title);
|
||||
result.additionalDescription = [](const QString &countryCode) {
|
||||
|
||||
const auto languageValue = [](const QString &countryCode) {
|
||||
if (countryCode.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
const auto &config = ConfigInstance();
|
||||
const auto i = config.languagesByCountryCode.find(
|
||||
countryCode);
|
||||
if (i == end(config.languagesByCountryCode)) {
|
||||
return QString();
|
||||
}
|
||||
return Lang::Current().getNonDefaultValue(
|
||||
kLanguageNamePrefix + i->second.toUtf8());
|
||||
};
|
||||
result.additionalHeader = [=](const QString &countryCode) {
|
||||
const auto language = languageValue(countryCode);
|
||||
return language.isEmpty()
|
||||
? lang(lng_passport_native_name_title)
|
||||
: lng_passport_native_name_language(
|
||||
lt_language,
|
||||
language);
|
||||
};
|
||||
result.additionalDescription = [=](const QString &countryCode) {
|
||||
const auto language = languageValue(countryCode);
|
||||
if (!language.isEmpty()) {
|
||||
return lang(lng_passport_native_name_language_about);
|
||||
}
|
||||
const auto name = CountrySelectBox::NameByISO(countryCode);
|
||||
Assert(!name.isEmpty());
|
||||
return lng_passport_native_name_about(
|
||||
@ -291,7 +317,18 @@ EditDocumentScheme GetDocumentScheme(
|
||||
name);
|
||||
};
|
||||
result.additionalShown = [](const QString &countryCode) {
|
||||
return !countryCode.isEmpty();
|
||||
using Result = EditDocumentScheme::AdditionalVisibility;
|
||||
if (countryCode.isEmpty()) {
|
||||
return Result::Hidden;
|
||||
}
|
||||
const auto &config = ConfigInstance();
|
||||
const auto i = config.languagesByCountryCode.find(
|
||||
countryCode);
|
||||
if (i != end(config.languagesByCountryCode)
|
||||
&& i->second == "en") {
|
||||
return Result::OnlyIfError;
|
||||
}
|
||||
return Result::Shown;
|
||||
};
|
||||
using Row = EditDocumentScheme::Row;
|
||||
auto additional = std::initializer_list<Row>{
|
||||
@ -303,6 +340,8 @@ EditDocumentScheme GetDocumentScheme(
|
||||
NativeNameValidate,
|
||||
DontFormat,
|
||||
kMaxNameSize,
|
||||
QString(),
|
||||
qsl("first_name"),
|
||||
},
|
||||
{
|
||||
ValueClass::Additional,
|
||||
@ -313,6 +352,7 @@ EditDocumentScheme GetDocumentScheme(
|
||||
DontFormat,
|
||||
kMaxNameSize,
|
||||
qsl("first_name_native"),
|
||||
qsl("middle_name"),
|
||||
},
|
||||
{
|
||||
ValueClass::Additional,
|
||||
@ -323,6 +363,7 @@ EditDocumentScheme GetDocumentScheme(
|
||||
DontFormat,
|
||||
kMaxNameSize,
|
||||
qsl("first_name_native"),
|
||||
qsl("last_name"),
|
||||
},
|
||||
};
|
||||
for (auto &row : additional) {
|
||||
|
@ -404,11 +404,47 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||
inner,
|
||||
object_ptr<Ui::VerticalLayout>(inner)));
|
||||
const auto added = wrap->entity();
|
||||
|
||||
auto showIfError = false;
|
||||
enumerateRows([&](
|
||||
int i,
|
||||
const Scheme::Row &row,
|
||||
const ValueMap &fields) {
|
||||
if (row.valueClass != Scheme::ValueClass::Additional) {
|
||||
return;
|
||||
}
|
||||
const auto it = fields.fields.find(row.key);
|
||||
if (it == end(fields.fields)) {
|
||||
return;
|
||||
} else if (!it->second.error.isEmpty()) {
|
||||
showIfError = true;
|
||||
} else if (it->second.text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto fallbackIt = fields.fields.find(
|
||||
row.additionalFallbackKey);
|
||||
if (fallbackIt != end(fields.fields)
|
||||
&& fallbackIt->second.text != it->second.text) {
|
||||
showIfError = true;
|
||||
}
|
||||
});
|
||||
const auto shown = [=](const QString &code) {
|
||||
using Result = Scheme::AdditionalVisibility;
|
||||
const auto value = _scheme.additionalShown(code);
|
||||
return (value == Result::Shown)
|
||||
|| (value == Result::OnlyIfError && showIfError);
|
||||
};
|
||||
|
||||
auto title = row->value(
|
||||
) | rpl::filter(
|
||||
shown
|
||||
) | rpl::map([=](const QString &code) {
|
||||
return _scheme.additionalHeader(code);
|
||||
});
|
||||
added->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
added,
|
||||
_scheme.additionalHeader,
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
std::move(title),
|
||||
st::passportFormHeader),
|
||||
st::passportNativeNameHeaderPadding);
|
||||
|
||||
@ -422,9 +458,9 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||
});
|
||||
|
||||
auto description = row->value(
|
||||
) | rpl::filter([=](const QString &code) {
|
||||
return _scheme.additionalShown(code);
|
||||
}) | rpl::map([=](const QString &code) {
|
||||
) | rpl::filter(
|
||||
shown
|
||||
) | rpl::map([=](const QString &code) {
|
||||
return _scheme.additionalDescription(code);
|
||||
});
|
||||
added->add(
|
||||
@ -437,11 +473,15 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||
st::passportFormLabelPadding),
|
||||
st::passportNativeNameAboutMargin);
|
||||
|
||||
wrap->toggleOn(row->value(
|
||||
) | rpl::map([=](const QString &code) {
|
||||
return _scheme.additionalShown(code);
|
||||
}));
|
||||
wrap->toggleOn(row->value() | rpl::map(shown));
|
||||
wrap->finishAnimating();
|
||||
|
||||
row->value(
|
||||
) | rpl::map(
|
||||
shown
|
||||
) | rpl::start_with_next([=](bool visible) {
|
||||
_additionalShown = visible;
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
inner->add(
|
||||
@ -469,8 +509,8 @@ void PanelEditDocument::createDetailsRow(
|
||||
const ValueMap &fields,
|
||||
int maxLabelWidth) {
|
||||
const auto valueOrEmpty = [&](
|
||||
const ValueMap &values,
|
||||
const QString &key) {
|
||||
const ValueMap &values,
|
||||
const QString &key) {
|
||||
const auto &fields = values.fields;
|
||||
if (const auto i = fields.find(key); i != fields.end()) {
|
||||
return i->second;
|
||||
@ -561,11 +601,31 @@ PanelEditDocument::Result PanelEditDocument::collect() const {
|
||||
auto &fields = (row.valueClass == Scheme::ValueClass::Scans)
|
||||
? result.filesData
|
||||
: result.data;
|
||||
if (row.valueClass == Scheme::ValueClass::Additional
|
||||
&& !_additionalShown) {
|
||||
continue;
|
||||
}
|
||||
fields.fields[row.key].text = field->valueCurrent();
|
||||
}
|
||||
if (!_additionalShown) {
|
||||
fillAdditionalFromFallbacks(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PanelEditDocument::fillAdditionalFromFallbacks(Result &result) const {
|
||||
for (const auto &row : _scheme.rows) {
|
||||
if (row.valueClass != Scheme::ValueClass::Additional) {
|
||||
continue;
|
||||
}
|
||||
Assert(!row.additionalFallbackKey.isEmpty());
|
||||
auto &fields = result.data;
|
||||
const auto j = fields.fields.find(row.additionalFallbackKey);
|
||||
Assert(j != end(fields.fields));
|
||||
fields.fields[row.key] = j->second;
|
||||
}
|
||||
}
|
||||
|
||||
bool PanelEditDocument::validate() {
|
||||
auto error = _editScans
|
||||
? _editScans->validateGetErrorTop()
|
||||
@ -585,6 +645,10 @@ bool PanelEditDocument::validate() {
|
||||
auto first = QPointer<PanelDetailsRow>();
|
||||
for (const auto [i, field] : base::reversed(_details)) {
|
||||
const auto &row = _scheme.rows[i];
|
||||
if (row.valueClass == Scheme::ValueClass::Additional
|
||||
&& !_additionalShown) {
|
||||
continue;
|
||||
}
|
||||
if (field->errorShown()) {
|
||||
field->showError();
|
||||
first = field;
|
||||
|
@ -44,6 +44,11 @@ struct EditDocumentScheme {
|
||||
Additional,
|
||||
Scans,
|
||||
};
|
||||
enum class AdditionalVisibility {
|
||||
Hidden,
|
||||
OnlyIfError,
|
||||
Shown,
|
||||
};
|
||||
struct Row {
|
||||
using Validator = Fn<base::optional<QString>(const QString &value)>;
|
||||
using Formatter = Fn<QString(const QString &value)>;
|
||||
@ -54,7 +59,8 @@ struct EditDocumentScheme {
|
||||
Validator error;
|
||||
Formatter format;
|
||||
int lengthLimit = 0;
|
||||
QString keyForAttachmentTo; // attach [last|middle]_name to first_*
|
||||
QString keyForAttachmentTo; // Attach [last|middle]_name to first_*.
|
||||
QString additionalFallbackKey; // *_name_native from *_name.
|
||||
};
|
||||
std::vector<Row> rows;
|
||||
QString fieldsHeader;
|
||||
@ -62,8 +68,8 @@ struct EditDocumentScheme {
|
||||
QString scansHeader;
|
||||
|
||||
QString additionalDependencyKey;
|
||||
Fn<bool(const QString &dependency)> additionalShown;
|
||||
QString additionalHeader;
|
||||
Fn<AdditionalVisibility(const QString &dependency)> additionalShown;
|
||||
Fn<QString(const QString &dependency)> additionalHeader;
|
||||
Fn<QString(const QString &dependency)> additionalDescription;
|
||||
|
||||
};
|
||||
@ -127,6 +133,7 @@ private:
|
||||
void updateCommonError();
|
||||
|
||||
Result collect() const;
|
||||
void fillAdditionalFromFallbacks(Result &result) const;
|
||||
bool validate();
|
||||
void save();
|
||||
|
||||
@ -149,6 +156,7 @@ private:
|
||||
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _commonError;
|
||||
std::map<int, QPointer<PanelDetailsRow>> _details;
|
||||
bool _fieldsChanged = false;
|
||||
bool _additionalShown = false;
|
||||
|
||||
QPointer<Info::Profile::Button> _delete;
|
||||
|
||||
|
@ -109,6 +109,7 @@
|
||||
'<@(style_files)',
|
||||
'<!@(<(list_sources_command) <(qt_moc_list_sources_arg))',
|
||||
'telegram_sources.txt',
|
||||
'<(res_loc)/langs/cloud_lang.strings',
|
||||
'<(res_loc)/export_html/css/style.css',
|
||||
'<(res_loc)/export_html/js/script.js',
|
||||
'<(res_loc)/export_html/images/back.png',
|
||||
|
Loading…
Reference in New Issue
Block a user