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_sure_cancel" = "If you continue your changes will be lost."; | ||||
| "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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -141,6 +141,7 @@ passportContactNewFieldPadding: margins(22px, 0px, 22px, 28px); | |||
| passportContactFieldPadding: margins(22px, 14px, 22px, 28px); | ||||
| 
 | ||||
| passportRowPadding: margins(22px, 8px, 25px, 8px); | ||||
| passportRowIconSkip: 10px; | ||||
| passportRowSkip: 2px; | ||||
| passportRowRipple: RippleAnimation(defaultRippleAnimation) { | ||||
| 	color: windowBgOver; | ||||
|  | @ -166,6 +167,10 @@ passportUploadButton: InfoProfileButton { | |||
| } | ||||
| passportUploadButtonPadding: margins(0px, 10px, 0px, 10px); | ||||
| passportUploadHeaderPadding: margins(22px, 14px, 22px, 3px); | ||||
| passportDeleteButton: InfoProfileButton(passportUploadButton) { | ||||
| 	textFg: attentionButtonFg; | ||||
| 	textFgOver: attentionButtonFgOver; | ||||
| } | ||||
| 
 | ||||
| passportScanNameStyle: TextStyle(defaultTextStyle) { | ||||
| 	font: font(boxFontSize semibold); | ||||
|  |  | |||
|  | @ -337,10 +337,7 @@ bytes::vector DecryptValueSecret( | |||
| 
 | ||||
| uint64 CountSecureSecretHash(bytes::const_span secret) { | ||||
| 	const auto full = openssl::Sha256(secret); | ||||
| 	const auto part = bytes::make_span(full).subspan( | ||||
| 		full.size() - sizeof(uint64), | ||||
| 		sizeof(uint64)); | ||||
| 	return *reinterpret_cast<const uint64*>(part.data()); | ||||
| 	return *reinterpret_cast<const uint64*>(full.data()); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	Expects(isEncryptedValue(value->type)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -240,6 +240,7 @@ public: | |||
| 		not_null<const Value*> value, | ||||
| 		const ValueMap &data) const; | ||||
| 	void saveValueEdit(not_null<const Value*> value, ValueMap &&data); | ||||
| 	void deleteValueEdit(not_null<const Value*> value); | ||||
| 	bool savingValue(not_null<const Value*> value) const; | ||||
| 
 | ||||
| 	void cancel(); | ||||
|  |  | |||
|  | @ -131,9 +131,8 @@ QString ComputeScopeRowReadyString(const Scope &scope) { | |||
| 				} | ||||
| 			}()); | ||||
| 		} | ||||
| 		if (document | ||||
| 			&& (document->scans.empty() | ||||
| 				|| (scope.selfieRequired && !document->selfie))) { | ||||
| 		if (!scope.documents.empty() | ||||
| 			&& (!document || (scope.selfieRequired && !document->selfie))) { | ||||
| 			return QString(); | ||||
| 		} | ||||
| 		const auto scheme = GetDocumentScheme(scope.type); | ||||
|  |  | |||
|  | @ -391,79 +391,60 @@ QString PanelController::defaultPhoneNumber() const { | |||
| 
 | ||||
| bool PanelController::canAddScan() const { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 
 | ||||
| 	return _form->canAddScan(_editScope->documents[_editDocumentIndex]); | ||||
| 	return _form->canAddScan(_editDocument); | ||||
| } | ||||
| 
 | ||||
| void PanelController::uploadScan(QByteArray &&content) { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 
 | ||||
| 	_form->uploadScan( | ||||
| 		_editScope->documents[_editDocumentIndex], | ||||
| 		std::move(content)); | ||||
| 	_form->uploadScan(_editDocument, std::move(content)); | ||||
| } | ||||
| 
 | ||||
| void PanelController::deleteScan(int fileIndex) { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 
 | ||||
| 	_form->deleteScan( | ||||
| 		_editScope->documents[_editDocumentIndex], | ||||
| 		fileIndex); | ||||
| 	_form->deleteScan(_editDocument, fileIndex); | ||||
| } | ||||
| 
 | ||||
| void PanelController::restoreScan(int fileIndex) { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 
 | ||||
| 	_form->restoreScan( | ||||
| 		_editScope->documents[_editDocumentIndex], | ||||
| 		fileIndex); | ||||
| 	_form->restoreScan(_editDocument, fileIndex); | ||||
| } | ||||
| 
 | ||||
| void PanelController::uploadSelfie(QByteArray &&content) { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 	Expects(_editScope->selfieRequired); | ||||
| 
 | ||||
| 	_form->uploadSelfie( | ||||
| 		_editScope->documents[_editDocumentIndex], | ||||
| 		std::move(content)); | ||||
| 	_form->uploadSelfie(_editDocument, std::move(content)); | ||||
| } | ||||
| 
 | ||||
| void PanelController::deleteSelfie() { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 	Expects(_editScope->selfieRequired); | ||||
| 
 | ||||
| 	_form->deleteSelfie( | ||||
| 		_editScope->documents[_editDocumentIndex]); | ||||
| 	_form->deleteSelfie(_editDocument); | ||||
| } | ||||
| 
 | ||||
| void PanelController::restoreSelfie() { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0 | ||||
| 		&& _editDocumentIndex < _editScope->documents.size()); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 	Expects(_editScope->selfieRequired); | ||||
| 
 | ||||
| 	_form->restoreSelfie( | ||||
| 		_editScope->documents[_editDocumentIndex]); | ||||
| 	_form->restoreSelfie(_editDocument); | ||||
| } | ||||
| 
 | ||||
| rpl::producer<ScanInfo> PanelController::scanUpdated() const { | ||||
| 	return _form->scanUpdated( | ||||
| 	) | rpl::filter([=](not_null<const EditFile*> file) { | ||||
| 		return (_editScope != nullptr) | ||||
| 			&& (_editDocumentIndex >= 0) | ||||
| 			&& (file->value == _editScope->documents[_editDocumentIndex]); | ||||
| 		return (file->value == _editDocument); | ||||
| 	}) | rpl::map([=](not_null<const EditFile*> file) { | ||||
| 		return collectScanInfo(*file); | ||||
| 	}); | ||||
|  | @ -471,7 +452,7 @@ rpl::producer<ScanInfo> PanelController::scanUpdated() const { | |||
| 
 | ||||
| ScanInfo PanelController::collectScanInfo(const EditFile &file) const { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editDocumentIndex >= 0); | ||||
| 	Expects(_editDocument != nullptr); | ||||
| 
 | ||||
| 	const auto status = [&] { | ||||
| 		if (file.fields.accessHash) { | ||||
|  | @ -502,10 +483,9 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const { | |||
| 			return formatDownloadText(0, file.fields.size); | ||||
| 		} | ||||
| 	}(); | ||||
| 	const auto &documents = _editScope->documents; | ||||
| 	auto isSelfie = (file.value == documents[_editDocumentIndex]) | ||||
| 		&& (documents[_editDocumentIndex]->selfieInEdit.has_value()) | ||||
| 		&& (&file == &*documents[_editDocumentIndex]->selfieInEdit); | ||||
| 	auto isSelfie = (file.value == _editDocument) | ||||
| 		&& (_editDocument->selfieInEdit.has_value()) | ||||
| 		&& (&file == &*_editDocument->selfieInEdit); | ||||
| 	return { | ||||
| 		FileKey{ file.fields.id, file.fields.dcId }, | ||||
| 		status, | ||||
|  | @ -514,6 +494,96 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const { | |||
| 		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 { | ||||
| 	switch (type) { | ||||
| 	case Scope::Type::Phone: | ||||
|  | @ -653,36 +723,38 @@ void PanelController::editScope(int index, int documentIndex) { | |||
| 			&& documentIndex < _scopes[index].documents.size())); | ||||
| 
 | ||||
| 	_editScope = &_scopes[index]; | ||||
| 	_editDocumentIndex = documentIndex; | ||||
| 	_editValue = _editScope->fields; | ||||
| 	_editDocument = (documentIndex >= 0) | ||||
| 		? _scopes[index].documents[documentIndex].get() | ||||
| 		: nullptr; | ||||
| 
 | ||||
| 	_form->startValueEdit(_editScope->fields); | ||||
| 	if (_editDocumentIndex >= 0) { | ||||
| 		_form->startValueEdit(_editScope->documents[_editDocumentIndex]); | ||||
| 	_form->startValueEdit(_editValue); | ||||
| 	if (_editDocument) { | ||||
| 		_form->startValueEdit(_editDocument); | ||||
| 	} | ||||
| 
 | ||||
| 	auto content = [&]() -> object_ptr<Ui::RpWidget> { | ||||
| 		switch (_editScope->type) { | ||||
| 		case Scope::Type::Identity: | ||||
| 		case Scope::Type::Address: { | ||||
| 			const auto &documents = _editScope->documents; | ||||
| 			auto result = (_editDocumentIndex >= 0) | ||||
| 			auto result = _editDocument | ||||
| 				? object_ptr<PanelEditDocument>( | ||||
| 					_panel.get(), | ||||
| 					this, | ||||
| 					GetDocumentScheme( | ||||
| 						_editScope->type, | ||||
| 						documents[_editDocumentIndex]->type), | ||||
| 					_editScope->fields->data.parsedInEdit, | ||||
| 					documents[_editDocumentIndex]->data.parsedInEdit, | ||||
| 					valueFiles(*documents[_editDocumentIndex]), | ||||
| 						_editDocument->type), | ||||
| 					_editValue->data.parsedInEdit, | ||||
| 					_editDocument->data.parsedInEdit, | ||||
| 					valueFiles(*_editDocument), | ||||
| 					(_editScope->selfieRequired | ||||
| 						? valueSelfie(*documents[_editDocumentIndex]) | ||||
| 						? valueSelfie(*_editDocument) | ||||
| 						: nullptr)) | ||||
| 				: object_ptr<PanelEditDocument>( | ||||
| 					_panel.get(), | ||||
| 					this, | ||||
| 					GetDocumentScheme(_editScope->type), | ||||
| 					_editScope->fields->data.parsedInEdit); | ||||
| 					_editValue->data.parsedInEdit); | ||||
| 			const auto weak = make_weak(result.data()); | ||||
| 			_panelHasUnsavedChanges = [=] { | ||||
| 				return weak ? weak->hasUnsavedChanges() : false; | ||||
|  | @ -691,7 +763,7 @@ void PanelController::editScope(int index, int documentIndex) { | |||
| 		} break; | ||||
| 		case Scope::Type::Phone: | ||||
| 		case Scope::Type::Email: { | ||||
| 			const auto &parsed = _editScope->fields->data.parsedInEdit; | ||||
| 			const auto &parsed = _editValue->data.parsedInEdit; | ||||
| 			const auto valueIt = parsed.fields.find("value"); | ||||
| 			_panelHasUnsavedChanges = nullptr; | ||||
| 			return object_ptr<PanelEditContact>( | ||||
|  | @ -736,18 +808,18 @@ void PanelController::processValueSaveFinished( | |||
| 		_verificationBoxes.erase(boxIt); | ||||
| 	} | ||||
| 
 | ||||
| 	const auto value1 = _editScope->fields; | ||||
| 	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(); | ||||
| 		} | ||||
| 	if (!savingScope()) { | ||||
| 		_panel->showForm(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool PanelController::savingScope() const { | ||||
| 	Expects(_editValue != nullptr); | ||||
| 
 | ||||
| 	return _form->savingValue(_editValue) | ||||
| 		|| (_editDocument && _form->savingValue(_editDocument)); | ||||
| } | ||||
| 
 | ||||
| void PanelController::processVerificationNeeded( | ||||
| 		not_null<const Value*> value) { | ||||
| 	const auto i = _verificationBoxes.find(value); | ||||
|  | @ -828,24 +900,27 @@ std::unique_ptr<ScanInfo> PanelController::valueSelfie( | |||
| } | ||||
| 
 | ||||
| void PanelController::cancelValueEdit() { | ||||
| 	if (const auto scope = base::take(_editScope)) { | ||||
| 		_form->cancelValueEdit(scope->fields); | ||||
| 		const auto index = std::exchange(_editDocumentIndex, -1); | ||||
| 		if (index >= 0) { | ||||
| 			_form->cancelValueEdit(scope->documents[index]); | ||||
| 		} | ||||
| 	Expects(_editScope != nullptr); | ||||
| 
 | ||||
| 	_editScopeBoxes.clear(); | ||||
| 	_form->cancelValueEdit(base::take(_editValue)); | ||||
| 	if (const auto document = base::take(_editDocument)) { | ||||
| 		_form->cancelValueEdit(document); | ||||
| 	} | ||||
| 	_editScope = nullptr; | ||||
| } | ||||
| 
 | ||||
| void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) { | ||||
| 	Expects(_panel != nullptr); | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editValue != nullptr); | ||||
| 
 | ||||
| 	_form->saveValueEdit(_editScope->fields, std::move(data)); | ||||
| 	if (_editDocumentIndex >= 0) { | ||||
| 		_form->saveValueEdit( | ||||
| 			_editScope->documents[_editDocumentIndex], | ||||
| 			std::move(filesData)); | ||||
| 	if (savingScope()) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	_form->saveValueEdit(_editValue, std::move(data)); | ||||
| 	if (_editDocument) { | ||||
| 		_form->saveValueEdit(_editDocument, std::move(filesData)); | ||||
| 	} else { | ||||
| 		Assert(filesData.fields.empty()); | ||||
| 	} | ||||
|  | @ -854,14 +929,12 @@ void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) { | |||
| bool PanelController::editScopeChanged( | ||||
| 		const ValueMap &data, | ||||
| 		const ValueMap &filesData) const { | ||||
| 	Expects(_editScope != nullptr); | ||||
| 	Expects(_editValue != nullptr); | ||||
| 
 | ||||
| 	if (_form->editValueChanged(_editScope->fields, data)) { | ||||
| 	if (_form->editValueChanged(_editValue, data)) { | ||||
| 		return true; | ||||
| 	} else if (_editDocumentIndex >= 0) { | ||||
| 		return _form->editValueChanged( | ||||
| 			_editScope->documents[_editDocumentIndex], | ||||
| 			filesData); | ||||
| 	} else if (_editDocument) { | ||||
| 		return _form->editValueChanged(_editDocument, filesData); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | @ -871,13 +944,11 @@ void PanelController::cancelEditScope() { | |||
| 
 | ||||
| 	if (_panelHasUnsavedChanges && _panelHasUnsavedChanges()) { | ||||
| 		if (!_confirmForgetChangesBox) { | ||||
| 			_confirmForgetChangesBox = BoxPointer(show(Box<ConfirmBox>( | ||||
| 			_confirmForgetChangesBox = show(Box<ConfirmBox>( | ||||
| 				lang(lng_passport_sure_cancel), | ||||
| 				lang(lng_continue), | ||||
| 				[=] { | ||||
| 					_panel->showForm(); | ||||
| 					base::take(_confirmForgetChangesBox); | ||||
| 				})).data()); | ||||
| 				[=] { _panel->showForm(); })); | ||||
| 			_editScopeBoxes.emplace_back(_confirmForgetChangesBox); | ||||
| 		} | ||||
| 	} else { | ||||
| 		_panel->showForm(); | ||||
|  |  | |||
|  | @ -69,6 +69,9 @@ public: | |||
| 	void restoreSelfie(); | ||||
| 	rpl::producer<ScanInfo> scanUpdated() const; | ||||
| 
 | ||||
| 	base::optional<rpl::producer<QString>> deleteValueLabel() const; | ||||
| 	void deleteValue(); | ||||
| 
 | ||||
| 	QString defaultEmail() const; | ||||
| 	QString defaultPhoneNumber() const; | ||||
| 
 | ||||
|  | @ -112,16 +115,23 @@ private: | |||
| 	void processValueSaveFinished(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; | ||||
| 	QString getDefaultContactValue(Scope::Type type) const; | ||||
| 	void deleteValueSure(bool withDetails); | ||||
| 
 | ||||
| 	not_null<FormController*> _form; | ||||
| 	std::vector<Scope> _scopes; | ||||
| 
 | ||||
| 	std::unique_ptr<Panel> _panel; | ||||
| 	base::lambda<bool()> _panelHasUnsavedChanges; | ||||
| 	BoxPointer _confirmForgetChangesBox; | ||||
| 	QPointer<BoxContent> _confirmForgetChangesBox; | ||||
| 	std::vector<BoxPointer> _editScopeBoxes; | ||||
| 	Scope *_editScope = nullptr; | ||||
| 	const Value *_editValue = nullptr; | ||||
| 	const Value *_editDocument = nullptr; | ||||
| 	int _editDocumentIndex = -1; | ||||
| 	BoxPointer _scopeDocumentTypeBox; | ||||
| 	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_details_row.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/scroll_area.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( | ||||
| 	QWidget*, | ||||
| 	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
 | ||||
| 
 | ||||
| struct PanelEditDocument::Result { | ||||
|  | @ -252,6 +328,17 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent( | |||
| 
 | ||||
| 	inner->add( | ||||
| 		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; | ||||
| } | ||||
|  | @ -301,12 +388,14 @@ PanelEditDocument::Result PanelEditDocument::collect() const { | |||
| } | ||||
| 
 | ||||
| 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 scrolltop = _scroll->mapToGlobal(QPoint(0, 0)); | ||||
| 		const auto scrolldelta = errortop.y() - scrolltop.y(); | ||||
| 		_scroll->scrollToY(_scroll->scrollTop() + scrolldelta); | ||||
| 		return false; | ||||
| 	} | ||||
| 	auto first = QPointer<PanelDetailsRow>(); | ||||
| 	for (const auto [i, field] : base::reversed(_details)) { | ||||
|  | @ -317,7 +406,7 @@ bool PanelEditDocument::validate() { | |||
| 		} | ||||
| 	} | ||||
| 	if (!first) { | ||||
| 		return true; | ||||
| 		return !error; | ||||
| 	} | ||||
| 	const auto firsttop = first->mapToGlobal(QPoint(0, 0)); | ||||
| 	const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0)); | ||||
|  | @ -356,4 +445,11 @@ object_ptr<BoxContent> RequestAddressType( | |||
| 		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
 | ||||
|  |  | |||
|  | @ -17,6 +17,12 @@ class PlainShadow; | |||
| class RoundButton; | ||||
| } // namespace Ui
 | ||||
| 
 | ||||
| namespace Info { | ||||
| namespace Profile { | ||||
| class Button; | ||||
| } // namespace Profile
 | ||||
| } // namespace Info
 | ||||
| 
 | ||||
| namespace Passport { | ||||
| 
 | ||||
| class PanelController; | ||||
|  | @ -98,6 +104,8 @@ private: | |||
| 	QPointer<EditScans> _editScans; | ||||
| 	std::map<int, QPointer<PanelDetailsRow>> _details; | ||||
| 
 | ||||
| 	QPointer<Info::Profile::Button> _delete; | ||||
| 
 | ||||
| 	object_ptr<Ui::RoundButton> _done; | ||||
| 
 | ||||
| }; | ||||
|  | @ -109,4 +117,9 @@ object_ptr<BoxContent> RequestAddressType( | |||
| 	base::lambda<void(int index)> submit, | ||||
| 	std::vector<QString> labels); | ||||
| 
 | ||||
| object_ptr<BoxContent> ConfirmDeleteDocument( | ||||
| 	base::lambda<void(bool withDetails)> submit, | ||||
| 	const QString &text, | ||||
| 	const QString &detailsCheckbox = QString()); | ||||
| 
 | ||||
| } // namespace Passport
 | ||||
|  |  | |||
|  | @ -92,7 +92,8 @@ int PanelForm::Row::countAvailableWidth(int newWidth) const { | |||
| 		- st::passportRowPadding.right() | ||||
| 		- (_ready | ||||
| 			? st::passportRowReadyIcon | ||||
| 			: st::passportRowEmptyIcon).width(); | ||||
| 			: st::passportRowEmptyIcon).width() | ||||
| 		- st::passportRowIconSkip; | ||||
| } | ||||
| 
 | ||||
| int PanelForm::Row::countAvailableWidth() const { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue