tdesktop/Telegram/SourceFiles/passport/passport_panel_controller.cpp

910 lines
24 KiB
C++
Raw Normal View History

/*
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 "passport/passport_panel_controller.h"
#include "lang/lang_keys.h"
#include "passport/passport_panel_edit_document.h"
2018-04-10 11:26:21 +00:00
#include "passport/passport_panel_details_row.h"
#include "passport/passport_panel_edit_contact.h"
2018-04-10 07:51:19 +00:00
#include "passport/passport_panel_edit_scans.h"
#include "passport/passport_panel.h"
#include "boxes/confirm_box.h"
2018-04-13 10:54:17 +00:00
#include "ui/toast/toast.h"
2018-04-12 10:20:54 +00:00
#include "ui/countryinput.h"
#include "layout.h"
namespace Passport {
2018-04-13 11:15:07 +00:00
constexpr auto kMaxNameSize = 255;
constexpr auto kMaxDocumentSize = 24;
constexpr auto kMaxStreetSize = 64;
constexpr auto kMinCitySize = 2;
constexpr auto kMaxCitySize = 64;
constexpr auto kMinPostcodeSize = 2;
constexpr auto kMaxPostcodeSize = 12;
2018-04-12 15:45:04 +00:00
EditDocumentScheme GetDocumentScheme(
2018-04-10 07:51:19 +00:00
Scope::Type type,
2018-04-12 15:45:04 +00:00
base::optional<Value::Type> scansType) {
using Scheme = EditDocumentScheme;
using ValueClass = Scheme::ValueClass;
2018-04-12 10:20:54 +00:00
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;
2018-04-13 11:15:07 +00:00
const auto LimitedValidate = [](int max, int min = 1) {
return [=](const QString &value) {
return (value.size() >= min) && (value.size() <= max);
};
};
2018-04-13 11:15:07 +00:00
const auto NameValidate = LimitedValidate(kMaxNameSize);
const auto DocumentValidate = LimitedValidate(kMaxDocumentSize);
const auto StreetValidate = LimitedValidate(kMaxStreetSize);
const auto CityValidate = LimitedValidate(kMaxCitySize, kMinCitySize);
const auto PostcodeValidate = LimitedValidate(
kMaxPostcodeSize,
kMinPostcodeSize);
const auto DateValidate = [](const QString &value) {
return QRegularExpression(
"^\\d{2}\\.\\d{2}\\.\\d{4}$"
).match(value).hasMatch();
};
const auto DateOrEmptyValidate = [=](const QString &value) {
return value.isEmpty() || DateValidate(value);
};
const auto GenderValidate = [](const QString &value) {
return value == qstr("male") || value == qstr("female");
};
2018-04-12 10:20:54 +00:00
const auto CountryValidate = [=](const QString &value) {
return !CountryFormat(value).isEmpty();
};
switch (type) {
case Scope::Type::Identity: {
auto result = Scheme();
result.rowsHeader = lang(lng_passport_personal_details);
2018-04-10 07:51:19 +00:00
if (scansType) {
switch (*scansType) {
case Value::Type::Passport:
result.scansHeader = lang(lng_passport_identity_passport);
break;
case Value::Type::DriverLicense:
result.scansHeader = lang(lng_passport_identity_license);
break;
case Value::Type::IdentityCard:
result.scansHeader = lang(lng_passport_identity_card);
break;
default:
Unexpected("scansType in GetDocumentScheme:Identity.");
}
}
result.rows = {
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("first_name"),
lang(lng_passport_first_name),
2018-04-13 11:15:07 +00:00
NameValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxNameSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("last_name"),
lang(lng_passport_last_name),
2018-04-13 11:15:07 +00:00
NameValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxNameSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Date,
qsl("birth_date"),
lang(lng_passport_birth_date),
DateValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Gender,
qsl("gender"),
lang(lng_passport_gender),
GenderValidate,
2018-04-12 10:20:54 +00:00
GenderFormat,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Country,
qsl("country_code"),
lang(lng_passport_country),
CountryValidate,
2018-04-12 10:20:54 +00:00
CountryFormat,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Scans,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("document_no"),
lang(lng_passport_document_number),
2018-04-13 11:15:07 +00:00
DocumentValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxDocumentSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Scans,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Date,
qsl("expiry_date"),
lang(lng_passport_expiry_date),
DateOrEmptyValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
},
};
return result;
} break;
case Scope::Type::Address: {
auto result = Scheme();
result.rowsHeader = lang(lng_passport_address);
2018-04-10 07:51:19 +00:00
if (scansType) {
switch (*scansType) {
case Value::Type::UtilityBill:
result.scansHeader = lang(lng_passport_address_bill);
break;
case Value::Type::BankStatement:
result.scansHeader = lang(lng_passport_address_statement);
break;
case Value::Type::RentalAgreement:
result.scansHeader = lang(lng_passport_address_agreement);
break;
default:
2018-04-12 10:20:54 +00:00
Unexpected("scansType in GetDocumentScheme:Address.");
2018-04-10 07:51:19 +00:00
}
}
result.rows = {
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("street_line1"),
lang(lng_passport_street),
2018-04-13 11:15:07 +00:00
StreetValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxStreetSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("street_line2"),
lang(lng_passport_street),
2018-04-12 10:20:54 +00:00
DontValidate,
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxStreetSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("city"),
lang(lng_passport_city),
2018-04-13 11:15:07 +00:00
CityValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxStreetSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("state"),
lang(lng_passport_state),
2018-04-12 10:20:54 +00:00
DontValidate,
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxStreetSize,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Country,
qsl("country_code"),
lang(lng_passport_country),
2018-04-12 10:20:54 +00:00
CountryValidate,
CountryFormat,
},
{
2018-04-12 15:45:04 +00:00
ValueClass::Fields,
2018-04-10 11:26:21 +00:00
PanelDetailsType::Text,
qsl("post_code"),
lang(lng_passport_postcode),
2018-04-13 11:15:07 +00:00
PostcodeValidate,
2018-04-12 10:20:54 +00:00
DontFormat,
2018-04-13 11:15:07 +00:00
kMaxPostcodeSize,
},
};
return result;
} break;
}
Unexpected("Type in GetDocumentScheme().");
}
2018-04-12 15:45:04 +00:00
EditContactScheme GetContactScheme(Scope::Type type) {
using Scheme = EditContactScheme;
using ValueType = Scheme::ValueType;
switch (type) {
case Scope::Type::Phone: {
2018-04-12 15:45:04 +00:00
auto result = Scheme(ValueType::Phone);
result.aboutExisting = lang(lng_passport_use_existing_phone);
result.newHeader = lang(lng_passport_new_phone);
result.aboutNew = lang(lng_passport_new_phone_code);
result.validate = [](const QString &value) {
return QRegularExpression(
"^\\d{2,12}$"
).match(value).hasMatch();
};
2018-04-12 10:20:54 +00:00
result.format = [](const QString &value) {
return App::formatPhone(value);
};
result.postprocess = [](QString value) {
return value.replace(QRegularExpression("[^\\d]"), QString());
};
return result;
} break;
case Scope::Type::Email: {
2018-04-12 15:45:04 +00:00
auto result = Scheme(ValueType::Text);
result.aboutExisting = lang(lng_passport_use_existing_email);
result.newHeader = lang(lng_passport_new_email);
result.newPlaceholder = langFactory(lng_passport_email_title);
result.aboutNew = lang(lng_passport_new_email_code);
result.validate = [](const QString &value) {
const auto at = value.indexOf('@');
const auto dot = value.lastIndexOf('.');
return (at > 0) && (dot > at);
};
2018-04-12 10:20:54 +00:00
result.format = result.postprocess = [](const QString &value) {
return value.trimmed();
};
return result;
} break;
}
Unexpected("Type in GetContactScheme().");
}
BoxPointer::BoxPointer(QPointer<BoxContent> value)
: _value(value) {
}
BoxPointer::BoxPointer(BoxPointer &&other)
: _value(base::take(other._value)) {
}
BoxPointer &BoxPointer::operator=(BoxPointer &&other) {
std::swap(_value, other._value);
return *this;
}
BoxPointer::~BoxPointer() {
if (const auto strong = get()) {
strong->closeBox();
}
}
BoxContent *BoxPointer::get() const {
return _value.data();
}
BoxPointer::operator BoxContent*() const {
return get();
}
BoxPointer::operator bool() const {
return get();
}
BoxContent *BoxPointer::operator->() const {
return get();
}
PanelController::PanelController(not_null<FormController*> form)
2018-04-03 18:24:31 +00:00
: _form(form)
, _scopes(ComputeScopes(_form)) {
_form->secretReadyEvents(
) | rpl::start_with_next([=] {
if (_panel) {
_panel->showForm();
}
}, lifetime());
_form->verificationNeeded(
) | rpl::start_with_next([=](not_null<const Value*> value) {
processVerificationNeeded(value);
}, lifetime());
_form->verificationUpdate(
) | rpl::filter([=](not_null<const Value*> field) {
return (field->verification.codeLength == 0);
}) | rpl::start_with_next([=](not_null<const Value*> field) {
_verificationBoxes.erase(field);
}, lifetime());
2018-04-03 18:24:31 +00:00
_scopes = ComputeScopes(_form);
}
not_null<UserData*> PanelController::bot() const {
return _form->bot();
}
2018-04-03 18:24:31 +00:00
QString PanelController::privacyPolicyUrl() const {
return _form->privacyPolicyUrl();
}
void PanelController::fillRows(
base::lambda<void(
QString title,
QString description,
bool ready)> callback) {
2018-04-03 18:24:31 +00:00
if (_scopes.empty()) {
_scopes = ComputeScopes(_form);
}
for (const auto &scope : _scopes) {
2018-04-12 15:45:04 +00:00
const auto row = ComputeScopeRow(scope);
2018-04-12 10:20:54 +00:00
callback(
row.title,
2018-04-12 15:45:04 +00:00
row.ready.isEmpty() ? row.description : row.ready,
!row.ready.isEmpty());
2018-04-03 18:24:31 +00:00
}
}
2018-04-12 15:45:04 +00:00
void PanelController::submitForm() {
_form->submit();
}
void PanelController::submitPassword(const QString &password) {
_form->submitPassword(password);
}
rpl::producer<QString> PanelController::passwordError() const {
return _form->passwordError();
}
QString PanelController::passwordHint() const {
return _form->passwordHint();
}
QString PanelController::defaultEmail() const {
return _form->defaultEmail();
}
QString PanelController::defaultPhoneNumber() const {
return _form->defaultPhoneNumber();
}
2018-04-13 10:54:17 +00:00
bool PanelController::canAddScan() const {
Expects(_editScope != nullptr);
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
return _form->canAddScan(_editScope->documents[_editDocumentIndex]);
}
2018-04-03 18:24:31 +00:00
void PanelController::uploadScan(QByteArray &&content) {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-03 18:24:31 +00:00
_form->uploadScan(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
2018-04-03 18:24:31 +00:00
std::move(content));
}
2018-04-03 18:24:31 +00:00
void PanelController::deleteScan(int fileIndex) {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-03 18:24:31 +00:00
_form->deleteScan(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
2018-04-03 18:24:31 +00:00
fileIndex);
}
2018-04-03 18:24:31 +00:00
void PanelController::restoreScan(int fileIndex) {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-03 18:24:31 +00:00
_form->restoreScan(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
2018-04-03 18:24:31 +00:00
fileIndex);
}
2018-04-10 19:00:52 +00:00
void PanelController::uploadSelfie(QByteArray &&content) {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-10 19:00:52 +00:00
Expects(_editScope->selfieRequired);
_form->uploadSelfie(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
2018-04-10 19:00:52 +00:00
std::move(content));
}
void PanelController::deleteSelfie() {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-10 19:00:52 +00:00
Expects(_editScope->selfieRequired);
_form->deleteSelfie(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex]);
2018-04-10 19:00:52 +00:00
}
void PanelController::restoreSelfie() {
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0
&& _editDocumentIndex < _editScope->documents.size());
2018-04-10 19:00:52 +00:00
Expects(_editScope->selfieRequired);
_form->restoreSelfie(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex]);
2018-04-10 19:00:52 +00:00
}
rpl::producer<ScanInfo> PanelController::scanUpdated() const {
return _form->scanUpdated(
2018-04-03 18:24:31 +00:00
) | rpl::filter([=](not_null<const EditFile*> file) {
return (_editScope != nullptr)
2018-04-12 15:45:04 +00:00
&& (_editDocumentIndex >= 0)
&& (file->value == _editScope->documents[_editDocumentIndex]);
2018-04-03 18:24:31 +00:00
}) | rpl::map([=](not_null<const EditFile*> file) {
return collectScanInfo(*file);
});
}
ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
2018-04-12 10:20:54 +00:00
Expects(_editScope != nullptr);
2018-04-12 15:45:04 +00:00
Expects(_editDocumentIndex >= 0);
2018-04-12 10:20:54 +00:00
const auto status = [&] {
if (file.fields.accessHash) {
if (file.fields.downloadOffset < 0) {
return lang(lng_attach_failed);
} else if (file.fields.downloadOffset < file.fields.size) {
return formatDownloadText(
file.fields.downloadOffset,
file.fields.size);
} else {
return lng_passport_scan_uploaded(
lt_date,
langDateTimeFull(ParseDateTime(file.fields.date)));
}
} else if (file.uploadData) {
if (file.uploadData->offset < 0) {
return lang(lng_attach_failed);
} else if (file.uploadData->fullId) {
return formatDownloadText(
file.uploadData->offset,
file.uploadData->bytes.size());
} else {
return lng_passport_scan_uploaded(
lt_date,
langDateTimeFull(ParseDateTime(file.fields.date)));
}
} else {
return formatDownloadText(0, file.fields.size);
}
}();
2018-04-12 15:45:04 +00:00
const auto &documents = _editScope->documents;
auto isSelfie = (file.value == documents[_editDocumentIndex])
&& (documents[_editDocumentIndex]->selfieInEdit.has_value())
&& (&file == &*documents[_editDocumentIndex]->selfieInEdit);
return {
FileKey{ file.fields.id, file.fields.dcId },
status,
file.fields.image,
2018-04-10 19:00:52 +00:00
file.deleted,
isSelfie };
}
QString PanelController::getDefaultContactValue(Scope::Type type) const {
switch (type) {
case Scope::Type::Phone:
return _form->defaultPhoneNumber();
case Scope::Type::Email:
return _form->defaultEmail();
}
Unexpected("Type in PanelController::getDefaultContactValue().");
}
void PanelController::showAskPassword() {
ensurePanelCreated();
_panel->showAskPassword();
}
void PanelController::showNoPassword() {
ensurePanelCreated();
_panel->showNoPassword();
}
void PanelController::showPasswordUnconfirmed() {
ensurePanelCreated();
_panel->showPasswordUnconfirmed();
}
void PanelController::ensurePanelCreated() {
if (!_panel) {
_panel = std::make_unique<Panel>(this);
}
}
2018-04-10 07:51:19 +00:00
int PanelController::findNonEmptyIndex(
const std::vector<not_null<const Value*>> &files) const {
const auto i = ranges::find_if(files, [](not_null<const Value*> file) {
2018-04-12 15:45:04 +00:00
return !file->scans.empty();
2018-04-10 07:51:19 +00:00
});
if (i != end(files)) {
return (i - begin(files));
}
return -1;
}
2018-04-03 18:24:31 +00:00
void PanelController::editScope(int index) {
Expects(_panel != nullptr);
2018-04-03 18:24:31 +00:00
Expects(index >= 0 && index < _scopes.size());
2018-04-12 15:45:04 +00:00
if (_scopes[index].documents.empty()) {
2018-04-12 10:20:54 +00:00
editScope(index, -1);
} else {
2018-04-12 15:45:04 +00:00
const auto documentIndex = findNonEmptyIndex(
_scopes[index].documents);
if (documentIndex >= 0) {
editScope(index, documentIndex);
} else if (_scopes[index].documents.size() > 1) {
2018-04-10 07:51:19 +00:00
requestScopeFilesType(index);
2018-04-12 10:20:54 +00:00
} else {
editWithUpload(index, 0);
2018-04-10 07:51:19 +00:00
}
}
}
void PanelController::requestScopeFilesType(int index) {
Expects(_panel != nullptr);
Expects(index >= 0 && index < _scopes.size());
const auto type = _scopes[index].type;
2018-04-12 15:45:04 +00:00
_scopeDocumentTypeBox = [&] {
2018-04-10 07:51:19 +00:00
if (type == Scope::Type::Identity) {
return show(RequestIdentityType(
2018-04-12 15:45:04 +00:00
[=](int documentIndex) {
editWithUpload(index, documentIndex);
2018-04-10 07:51:19 +00:00
},
ranges::view::all(
2018-04-12 15:45:04 +00:00
_scopes[index].documents
2018-04-10 07:51:19 +00:00
) | ranges::view::transform([](auto value) {
return value->type;
}) | ranges::view::transform([](Value::Type type) {
switch (type) {
case Value::Type::Passport:
return lang(lng_passport_identity_passport);
case Value::Type::IdentityCard:
return lang(lng_passport_identity_card);
case Value::Type::DriverLicense:
return lang(lng_passport_identity_license);
default:
Unexpected("IdentityType in requestScopeFilesType");
}
}) | ranges::to_vector));
} else if (type == Scope::Type::Address) {
return show(RequestAddressType(
2018-04-12 15:45:04 +00:00
[=](int documentIndex) {
editWithUpload(index, documentIndex);
2018-04-10 07:51:19 +00:00
},
ranges::view::all(
2018-04-12 15:45:04 +00:00
_scopes[index].documents
2018-04-10 07:51:19 +00:00
) | ranges::view::transform([](auto value) {
return value->type;
}) | ranges::view::transform([](Value::Type type) {
switch (type) {
case Value::Type::UtilityBill:
return lang(lng_passport_address_bill);
case Value::Type::BankStatement:
return lang(lng_passport_address_statement);
case Value::Type::RentalAgreement:
return lang(lng_passport_address_agreement);
default:
Unexpected("AddressType in requestScopeFilesType");
}
}) | ranges::to_vector));
} else {
Unexpected("Type in processVerificationNeeded.");
}
}();
}
2018-04-12 15:45:04 +00:00
void PanelController::editWithUpload(int index, int documentIndex) {
2018-04-10 07:51:19 +00:00
Expects(_panel != nullptr);
Expects(index >= 0 && index < _scopes.size());
2018-04-12 15:45:04 +00:00
Expects(documentIndex >= 0
&& documentIndex < _scopes[index].documents.size());
2018-04-10 07:51:19 +00:00
EditScans::ChooseScan(
base::lambda_guarded(_panel.get(),
[=](QByteArray &&content) {
2018-04-12 15:45:04 +00:00
base::take(_scopeDocumentTypeBox);
editScope(index, documentIndex);
2018-04-10 07:51:19 +00:00
uploadScan(std::move(content));
}));
}
2018-04-12 15:45:04 +00:00
void PanelController::editScope(int index, int documentIndex) {
2018-04-10 07:51:19 +00:00
Expects(_panel != nullptr);
Expects(index >= 0 && index < _scopes.size());
2018-04-12 15:45:04 +00:00
Expects((documentIndex < 0)
|| (documentIndex >= 0
&& documentIndex < _scopes[index].documents.size()));
2018-04-10 07:51:19 +00:00
_editScope = &_scopes[index];
2018-04-12 15:45:04 +00:00
_editDocumentIndex = documentIndex;
2018-04-03 18:24:31 +00:00
_form->startValueEdit(_editScope->fields);
2018-04-12 15:45:04 +00:00
if (_editDocumentIndex >= 0) {
_form->startValueEdit(_editScope->documents[_editDocumentIndex]);
2018-04-03 18:24:31 +00:00
}
auto content = [&]() -> object_ptr<Ui::RpWidget> {
2018-04-03 18:24:31 +00:00
switch (_editScope->type) {
case Scope::Type::Identity:
case Scope::Type::Address: {
2018-04-12 15:45:04 +00:00
const auto &documents = _editScope->documents;
auto result = (_editDocumentIndex >= 0)
? object_ptr<PanelEditDocument>(
_panel.get(),
this,
2018-04-10 07:51:19 +00:00
GetDocumentScheme(
_editScope->type,
2018-04-12 15:45:04 +00:00
documents[_editDocumentIndex]->type),
_editScope->fields->data.parsedInEdit,
2018-04-12 15:45:04 +00:00
documents[_editDocumentIndex]->data.parsedInEdit,
valueFiles(*documents[_editDocumentIndex]),
2018-04-10 19:00:52 +00:00
(_editScope->selfieRequired
2018-04-12 15:45:04 +00:00
? valueSelfie(*documents[_editDocumentIndex])
2018-04-10 19:00:52 +00:00
: nullptr))
: object_ptr<PanelEditDocument>(
_panel.get(),
this,
2018-04-10 07:51:19 +00:00
GetDocumentScheme(_editScope->type),
_editScope->fields->data.parsedInEdit);
const auto weak = make_weak(result.data());
_panelHasUnsavedChanges = [=] {
return weak ? weak->hasUnsavedChanges() : false;
};
return std::move(result);
} break;
case Scope::Type::Phone:
case Scope::Type::Email: {
const auto &parsed = _editScope->fields->data.parsedInEdit;
const auto valueIt = parsed.fields.find("value");
_panelHasUnsavedChanges = nullptr;
return object_ptr<PanelEditContact>(
_panel.get(),
this,
GetContactScheme(_editScope->type),
(valueIt == end(parsed.fields)
? QString()
: valueIt->second),
getDefaultContactValue(_editScope->type));
} break;
}
Unexpected("Type in PanelController::editScope().");
}();
content->lifetime().add([=] {
cancelValueEdit();
});
_panel->setBackAllowed(true);
_panel->backRequests(
) | rpl::start_with_next([=] {
cancelEditScope();
}, content->lifetime());
_form->valueSaveFinished(
) | rpl::start_with_next([=](not_null<const Value*> value) {
processValueSaveFinished(value);
}, content->lifetime());
_panel->showEditValue(std::move(content));
}
void PanelController::processValueSaveFinished(
not_null<const Value*> value) {
Expects(_editScope != nullptr);
const auto boxIt = _verificationBoxes.find(value);
if (boxIt != end(_verificationBoxes)) {
const auto saved = std::move(boxIt->second);
_verificationBoxes.erase(boxIt);
}
const auto value1 = _editScope->fields;
2018-04-12 15:45:04 +00:00
const auto value2 = (_editDocumentIndex >= 0)
? _editScope->documents[_editDocumentIndex].get()
: nullptr;
if (value == value1 || value == value2) {
if (!_form->savingValue(value1)
&& (!value2 || !_form->savingValue(value2))) {
_panel->showForm();
}
}
}
void PanelController::processVerificationNeeded(
not_null<const Value*> value) {
const auto i = _verificationBoxes.find(value);
if (i != _verificationBoxes.end()) {
LOG(("API Error: Requesting for verification repeatedly."));
return;
}
const auto textIt = value->data.parsedInEdit.fields.find("value");
Assert(textIt != end(value->data.parsedInEdit.fields));
const auto text = textIt->second;
const auto type = value->type;
const auto update = _form->verificationUpdate(
) | rpl::filter([=](not_null<const Value*> field) {
return (field == value);
});
const auto box = [&] {
if (type == Value::Type::Phone) {
return show(VerifyPhoneBox(
text,
value->verification.codeLength,
[=](const QString &code) { _form->verify(value, code); },
value->verification.call ? rpl::single(
value->verification.call->getText()
) | rpl::then(rpl::duplicate(
update
) | rpl::filter([=](not_null<const Value*> field) {
return field->verification.call != nullptr;
}) | rpl::map([=](not_null<const Value*> field) {
return field->verification.call->getText();
})) : (rpl::single(QString()) | rpl::type_erased()),
rpl::duplicate(
update
) | rpl::map([=](not_null<const Value*> field) {
return field->verification.error;
}) | rpl::distinct_until_changed()));
} else if (type == Value::Type::Email) {
return show(VerifyEmailBox(
text,
value->verification.codeLength,
[=](const QString &code) { _form->verify(value, code); },
rpl::duplicate(
update
) | rpl::map([=](not_null<const Value*> field) {
return field->verification.error;
}) | rpl::distinct_until_changed()));
} else {
Unexpected("Type in processVerificationNeeded.");
}
}();
box->boxClosing(
) | rpl::start_with_next([=] {
_form->cancelValueVerification(value);
}, lifetime());
_verificationBoxes.emplace(value, box);
}
std::vector<ScanInfo> PanelController::valueFiles(
const Value &value) const {
auto result = std::vector<ScanInfo>();
2018-04-12 15:45:04 +00:00
for (const auto &scan : value.scansInEdit) {
result.push_back(collectScanInfo(scan));
}
return result;
}
2018-04-10 19:00:52 +00:00
std::unique_ptr<ScanInfo> PanelController::valueSelfie(
const Value &value) const {
if (value.selfieInEdit) {
return std::make_unique<ScanInfo>(
collectScanInfo(*value.selfieInEdit));
}
return std::make_unique<ScanInfo>();
}
void PanelController::cancelValueEdit() {
2018-04-03 18:24:31 +00:00
if (const auto scope = base::take(_editScope)) {
_form->cancelValueEdit(scope->fields);
2018-04-12 15:45:04 +00:00
const auto index = std::exchange(_editDocumentIndex, -1);
2018-04-03 18:24:31 +00:00
if (index >= 0) {
2018-04-12 15:45:04 +00:00
_form->cancelValueEdit(scope->documents[index]);
2018-04-03 18:24:31 +00:00
}
}
}
2018-04-03 18:24:31 +00:00
void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
Expects(_panel != nullptr);
2018-04-03 18:24:31 +00:00
Expects(_editScope != nullptr);
_form->saveValueEdit(_editScope->fields, std::move(data));
2018-04-12 15:45:04 +00:00
if (_editDocumentIndex >= 0) {
_form->saveValueEdit(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
std::move(filesData));
2018-04-03 18:24:31 +00:00
} else {
Assert(filesData.fields.empty());
}
}
bool PanelController::editScopeChanged(
const ValueMap &data,
const ValueMap &filesData) const {
Expects(_editScope != nullptr);
if (_form->editValueChanged(_editScope->fields, data)) {
return true;
2018-04-12 15:45:04 +00:00
} else if (_editDocumentIndex >= 0) {
return _form->editValueChanged(
2018-04-12 15:45:04 +00:00
_editScope->documents[_editDocumentIndex],
filesData);
}
return false;
}
void PanelController::cancelEditScope() {
Expects(_editScope != nullptr);
if (_panelHasUnsavedChanges && _panelHasUnsavedChanges()) {
if (!_confirmForgetChangesBox) {
_confirmForgetChangesBox = BoxPointer(show(Box<ConfirmBox>(
lang(lng_passport_sure_cancel),
lang(lng_continue),
2018-04-10 11:26:21 +00:00
[=] {
_panel->showForm();
base::take(_confirmForgetChangesBox);
2018-04-10 16:22:27 +00:00
})).data());
}
} else {
_panel->showForm();
}
}
void PanelController::cancelAuth() {
_form->cancel();
}
2018-04-06 16:23:09 +00:00
void PanelController::showBox(object_ptr<BoxContent> box) {
_panel->showBox(std::move(box));
}
2018-04-13 10:54:17 +00:00
void PanelController::showToast(const QString &text) {
Expects(_panel != nullptr);
auto toast = Ui::Toast::Config();
toast.text = text;
Ui::Toast::Show(_panel.get(), toast);
}
rpl::lifetime &PanelController::lifetime() {
return _lifetime;
}
PanelController::~PanelController() = default;
} // namespace Passport