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,16 +808,16 @@ void PanelController::processValueSaveFinished( | ||||||
| 		_verificationBoxes.erase(boxIt); | 		_verificationBoxes.erase(boxIt); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const auto value1 = _editScope->fields; | 	if (!savingScope()) { | ||||||
| 	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(); | 		_panel->showForm(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool PanelController::savingScope() const { | ||||||
|  | 	Expects(_editValue != nullptr); | ||||||
|  | 
 | ||||||
|  | 	return _form->savingValue(_editValue) | ||||||
|  | 		|| (_editDocument && _form->savingValue(_editDocument)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PanelController::processVerificationNeeded( | void PanelController::processVerificationNeeded( | ||||||
|  | @ -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