mirror of https://github.com/procxx/kepka.git
Allow deleting documents in passport.
This commit is contained in:
parent
e82430cb50
commit
e4ae5bfcad
|
@ -1584,6 +1584,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passport_confirm_email" = "We've sent a confirmation code to your email {email}.";
|
"lng_passport_confirm_email" = "We've sent a confirmation code to your email {email}.";
|
||||||
"lng_passport_sure_cancel" = "If you continue your changes will be lost.";
|
"lng_passport_sure_cancel" = "If you continue your changes will be lost.";
|
||||||
"lng_passport_scans_limit_reached" = "Scans limit reached.";
|
"lng_passport_scans_limit_reached" = "Scans limit reached.";
|
||||||
|
"lng_passport_delete_document" = "Delete document";
|
||||||
|
"lng_passport_delete_document_sure" = "Are you sure you want to delete this document?";
|
||||||
|
"lng_passport_delete_details" = "Delete personal details";
|
||||||
|
"lng_passport_delete_details_sure" = "Are you sure you want to delete your personal details?";
|
||||||
|
"lng_passport_delete_address" = "Delete address information";
|
||||||
|
"lng_passport_delete_address_sure" = "Are you sure you wnat to delete your address information?";
|
||||||
|
"lng_passport_delete_email" = "Delete email";
|
||||||
|
"lng_passport_delete_email_sure" = "Are you sure you want to delete your email?";
|
||||||
|
"lng_passport_delete_phone" = "Delete phone number";
|
||||||
|
"lng_passport_delete_phone_sure" = "Are you sure you want to delete your phone number?";
|
||||||
|
|
||||||
// Wnd specific
|
// Wnd specific
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,7 @@ passportContactNewFieldPadding: margins(22px, 0px, 22px, 28px);
|
||||||
passportContactFieldPadding: margins(22px, 14px, 22px, 28px);
|
passportContactFieldPadding: margins(22px, 14px, 22px, 28px);
|
||||||
|
|
||||||
passportRowPadding: margins(22px, 8px, 25px, 8px);
|
passportRowPadding: margins(22px, 8px, 25px, 8px);
|
||||||
|
passportRowIconSkip: 10px;
|
||||||
passportRowSkip: 2px;
|
passportRowSkip: 2px;
|
||||||
passportRowRipple: RippleAnimation(defaultRippleAnimation) {
|
passportRowRipple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: windowBgOver;
|
color: windowBgOver;
|
||||||
|
@ -166,6 +167,10 @@ passportUploadButton: InfoProfileButton {
|
||||||
}
|
}
|
||||||
passportUploadButtonPadding: margins(0px, 10px, 0px, 10px);
|
passportUploadButtonPadding: margins(0px, 10px, 0px, 10px);
|
||||||
passportUploadHeaderPadding: margins(22px, 14px, 22px, 3px);
|
passportUploadHeaderPadding: margins(22px, 14px, 22px, 3px);
|
||||||
|
passportDeleteButton: InfoProfileButton(passportUploadButton) {
|
||||||
|
textFg: attentionButtonFg;
|
||||||
|
textFgOver: attentionButtonFgOver;
|
||||||
|
}
|
||||||
|
|
||||||
passportScanNameStyle: TextStyle(defaultTextStyle) {
|
passportScanNameStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(boxFontSize semibold);
|
font: font(boxFontSize semibold);
|
||||||
|
|
|
@ -337,10 +337,7 @@ bytes::vector DecryptValueSecret(
|
||||||
|
|
||||||
uint64 CountSecureSecretHash(bytes::const_span secret) {
|
uint64 CountSecureSecretHash(bytes::const_span secret) {
|
||||||
const auto full = openssl::Sha256(secret);
|
const auto full = openssl::Sha256(secret);
|
||||||
const auto part = bytes::make_span(full).subspan(
|
return *reinterpret_cast<const uint64*>(full.data());
|
||||||
full.size() - sizeof(uint64),
|
|
||||||
sizeof(uint64));
|
|
||||||
return *reinterpret_cast<const uint64*>(part.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes::vector EncryptCredentialsSecret(
|
bytes::vector EncryptCredentialsSecret(
|
||||||
|
|
|
@ -1017,6 +1017,26 @@ void FormController::saveValueEdit(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormController::deleteValueEdit(not_null<const Value*> value) {
|
||||||
|
if (savingValue(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto nonconst = findValue(value);
|
||||||
|
nonconst->saveRequestId = request(MTPaccount_DeleteSecureValue(
|
||||||
|
MTP_vector<MTPSecureValueType>(1, ConvertType(nonconst->type))
|
||||||
|
)).done([=](const MTPBool &result) {
|
||||||
|
const auto editScreens = value->editScreens;
|
||||||
|
*nonconst = Value(nonconst->type);
|
||||||
|
nonconst->editScreens = editScreens;
|
||||||
|
|
||||||
|
_valueSaveFinished.fire_copy(value);
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
nonconst->saveRequestId = 0;
|
||||||
|
valueSaveFailed(nonconst, error);
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::saveEncryptedValue(not_null<Value*> value) {
|
void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
Expects(isEncryptedValue(value->type));
|
Expects(isEncryptedValue(value->type));
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,7 @@ public:
|
||||||
not_null<const Value*> value,
|
not_null<const Value*> value,
|
||||||
const ValueMap &data) const;
|
const ValueMap &data) const;
|
||||||
void saveValueEdit(not_null<const Value*> value, ValueMap &&data);
|
void saveValueEdit(not_null<const Value*> value, ValueMap &&data);
|
||||||
|
void deleteValueEdit(not_null<const Value*> value);
|
||||||
bool savingValue(not_null<const Value*> value) const;
|
bool savingValue(not_null<const Value*> value) const;
|
||||||
|
|
||||||
void cancel();
|
void cancel();
|
||||||
|
|
|
@ -131,9 +131,8 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
if (document
|
if (!scope.documents.empty()
|
||||||
&& (document->scans.empty()
|
&& (!document || (scope.selfieRequired && !document->selfie))) {
|
||||||
|| (scope.selfieRequired && !document->selfie))) {
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto scheme = GetDocumentScheme(scope.type);
|
const auto scheme = GetDocumentScheme(scope.type);
|
||||||
|
|
|
@ -391,79 +391,60 @@ QString PanelController::defaultPhoneNumber() const {
|
||||||
|
|
||||||
bool PanelController::canAddScan() const {
|
bool PanelController::canAddScan() const {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
|
|
||||||
return _form->canAddScan(_editScope->documents[_editDocumentIndex]);
|
return _form->canAddScan(_editDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::uploadScan(QByteArray &&content) {
|
void PanelController::uploadScan(QByteArray &&content) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
|
|
||||||
_form->uploadScan(
|
_form->uploadScan(_editDocument, std::move(content));
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
std::move(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::deleteScan(int fileIndex) {
|
void PanelController::deleteScan(int fileIndex) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
|
|
||||||
_form->deleteScan(
|
_form->deleteScan(_editDocument, fileIndex);
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
fileIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::restoreScan(int fileIndex) {
|
void PanelController::restoreScan(int fileIndex) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
|
|
||||||
_form->restoreScan(
|
_form->restoreScan(_editDocument, fileIndex);
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
fileIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::uploadSelfie(QByteArray &&content) {
|
void PanelController::uploadSelfie(QByteArray &&content) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
Expects(_editScope->selfieRequired);
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
_form->uploadSelfie(
|
_form->uploadSelfie(_editDocument, std::move(content));
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
std::move(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::deleteSelfie() {
|
void PanelController::deleteSelfie() {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
Expects(_editScope->selfieRequired);
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
_form->deleteSelfie(
|
_form->deleteSelfie(_editDocument);
|
||||||
_editScope->documents[_editDocumentIndex]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::restoreSelfie() {
|
void PanelController::restoreSelfie() {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocument != nullptr);
|
||||||
&& _editDocumentIndex < _editScope->documents.size());
|
|
||||||
Expects(_editScope->selfieRequired);
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
_form->restoreSelfie(
|
_form->restoreSelfie(_editDocument);
|
||||||
_editScope->documents[_editDocumentIndex]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<ScanInfo> PanelController::scanUpdated() const {
|
rpl::producer<ScanInfo> PanelController::scanUpdated() const {
|
||||||
return _form->scanUpdated(
|
return _form->scanUpdated(
|
||||||
) | rpl::filter([=](not_null<const EditFile*> file) {
|
) | rpl::filter([=](not_null<const EditFile*> file) {
|
||||||
return (_editScope != nullptr)
|
return (file->value == _editDocument);
|
||||||
&& (_editDocumentIndex >= 0)
|
|
||||||
&& (file->value == _editScope->documents[_editDocumentIndex]);
|
|
||||||
}) | rpl::map([=](not_null<const EditFile*> file) {
|
}) | rpl::map([=](not_null<const EditFile*> file) {
|
||||||
return collectScanInfo(*file);
|
return collectScanInfo(*file);
|
||||||
});
|
});
|
||||||
|
@ -471,7 +452,7 @@ rpl::producer<ScanInfo> PanelController::scanUpdated() const {
|
||||||
|
|
||||||
ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0);
|
Expects(_editDocument != nullptr);
|
||||||
|
|
||||||
const auto status = [&] {
|
const auto status = [&] {
|
||||||
if (file.fields.accessHash) {
|
if (file.fields.accessHash) {
|
||||||
|
@ -502,10 +483,9 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
||||||
return formatDownloadText(0, file.fields.size);
|
return formatDownloadText(0, file.fields.size);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
const auto &documents = _editScope->documents;
|
auto isSelfie = (file.value == _editDocument)
|
||||||
auto isSelfie = (file.value == documents[_editDocumentIndex])
|
&& (_editDocument->selfieInEdit.has_value())
|
||||||
&& (documents[_editDocumentIndex]->selfieInEdit.has_value())
|
&& (&file == &*_editDocument->selfieInEdit);
|
||||||
&& (&file == &*documents[_editDocumentIndex]->selfieInEdit);
|
|
||||||
return {
|
return {
|
||||||
FileKey{ file.fields.id, file.fields.dcId },
|
FileKey{ file.fields.id, file.fields.dcId },
|
||||||
status,
|
status,
|
||||||
|
@ -514,6 +494,96 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
||||||
isSelfie };
|
isSelfie };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto PanelController::deleteValueLabel() const
|
||||||
|
-> base::optional<rpl::producer<QString>> {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
|
||||||
|
if (hasValueDocument()) {
|
||||||
|
return Lang::Viewer(lng_passport_delete_document);
|
||||||
|
}
|
||||||
|
if (!hasValueFields()) {
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
switch (_editScope->type) {
|
||||||
|
case Scope::Type::Identity:
|
||||||
|
return Lang::Viewer(lng_passport_delete_details);
|
||||||
|
case Scope::Type::Address:
|
||||||
|
return Lang::Viewer(lng_passport_delete_address);
|
||||||
|
case Scope::Type::Email:
|
||||||
|
return Lang::Viewer(lng_passport_delete_email);
|
||||||
|
case Scope::Type::Phone:
|
||||||
|
return Lang::Viewer(lng_passport_delete_phone);
|
||||||
|
}
|
||||||
|
Unexpected("Type in PanelController::deleteValueLabel.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PanelController::hasValueDocument() const {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
|
||||||
|
if (!_editDocument) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !_editDocument->data.parsed.fields.empty()
|
||||||
|
|| !_editDocument->scans.empty()
|
||||||
|
|| _editDocument->selfie.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PanelController::hasValueFields() const {
|
||||||
|
Expects(_editValue != nullptr);
|
||||||
|
|
||||||
|
return !_editValue->data.parsed.fields.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PanelController::deleteValue() {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
|
||||||
|
if (savingScope()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto text = [&] {
|
||||||
|
switch (_editScope->type) {
|
||||||
|
case Scope::Type::Identity:
|
||||||
|
return lang(hasValueDocument()
|
||||||
|
? lng_passport_delete_document_sure
|
||||||
|
: lng_passport_delete_details_sure);
|
||||||
|
case Scope::Type::Address:
|
||||||
|
return lang(hasValueDocument()
|
||||||
|
? lng_passport_delete_document_sure
|
||||||
|
: lng_passport_delete_address_sure);
|
||||||
|
case Scope::Type::Phone:
|
||||||
|
return lang(lng_passport_delete_phone_sure);
|
||||||
|
case Scope::Type::Email:
|
||||||
|
return lang(lng_passport_delete_email_sure);
|
||||||
|
}
|
||||||
|
Unexpected("Type in deleteValue.");
|
||||||
|
}();
|
||||||
|
const auto checkbox = (hasValueDocument() && hasValueFields()) ? [&] {
|
||||||
|
switch (_editScope->type) {
|
||||||
|
case Scope::Type::Identity:
|
||||||
|
return lang(lng_passport_delete_details);
|
||||||
|
case Scope::Type::Address:
|
||||||
|
return lang(lng_passport_delete_address);
|
||||||
|
}
|
||||||
|
Unexpected("Type in deleteValue.");
|
||||||
|
}() : QString();
|
||||||
|
|
||||||
|
_editScopeBoxes.emplace_back(show(ConfirmDeleteDocument(
|
||||||
|
[=](bool withDetails) { deleteValueSure(withDetails); },
|
||||||
|
text,
|
||||||
|
checkbox)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PanelController::deleteValueSure(bool withDetails) {
|
||||||
|
Expects(_editValue != nullptr);
|
||||||
|
|
||||||
|
if (hasValueDocument()) {
|
||||||
|
_form->deleteValueEdit(_editDocument);
|
||||||
|
}
|
||||||
|
if (withDetails || !hasValueDocument()) {
|
||||||
|
_form->deleteValueEdit(_editValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString PanelController::getDefaultContactValue(Scope::Type type) const {
|
QString PanelController::getDefaultContactValue(Scope::Type type) const {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Scope::Type::Phone:
|
case Scope::Type::Phone:
|
||||||
|
@ -653,36 +723,38 @@ void PanelController::editScope(int index, int documentIndex) {
|
||||||
&& documentIndex < _scopes[index].documents.size()));
|
&& documentIndex < _scopes[index].documents.size()));
|
||||||
|
|
||||||
_editScope = &_scopes[index];
|
_editScope = &_scopes[index];
|
||||||
_editDocumentIndex = documentIndex;
|
_editValue = _editScope->fields;
|
||||||
|
_editDocument = (documentIndex >= 0)
|
||||||
|
? _scopes[index].documents[documentIndex].get()
|
||||||
|
: nullptr;
|
||||||
|
|
||||||
_form->startValueEdit(_editScope->fields);
|
_form->startValueEdit(_editValue);
|
||||||
if (_editDocumentIndex >= 0) {
|
if (_editDocument) {
|
||||||
_form->startValueEdit(_editScope->documents[_editDocumentIndex]);
|
_form->startValueEdit(_editDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto content = [&]() -> object_ptr<Ui::RpWidget> {
|
auto content = [&]() -> object_ptr<Ui::RpWidget> {
|
||||||
switch (_editScope->type) {
|
switch (_editScope->type) {
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
case Scope::Type::Address: {
|
case Scope::Type::Address: {
|
||||||
const auto &documents = _editScope->documents;
|
auto result = _editDocument
|
||||||
auto result = (_editDocumentIndex >= 0)
|
|
||||||
? object_ptr<PanelEditDocument>(
|
? object_ptr<PanelEditDocument>(
|
||||||
_panel.get(),
|
_panel.get(),
|
||||||
this,
|
this,
|
||||||
GetDocumentScheme(
|
GetDocumentScheme(
|
||||||
_editScope->type,
|
_editScope->type,
|
||||||
documents[_editDocumentIndex]->type),
|
_editDocument->type),
|
||||||
_editScope->fields->data.parsedInEdit,
|
_editValue->data.parsedInEdit,
|
||||||
documents[_editDocumentIndex]->data.parsedInEdit,
|
_editDocument->data.parsedInEdit,
|
||||||
valueFiles(*documents[_editDocumentIndex]),
|
valueFiles(*_editDocument),
|
||||||
(_editScope->selfieRequired
|
(_editScope->selfieRequired
|
||||||
? valueSelfie(*documents[_editDocumentIndex])
|
? valueSelfie(*_editDocument)
|
||||||
: nullptr))
|
: nullptr))
|
||||||
: object_ptr<PanelEditDocument>(
|
: object_ptr<PanelEditDocument>(
|
||||||
_panel.get(),
|
_panel.get(),
|
||||||
this,
|
this,
|
||||||
GetDocumentScheme(_editScope->type),
|
GetDocumentScheme(_editScope->type),
|
||||||
_editScope->fields->data.parsedInEdit);
|
_editValue->data.parsedInEdit);
|
||||||
const auto weak = make_weak(result.data());
|
const auto weak = make_weak(result.data());
|
||||||
_panelHasUnsavedChanges = [=] {
|
_panelHasUnsavedChanges = [=] {
|
||||||
return weak ? weak->hasUnsavedChanges() : false;
|
return weak ? weak->hasUnsavedChanges() : false;
|
||||||
|
@ -691,7 +763,7 @@ void PanelController::editScope(int index, int documentIndex) {
|
||||||
} break;
|
} break;
|
||||||
case Scope::Type::Phone:
|
case Scope::Type::Phone:
|
||||||
case Scope::Type::Email: {
|
case Scope::Type::Email: {
|
||||||
const auto &parsed = _editScope->fields->data.parsedInEdit;
|
const auto &parsed = _editValue->data.parsedInEdit;
|
||||||
const auto valueIt = parsed.fields.find("value");
|
const auto valueIt = parsed.fields.find("value");
|
||||||
_panelHasUnsavedChanges = nullptr;
|
_panelHasUnsavedChanges = nullptr;
|
||||||
return object_ptr<PanelEditContact>(
|
return object_ptr<PanelEditContact>(
|
||||||
|
@ -736,18 +808,18 @@ void PanelController::processValueSaveFinished(
|
||||||
_verificationBoxes.erase(boxIt);
|
_verificationBoxes.erase(boxIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto value1 = _editScope->fields;
|
if (!savingScope()) {
|
||||||
const auto value2 = (_editDocumentIndex >= 0)
|
_panel->showForm();
|
||||||
? _editScope->documents[_editDocumentIndex].get()
|
|
||||||
: nullptr;
|
|
||||||
if (value == value1 || value == value2) {
|
|
||||||
if (!_form->savingValue(value1)
|
|
||||||
&& (!value2 || !_form->savingValue(value2))) {
|
|
||||||
_panel->showForm();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PanelController::savingScope() const {
|
||||||
|
Expects(_editValue != nullptr);
|
||||||
|
|
||||||
|
return _form->savingValue(_editValue)
|
||||||
|
|| (_editDocument && _form->savingValue(_editDocument));
|
||||||
|
}
|
||||||
|
|
||||||
void PanelController::processVerificationNeeded(
|
void PanelController::processVerificationNeeded(
|
||||||
not_null<const Value*> value) {
|
not_null<const Value*> value) {
|
||||||
const auto i = _verificationBoxes.find(value);
|
const auto i = _verificationBoxes.find(value);
|
||||||
|
@ -828,24 +900,27 @@ std::unique_ptr<ScanInfo> PanelController::valueSelfie(
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::cancelValueEdit() {
|
void PanelController::cancelValueEdit() {
|
||||||
if (const auto scope = base::take(_editScope)) {
|
Expects(_editScope != nullptr);
|
||||||
_form->cancelValueEdit(scope->fields);
|
|
||||||
const auto index = std::exchange(_editDocumentIndex, -1);
|
_editScopeBoxes.clear();
|
||||||
if (index >= 0) {
|
_form->cancelValueEdit(base::take(_editValue));
|
||||||
_form->cancelValueEdit(scope->documents[index]);
|
if (const auto document = base::take(_editDocument)) {
|
||||||
}
|
_form->cancelValueEdit(document);
|
||||||
}
|
}
|
||||||
|
_editScope = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
||||||
Expects(_panel != nullptr);
|
Expects(_panel != nullptr);
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editValue != nullptr);
|
||||||
|
|
||||||
_form->saveValueEdit(_editScope->fields, std::move(data));
|
if (savingScope()) {
|
||||||
if (_editDocumentIndex >= 0) {
|
return;
|
||||||
_form->saveValueEdit(
|
}
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
std::move(filesData));
|
_form->saveValueEdit(_editValue, std::move(data));
|
||||||
|
if (_editDocument) {
|
||||||
|
_form->saveValueEdit(_editDocument, std::move(filesData));
|
||||||
} else {
|
} else {
|
||||||
Assert(filesData.fields.empty());
|
Assert(filesData.fields.empty());
|
||||||
}
|
}
|
||||||
|
@ -854,14 +929,12 @@ void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
||||||
bool PanelController::editScopeChanged(
|
bool PanelController::editScopeChanged(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &filesData) const {
|
const ValueMap &filesData) const {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editValue != nullptr);
|
||||||
|
|
||||||
if (_form->editValueChanged(_editScope->fields, data)) {
|
if (_form->editValueChanged(_editValue, data)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (_editDocumentIndex >= 0) {
|
} else if (_editDocument) {
|
||||||
return _form->editValueChanged(
|
return _form->editValueChanged(_editDocument, filesData);
|
||||||
_editScope->documents[_editDocumentIndex],
|
|
||||||
filesData);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -871,13 +944,11 @@ void PanelController::cancelEditScope() {
|
||||||
|
|
||||||
if (_panelHasUnsavedChanges && _panelHasUnsavedChanges()) {
|
if (_panelHasUnsavedChanges && _panelHasUnsavedChanges()) {
|
||||||
if (!_confirmForgetChangesBox) {
|
if (!_confirmForgetChangesBox) {
|
||||||
_confirmForgetChangesBox = BoxPointer(show(Box<ConfirmBox>(
|
_confirmForgetChangesBox = show(Box<ConfirmBox>(
|
||||||
lang(lng_passport_sure_cancel),
|
lang(lng_passport_sure_cancel),
|
||||||
lang(lng_continue),
|
lang(lng_continue),
|
||||||
[=] {
|
[=] { _panel->showForm(); }));
|
||||||
_panel->showForm();
|
_editScopeBoxes.emplace_back(_confirmForgetChangesBox);
|
||||||
base::take(_confirmForgetChangesBox);
|
|
||||||
})).data());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_panel->showForm();
|
_panel->showForm();
|
||||||
|
|
|
@ -69,6 +69,9 @@ public:
|
||||||
void restoreSelfie();
|
void restoreSelfie();
|
||||||
rpl::producer<ScanInfo> scanUpdated() const;
|
rpl::producer<ScanInfo> scanUpdated() const;
|
||||||
|
|
||||||
|
base::optional<rpl::producer<QString>> deleteValueLabel() const;
|
||||||
|
void deleteValue();
|
||||||
|
|
||||||
QString defaultEmail() const;
|
QString defaultEmail() const;
|
||||||
QString defaultPhoneNumber() const;
|
QString defaultPhoneNumber() const;
|
||||||
|
|
||||||
|
@ -112,16 +115,23 @@ private:
|
||||||
void processValueSaveFinished(not_null<const Value*> value);
|
void processValueSaveFinished(not_null<const Value*> value);
|
||||||
void processVerificationNeeded(not_null<const Value*> value);
|
void processVerificationNeeded(not_null<const Value*> value);
|
||||||
|
|
||||||
|
bool savingScope() const;
|
||||||
|
bool hasValueDocument() const;
|
||||||
|
bool hasValueFields() const;
|
||||||
ScanInfo collectScanInfo(const EditFile &file) const;
|
ScanInfo collectScanInfo(const EditFile &file) const;
|
||||||
QString getDefaultContactValue(Scope::Type type) const;
|
QString getDefaultContactValue(Scope::Type type) const;
|
||||||
|
void deleteValueSure(bool withDetails);
|
||||||
|
|
||||||
not_null<FormController*> _form;
|
not_null<FormController*> _form;
|
||||||
std::vector<Scope> _scopes;
|
std::vector<Scope> _scopes;
|
||||||
|
|
||||||
std::unique_ptr<Panel> _panel;
|
std::unique_ptr<Panel> _panel;
|
||||||
base::lambda<bool()> _panelHasUnsavedChanges;
|
base::lambda<bool()> _panelHasUnsavedChanges;
|
||||||
BoxPointer _confirmForgetChangesBox;
|
QPointer<BoxContent> _confirmForgetChangesBox;
|
||||||
|
std::vector<BoxPointer> _editScopeBoxes;
|
||||||
Scope *_editScope = nullptr;
|
Scope *_editScope = nullptr;
|
||||||
|
const Value *_editValue = nullptr;
|
||||||
|
const Value *_editDocument = nullptr;
|
||||||
int _editDocumentIndex = -1;
|
int _editDocumentIndex = -1;
|
||||||
BoxPointer _scopeDocumentTypeBox;
|
BoxPointer _scopeDocumentTypeBox;
|
||||||
std::map<not_null<const Value*>, BoxPointer> _verificationBoxes;
|
std::map<not_null<const Value*>, BoxPointer> _verificationBoxes;
|
||||||
|
|
|
@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "passport/passport_panel_controller.h"
|
#include "passport/passport_panel_controller.h"
|
||||||
#include "passport/passport_panel_details_row.h"
|
#include "passport/passport_panel_details_row.h"
|
||||||
#include "passport/passport_panel_edit_scans.h"
|
#include "passport/passport_panel_edit_scans.h"
|
||||||
|
#include "info/profile/info_profile_button.h"
|
||||||
|
#include "info/profile/info_profile_values.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
@ -52,6 +54,28 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeleteDocumentBox : public BoxContent {
|
||||||
|
public:
|
||||||
|
DeleteDocumentBox(
|
||||||
|
QWidget*,
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox,
|
||||||
|
base::lambda<void(bool withDetails)> submit);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void prepare() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupControls(
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox,
|
||||||
|
base::lambda<void(bool withDetails)> submit);
|
||||||
|
|
||||||
|
base::lambda<void()> _submit;
|
||||||
|
int _height = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
RequestTypeBox::RequestTypeBox(
|
RequestTypeBox::RequestTypeBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
|
@ -122,6 +146,58 @@ void RequestTypeBox::setupControls(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeleteDocumentBox::DeleteDocumentBox(
|
||||||
|
QWidget*,
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox,
|
||||||
|
base::lambda<void(bool withDetails)> submit) {
|
||||||
|
setupControls(text, detailsCheckbox, submit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteDocumentBox::prepare() {
|
||||||
|
addButton(langFactory(lng_box_delete), _submit);
|
||||||
|
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||||
|
|
||||||
|
setDimensions(st::boxWidth, _height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteDocumentBox::setupControls(
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox,
|
||||||
|
base::lambda<void(bool withDetails)> submit) {
|
||||||
|
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
|
this,
|
||||||
|
text,
|
||||||
|
Ui::FlatLabel::InitType::Simple,
|
||||||
|
st::boxLabel);
|
||||||
|
const auto details = !detailsCheckbox.isEmpty()
|
||||||
|
? Ui::CreateChild<Ui::Checkbox>(
|
||||||
|
this,
|
||||||
|
detailsCheckbox,
|
||||||
|
false,
|
||||||
|
st::defaultBoxCheckbox)
|
||||||
|
: nullptr;
|
||||||
|
|
||||||
|
_height = st::boxPadding.top();
|
||||||
|
const auto availableWidth = st::boxWidth
|
||||||
|
- st::boxPadding.left()
|
||||||
|
- st::boxPadding.right();
|
||||||
|
label->resizeToWidth(availableWidth);
|
||||||
|
label->moveToLeft(st::boxPadding.left(), _height);
|
||||||
|
_height += label->height();
|
||||||
|
|
||||||
|
if (details) {
|
||||||
|
_height += st::boxPadding.bottom();
|
||||||
|
details->moveToLeft(st::boxPadding.left(), _height);
|
||||||
|
_height += details->heightNoMargins();
|
||||||
|
}
|
||||||
|
_height += st::boxPadding.bottom();
|
||||||
|
|
||||||
|
_submit = [=] {
|
||||||
|
submit(details ? details->checked() : false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct PanelEditDocument::Result {
|
struct PanelEditDocument::Result {
|
||||||
|
@ -252,6 +328,17 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||||
|
|
||||||
inner->add(
|
inner->add(
|
||||||
object_ptr<Ui::FixedHeightWidget>(inner, st::passportDetailsSkip));
|
object_ptr<Ui::FixedHeightWidget>(inner, st::passportDetailsSkip));
|
||||||
|
if (auto text = _controller->deleteValueLabel()) {
|
||||||
|
_delete = inner->add(
|
||||||
|
object_ptr<Info::Profile::Button>(
|
||||||
|
inner,
|
||||||
|
std::move(*text) | Info::Profile::ToUpperValue(),
|
||||||
|
st::passportDeleteButton),
|
||||||
|
st::passportUploadButtonPadding);
|
||||||
|
_delete->addClickHandler([=] {
|
||||||
|
_controller->deleteValue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return inner;
|
return inner;
|
||||||
}
|
}
|
||||||
|
@ -301,12 +388,14 @@ PanelEditDocument::Result PanelEditDocument::collect() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PanelEditDocument::validate() {
|
bool PanelEditDocument::validate() {
|
||||||
if (const auto error = _editScans->validateGetErrorTop()) {
|
const auto error = _editScans
|
||||||
|
? _editScans->validateGetErrorTop()
|
||||||
|
: base::none;
|
||||||
|
if (error) {
|
||||||
const auto errortop = _editScans->mapToGlobal(QPoint(0, *error));
|
const auto errortop = _editScans->mapToGlobal(QPoint(0, *error));
|
||||||
const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0));
|
const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0));
|
||||||
const auto scrolldelta = errortop.y() - scrolltop.y();
|
const auto scrolldelta = errortop.y() - scrolltop.y();
|
||||||
_scroll->scrollToY(_scroll->scrollTop() + scrolldelta);
|
_scroll->scrollToY(_scroll->scrollTop() + scrolldelta);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
auto first = QPointer<PanelDetailsRow>();
|
auto first = QPointer<PanelDetailsRow>();
|
||||||
for (const auto [i, field] : base::reversed(_details)) {
|
for (const auto [i, field] : base::reversed(_details)) {
|
||||||
|
@ -317,7 +406,7 @@ bool PanelEditDocument::validate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!first) {
|
if (!first) {
|
||||||
return true;
|
return !error;
|
||||||
}
|
}
|
||||||
const auto firsttop = first->mapToGlobal(QPoint(0, 0));
|
const auto firsttop = first->mapToGlobal(QPoint(0, 0));
|
||||||
const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0));
|
const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0));
|
||||||
|
@ -356,4 +445,11 @@ object_ptr<BoxContent> RequestAddressType(
|
||||||
submit);
|
submit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_ptr<BoxContent> ConfirmDeleteDocument(
|
||||||
|
base::lambda<void(bool withDetails)> submit,
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox) {
|
||||||
|
return Box<DeleteDocumentBox>(text, detailsCheckbox, submit);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -17,6 +17,12 @@ class PlainShadow;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Info {
|
||||||
|
namespace Profile {
|
||||||
|
class Button;
|
||||||
|
} // namespace Profile
|
||||||
|
} // namespace Info
|
||||||
|
|
||||||
namespace Passport {
|
namespace Passport {
|
||||||
|
|
||||||
class PanelController;
|
class PanelController;
|
||||||
|
@ -98,6 +104,8 @@ private:
|
||||||
QPointer<EditScans> _editScans;
|
QPointer<EditScans> _editScans;
|
||||||
std::map<int, QPointer<PanelDetailsRow>> _details;
|
std::map<int, QPointer<PanelDetailsRow>> _details;
|
||||||
|
|
||||||
|
QPointer<Info::Profile::Button> _delete;
|
||||||
|
|
||||||
object_ptr<Ui::RoundButton> _done;
|
object_ptr<Ui::RoundButton> _done;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -109,4 +117,9 @@ object_ptr<BoxContent> RequestAddressType(
|
||||||
base::lambda<void(int index)> submit,
|
base::lambda<void(int index)> submit,
|
||||||
std::vector<QString> labels);
|
std::vector<QString> labels);
|
||||||
|
|
||||||
|
object_ptr<BoxContent> ConfirmDeleteDocument(
|
||||||
|
base::lambda<void(bool withDetails)> submit,
|
||||||
|
const QString &text,
|
||||||
|
const QString &detailsCheckbox = QString());
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -92,7 +92,8 @@ int PanelForm::Row::countAvailableWidth(int newWidth) const {
|
||||||
- st::passportRowPadding.right()
|
- st::passportRowPadding.right()
|
||||||
- (_ready
|
- (_ready
|
||||||
? st::passportRowReadyIcon
|
? st::passportRowReadyIcon
|
||||||
: st::passportRowEmptyIcon).width();
|
: st::passportRowEmptyIcon).width()
|
||||||
|
- st::passportRowIconSkip;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PanelForm::Row::countAvailableWidth() const {
|
int PanelForm::Row::countAvailableWidth() const {
|
||||||
|
|
Loading…
Reference in New Issue