mirror of https://github.com/procxx/kepka.git
				
				
				
			Move scans upload to a separate module.
This commit is contained in:
		
							parent
							
								
									f0b7ff24b1
								
							
						
					
					
						commit
						2790919733
					
				|  | @ -9,184 +9,22 @@ 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 "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" | ||||||
| #include "ui/widgets/buttons.h" | #include "ui/widgets/buttons.h" | ||||||
| #include "ui/widgets/shadow.h" | #include "ui/widgets/shadow.h" | ||||||
| #include "ui/wrap/vertical_layout.h" | #include "ui/wrap/vertical_layout.h" | ||||||
| #include "ui/wrap/slide_wrap.h" |  | ||||||
| #include "ui/wrap/fade_wrap.h" | #include "ui/wrap/fade_wrap.h" | ||||||
| #include "ui/text_options.h" |  | ||||||
| #include "info/profile/info_profile_button.h" |  | ||||||
| #include "info/profile/info_profile_values.h" |  | ||||||
| #include "boxes/abstract_box.h" | #include "boxes/abstract_box.h" | ||||||
| #include "lang/lang_keys.h" | #include "lang/lang_keys.h" | ||||||
| #include "core/file_utilities.h" |  | ||||||
| #include "styles/style_widgets.h" | #include "styles/style_widgets.h" | ||||||
| #include "styles/style_boxes.h" | #include "styles/style_boxes.h" | ||||||
| #include "styles/style_passport.h" | #include "styles/style_passport.h" | ||||||
| 
 | 
 | ||||||
| namespace Passport { | namespace Passport { | ||||||
| 
 | 
 | ||||||
| class ScanButton : public Ui::AbstractButton { |  | ||||||
| public: |  | ||||||
| 	ScanButton( |  | ||||||
| 		QWidget *parent, |  | ||||||
| 		const style::PassportScanRow &st, |  | ||||||
| 		const QString &name, |  | ||||||
| 		const QString &status, |  | ||||||
| 		bool deleted); |  | ||||||
| 
 |  | ||||||
| 	void setImage(const QImage &image); |  | ||||||
| 	void setStatus(const QString &status); |  | ||||||
| 	void setDeleted(bool deleted); |  | ||||||
| 
 |  | ||||||
| 	rpl::producer<> deleteClicks() const { |  | ||||||
| 		return _delete->entity()->clicks(); |  | ||||||
| 	} |  | ||||||
| 	rpl::producer<> restoreClicks() const { |  | ||||||
| 		return _restore->entity()->clicks(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| protected: |  | ||||||
| 	int resizeGetHeight(int newWidth) override; |  | ||||||
| 
 |  | ||||||
| 	void paintEvent(QPaintEvent *e) override; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| 	int countAvailableWidth() const; |  | ||||||
| 
 |  | ||||||
| 	const style::PassportScanRow &_st; |  | ||||||
| 	Text _name; |  | ||||||
| 	Text _status; |  | ||||||
| 	int _nameHeight = 0; |  | ||||||
| 	int _statusHeight = 0; |  | ||||||
| 	QImage _image; |  | ||||||
| 	object_ptr<Ui::FadeWrapScaled<Ui::IconButton>> _delete; |  | ||||||
| 	object_ptr<Ui::FadeWrapScaled<Ui::RoundButton>> _restore; |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ScanButton::ScanButton( |  | ||||||
| 	QWidget *parent, |  | ||||||
| 	const style::PassportScanRow &st, |  | ||||||
| 	const QString &name, |  | ||||||
| 	const QString &status, |  | ||||||
| 	bool deleted) |  | ||||||
| : AbstractButton(parent) |  | ||||||
| , _st(st) |  | ||||||
| , _name( |  | ||||||
| 	st::passportScanNameStyle, |  | ||||||
| 	name, |  | ||||||
| 	Ui::NameTextOptions()) |  | ||||||
| , _status( |  | ||||||
| 	st::defaultTextStyle, |  | ||||||
| 	status, |  | ||||||
| 	Ui::NameTextOptions()) |  | ||||||
| , _delete(this, object_ptr<Ui::IconButton>(this, _st.remove)) |  | ||||||
| , _restore( |  | ||||||
| 	this, |  | ||||||
| 	object_ptr<Ui::RoundButton>( |  | ||||||
| 		this, |  | ||||||
| 		langFactory(lng_passport_delete_scan_undo), |  | ||||||
| 		_st.restore)) { |  | ||||||
| 	_delete->toggle(!deleted, anim::type::instant); |  | ||||||
| 	_restore->toggle(deleted, anim::type::instant); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ScanButton::setImage(const QImage &image) { |  | ||||||
| 	_image = image; |  | ||||||
| 	update(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ScanButton::setStatus(const QString &status) { |  | ||||||
| 	_status.setText( |  | ||||||
| 		st::defaultTextStyle, |  | ||||||
| 		status, |  | ||||||
| 		Ui::NameTextOptions()); |  | ||||||
| 	update(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ScanButton::setDeleted(bool deleted) { |  | ||||||
| 	_delete->toggle(!deleted, anim::type::instant); |  | ||||||
| 	_restore->toggle(deleted, anim::type::instant); |  | ||||||
| 	update(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int ScanButton::resizeGetHeight(int newWidth) { |  | ||||||
| 	_nameHeight = st::semiboldFont->height; |  | ||||||
| 	_statusHeight = st::normalFont->height; |  | ||||||
| 	const auto result = _st.padding.top() + _st.size + _st.padding.bottom(); |  | ||||||
| 	const auto right = _st.padding.right(); |  | ||||||
| 	_delete->moveToRight( |  | ||||||
| 		right, |  | ||||||
| 		(result - _delete->height()) / 2, |  | ||||||
| 		newWidth); |  | ||||||
| 	_restore->moveToRight( |  | ||||||
| 		right, |  | ||||||
| 		(result - _restore->height()) / 2, |  | ||||||
| 		newWidth); |  | ||||||
| 	return result + st::lineWidth; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int ScanButton::countAvailableWidth() const { |  | ||||||
| 	return width() |  | ||||||
| 		- _st.padding.left() |  | ||||||
| 		- _st.textLeft |  | ||||||
| 		- _st.padding.right() |  | ||||||
| 		- std::max(_delete->width(), _restore->width()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ScanButton::paintEvent(QPaintEvent *e) { |  | ||||||
| 	Painter p(this); |  | ||||||
| 
 |  | ||||||
| 	const auto left = _st.padding.left(); |  | ||||||
| 	const auto top = _st.padding.top(); |  | ||||||
| 	p.fillRect( |  | ||||||
| 		left, |  | ||||||
| 		height() - _st.border, |  | ||||||
| 		width() - left, |  | ||||||
| 		_st.border, |  | ||||||
| 		_st.borderFg); |  | ||||||
| 
 |  | ||||||
| 	if (_restore->toggled()) { |  | ||||||
| 		p.setOpacity(st::passportScanDeletedOpacity); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (_image.isNull()) { |  | ||||||
| 		p.fillRect(left, top, _st.size, _st.size, Qt::black); |  | ||||||
| 	} else { |  | ||||||
| 		PainterHighQualityEnabler hq(p); |  | ||||||
| 		const auto fromRect = [&] { |  | ||||||
| 			if (_image.width() > _image.height()) { |  | ||||||
| 				const auto shift = (_image.width() - _image.height()) / 2; |  | ||||||
| 				return QRect(shift, 0, _image.height(), _image.height()); |  | ||||||
| 			} else { |  | ||||||
| 				const auto shift = (_image.height() - _image.width()) / 2; |  | ||||||
| 				return QRect(0, shift, _image.width(), _image.width()); |  | ||||||
| 			} |  | ||||||
| 		}(); |  | ||||||
| 		p.drawImage(QRect(left, top, _st.size, _st.size), _image, fromRect); |  | ||||||
| 	} |  | ||||||
| 	const auto availableWidth = countAvailableWidth(); |  | ||||||
| 
 |  | ||||||
| 	p.setPen(st::windowFg); |  | ||||||
| 	_name.drawLeftElided( |  | ||||||
| 		p, |  | ||||||
| 		left + _st.textLeft, |  | ||||||
| 		top + _st.nameTop, |  | ||||||
| 		availableWidth, |  | ||||||
| 		width()); |  | ||||||
| 	p.setPen(st::windowSubTextFg); |  | ||||||
| 	_status.drawLeftElided( |  | ||||||
| 		p, |  | ||||||
| 		left + _st.textLeft, |  | ||||||
| 		top + _st.statusTop, |  | ||||||
| 		availableWidth, |  | ||||||
| 		width()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| PanelEditIdentity::PanelEditIdentity( | PanelEditIdentity::PanelEditIdentity( | ||||||
| 	QWidget*, | 	QWidget*, | ||||||
| 	not_null<PanelController*> controller, | 	not_null<PanelController*> controller, | ||||||
|  | @ -194,7 +32,6 @@ PanelEditIdentity::PanelEditIdentity( | ||||||
| 	const ValueMap &scanData, | 	const ValueMap &scanData, | ||||||
| 	std::vector<ScanInfo> &&files) | 	std::vector<ScanInfo> &&files) | ||||||
| : _controller(controller) | : _controller(controller) | ||||||
| , _files(std::move(files)) |  | ||||||
| , _scroll(this, st::passportPanelScroll) | , _scroll(this, st::passportPanelScroll) | ||||||
| , _topShadow(this) | , _topShadow(this) | ||||||
| , _bottomShadow(this) | , _bottomShadow(this) | ||||||
|  | @ -202,13 +39,14 @@ PanelEditIdentity::PanelEditIdentity( | ||||||
| 		this, | 		this, | ||||||
| 		langFactory(lng_passport_save_value), | 		langFactory(lng_passport_save_value), | ||||||
| 		st::passportPanelSaveValue) { | 		st::passportPanelSaveValue) { | ||||||
| 	setupControls(data, scanData); | 	setupControls(data, scanData, std::move(files)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PanelEditIdentity::setupControls( | void PanelEditIdentity::setupControls( | ||||||
| 		const ValueMap &data, | 		const ValueMap &data, | ||||||
| 		const ValueMap &scanData) { | 		const ValueMap &scanData, | ||||||
| 	const auto inner = setupContent(data, scanData); | 		std::vector<ScanInfo> &&files) { | ||||||
|  | 	const auto inner = setupContent(data, scanData, std::move(files)); | ||||||
| 
 | 
 | ||||||
| 	using namespace rpl::mappers; | 	using namespace rpl::mappers; | ||||||
| 
 | 
 | ||||||
|  | @ -219,15 +57,12 @@ void PanelEditIdentity::setupControls( | ||||||
| 			save(); | 			save(); | ||||||
| 		}); | 		}); | ||||||
| 	}); | 	}); | ||||||
| 	_controller->scanUpdated( |  | ||||||
| 	) | rpl::start_with_next([=](ScanInfo &&info) { |  | ||||||
| 		updateScan(std::move(info)); |  | ||||||
| 	}, lifetime()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| not_null<Ui::RpWidget*> PanelEditIdentity::setupContent( | not_null<Ui::RpWidget*> PanelEditIdentity::setupContent( | ||||||
| 		const ValueMap &data, | 		const ValueMap &data, | ||||||
| 		const ValueMap &scanData) { | 		const ValueMap &scanData, | ||||||
|  | 		std::vector<ScanInfo> &&files) { | ||||||
| 	const auto inner = _scroll->setOwnedWidget( | 	const auto inner = _scroll->setOwnedWidget( | ||||||
| 		object_ptr<Ui::VerticalLayout>(this)); | 		object_ptr<Ui::VerticalLayout>(this)); | ||||||
| 	_scroll->widthValue( | 	_scroll->widthValue( | ||||||
|  | @ -235,42 +70,8 @@ not_null<Ui::RpWidget*> PanelEditIdentity::setupContent( | ||||||
| 		inner->resizeToWidth(width); | 		inner->resizeToWidth(width); | ||||||
| 	}, inner->lifetime()); | 	}, inner->lifetime()); | ||||||
| 
 | 
 | ||||||
| 	_scansDivider = inner->add( | 	_editScans = inner->add( | ||||||
| 		object_ptr<Ui::SlideWrap<BoxContentDivider>>( | 		object_ptr<EditScans>(inner, _controller, std::move(files))); | ||||||
| 			inner, |  | ||||||
| 			object_ptr<BoxContentDivider>( |  | ||||||
| 				inner, |  | ||||||
| 				st::passportFormDividerHeight))); |  | ||||||
| 	_scansDivider->toggle(_files.empty(), anim::type::instant); |  | ||||||
| 
 |  | ||||||
| 	_scansHeader = inner->add( |  | ||||||
| 		object_ptr<Ui::SlideWrap<Ui::FlatLabel>>( |  | ||||||
| 			inner, |  | ||||||
| 			object_ptr<Ui::FlatLabel>( |  | ||||||
| 				inner, |  | ||||||
| 				lang(lng_passport_upload_header), |  | ||||||
| 				Ui::FlatLabel::InitType::Simple, |  | ||||||
| 				st::passportFormHeader), |  | ||||||
| 			st::passportUploadHeaderPadding)); |  | ||||||
| 	_scansHeader->toggle(!_files.empty(), anim::type::instant); |  | ||||||
| 
 |  | ||||||
| 	_scansWrap = inner->add(object_ptr<Ui::VerticalLayout>(inner)); |  | ||||||
| 	for (const auto &scan : _files) { |  | ||||||
| 		pushScan(scan); |  | ||||||
| 		_scans.back()->show(anim::type::instant); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	_scansUpload = inner->add( |  | ||||||
| 		object_ptr<Info::Profile::Button>( |  | ||||||
| 			inner, |  | ||||||
| 			_scansUploadTexts.events_starting_with( |  | ||||||
| 				uploadButtonText() |  | ||||||
| 			) | rpl::flatten_latest(), |  | ||||||
| 			st::passportUploadButton), |  | ||||||
| 		st::passportUploadButtonPadding); |  | ||||||
| 	_scansUpload->addClickHandler([=] { |  | ||||||
| 		chooseScan(); |  | ||||||
| 	}); |  | ||||||
| 
 | 
 | ||||||
| 	inner->add(object_ptr<BoxContentDivider>( | 	inner->add(object_ptr<BoxContentDivider>( | ||||||
| 		inner, | 		inner, | ||||||
|  | @ -302,53 +103,6 @@ not_null<Ui::RpWidget*> PanelEditIdentity::setupContent( | ||||||
| 	return inner; | 	return inner; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PanelEditIdentity::updateScan(ScanInfo &&info) { |  | ||||||
| 	const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) { |  | ||||||
| 		return file.key; |  | ||||||
| 	}); |  | ||||||
| 	if (i != _files.end()) { |  | ||||||
| 		*i = info; |  | ||||||
| 		const auto scan = _scans[i - _files.begin()]->entity(); |  | ||||||
| 		scan->setStatus(i->status); |  | ||||||
| 		scan->setImage(i->thumb); |  | ||||||
| 		scan->setDeleted(i->deleted); |  | ||||||
| 	} else { |  | ||||||
| 		_files.push_back(std::move(info)); |  | ||||||
| 		pushScan(_files.back()); |  | ||||||
| 		_scansWrap->resizeToWidth(width()); |  | ||||||
| 		_scans.back()->show(anim::type::normal); |  | ||||||
| 		_scansDivider->hide(anim::type::normal); |  | ||||||
| 		_scansHeader->show(anim::type::normal); |  | ||||||
| 		_scansUploadTexts.fire(uploadButtonText()); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PanelEditIdentity::pushScan(const ScanInfo &info) { |  | ||||||
| 	const auto index = _scans.size(); |  | ||||||
| 	_scans.push_back(base::unique_qptr<Ui::SlideWrap<ScanButton>>( |  | ||||||
| 		_scansWrap->add(object_ptr<Ui::SlideWrap<ScanButton>>( |  | ||||||
| 			_scansWrap, |  | ||||||
| 			object_ptr<ScanButton>( |  | ||||||
| 				_scansWrap, |  | ||||||
| 				st::passportScanRow, |  | ||||||
| 				lng_passport_scan_index(lt_index, QString::number(index + 1)), |  | ||||||
| 				info.status, |  | ||||||
| 				info.deleted))))); |  | ||||||
| 	_scans.back()->hide(anim::type::instant); |  | ||||||
| 	const auto scan = _scans.back()->entity(); |  | ||||||
| 	scan->setImage(info.thumb); |  | ||||||
| 
 |  | ||||||
| 	scan->deleteClicks( |  | ||||||
| 	) | rpl::start_with_next([=] { |  | ||||||
| 		_controller->deleteScan(index); |  | ||||||
| 	}, scan->lifetime()); |  | ||||||
| 
 |  | ||||||
| 	scan->restoreClicks( |  | ||||||
| 	) | rpl::start_with_next([=] { |  | ||||||
| 		_controller->restoreScan(index); |  | ||||||
| 	}, scan->lifetime()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PanelEditIdentity::focusInEvent(QFocusEvent *e) { | void PanelEditIdentity::focusInEvent(QFocusEvent *e) { | ||||||
| 	_firstName->setFocusFast(); | 	_firstName->setFocusFast(); | ||||||
| } | } | ||||||
|  | @ -370,38 +124,6 @@ void PanelEditIdentity::updateControlsGeometry() { | ||||||
| 	_scroll->updateBars(); | 	_scroll->updateBars(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PanelEditIdentity::chooseScan() { |  | ||||||
| 	const auto filter = FileDialog::AllFilesFilter() |  | ||||||
| 		+ qsl(";;Image files (*") |  | ||||||
| 		+ cImgExtensions().join(qsl(" *")) |  | ||||||
| 		+ qsl(")"); |  | ||||||
| 	const auto callback = [=](FileDialog::OpenResult &&result) { |  | ||||||
| 		if (result.paths.size() == 1) { |  | ||||||
| 			encryptScan(result.paths.front()); |  | ||||||
| 		} else if (!result.remoteContent.isEmpty()) { |  | ||||||
| 			encryptScanContent(std::move(result.remoteContent)); |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 	FileDialog::GetOpenPath( |  | ||||||
| 		lang(lng_passport_choose_image), |  | ||||||
| 		filter, |  | ||||||
| 		base::lambda_guarded(this, callback)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PanelEditIdentity::encryptScan(const QString &path) { |  | ||||||
| 	encryptScanContent([&] { |  | ||||||
| 		QFile f(path); |  | ||||||
| 		if (!f.open(QIODevice::ReadOnly)) { |  | ||||||
| 			return QByteArray(); |  | ||||||
| 		} |  | ||||||
| 		return f.readAll(); |  | ||||||
| 	}()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PanelEditIdentity::encryptScanContent(QByteArray &&content) { |  | ||||||
| 	_controller->uploadScan(std::move(content)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void PanelEditIdentity::save() { | void PanelEditIdentity::save() { | ||||||
| 	auto data = ValueMap(); | 	auto data = ValueMap(); | ||||||
| 	data.fields["first_name"] = _firstName->getLastText(); | 	data.fields["first_name"] = _firstName->getLastText(); | ||||||
|  | @ -410,10 +132,4 @@ void PanelEditIdentity::save() { | ||||||
| 	_controller->saveScope(std::move(data), std::move(scanData)); | 	_controller->saveScope(std::move(data), std::move(scanData)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| rpl::producer<QString> PanelEditIdentity::uploadButtonText() const { |  | ||||||
| 	return Lang::Viewer(_files.empty() |  | ||||||
| 		? lng_passport_upload_scans |  | ||||||
| 		: lng_passport_upload_more) | Info::Profile::ToUpperValue(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Passport
 | } // namespace Passport
 | ||||||
|  |  | ||||||
|  | @ -9,32 +9,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| 
 | 
 | ||||||
| #include "ui/rp_widget.h" | #include "ui/rp_widget.h" | ||||||
| 
 | 
 | ||||||
| class BoxContentDivider; |  | ||||||
| 
 |  | ||||||
| namespace Ui { | namespace Ui { | ||||||
| class InputField; | class InputField; | ||||||
| class VerticalLayout; |  | ||||||
| class ScrollArea; | class ScrollArea; | ||||||
| class FadeShadow; | class FadeShadow; | ||||||
| class PlainShadow; | class PlainShadow; | ||||||
| class FlatLabel; |  | ||||||
| class RoundButton; | class RoundButton; | ||||||
| template <typename Widget> |  | ||||||
| class SlideWrap; |  | ||||||
| } // namespace Ui
 | } // namespace Ui
 | ||||||
| 
 | 
 | ||||||
| namespace Info { |  | ||||||
| namespace Profile { |  | ||||||
| class Button; |  | ||||||
| } // namespace Profile
 |  | ||||||
| } // namespace Info
 |  | ||||||
| 
 |  | ||||||
| namespace Passport { | namespace Passport { | ||||||
| 
 | 
 | ||||||
| class PanelController; | class PanelController; | ||||||
| struct ValueMap; | struct ValueMap; | ||||||
| struct ScanInfo; | struct ScanInfo; | ||||||
| class ScanButton; | class EditScans; | ||||||
| 
 | 
 | ||||||
| class PanelEditIdentity : public Ui::RpWidget { | class PanelEditIdentity : public Ui::RpWidget { | ||||||
| public: | public: | ||||||
|  | @ -50,35 +38,25 @@ protected: | ||||||
| 	void resizeEvent(QResizeEvent *e) override; | 	void resizeEvent(QResizeEvent *e) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	void setupControls(const ValueMap &data, const ValueMap &scanData); | 	void setupControls( | ||||||
|  | 		const ValueMap &data, | ||||||
|  | 		const ValueMap &scanData, | ||||||
|  | 		std::vector<ScanInfo> &&files); | ||||||
| 	not_null<Ui::RpWidget*> setupContent( | 	not_null<Ui::RpWidget*> setupContent( | ||||||
| 		const ValueMap &data, | 		const ValueMap &data, | ||||||
| 		const ValueMap &scanData); | 		const ValueMap &scanData, | ||||||
|  | 		std::vector<ScanInfo> &&files); | ||||||
| 	void updateControlsGeometry(); | 	void updateControlsGeometry(); | ||||||
| 
 | 
 | ||||||
| 	void chooseScan(); |  | ||||||
| 	void encryptScan(const QString &path); |  | ||||||
| 	void encryptScanContent(QByteArray &&content); |  | ||||||
| 	void updateScan(ScanInfo &&info); |  | ||||||
| 	void pushScan(const ScanInfo &info); |  | ||||||
| 
 |  | ||||||
| 	rpl::producer<QString> uploadButtonText() const; |  | ||||||
| 	void save(); | 	void save(); | ||||||
| 
 | 
 | ||||||
| 	not_null<PanelController*> _controller; | 	not_null<PanelController*> _controller; | ||||||
| 	std::vector<ScanInfo> _files; |  | ||||||
| 
 | 
 | ||||||
| 	object_ptr<Ui::ScrollArea> _scroll; | 	object_ptr<Ui::ScrollArea> _scroll; | ||||||
| 	object_ptr<Ui::FadeShadow> _topShadow; | 	object_ptr<Ui::FadeShadow> _topShadow; | ||||||
| 	object_ptr<Ui::PlainShadow> _bottomShadow; | 	object_ptr<Ui::PlainShadow> _bottomShadow; | ||||||
| 
 | 
 | ||||||
| 	QPointer<Ui::SlideWrap<BoxContentDivider>> _scansDivider; | 	QPointer<EditScans> _editScans; | ||||||
| 	QPointer<Ui::SlideWrap<Ui::FlatLabel>> _scansHeader; |  | ||||||
| 	QPointer<Ui::VerticalLayout> _scansWrap; |  | ||||||
| 	std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _scans; |  | ||||||
| 	QPointer<Info::Profile::Button> _scansUpload; |  | ||||||
| 	rpl::event_stream<rpl::producer<QString>> _scansUploadTexts; |  | ||||||
| 
 |  | ||||||
| 	QPointer<Ui::InputField> _firstName; | 	QPointer<Ui::InputField> _firstName; | ||||||
| 	QPointer<Ui::InputField> _lastName; | 	QPointer<Ui::InputField> _lastName; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,336 @@ | ||||||
|  | /*
 | ||||||
|  | This file is part of Telegram Desktop, | ||||||
|  | the official desktop application for the Telegram messaging service. | ||||||
|  | 
 | ||||||
|  | For license and copyright information please follow this link: | ||||||
|  | https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | ||||||
|  | */ | ||||||
|  | #include "passport/passport_panel_edit_scans.h" | ||||||
|  | 
 | ||||||
|  | #include "passport/passport_panel_controller.h" | ||||||
|  | #include "info/profile/info_profile_button.h" | ||||||
|  | #include "info/profile/info_profile_values.h" | ||||||
|  | #include "ui/widgets/buttons.h" | ||||||
|  | #include "ui/widgets/labels.h" | ||||||
|  | #include "ui/wrap/fade_wrap.h" | ||||||
|  | #include "ui/wrap/slide_wrap.h" | ||||||
|  | #include "ui/wrap/vertical_layout.h" | ||||||
|  | #include "ui/text_options.h" | ||||||
|  | #include "core/file_utilities.h" | ||||||
|  | #include "lang/lang_keys.h" | ||||||
|  | #include "boxes/abstract_box.h" | ||||||
|  | #include "styles/style_passport.h" | ||||||
|  | 
 | ||||||
|  | namespace Passport { | ||||||
|  | 
 | ||||||
|  | class ScanButton : public Ui::AbstractButton { | ||||||
|  | public: | ||||||
|  | 	ScanButton( | ||||||
|  | 		QWidget *parent, | ||||||
|  | 		const style::PassportScanRow &st, | ||||||
|  | 		const QString &name, | ||||||
|  | 		const QString &status, | ||||||
|  | 		bool deleted); | ||||||
|  | 
 | ||||||
|  | 	void setImage(const QImage &image); | ||||||
|  | 	void setStatus(const QString &status); | ||||||
|  | 	void setDeleted(bool deleted); | ||||||
|  | 
 | ||||||
|  | 	rpl::producer<> deleteClicks() const { | ||||||
|  | 		return _delete->entity()->clicks(); | ||||||
|  | 	} | ||||||
|  | 	rpl::producer<> restoreClicks() const { | ||||||
|  | 		return _restore->entity()->clicks(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 	int resizeGetHeight(int newWidth) override; | ||||||
|  | 
 | ||||||
|  | 	void paintEvent(QPaintEvent *e) override; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	int countAvailableWidth() const; | ||||||
|  | 
 | ||||||
|  | 	const style::PassportScanRow &_st; | ||||||
|  | 	Text _name; | ||||||
|  | 	Text _status; | ||||||
|  | 	int _nameHeight = 0; | ||||||
|  | 	int _statusHeight = 0; | ||||||
|  | 	QImage _image; | ||||||
|  | 	object_ptr<Ui::FadeWrapScaled<Ui::IconButton>> _delete; | ||||||
|  | 	object_ptr<Ui::FadeWrapScaled<Ui::RoundButton>> _restore; | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ScanButton::ScanButton( | ||||||
|  | 	QWidget *parent, | ||||||
|  | 	const style::PassportScanRow &st, | ||||||
|  | 	const QString &name, | ||||||
|  | 	const QString &status, | ||||||
|  | 	bool deleted) | ||||||
|  | : AbstractButton(parent) | ||||||
|  | , _st(st) | ||||||
|  | , _name( | ||||||
|  | 	st::passportScanNameStyle, | ||||||
|  | 	name, | ||||||
|  | 	Ui::NameTextOptions()) | ||||||
|  | , _status( | ||||||
|  | 	st::defaultTextStyle, | ||||||
|  | 	status, | ||||||
|  | 	Ui::NameTextOptions()) | ||||||
|  | , _delete(this, object_ptr<Ui::IconButton>(this, _st.remove)) | ||||||
|  | , _restore( | ||||||
|  | 	this, | ||||||
|  | 	object_ptr<Ui::RoundButton>( | ||||||
|  | 		this, | ||||||
|  | 		langFactory(lng_passport_delete_scan_undo), | ||||||
|  | 		_st.restore)) { | ||||||
|  | 	_delete->toggle(!deleted, anim::type::instant); | ||||||
|  | 	_restore->toggle(deleted, anim::type::instant); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScanButton::setImage(const QImage &image) { | ||||||
|  | 	_image = image; | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScanButton::setStatus(const QString &status) { | ||||||
|  | 	_status.setText( | ||||||
|  | 		st::defaultTextStyle, | ||||||
|  | 		status, | ||||||
|  | 		Ui::NameTextOptions()); | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScanButton::setDeleted(bool deleted) { | ||||||
|  | 	_delete->toggle(!deleted, anim::type::instant); | ||||||
|  | 	_restore->toggle(deleted, anim::type::instant); | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ScanButton::resizeGetHeight(int newWidth) { | ||||||
|  | 	_nameHeight = st::semiboldFont->height; | ||||||
|  | 	_statusHeight = st::normalFont->height; | ||||||
|  | 	const auto result = _st.padding.top() + _st.size + _st.padding.bottom(); | ||||||
|  | 	const auto right = _st.padding.right(); | ||||||
|  | 	_delete->moveToRight( | ||||||
|  | 		right, | ||||||
|  | 		(result - _delete->height()) / 2, | ||||||
|  | 		newWidth); | ||||||
|  | 	_restore->moveToRight( | ||||||
|  | 		right, | ||||||
|  | 		(result - _restore->height()) / 2, | ||||||
|  | 		newWidth); | ||||||
|  | 	return result + st::lineWidth; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ScanButton::countAvailableWidth() const { | ||||||
|  | 	return width() | ||||||
|  | 		- _st.padding.left() | ||||||
|  | 		- _st.textLeft | ||||||
|  | 		- _st.padding.right() | ||||||
|  | 		- std::max(_delete->width(), _restore->width()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScanButton::paintEvent(QPaintEvent *e) { | ||||||
|  | 	Painter p(this); | ||||||
|  | 
 | ||||||
|  | 	const auto left = _st.padding.left(); | ||||||
|  | 	const auto top = _st.padding.top(); | ||||||
|  | 	p.fillRect( | ||||||
|  | 		left, | ||||||
|  | 		height() - _st.border, | ||||||
|  | 		width() - left, | ||||||
|  | 		_st.border, | ||||||
|  | 		_st.borderFg); | ||||||
|  | 
 | ||||||
|  | 	if (_restore->toggled()) { | ||||||
|  | 		p.setOpacity(st::passportScanDeletedOpacity); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (_image.isNull()) { | ||||||
|  | 		p.fillRect(left, top, _st.size, _st.size, Qt::black); | ||||||
|  | 	} else { | ||||||
|  | 		PainterHighQualityEnabler hq(p); | ||||||
|  | 		const auto fromRect = [&] { | ||||||
|  | 			if (_image.width() > _image.height()) { | ||||||
|  | 				const auto shift = (_image.width() - _image.height()) / 2; | ||||||
|  | 				return QRect(shift, 0, _image.height(), _image.height()); | ||||||
|  | 			} else { | ||||||
|  | 				const auto shift = (_image.height() - _image.width()) / 2; | ||||||
|  | 				return QRect(0, shift, _image.width(), _image.width()); | ||||||
|  | 			} | ||||||
|  | 		}(); | ||||||
|  | 		p.drawImage(QRect(left, top, _st.size, _st.size), _image, fromRect); | ||||||
|  | 	} | ||||||
|  | 	const auto availableWidth = countAvailableWidth(); | ||||||
|  | 
 | ||||||
|  | 	p.setPen(st::windowFg); | ||||||
|  | 	_name.drawLeftElided( | ||||||
|  | 		p, | ||||||
|  | 		left + _st.textLeft, | ||||||
|  | 		top + _st.nameTop, | ||||||
|  | 		availableWidth, | ||||||
|  | 		width()); | ||||||
|  | 	p.setPen(st::windowSubTextFg); | ||||||
|  | 	_status.drawLeftElided( | ||||||
|  | 		p, | ||||||
|  | 		left + _st.textLeft, | ||||||
|  | 		top + _st.statusTop, | ||||||
|  | 		availableWidth, | ||||||
|  | 		width()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | EditScans::EditScans( | ||||||
|  | 	QWidget *parent, | ||||||
|  | 	not_null<PanelController*> controller, | ||||||
|  | 	std::vector<ScanInfo> &&files) | ||||||
|  | : RpWidget(parent) | ||||||
|  | , _controller(controller) | ||||||
|  | , _files(std::move(files)) | ||||||
|  | , _content(this) { | ||||||
|  | 	setupContent(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::setupContent() { | ||||||
|  | 	const auto inner = _content.data(); | ||||||
|  | 	inner->move(0, 0); | ||||||
|  | 
 | ||||||
|  | 	_divider = inner->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<BoxContentDivider>>( | ||||||
|  | 			inner, | ||||||
|  | 			object_ptr<BoxContentDivider>( | ||||||
|  | 				inner, | ||||||
|  | 				st::passportFormDividerHeight))); | ||||||
|  | 	_divider->toggle(_files.empty(), anim::type::instant); | ||||||
|  | 
 | ||||||
|  | 	_header = inner->add( | ||||||
|  | 		object_ptr<Ui::SlideWrap<Ui::FlatLabel>>( | ||||||
|  | 			inner, | ||||||
|  | 			object_ptr<Ui::FlatLabel>( | ||||||
|  | 				inner, | ||||||
|  | 				lang(lng_passport_upload_header), | ||||||
|  | 				Ui::FlatLabel::InitType::Simple, | ||||||
|  | 				st::passportFormHeader), | ||||||
|  | 			st::passportUploadHeaderPadding)); | ||||||
|  | 	_header->toggle(!_files.empty(), anim::type::instant); | ||||||
|  | 
 | ||||||
|  | 	_wrap = inner->add(object_ptr<Ui::VerticalLayout>(inner)); | ||||||
|  | 	for (const auto &scan : _files) { | ||||||
|  | 		pushScan(scan); | ||||||
|  | 		_rows.back()->show(anim::type::instant); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_upload = inner->add( | ||||||
|  | 		object_ptr<Info::Profile::Button>( | ||||||
|  | 			inner, | ||||||
|  | 			_uploadTexts.events_starting_with( | ||||||
|  | 				uploadButtonText() | ||||||
|  | 			) | rpl::flatten_latest(), | ||||||
|  | 			st::passportUploadButton), | ||||||
|  | 		st::passportUploadButtonPadding); | ||||||
|  | 	_upload->addClickHandler([=] { | ||||||
|  | 		chooseScan(); | ||||||
|  | 	}); | ||||||
|  | 	_controller->scanUpdated( | ||||||
|  | 	) | rpl::start_with_next([=](ScanInfo &&info) { | ||||||
|  | 		updateScan(std::move(info)); | ||||||
|  | 	}, lifetime()); | ||||||
|  | 
 | ||||||
|  | 	widthValue( | ||||||
|  | 	) | rpl::start_with_next([=](int width) { | ||||||
|  | 		_content->resizeToWidth(width); | ||||||
|  | 	}, _content->lifetime()); | ||||||
|  | 
 | ||||||
|  | 	_content->heightValue( | ||||||
|  | 	) | rpl::start_with_next([=](int height) { | ||||||
|  | 		resize(width(), height); | ||||||
|  | 	}, _content->lifetime()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::updateScan(ScanInfo &&info) { | ||||||
|  | 	const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) { | ||||||
|  | 		return file.key; | ||||||
|  | 	}); | ||||||
|  | 	if (i != _files.end()) { | ||||||
|  | 		*i = info; | ||||||
|  | 		const auto scan = _rows[i - _files.begin()]->entity(); | ||||||
|  | 		scan->setStatus(i->status); | ||||||
|  | 		scan->setImage(i->thumb); | ||||||
|  | 		scan->setDeleted(i->deleted); | ||||||
|  | 	} else { | ||||||
|  | 		_files.push_back(std::move(info)); | ||||||
|  | 		pushScan(_files.back()); | ||||||
|  | 		_wrap->resizeToWidth(width()); | ||||||
|  | 		_rows.back()->show(anim::type::normal); | ||||||
|  | 		_divider->hide(anim::type::normal); | ||||||
|  | 		_header->show(anim::type::normal); | ||||||
|  | 		_uploadTexts.fire(uploadButtonText()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::pushScan(const ScanInfo &info) { | ||||||
|  | 	const auto index = _rows.size(); | ||||||
|  | 	_rows.push_back(base::unique_qptr<Ui::SlideWrap<ScanButton>>( | ||||||
|  | 		_wrap->add(object_ptr<Ui::SlideWrap<ScanButton>>( | ||||||
|  | 			_wrap, | ||||||
|  | 			object_ptr<ScanButton>( | ||||||
|  | 				_wrap, | ||||||
|  | 				st::passportScanRow, | ||||||
|  | 				lng_passport_scan_index(lt_index, QString::number(index + 1)), | ||||||
|  | 				info.status, | ||||||
|  | 				info.deleted))))); | ||||||
|  | 	_rows.back()->hide(anim::type::instant); | ||||||
|  | 	const auto scan = _rows.back()->entity(); | ||||||
|  | 	scan->setImage(info.thumb); | ||||||
|  | 
 | ||||||
|  | 	scan->deleteClicks( | ||||||
|  | 	) | rpl::start_with_next([=] { | ||||||
|  | 		_controller->deleteScan(index); | ||||||
|  | 	}, scan->lifetime()); | ||||||
|  | 
 | ||||||
|  | 	scan->restoreClicks( | ||||||
|  | 	) | rpl::start_with_next([=] { | ||||||
|  | 		_controller->restoreScan(index); | ||||||
|  | 	}, scan->lifetime()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::chooseScan() { | ||||||
|  | 	const auto filter = FileDialog::AllFilesFilter() | ||||||
|  | 		+ qsl(";;Image files (*") | ||||||
|  | 		+ cImgExtensions().join(qsl(" *")) | ||||||
|  | 		+ qsl(")"); | ||||||
|  | 	const auto callback = [=](FileDialog::OpenResult &&result) { | ||||||
|  | 		if (result.paths.size() == 1) { | ||||||
|  | 			encryptScan(result.paths.front()); | ||||||
|  | 		} else if (!result.remoteContent.isEmpty()) { | ||||||
|  | 			encryptScanContent(std::move(result.remoteContent)); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	FileDialog::GetOpenPath( | ||||||
|  | 		lang(lng_passport_choose_image), | ||||||
|  | 		filter, | ||||||
|  | 		base::lambda_guarded(this, callback)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::encryptScan(const QString &path) { | ||||||
|  | 	encryptScanContent([&] { | ||||||
|  | 		QFile f(path); | ||||||
|  | 		if (!f.open(QIODevice::ReadOnly)) { | ||||||
|  | 			return QByteArray(); | ||||||
|  | 		} | ||||||
|  | 		return f.readAll(); | ||||||
|  | 	}()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void EditScans::encryptScanContent(QByteArray &&content) { | ||||||
|  | 	_controller->uploadScan(std::move(content)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | rpl::producer<QString> EditScans::uploadButtonText() const { | ||||||
|  | 	return Lang::Viewer(_files.empty() | ||||||
|  | 		? lng_passport_upload_scans | ||||||
|  | 		: lng_passport_upload_more) | Info::Profile::ToUpperValue(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Passport
 | ||||||
|  | @ -0,0 +1,63 @@ | ||||||
|  | /*
 | ||||||
|  | This file is part of Telegram Desktop, | ||||||
|  | the official desktop application for the Telegram messaging service. | ||||||
|  | 
 | ||||||
|  | For license and copyright information please follow this link: | ||||||
|  | https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | ||||||
|  | */ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "ui/rp_widget.h" | ||||||
|  | 
 | ||||||
|  | class BoxContentDivider; | ||||||
|  | 
 | ||||||
|  | namespace Ui { | ||||||
|  | class VerticalLayout; | ||||||
|  | class FlatLabel; | ||||||
|  | template <typename Widget> | ||||||
|  | class SlideWrap; | ||||||
|  | } // namespace Ui
 | ||||||
|  | 
 | ||||||
|  | namespace Info { | ||||||
|  | namespace Profile { | ||||||
|  | class Button; | ||||||
|  | } // namespace Profile
 | ||||||
|  | } // namespace Info
 | ||||||
|  | 
 | ||||||
|  | namespace Passport { | ||||||
|  | 
 | ||||||
|  | class PanelController; | ||||||
|  | class ScanButton; | ||||||
|  | struct ScanInfo; | ||||||
|  | 
 | ||||||
|  | class EditScans : public Ui::RpWidget { | ||||||
|  | public: | ||||||
|  | 	EditScans( | ||||||
|  | 		QWidget *parent, | ||||||
|  | 		not_null<PanelController*> controller, | ||||||
|  | 		std::vector<ScanInfo> &&files); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	void setupContent(); | ||||||
|  | 	void chooseScan(); | ||||||
|  | 	void encryptScan(const QString &path); | ||||||
|  | 	void encryptScanContent(QByteArray &&content); | ||||||
|  | 	void updateScan(ScanInfo &&info); | ||||||
|  | 	void pushScan(const ScanInfo &info); | ||||||
|  | 
 | ||||||
|  | 	rpl::producer<QString> uploadButtonText() const; | ||||||
|  | 
 | ||||||
|  | 	not_null<PanelController*> _controller; | ||||||
|  | 	std::vector<ScanInfo> _files; | ||||||
|  | 
 | ||||||
|  | 	object_ptr<Ui::VerticalLayout> _content; | ||||||
|  | 	QPointer<Ui::SlideWrap<BoxContentDivider>> _divider; | ||||||
|  | 	QPointer<Ui::SlideWrap<Ui::FlatLabel>> _header; | ||||||
|  | 	QPointer<Ui::VerticalLayout> _wrap; | ||||||
|  | 	std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _rows; | ||||||
|  | 	QPointer<Info::Profile::Button> _upload; | ||||||
|  | 	rpl::event_stream<rpl::producer<QString>> _uploadTexts; | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Passport
 | ||||||
|  | @ -468,6 +468,8 @@ | ||||||
| <(src_loc)/passport/passport_panel_details_row.h | <(src_loc)/passport/passport_panel_details_row.h | ||||||
| <(src_loc)/passport/passport_panel_edit_identity.cpp | <(src_loc)/passport/passport_panel_edit_identity.cpp | ||||||
| <(src_loc)/passport/passport_panel_edit_identity.h | <(src_loc)/passport/passport_panel_edit_identity.h | ||||||
|  | <(src_loc)/passport/passport_panel_edit_scans.cpp | ||||||
|  | <(src_loc)/passport/passport_panel_edit_scans.h | ||||||
| <(src_loc)/passport/passport_panel_form.cpp | <(src_loc)/passport/passport_panel_form.cpp | ||||||
| <(src_loc)/passport/passport_panel_form.h | <(src_loc)/passport/passport_panel_form.h | ||||||
| <(src_loc)/passport/passport_panel_password.cpp | <(src_loc)/passport/passport_panel_password.cpp | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue