mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 22:55:11 +00:00
Allow selecting country in passport.
This commit is contained in:
@@ -183,7 +183,7 @@ passportScanDeletedOpacity: stickersRowDisabledOpacity;
|
||||
passportDetailsHeaderPadding: margins(22px, 20px, 33px, 10px);
|
||||
passportDetailsPadding: margins(22px, 10px, 28px, 10px);
|
||||
passportDetailsField: InputField(defaultInputField) {
|
||||
textMargins: margins(2px, 7px, 2px, 0px);
|
||||
textMargins: margins(2px, 8px, 2px, 0px);
|
||||
placeholderScale: 0.;
|
||||
heightMin: 32px;
|
||||
font: normalFont;
|
||||
|
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "passport/passport_panel_edit_document.h"
|
||||
#include "passport/passport_panel_details_row.h"
|
||||
#include "passport/passport_panel_edit_contact.h"
|
||||
#include "passport/passport_panel_edit_scans.h"
|
||||
#include "passport/passport_panel.h"
|
||||
@@ -64,42 +65,49 @@ PanelEditDocument::Scheme GetDocumentScheme(
|
||||
result.rows = {
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("first_name"),
|
||||
lang(lng_passport_first_name),
|
||||
NotEmptyValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("last_name"),
|
||||
lang(lng_passport_last_name),
|
||||
DontValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Date,
|
||||
qsl("birth_date"),
|
||||
lang(lng_passport_birth_date),
|
||||
DateValidate,
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Gender,
|
||||
qsl("gender"),
|
||||
lang(lng_passport_gender),
|
||||
GenderValidate,
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Country,
|
||||
qsl("country_code"),
|
||||
lang(lng_passport_country),
|
||||
CountryValidate,
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Scans,
|
||||
PanelDetailsType::Text,
|
||||
qsl("document_no"),
|
||||
lang(lng_passport_document_number),
|
||||
NotEmptyValidate,
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Scans,
|
||||
PanelDetailsType::Date,
|
||||
qsl("expiry_date"),
|
||||
lang(lng_passport_expiry_date),
|
||||
DateOrEmptyValidate,
|
||||
@@ -129,36 +137,42 @@ PanelEditDocument::Scheme GetDocumentScheme(
|
||||
result.rows = {
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("street_line1"),
|
||||
lang(lng_passport_street),
|
||||
NotEmptyValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("street_line2"),
|
||||
lang(lng_passport_street),
|
||||
DontValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("city"),
|
||||
lang(lng_passport_city),
|
||||
NotEmptyValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("state"),
|
||||
lang(lng_passport_state),
|
||||
DontValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Country,
|
||||
qsl("country_code"),
|
||||
lang(lng_passport_country),
|
||||
CountryValidate
|
||||
},
|
||||
{
|
||||
Scheme::ValueType::Fields,
|
||||
PanelDetailsType::Text,
|
||||
qsl("post_code"),
|
||||
lang(lng_passport_postcode),
|
||||
NotEmptyValidate
|
||||
@@ -768,7 +782,10 @@ void PanelController::cancelEditScope() {
|
||||
_confirmForgetChangesBox = BoxPointer(show(Box<ConfirmBox>(
|
||||
lang(lng_passport_sure_cancel),
|
||||
lang(lng_continue),
|
||||
[=] { _panel->showForm(); })).data());
|
||||
[=] {
|
||||
_panel->showForm();
|
||||
base::take(_confirmForgetChangesBox);
|
||||
})).data());
|
||||
}
|
||||
} else {
|
||||
_panel->showForm();
|
||||
|
@@ -7,10 +7,207 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "passport/passport_panel_details_row.h"
|
||||
|
||||
#include "passport/passport_panel_controller.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/countryinput.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_passport.h"
|
||||
|
||||
namespace Passport {
|
||||
namespace {
|
||||
|
||||
class TextRow : public PanelDetailsRow {
|
||||
public:
|
||||
TextRow(QWidget *parent, const QString &label, const QString &value);
|
||||
|
||||
bool setFocusFast() override;
|
||||
rpl::producer<QString> value() const override;
|
||||
QString valueCurrent() const override;
|
||||
|
||||
private:
|
||||
int resizeInner(int left, int top, int width) override;
|
||||
void showInnerError() override;
|
||||
void finishInnerAnimating() override;
|
||||
|
||||
object_ptr<Ui::InputField> _field;
|
||||
rpl::variable<QString> _value;
|
||||
|
||||
};
|
||||
|
||||
class CountryRow : public PanelDetailsRow {
|
||||
public:
|
||||
CountryRow(
|
||||
QWidget *parent,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
const QString &value);
|
||||
|
||||
rpl::producer<QString> value() const override;
|
||||
QString valueCurrent() const override;
|
||||
|
||||
private:
|
||||
int resizeInner(int left, int top, int width) override;
|
||||
void showInnerError() override;
|
||||
void finishInnerAnimating() override;
|
||||
|
||||
void chooseCountry();
|
||||
void hideCountryError();
|
||||
void toggleError(bool shown);
|
||||
void errorAnimationCallback();
|
||||
|
||||
not_null<PanelController*> _controller;
|
||||
object_ptr<Ui::LinkButton> _link;
|
||||
rpl::variable<QString> _value;
|
||||
bool _errorShown = false;
|
||||
Animation _errorAnimation;
|
||||
|
||||
};
|
||||
|
||||
class DateRow : public TextRow {
|
||||
public:
|
||||
using TextRow::TextRow;
|
||||
|
||||
};
|
||||
|
||||
class GenderRow : public TextRow {
|
||||
public:
|
||||
using TextRow::TextRow;
|
||||
|
||||
};
|
||||
|
||||
TextRow::TextRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
const QString &value)
|
||||
: PanelDetailsRow(parent, label)
|
||||
, _field(this, st::passportDetailsField, nullptr, value)
|
||||
, _value(value) {
|
||||
connect(_field, &Ui::InputField::changed, [=] {
|
||||
_value = valueCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
bool TextRow::setFocusFast() {
|
||||
_field->setFocusFast();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString TextRow::valueCurrent() const {
|
||||
return _field->getLastText();
|
||||
}
|
||||
|
||||
rpl::producer<QString> TextRow::value() const {
|
||||
return _value.value();
|
||||
}
|
||||
|
||||
int TextRow::resizeInner(int left, int top, int width) {
|
||||
_field->setGeometry(left, top, width, _field->height());
|
||||
return st::semiboldFont->height;
|
||||
}
|
||||
|
||||
void TextRow::showInnerError() {
|
||||
_field->showError();
|
||||
}
|
||||
|
||||
void TextRow::finishInnerAnimating() {
|
||||
_field->finishAnimating();
|
||||
}
|
||||
|
||||
QString CountryString(const QString &code) {
|
||||
const auto name = CountrySelectBox::NameByISO(code);
|
||||
return name.isEmpty() ? lang(lng_passport_country_choose) : name;
|
||||
}
|
||||
|
||||
CountryRow::CountryRow(
|
||||
QWidget *parent,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
const QString &value)
|
||||
: PanelDetailsRow(parent, label)
|
||||
, _controller(controller)
|
||||
, _link(this, CountryString(value), st::boxLinkButton)
|
||||
, _value(value) {
|
||||
_value.changes(
|
||||
) | rpl::start_with_next([=] {
|
||||
hideCountryError();
|
||||
}, lifetime());
|
||||
|
||||
_link->addClickHandler([=] {
|
||||
chooseCountry();
|
||||
});
|
||||
}
|
||||
|
||||
QString CountryRow::valueCurrent() const {
|
||||
return _value.current();
|
||||
}
|
||||
|
||||
rpl::producer<QString> CountryRow::value() const {
|
||||
return _value.value();
|
||||
}
|
||||
|
||||
int CountryRow::resizeInner(int left, int top, int width) {
|
||||
_link->move(left, st::passportDetailsField.textMargins.top() + top);
|
||||
return st::semiboldFont->height;
|
||||
}
|
||||
|
||||
void CountryRow::showInnerError() {
|
||||
toggleError(true);
|
||||
}
|
||||
|
||||
void CountryRow::finishInnerAnimating() {
|
||||
if (_errorAnimation.animating()) {
|
||||
_errorAnimation.finish();
|
||||
errorAnimationCallback();
|
||||
}
|
||||
}
|
||||
|
||||
void CountryRow::hideCountryError() {
|
||||
toggleError(false);
|
||||
}
|
||||
|
||||
void CountryRow::toggleError(bool shown) {
|
||||
if (_errorShown != shown) {
|
||||
_errorShown = shown;
|
||||
_errorAnimation.start(
|
||||
[=] { errorAnimationCallback(); },
|
||||
_errorShown ? 0. : 1.,
|
||||
_errorShown ? 1. : 0.,
|
||||
st::passportDetailsField.duration);
|
||||
}
|
||||
}
|
||||
|
||||
void CountryRow::errorAnimationCallback() {
|
||||
const auto error = _errorAnimation.current(_errorShown ? 1. : 0.);
|
||||
if (error == 0.) {
|
||||
_link->setColorOverride(nullptr);
|
||||
} else {
|
||||
_link->setColorOverride(anim::color(
|
||||
st::boxLinkButton.color,
|
||||
st::boxTextFgError,
|
||||
error));
|
||||
}
|
||||
}
|
||||
|
||||
void CountryRow::chooseCountry() {
|
||||
const auto top = _value.current();
|
||||
const auto name = CountrySelectBox::NameByISO(top);
|
||||
const auto box = _controller->show(Box<CountrySelectBox>(
|
||||
(name.isEmpty() ? Platform::SystemCountry() : top),
|
||||
CountrySelectBox::Type::Countries));
|
||||
connect(box, &CountrySelectBox::countryChosen, this, [=](QString iso) {
|
||||
_value = iso;
|
||||
_link->setText(CountryString(iso));
|
||||
hideCountryError();
|
||||
box->closeBox();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int PanelLabel::naturalWidth() const {
|
||||
return -1;
|
||||
@@ -24,19 +221,40 @@ void PanelLabel::resizeEvent(QResizeEvent *e) {
|
||||
|
||||
PanelDetailsRow::PanelDetailsRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
const QString &value)
|
||||
: _label(label)
|
||||
, _field(this, st::passportDetailsField, nullptr, value) {
|
||||
const QString &label)
|
||||
: _label(label) {
|
||||
}
|
||||
|
||||
object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
||||
QWidget *parent,
|
||||
Type type,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
const QString &value,
|
||||
const QString &error) {
|
||||
auto result = [&]() -> object_ptr<PanelDetailsRow> {
|
||||
switch (type) {
|
||||
case Type::Text:
|
||||
return object_ptr<TextRow>(parent, label, value);
|
||||
case Type::Country:
|
||||
return object_ptr<CountryRow>(parent, controller, label, value);
|
||||
case Type::Gender:
|
||||
return object_ptr<GenderRow>(parent, label, value);
|
||||
case Type::Date:
|
||||
return object_ptr<DateRow>(parent, label, value);
|
||||
default:
|
||||
Unexpected("Type in PanelDetailsRow::Create.");
|
||||
}
|
||||
}();
|
||||
if (!error.isEmpty()) {
|
||||
result->showError(error);
|
||||
result->finishAnimating();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PanelDetailsRow::setFocusFast() {
|
||||
_field->setFocusFast();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString PanelDetailsRow::getValue() const {
|
||||
return _field->getLastText();
|
||||
return false;
|
||||
}
|
||||
|
||||
int PanelDetailsRow::resizeGetHeight(int newWidth) {
|
||||
@@ -45,15 +263,76 @@ int PanelDetailsRow::resizeGetHeight(int newWidth) {
|
||||
const auto inputTop = st::passportDetailsFieldTop;
|
||||
const auto inputRight = padding.right();
|
||||
const auto inputWidth = std::max(newWidth - inputLeft - inputRight, 0);
|
||||
_field->setGeometry(inputLeft, inputTop, inputWidth, _field->height());
|
||||
return padding.top() + st::semiboldFont->height + padding.bottom();
|
||||
const auto innerHeight = resizeInner(inputLeft, inputTop, inputWidth);
|
||||
return padding.top()
|
||||
+ innerHeight
|
||||
+ (_error ? _error->height() : 0)
|
||||
+ padding.bottom();
|
||||
}
|
||||
|
||||
void PanelDetailsRow::showError(const QString &error) {
|
||||
showInnerError();
|
||||
startErrorAnimation(true);
|
||||
if (!error.isEmpty()) {
|
||||
if (!_error) {
|
||||
_error.create(
|
||||
this,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
error,
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::passportVerifyErrorLabel));
|
||||
value(
|
||||
) | rpl::start_with_next([=] {
|
||||
hideError();
|
||||
}, lifetime());
|
||||
} else {
|
||||
_error->entity()->setText(error);
|
||||
}
|
||||
_error->show(anim::type::normal);
|
||||
} else if (_error) {
|
||||
_error->hide(anim::type::normal);
|
||||
}
|
||||
}
|
||||
|
||||
void PanelDetailsRow::hideError() {
|
||||
startErrorAnimation(false);
|
||||
if (_error) {
|
||||
_error->hide(anim::type::normal);
|
||||
}
|
||||
}
|
||||
|
||||
void PanelDetailsRow::startErrorAnimation(bool shown) {
|
||||
if (_errorShown != shown) {
|
||||
_errorShown = shown;
|
||||
_errorAnimation.start(
|
||||
[=] { update(); },
|
||||
_errorShown ? 0. : 1.,
|
||||
_errorShown ? 1. : 0.,
|
||||
st::passportDetailsField.duration);
|
||||
}
|
||||
}
|
||||
|
||||
void PanelDetailsRow::finishAnimating() {
|
||||
if (_error) {
|
||||
_error->finishAnimating();
|
||||
}
|
||||
if (_errorAnimation.animating()) {
|
||||
_errorAnimation.finish();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PanelDetailsRow::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
const auto ms = getms();
|
||||
const auto error = _errorAnimation.current(ms, _errorShown ? 1. : 0.);
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(st::passportDetailsField.placeholderFg);
|
||||
p.setPen(anim::pen(
|
||||
st::passportDetailsField.placeholderFg,
|
||||
st::passportDetailsField.placeholderFgError,
|
||||
error));
|
||||
const auto padding = st::passportDetailsPadding;
|
||||
p.drawTextLeft(padding.left(), padding.top(), width(), _label);
|
||||
}
|
||||
|
@@ -14,10 +14,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
class FlatLabel;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Passport {
|
||||
|
||||
class PanelController;
|
||||
|
||||
enum class PanelDetailsType {
|
||||
Text,
|
||||
Country,
|
||||
Date,
|
||||
Gender,
|
||||
};
|
||||
|
||||
class PanelLabel : public Ui::PaddingWrap<Ui::FlatLabel> {
|
||||
public:
|
||||
using PaddingWrap::PaddingWrap;
|
||||
@@ -34,13 +46,26 @@ private:
|
||||
|
||||
class PanelDetailsRow : public Ui::RpWidget {
|
||||
public:
|
||||
using Type = PanelDetailsType;
|
||||
|
||||
PanelDetailsRow(
|
||||
QWidget *parent,
|
||||
const QString &label,
|
||||
const QString &value);
|
||||
const QString &label);
|
||||
|
||||
bool setFocusFast();
|
||||
QString getValue() const;
|
||||
static object_ptr<PanelDetailsRow> Create(
|
||||
QWidget *parent,
|
||||
Type type,
|
||||
not_null<PanelController*> controller,
|
||||
const QString &label,
|
||||
const QString &value,
|
||||
const QString &error);
|
||||
|
||||
virtual bool setFocusFast();
|
||||
virtual rpl::producer<QString> value() const = 0;
|
||||
virtual QString valueCurrent() const = 0;
|
||||
void showError(const QString &error);
|
||||
void hideError();
|
||||
void finishAnimating();
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
@@ -48,8 +73,16 @@ protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
virtual int resizeInner(int left, int top, int width) = 0;
|
||||
virtual void showInnerError() = 0;
|
||||
virtual void finishInnerAnimating() = 0;
|
||||
|
||||
void startErrorAnimation(bool shown);
|
||||
|
||||
QString _label;
|
||||
object_ptr<Ui::InputField> _field;
|
||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||
bool _errorShown = false;
|
||||
Animation _errorAnimation;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -231,10 +231,13 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||
if (!fields) {
|
||||
continue;
|
||||
}
|
||||
_details.emplace(i, inner->add(object_ptr<PanelDetailsRow>(
|
||||
_details.emplace(i, inner->add(PanelDetailsRow::Create(
|
||||
inner,
|
||||
row.inputType,
|
||||
_controller,
|
||||
row.label,
|
||||
valueOrEmpty(*fields, row.key))));
|
||||
valueOrEmpty(*fields, row.key),
|
||||
QString())));
|
||||
}
|
||||
|
||||
return inner;
|
||||
@@ -277,7 +280,7 @@ PanelEditDocument::Result PanelEditDocument::collect() const {
|
||||
auto &fields = (row.type == Scheme::ValueType::Fields)
|
||||
? result.data
|
||||
: result.filesData;
|
||||
fields.fields[row.key] = field->getValue();
|
||||
fields.fields[row.key] = field->valueCurrent();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ struct ValueMap;
|
||||
struct ScanInfo;
|
||||
class EditScans;
|
||||
class PanelDetailsRow;
|
||||
enum class PanelDetailsType;
|
||||
|
||||
class PanelEditDocument : public Ui::RpWidget {
|
||||
public:
|
||||
@@ -34,6 +35,7 @@ public:
|
||||
};
|
||||
struct Row {
|
||||
ValueType type = ValueType::Fields;
|
||||
PanelDetailsType inputType = PanelDetailsType();
|
||||
QString key;
|
||||
QString label;
|
||||
base::lambda<bool(const QString &value)> validate;
|
||||
|
Reference in New Issue
Block a user