mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Removed static storing of passport config.
This commit is contained in:
parent
adb0a9b6f0
commit
2efd735243
7 changed files with 198 additions and 150 deletions
|
@ -42,8 +42,6 @@ constexpr auto kTranslationScansLimit = 20;
|
|||
constexpr auto kShortPollTimeout = crl::time(3000);
|
||||
constexpr auto kRememberCredentialsDelay = crl::time(1800 * 1000);
|
||||
|
||||
Config GlobalConfig;
|
||||
|
||||
bool ForwardServiceErrorRequired(const QString &error) {
|
||||
return (error == qstr("BOT_INVALID"))
|
||||
|| (error == qstr("PUBLIC_KEY_REQUIRED"))
|
||||
|
@ -239,46 +237,35 @@ QString ValidateUrl(const QString &url) {
|
|||
: result;
|
||||
}
|
||||
|
||||
auto ParseConfig(const QByteArray &json) {
|
||||
auto languagesByCountryCode = std::map<QString, QString>();
|
||||
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
||||
const auto document = QJsonDocument::fromJson(json, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
LOG(("API Error: Failed to parse passport config, error: %1."
|
||||
).arg(error.errorString()));
|
||||
return languagesByCountryCode;
|
||||
} else if (!document.isObject()) {
|
||||
LOG(("API Error: Not an object received in passport config."));
|
||||
return languagesByCountryCode;
|
||||
}
|
||||
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;
|
||||
}
|
||||
languagesByCountryCode.emplace(
|
||||
countryCode,
|
||||
language.toString());
|
||||
}
|
||||
return languagesByCountryCode;
|
||||
}
|
||||
|
||||
} // 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");
|
||||
|
@ -638,7 +625,6 @@ Main::Session &FormController::session() const {
|
|||
void FormController::show() {
|
||||
requestForm();
|
||||
requestPassword();
|
||||
requestConfig();
|
||||
}
|
||||
|
||||
UserData *FormController::bot() const {
|
||||
|
@ -1242,6 +1228,44 @@ void FormController::fillErrors() {
|
|||
}
|
||||
}
|
||||
|
||||
rpl::producer<EditDocumentCountry> FormController::preferredLanguage(
|
||||
const QString &countryCode) {
|
||||
const auto findLang = [=] {
|
||||
if (countryCode.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
auto &langs = _passportConfig.languagesByCountryCode;
|
||||
const auto i = langs.find(countryCode);
|
||||
return (i == end(langs)) ? QString() : i->second;
|
||||
};
|
||||
return [=](auto consumer) {
|
||||
const auto hash = _passportConfig.hash;
|
||||
if (hash) {
|
||||
consumer.put_next({ countryCode, findLang() });
|
||||
consumer.put_done();
|
||||
return rpl::lifetime() ;
|
||||
}
|
||||
|
||||
_api.request(MTPhelp_GetPassportConfig(
|
||||
MTP_int(hash)
|
||||
)).done([=](const MTPhelp_PassportConfig &result) {
|
||||
result.match([&](const MTPDhelp_passportConfig &data) {
|
||||
_passportConfig.hash = data.vhash().v;
|
||||
_passportConfig.languagesByCountryCode = ParseConfig(
|
||||
data.vcountries_langs().c_dataJSON().vdata().v);
|
||||
}, [](const MTPDhelp_passportConfigNotModified &data) {
|
||||
});
|
||||
consumer.put_next({ countryCode, findLang() });
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_next({ countryCode, QString() });
|
||||
consumer.put_done();
|
||||
}).send();
|
||||
|
||||
return rpl::lifetime();
|
||||
};
|
||||
}
|
||||
|
||||
void FormController::fillNativeFromFallback() {
|
||||
// Check if additional values (*_name_native) were requested.
|
||||
const auto i = _form.values.find(Value::Type::PersonalDetails);
|
||||
|
@ -1254,48 +1278,58 @@ void FormController::fillNativeFromFallback() {
|
|||
const auto scheme = GetDocumentScheme(
|
||||
Scope::Type::PersonalDetails,
|
||||
std::nullopt,
|
||||
true);
|
||||
true,
|
||||
[=](const QString &code) { return preferredLanguage(code); });
|
||||
const auto dependencyIt = values.fields.find(
|
||||
scheme.additionalDependencyKey);
|
||||
const auto dependency = (dependencyIt == end(values.fields))
|
||||
? QString()
|
||||
: dependencyIt->second.text;
|
||||
if (scheme.additionalShown(dependency)
|
||||
!= EditDocumentScheme::AdditionalVisibility::OnlyIfError) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy additional values from fallback if they're not filled yet.
|
||||
auto changed = false;
|
||||
using Scheme = EditDocumentScheme;
|
||||
for (const auto &row : scheme.rows) {
|
||||
if (row.valueClass == Scheme::ValueClass::Additional) {
|
||||
const auto nativeIt = values.fields.find(row.key);
|
||||
const auto native = (nativeIt == end(values.fields))
|
||||
? QString()
|
||||
: nativeIt->second.text;
|
||||
if (!native.isEmpty()
|
||||
|| (nativeIt != end(values.fields)
|
||||
&& !nativeIt->second.error.isEmpty())) {
|
||||
return;
|
||||
}
|
||||
const auto latinIt = values.fields.find(
|
||||
row.additionalFallbackKey);
|
||||
const auto latin = (latinIt == end(values.fields))
|
||||
? QString()
|
||||
: latinIt->second.text;
|
||||
if (row.error(latin).has_value()) {
|
||||
return;
|
||||
} else if (native != latin) {
|
||||
values.fields[row.key].text = latin;
|
||||
changed = true;
|
||||
scheme.preferredLanguage(
|
||||
dependency
|
||||
) | rpl::map(
|
||||
scheme.additionalShown
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](Scheme::AdditionalVisibility v) {
|
||||
if (v != Scheme::AdditionalVisibility::OnlyIfError) {
|
||||
return;
|
||||
}
|
||||
auto values = i->second.data.parsed;
|
||||
auto changed = false;
|
||||
|
||||
for (const auto &row : scheme.rows) {
|
||||
if (row.valueClass == Scheme::ValueClass::Additional) {
|
||||
const auto nativeIt = values.fields.find(row.key);
|
||||
const auto native = (nativeIt == end(values.fields))
|
||||
? QString()
|
||||
: nativeIt->second.text;
|
||||
if (!native.isEmpty()
|
||||
|| (nativeIt != end(values.fields)
|
||||
&& !nativeIt->second.error.isEmpty())) {
|
||||
return;
|
||||
}
|
||||
const auto latinIt = values.fields.find(
|
||||
row.additionalFallbackKey);
|
||||
const auto latin = (latinIt == end(values.fields))
|
||||
? QString()
|
||||
: latinIt->second.text;
|
||||
if (row.error(latin).has_value()) {
|
||||
return;
|
||||
} else if (native != latin) {
|
||||
values.fields[row.key].text = latin;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
startValueEdit(&i->second);
|
||||
saveValueEdit(&i->second, std::move(values));
|
||||
}
|
||||
if (changed) {
|
||||
startValueEdit(&i->second);
|
||||
saveValueEdit(&i->second, std::move(values));
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
void FormController::decryptValue(Value &value) const {
|
||||
|
@ -2507,20 +2541,6 @@ void FormController::formDone(const MTPaccount_AuthorizationForm &result) {
|
|||
}
|
||||
}
|
||||
|
||||
void FormController::requestConfig() {
|
||||
const auto hash = ConfigInstance().hash;
|
||||
_configRequestId = _api.request(MTPhelp_GetPassportConfig(
|
||||
MTP_int(hash)
|
||||
)).done([=](const MTPhelp_PassportConfig &result) {
|
||||
_configRequestId = 0;
|
||||
ConfigInstance() = ParseConfig(result);
|
||||
showForm();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_configRequestId = 0;
|
||||
showForm();
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
||||
Expects(result.type() == mtpc_account_authorizationForm);
|
||||
|
||||
|
@ -2614,7 +2634,7 @@ void FormController::shortPollEmailConfirmation() {
|
|||
}
|
||||
|
||||
void FormController::showForm() {
|
||||
if (_formRequestId || _passwordRequestId || _configRequestId) {
|
||||
if (_formRequestId || _passwordRequestId) {
|
||||
return;
|
||||
} else if (!_bot) {
|
||||
formFail(Lang::Hard::NoAuthorizationBot());
|
||||
|
|
|
@ -29,12 +29,7 @@ class Session;
|
|||
|
||||
namespace Passport {
|
||||
|
||||
struct Config {
|
||||
int32 hash = 0;
|
||||
std::map<QString, QString> languagesByCountryCode;
|
||||
};
|
||||
Config &ConfigInstance();
|
||||
Config ParseConfig(const MTPhelp_PassportConfig &data);
|
||||
struct EditDocumentCountry;
|
||||
|
||||
struct SavedCredentials {
|
||||
bytes::vector hashForAuth;
|
||||
|
@ -416,6 +411,9 @@ public:
|
|||
void cancel();
|
||||
void cancelSure();
|
||||
|
||||
[[nodiscard]] rpl::producer<EditDocumentCountry> preferredLanguage(
|
||||
const QString &countryCode);
|
||||
|
||||
rpl::lifetime &lifetime();
|
||||
|
||||
~FormController();
|
||||
|
@ -439,7 +437,6 @@ private:
|
|||
|
||||
void requestForm();
|
||||
void requestPassword();
|
||||
void requestConfig();
|
||||
|
||||
void formDone(const MTPaccount_AuthorizationForm &result);
|
||||
void formFail(const QString &error);
|
||||
|
@ -560,7 +557,6 @@ private:
|
|||
mtpRequestId _formRequestId = 0;
|
||||
mtpRequestId _passwordRequestId = 0;
|
||||
mtpRequestId _passwordCheckRequestId = 0;
|
||||
mtpRequestId _configRequestId = 0;
|
||||
|
||||
PasswordSettings _password;
|
||||
crl::time _lastSrpIdInvalidTime = 0;
|
||||
|
@ -572,6 +568,11 @@ private:
|
|||
mtpRequestId _recoverRequestId = 0;
|
||||
base::flat_map<FileKey, std::unique_ptr<mtpFileLoader>> _fileLoaders;
|
||||
|
||||
struct {
|
||||
int32 hash = 0;
|
||||
std::map<QString, QString> languagesByCountryCode;
|
||||
} _passportConfig;
|
||||
|
||||
rpl::event_stream<not_null<const EditFile*>> _scanUpdated;
|
||||
rpl::event_stream<not_null<const Value*>> _valueSaveFinished;
|
||||
rpl::event_stream<not_null<const Value*>> _verificationNeeded;
|
||||
|
|
|
@ -377,7 +377,8 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
|||
const auto scheme = GetDocumentScheme(
|
||||
scope.type,
|
||||
document ? base::make_optional(document->type) : std::nullopt,
|
||||
scope.details ? scope.details->nativeNames : false);
|
||||
scope.details ? scope.details->nativeNames : false,
|
||||
nullptr);
|
||||
using ValueClass = EditDocumentScheme::ValueClass;
|
||||
const auto skipAdditional = [&] {
|
||||
if (!fields) {
|
||||
|
|
|
@ -117,7 +117,8 @@ std::map<FileType, ScanInfo> PrepareSpecialFiles(const Value &value) {
|
|||
EditDocumentScheme GetDocumentScheme(
|
||||
Scope::Type type,
|
||||
std::optional<Value::Type> scansType,
|
||||
bool nativeNames) {
|
||||
bool nativeNames,
|
||||
preferredLangCallback &&preferredLanguage) {
|
||||
using Scheme = EditDocumentScheme;
|
||||
using ValueClass = Scheme::ValueClass;
|
||||
const auto DontFormat = nullptr;
|
||||
|
@ -294,21 +295,17 @@ EditDocumentScheme GetDocumentScheme(
|
|||
if (nativeNames) {
|
||||
result.additionalDependencyKey = qsl("residence_country_code");
|
||||
|
||||
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::GetNonDefaultValue(
|
||||
kLanguageNamePrefix + i->second.toUtf8());
|
||||
result.preferredLanguage = preferredLanguage
|
||||
? std::move(preferredLanguage)
|
||||
: [](const QString &) {
|
||||
return rpl::single(EditDocumentCountry());
|
||||
};
|
||||
const auto languageValue = [](const QString &langCode) {
|
||||
return Lang::GetNonDefaultValue(kLanguageNamePrefix
|
||||
+ langCode.toUtf8());
|
||||
};
|
||||
result.additionalHeader = [=](const QString &countryCode) {
|
||||
const auto language = languageValue(countryCode);
|
||||
result.additionalHeader = [=](const EditDocumentCountry &info) {
|
||||
const auto language = languageValue(info.languageCode);
|
||||
return language.isEmpty()
|
||||
? tr::lng_passport_native_name_title(tr::now)
|
||||
: tr::lng_passport_native_name_language(
|
||||
|
@ -316,32 +313,28 @@ EditDocumentScheme GetDocumentScheme(
|
|||
lt_language,
|
||||
language);
|
||||
};
|
||||
result.additionalDescription = [=](const QString &countryCode) {
|
||||
const auto language = languageValue(countryCode);
|
||||
result.additionalDescription = [=](
|
||||
const EditDocumentCountry &info) {
|
||||
const auto language = languageValue(info.languageCode);
|
||||
if (!language.isEmpty()) {
|
||||
return tr::lng_passport_native_name_language_about(tr::now);
|
||||
return tr::lng_passport_native_name_language_about(
|
||||
tr::now);
|
||||
}
|
||||
const auto name = Countries::Instance().countryNameByISO2(
|
||||
countryCode);
|
||||
info.countryCode);
|
||||
Assert(!name.isEmpty());
|
||||
return tr::lng_passport_native_name_about(
|
||||
tr::now,
|
||||
lt_country,
|
||||
name);
|
||||
};
|
||||
result.additionalShown = [](const QString &countryCode) {
|
||||
result.additionalShown = [](const EditDocumentCountry &info) {
|
||||
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;
|
||||
return (info.countryCode.isEmpty())
|
||||
? Result::Hidden
|
||||
: (info.languageCode == "en")
|
||||
? Result::OnlyIfError
|
||||
: Result::Shown;
|
||||
};
|
||||
using Row = EditDocumentScheme::Row;
|
||||
auto additional = std::initializer_list<Row>{
|
||||
|
@ -1149,6 +1142,10 @@ void PanelController::startScopeEdit(
|
|||
_form->startValueEdit(_editDocument);
|
||||
}
|
||||
|
||||
auto preferredLanguage = [=](const QString &countryCode) {
|
||||
return _form->preferredLanguage(countryCode);
|
||||
};
|
||||
|
||||
auto content = [&]() -> object_ptr<Ui::RpWidget> {
|
||||
switch (_editScope->type) {
|
||||
case Scope::Type::Identity:
|
||||
|
@ -1169,7 +1166,8 @@ void PanelController::startScopeEdit(
|
|||
GetDocumentScheme(
|
||||
_editScope->type,
|
||||
_editDocument->type,
|
||||
_editValue->nativeNames),
|
||||
_editValue->nativeNames,
|
||||
std::move(preferredLanguage)),
|
||||
_editValue->error,
|
||||
_editValue->data.parsedInEdit,
|
||||
_editDocument->error,
|
||||
|
@ -1183,7 +1181,8 @@ void PanelController::startScopeEdit(
|
|||
GetDocumentScheme(
|
||||
_editScope->type,
|
||||
_editDocument->type,
|
||||
false),
|
||||
false,
|
||||
std::move(preferredLanguage)),
|
||||
_editDocument->error,
|
||||
_editDocument->data.parsedInEdit,
|
||||
std::move(scans),
|
||||
|
@ -1204,7 +1203,8 @@ void PanelController::startScopeEdit(
|
|||
GetDocumentScheme(
|
||||
_editScope->type,
|
||||
std::nullopt,
|
||||
_editValue->nativeNames),
|
||||
_editValue->nativeNames,
|
||||
std::move(preferredLanguage)),
|
||||
_editValue->error,
|
||||
_editValue->data.parsedInEdit);
|
||||
const auto weak = Ui::MakeWeak(result.data());
|
||||
|
|
|
@ -20,15 +20,19 @@ namespace Passport {
|
|||
class FormController;
|
||||
class Panel;
|
||||
|
||||
struct EditDocumentCountry;
|
||||
struct EditDocumentScheme;
|
||||
struct EditContactScheme;
|
||||
|
||||
enum class ReadScanError;
|
||||
|
||||
using preferredLangCallback =
|
||||
Fn<rpl::producer<EditDocumentCountry>(const QString &)>;
|
||||
EditDocumentScheme GetDocumentScheme(
|
||||
Scope::Type type,
|
||||
std::optional<Value::Type> scansType,
|
||||
bool nativeNames);
|
||||
bool nativeNames,
|
||||
preferredLangCallback &&preferredLanguage);
|
||||
EditContactScheme GetContactScheme(Scope::Type type);
|
||||
|
||||
const std::map<QString, QString> &LatinToNativeMap();
|
||||
|
|
|
@ -425,25 +425,42 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
|||
showIfError = true;
|
||||
}
|
||||
});
|
||||
const auto shown = [=](const QString &code) {
|
||||
const auto shown = [=](const Scheme::CountryInfo &info) {
|
||||
using Result = Scheme::AdditionalVisibility;
|
||||
const auto value = _scheme.additionalShown(code);
|
||||
const auto value = _scheme.additionalShown(info);
|
||||
return (value == Result::Shown)
|
||||
|| (value == Result::OnlyIfError && showIfError);
|
||||
};
|
||||
|
||||
auto title = row->value(
|
||||
) | rpl::filter(
|
||||
auto langValue = row->value(
|
||||
) | rpl::map(
|
||||
_scheme.preferredLanguage
|
||||
) | rpl::flatten_latest();
|
||||
|
||||
auto title = rpl::duplicate(langValue) | rpl::filter(
|
||||
shown
|
||||
) | rpl::map([=](const QString &code) {
|
||||
return _scheme.additionalHeader(code);
|
||||
) | rpl::map([=](const Scheme::CountryInfo &info) {
|
||||
return _scheme.additionalHeader(info);
|
||||
});
|
||||
added->add(
|
||||
const auto headerLabel = added->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
added,
|
||||
std::move(title),
|
||||
rpl::duplicate(title),
|
||||
st::passportFormHeader),
|
||||
st::passportNativeNameHeaderPadding);
|
||||
std::move(
|
||||
title
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto &padding = st::passportNativeNameHeaderPadding;
|
||||
const auto available = added->width()
|
||||
- padding.left()
|
||||
- padding.right();
|
||||
headerLabel->resizeToNaturalWidth(available);
|
||||
headerLabel->moveToLeft(
|
||||
padding.left(),
|
||||
padding.top(),
|
||||
available);
|
||||
}, headerLabel->lifetime());
|
||||
|
||||
enumerateRows([&](
|
||||
int i,
|
||||
|
@ -454,11 +471,10 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
|||
}
|
||||
});
|
||||
|
||||
auto description = row->value(
|
||||
) | rpl::filter(
|
||||
auto description = rpl::duplicate(langValue) | rpl::filter(
|
||||
shown
|
||||
) | rpl::map([=](const QString &code) {
|
||||
return _scheme.additionalDescription(code);
|
||||
) | rpl::map([=](const Scheme::CountryInfo &info) {
|
||||
return _scheme.additionalDescription(info);
|
||||
});
|
||||
added->add(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
|
@ -470,11 +486,10 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
|||
st::passportFormLabelPadding),
|
||||
st::passportNativeNameAboutMargin);
|
||||
|
||||
wrap->toggleOn(row->value() | rpl::map(shown));
|
||||
wrap->toggleOn(rpl::duplicate(langValue) | rpl::map(shown));
|
||||
wrap->finishAnimating();
|
||||
|
||||
row->value(
|
||||
) | rpl::map(
|
||||
std::move(langValue) | rpl::map(
|
||||
shown
|
||||
) | rpl::start_with_next([=](bool visible) {
|
||||
_additionalShown = visible;
|
||||
|
|
|
@ -39,6 +39,11 @@ class EditScans;
|
|||
enum class FileType;
|
||||
struct ScanListData;
|
||||
|
||||
struct EditDocumentCountry {
|
||||
QString countryCode;
|
||||
QString languageCode;
|
||||
};
|
||||
|
||||
struct EditDocumentScheme {
|
||||
enum class ValueClass {
|
||||
Fields,
|
||||
|
@ -50,6 +55,7 @@ struct EditDocumentScheme {
|
|||
OnlyIfError,
|
||||
Shown,
|
||||
};
|
||||
using CountryInfo = EditDocumentCountry;
|
||||
struct Row {
|
||||
using Validator = Fn<std::optional<QString>(const QString &value)>;
|
||||
using Formatter = Fn<QString(const QString &value)>;
|
||||
|
@ -69,9 +75,10 @@ struct EditDocumentScheme {
|
|||
QString scansHeader;
|
||||
|
||||
QString additionalDependencyKey;
|
||||
Fn<AdditionalVisibility(const QString &dependency)> additionalShown;
|
||||
Fn<QString(const QString &dependency)> additionalHeader;
|
||||
Fn<QString(const QString &dependency)> additionalDescription;
|
||||
Fn<AdditionalVisibility(const CountryInfo &dependency)> additionalShown;
|
||||
Fn<QString(const CountryInfo &dependency)> additionalHeader;
|
||||
Fn<QString(const CountryInfo &dependency)> additionalDescription;
|
||||
Fn<rpl::producer<CountryInfo>(const QString &)> preferredLanguage;
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue