Allow deleting documents in passport.

This commit is contained in:
John Preston 2018-04-13 20:43:17 +04:00
parent e82430cb50
commit e4ae5bfcad
11 changed files with 319 additions and 96 deletions

View File

@ -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

View File

@ -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);

View File

@ -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(

View File

@ -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));

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 {