143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
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 "base/object_ptr.h"
 | 
						|
#include "base/unique_qptr.h"
 | 
						|
 | 
						|
namespace Ui {
 | 
						|
class RpWidget;
 | 
						|
class InputField;
 | 
						|
class MaskedInputField;
 | 
						|
class BoxContent;
 | 
						|
} // namespace Ui
 | 
						|
 | 
						|
namespace Payments::Ui {
 | 
						|
 | 
						|
using namespace ::Ui;
 | 
						|
 | 
						|
enum class FieldType {
 | 
						|
	Text,
 | 
						|
	CardNumber,
 | 
						|
	CardExpireDate,
 | 
						|
	CardCVC,
 | 
						|
	Country,
 | 
						|
	Phone,
 | 
						|
	Email,
 | 
						|
	Money,
 | 
						|
};
 | 
						|
 | 
						|
struct FieldValidateRequest {
 | 
						|
	QString wasValue;
 | 
						|
	int wasPosition = 0;
 | 
						|
	int wasAnchor = 0;
 | 
						|
	QString nowValue;
 | 
						|
	int nowPosition = 0;
 | 
						|
};
 | 
						|
 | 
						|
struct FieldValidateResult {
 | 
						|
	QString value;
 | 
						|
	int position = 0;
 | 
						|
	bool invalid = false;
 | 
						|
	bool finished = false;
 | 
						|
};
 | 
						|
 | 
						|
[[nodiscard]] inline auto RangeLengthValidator(int minLength, int maxLength) {
 | 
						|
	return [=](FieldValidateRequest request) {
 | 
						|
		return FieldValidateResult{
 | 
						|
			.value = request.nowValue,
 | 
						|
			.position = request.nowPosition,
 | 
						|
			.invalid = (request.nowValue.size() < minLength
 | 
						|
				|| request.nowValue.size() > maxLength),
 | 
						|
		};
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] inline auto MaxLengthValidator(int maxLength) {
 | 
						|
	return RangeLengthValidator(0, maxLength);
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] inline auto RequiredValidator() {
 | 
						|
	return RangeLengthValidator(1, std::numeric_limits<int>::max());
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] inline auto RequiredFinishedValidator() {
 | 
						|
	return [=](FieldValidateRequest request) {
 | 
						|
		return FieldValidateResult{
 | 
						|
			.value = request.nowValue,
 | 
						|
			.position = request.nowPosition,
 | 
						|
			.invalid = request.nowValue.isEmpty(),
 | 
						|
			.finished = !request.nowValue.isEmpty(),
 | 
						|
		};
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
struct FieldConfig {
 | 
						|
	FieldType type = FieldType::Text;
 | 
						|
	rpl::producer<QString> placeholder;
 | 
						|
	QString value;
 | 
						|
	Fn<FieldValidateResult(FieldValidateRequest)> validator;
 | 
						|
	Fn<void(object_ptr<BoxContent>)> showBox;
 | 
						|
	QString currency;
 | 
						|
	QString defaultPhone;
 | 
						|
	QString defaultCountry;
 | 
						|
};
 | 
						|
 | 
						|
class Field final {
 | 
						|
public:
 | 
						|
	Field(QWidget *parent, FieldConfig &&config);
 | 
						|
 | 
						|
	[[nodiscard]] RpWidget *widget() const;
 | 
						|
	[[nodiscard]] object_ptr<RpWidget> ownedWidget() const;
 | 
						|
 | 
						|
	[[nodiscard]] QString value() const;
 | 
						|
	[[nodiscard]] rpl::producer<> frontBackspace() const;
 | 
						|
	[[nodiscard]] rpl::producer<> finished() const;
 | 
						|
	[[nodiscard]] rpl::producer<> submitted() const;
 | 
						|
 | 
						|
	void activate();
 | 
						|
	void setFocus();
 | 
						|
	void setFocusFast();
 | 
						|
	void showError();
 | 
						|
	void showErrorNoFocus();
 | 
						|
 | 
						|
	void setNextField(not_null<Field*> field);
 | 
						|
	void setPreviousField(not_null<Field*> field);
 | 
						|
 | 
						|
private:
 | 
						|
	struct State {
 | 
						|
		QString value;
 | 
						|
		int position = 0;
 | 
						|
		int anchor = 0;
 | 
						|
	};
 | 
						|
	using ValidateRequest = FieldValidateRequest;
 | 
						|
	using ValidateResult = FieldValidateResult;
 | 
						|
 | 
						|
	void setupMaskedGeometry();
 | 
						|
	void setupCountry();
 | 
						|
	void setupValidator(Fn<ValidateResult(ValidateRequest)> validator);
 | 
						|
	void setupFrontBackspace();
 | 
						|
	void setupSubmit();
 | 
						|
 | 
						|
	const FieldConfig _config;
 | 
						|
	const base::unique_qptr<RpWidget> _wrap;
 | 
						|
	rpl::event_stream<> _frontBackspace;
 | 
						|
	rpl::event_stream<> _finished;
 | 
						|
	rpl::event_stream<> _submitted;
 | 
						|
	rpl::event_stream<> _textPossiblyChanged; // Must be above _masked.
 | 
						|
	InputField *_input = nullptr;
 | 
						|
	MaskedInputField *_masked = nullptr;
 | 
						|
	Field *_nextField = nullptr;
 | 
						|
	QString _countryIso2;
 | 
						|
	State _was;
 | 
						|
	bool _validating = false;
 | 
						|
	bool _valid = true;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
} // namespace Payments::Ui
 |