mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Implement a nice money input field.
This commit is contained in:
@@ -418,7 +418,8 @@ bool CheckoutProcess::panelWebviewNavigationAttempt(const QString &uri) {
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelCancelEdit() {
|
||||
if (_submitState != SubmitState::None) {
|
||||
if (_submitState != SubmitState::None
|
||||
&& _submitState != SubmitState::Validated) {
|
||||
return;
|
||||
}
|
||||
showForm();
|
||||
@@ -463,7 +464,8 @@ void CheckoutProcess::showForm() {
|
||||
}
|
||||
|
||||
void CheckoutProcess::showEditInformation(Ui::InformationField field) {
|
||||
if (_submitState != SubmitState::None) {
|
||||
if (_submitState != SubmitState::None
|
||||
&& _submitState != SubmitState::Validated) {
|
||||
return;
|
||||
}
|
||||
_panel->showEditInformation(
|
||||
@@ -473,6 +475,8 @@ void CheckoutProcess::showEditInformation(Ui::InformationField field) {
|
||||
}
|
||||
|
||||
void CheckoutProcess::showInformationError(Ui::InformationField field) {
|
||||
Expects(_submitState != SubmitState::Validated);
|
||||
|
||||
if (_submitState != SubmitState::None) {
|
||||
return;
|
||||
}
|
||||
@@ -483,7 +487,8 @@ void CheckoutProcess::showInformationError(Ui::InformationField field) {
|
||||
}
|
||||
|
||||
void CheckoutProcess::showCardError(Ui::CardField field) {
|
||||
if (_submitState != SubmitState::None) {
|
||||
if (_submitState != SubmitState::None
|
||||
&& _submitState != SubmitState::Validated) {
|
||||
return;
|
||||
}
|
||||
_panel->showCardError(_form->paymentMethod().ui.native, field);
|
||||
|
||||
@@ -59,6 +59,10 @@ paymentsIconPhone: icon {{ "payments/payment_phone", menuIconFg }};
|
||||
paymentsIconShippingMethod: icon {{ "payments/payment_shipping", menuIconFg }};
|
||||
|
||||
paymentsField: defaultInputField;
|
||||
paymentsFieldAdditional: FlatLabel(defaultFlatLabel) {
|
||||
style: boxTextStyle;
|
||||
}
|
||||
|
||||
paymentsFieldPadding: margins(28px, 0px, 28px, 2px);
|
||||
paymentsSaveCheckboxPadding: margins(28px, 20px, 28px, 8px);
|
||||
paymentsExpireCvcSkip: 34px;
|
||||
@@ -79,3 +83,9 @@ paymentsShippingPrice: FlatLabel(defaultFlatLabel) {
|
||||
}
|
||||
paymentsShippingLabelPosition: point(43px, 8px);
|
||||
paymentsShippingPricePosition: point(43px, 29px);
|
||||
|
||||
paymentTipsErrorLabel: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 275px;
|
||||
textFg: boxTextFgError;
|
||||
}
|
||||
paymentTipsErrorPadding: margins(22px, 6px, 22px, 0px);
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/boxes/country_select_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/special_fields.h"
|
||||
#include "data/data_countries.h"
|
||||
@@ -16,12 +17,190 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/event_filter.h"
|
||||
#include "styles/style_payments.h"
|
||||
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
namespace Payments::Ui {
|
||||
namespace {
|
||||
|
||||
struct SimpleFieldState {
|
||||
QString value;
|
||||
int position = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] char FieldThousandsSeparator(const CurrencyRule &rule) {
|
||||
return (rule.thousands == '.' || rule.thousands == ',')
|
||||
? ' '
|
||||
: rule.thousands;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString RemoveNonNumbers(QString value) {
|
||||
return value.replace(QRegularExpression("[^0-9]"), QString());
|
||||
}
|
||||
|
||||
[[nodiscard]] SimpleFieldState CleanMoneyState(
|
||||
const CurrencyRule &rule,
|
||||
SimpleFieldState state) {
|
||||
const auto withDecimal = state.value.replace(
|
||||
QChar('.'),
|
||||
rule.decimal
|
||||
).replace(
|
||||
QChar(','),
|
||||
rule.decimal
|
||||
);
|
||||
const auto digitsLimit = 16 - rule.exponent;
|
||||
const auto beforePosition = state.value.mid(0, state.position);
|
||||
auto decimalPosition = withDecimal.lastIndexOf(rule.decimal);
|
||||
if (decimalPosition < 0) {
|
||||
state = {
|
||||
.value = RemoveNonNumbers(state.value),
|
||||
.position = RemoveNonNumbers(beforePosition).size(),
|
||||
};
|
||||
} else {
|
||||
const auto onlyNumbersBeforeDecimal = RemoveNonNumbers(
|
||||
state.value.mid(0, decimalPosition));
|
||||
state = {
|
||||
.value = (onlyNumbersBeforeDecimal
|
||||
+ QChar(rule.decimal)
|
||||
+ RemoveNonNumbers(state.value.mid(decimalPosition + 1))),
|
||||
.position = (RemoveNonNumbers(beforePosition).size()
|
||||
+ (state.position > decimalPosition ? 1 : 0)),
|
||||
};
|
||||
decimalPosition = onlyNumbersBeforeDecimal.size();
|
||||
const auto maxLength = decimalPosition + 1 + rule.exponent;
|
||||
if (state.value.size() > maxLength) {
|
||||
state = {
|
||||
.value = state.value.mid(0, maxLength),
|
||||
.position = std::min(state.position, maxLength),
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!state.value.isEmpty() && state.value[0] == QChar(rule.decimal)) {
|
||||
state = {
|
||||
.value = QChar('0') + state.value,
|
||||
.position = state.position + 1,
|
||||
};
|
||||
if (decimalPosition >= 0) {
|
||||
++decimalPosition;
|
||||
}
|
||||
}
|
||||
auto skip = 0;
|
||||
while (state.value.size() > skip + 1
|
||||
&& state.value[skip] == QChar('0')
|
||||
&& state.value[skip + 1] != QChar(rule.decimal)) {
|
||||
++skip;
|
||||
}
|
||||
state = {
|
||||
.value = state.value.mid(skip),
|
||||
.position = std::max(state.position - skip, 0),
|
||||
};
|
||||
if (decimalPosition >= 0) {
|
||||
Assert(decimalPosition >= skip);
|
||||
decimalPosition -= skip;
|
||||
}
|
||||
if (decimalPosition > digitsLimit) {
|
||||
state = {
|
||||
.value = (state.value.mid(0, digitsLimit)
|
||||
+ state.value.mid(decimalPosition)),
|
||||
.position = (state.position > digitsLimit
|
||||
? std::max(
|
||||
state.position - (decimalPosition - digitsLimit),
|
||||
digitsLimit)
|
||||
: state.position),
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
[[nodiscard]] SimpleFieldState PostprocessMoneyResult(
|
||||
const CurrencyRule &rule,
|
||||
SimpleFieldState result) {
|
||||
const auto position = result.value.indexOf(rule.decimal);
|
||||
const auto from = (position >= 0) ? position : result.value.size();
|
||||
for (auto insertAt = from - 3; insertAt > 0; insertAt -= 3) {
|
||||
result.value.insert(insertAt, QChar(FieldThousandsSeparator(rule)));
|
||||
if (result.position >= insertAt) {
|
||||
++result.position;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsBackspace(const FieldValidateRequest &request) {
|
||||
return (request.wasAnchor == request.wasPosition)
|
||||
&& (request.wasPosition == request.nowPosition + 1)
|
||||
&& (request.wasValue.midRef(0, request.wasPosition - 1)
|
||||
== request.nowValue.midRef(0, request.nowPosition))
|
||||
&& (request.wasValue.midRef(request.wasPosition)
|
||||
== request.nowValue.midRef(request.nowPosition));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsDelete(const FieldValidateRequest &request) {
|
||||
return (request.wasAnchor == request.wasPosition)
|
||||
&& (request.wasPosition == request.nowPosition)
|
||||
&& (request.wasValue.midRef(0, request.wasPosition)
|
||||
== request.nowValue.midRef(0, request.nowPosition))
|
||||
&& (request.wasValue.midRef(request.wasPosition + 1)
|
||||
== request.nowValue.midRef(request.nowPosition));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto MoneyValidator(const CurrencyRule &rule) {
|
||||
return [=](FieldValidateRequest request) {
|
||||
const auto realNowState = [&] {
|
||||
const auto backspaced = IsBackspace(request);
|
||||
const auto deleted = IsDelete(request);
|
||||
if (!backspaced && !deleted) {
|
||||
return CleanMoneyState(rule, {
|
||||
.value = request.nowValue,
|
||||
.position = request.nowPosition,
|
||||
});
|
||||
}
|
||||
const auto realWasState = CleanMoneyState(rule, {
|
||||
.value = request.wasValue,
|
||||
.position = request.wasPosition,
|
||||
});
|
||||
const auto changedValue = deleted
|
||||
? (realWasState.value.mid(0, realWasState.position)
|
||||
+ realWasState.value.mid(realWasState.position + 1))
|
||||
: (realWasState.position > 1)
|
||||
? (realWasState.value.mid(0, realWasState.position - 1)
|
||||
+ realWasState.value.mid(realWasState.position))
|
||||
: realWasState.value.mid(realWasState.position);
|
||||
return SimpleFieldState{
|
||||
.value = changedValue,
|
||||
.position = (deleted
|
||||
? realWasState.position
|
||||
: std::max(realWasState.position - 1, 0))
|
||||
};
|
||||
}();
|
||||
const auto postprocessed = PostprocessMoneyResult(
|
||||
rule,
|
||||
realNowState);
|
||||
return FieldValidateResult{
|
||||
.value = postprocessed.value,
|
||||
.position = postprocessed.position,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] QString Parse(const FieldConfig &config) {
|
||||
if (config.type == FieldType::Country) {
|
||||
return Data::CountryNameByISO2(config.value);
|
||||
} else if (config.type == FieldType::Money) {
|
||||
const auto amount = config.value.toLongLong();
|
||||
if (!amount) {
|
||||
return QString();
|
||||
}
|
||||
const auto rule = LookupCurrencyRule(config.currency);
|
||||
const auto value = std::abs(amount) / std::pow(10., rule.exponent);
|
||||
const auto precision = (!rule.stripDotZero
|
||||
|| std::floor(value) != value)
|
||||
? rule.exponent
|
||||
: 0;
|
||||
return FormatWithSeparators(
|
||||
value,
|
||||
precision,
|
||||
rule.decimal,
|
||||
FieldThousandsSeparator(rule));
|
||||
}
|
||||
return config.value;
|
||||
}
|
||||
@@ -32,6 +211,20 @@ namespace {
|
||||
const QString &countryIso2) {
|
||||
if (config.type == FieldType::Country) {
|
||||
return countryIso2;
|
||||
} else if (config.type == FieldType::Money) {
|
||||
const auto rule = LookupCurrencyRule(config.currency);
|
||||
const auto real = QString(parsed).replace(
|
||||
QChar(rule.decimal),
|
||||
QChar('.')
|
||||
).replace(
|
||||
QChar(','),
|
||||
QChar('.')
|
||||
).replace(
|
||||
QRegularExpression("[^0-9\\.]"),
|
||||
QString()
|
||||
).toDouble();
|
||||
return QString::number(
|
||||
int64(std::round(real * std::pow(10., rule.exponent))));
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
@@ -46,7 +239,7 @@ namespace {
|
||||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::Phone:
|
||||
case FieldType::PriceAmount:
|
||||
case FieldType::Money:
|
||||
return true;
|
||||
}
|
||||
Unexpected("FieldType in Payments::Ui::UseMaskedField.");
|
||||
@@ -68,7 +261,7 @@ namespace {
|
||||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::Phone:
|
||||
case FieldType::PriceAmount:
|
||||
case FieldType::Money:
|
||||
return base::make_unique_q<RpWidget>(parent);
|
||||
}
|
||||
Unexpected("FieldType in Payments::Ui::CreateWrap.");
|
||||
@@ -82,9 +275,106 @@ namespace {
|
||||
: static_cast<InputField*>(wrap.get());
|
||||
}
|
||||
|
||||
[[nodiscard]] MaskedInputField *CreateMoneyField(
|
||||
not_null<RpWidget*> wrap,
|
||||
FieldConfig &config,
|
||||
rpl::producer<> textPossiblyChanged) {
|
||||
struct State {
|
||||
CurrencyRule rule;
|
||||
style::InputField st;
|
||||
QString currencyText;
|
||||
int currencySkip = 0;
|
||||
FlatLabel *left = nullptr;
|
||||
FlatLabel *right = nullptr;
|
||||
};
|
||||
const auto state = wrap->lifetime().make_state<State>(State{
|
||||
.rule = LookupCurrencyRule(config.currency),
|
||||
.st = st::paymentsField,
|
||||
});
|
||||
const auto &rule = state->rule;
|
||||
state->currencySkip = rule.space ? state->st.font->spacew : 0;
|
||||
state->currencyText = ((!rule.left && rule.space)
|
||||
? QString(QChar(' '))
|
||||
: QString()) + (*rule.international
|
||||
? QString(rule.international)
|
||||
: config.currency) + ((rule.left && rule.space)
|
||||
? QString(QChar(' '))
|
||||
: QString());
|
||||
if (rule.left) {
|
||||
state->left = CreateChild<FlatLabel>(
|
||||
wrap.get(),
|
||||
state->currencyText,
|
||||
st::paymentsFieldAdditional);
|
||||
}
|
||||
state->right = CreateChild<FlatLabel>(
|
||||
wrap.get(),
|
||||
QString(),
|
||||
st::paymentsFieldAdditional);
|
||||
const auto leftSkip = state->left
|
||||
? (state->left->naturalWidth() + state->currencySkip)
|
||||
: 0;
|
||||
const auto rightSkip = st::paymentsFieldAdditional.style.font->width(
|
||||
QString(QChar(rule.decimal))
|
||||
+ QString(QChar('0')).repeated(rule.exponent)
|
||||
+ (rule.left ? QString() : state->currencyText));
|
||||
state->st.textMargins += QMargins(leftSkip, 0, rightSkip, 0);
|
||||
state->st.placeholderMargins -= QMargins(leftSkip, 0, rightSkip, 0);
|
||||
const auto result = CreateChild<MaskedInputField>(
|
||||
wrap.get(),
|
||||
state->st,
|
||||
std::move(config.placeholder),
|
||||
Parse(config));
|
||||
result->setPlaceholderHidden(true);
|
||||
if (state->left) {
|
||||
state->left->move(0, state->st.textMargins.top());
|
||||
}
|
||||
const auto updateRight = [=] {
|
||||
const auto text = result->getLastText();
|
||||
const auto width = state->st.font->width(text);
|
||||
const auto rect = result->getTextRect();
|
||||
const auto &rule = state->rule;
|
||||
const auto symbol = QChar(rule.decimal);
|
||||
const auto decimal = text.indexOf(symbol);
|
||||
const auto zeros = (decimal >= 0)
|
||||
? std::max(rule.exponent - (text.size() - decimal - 1), 0)
|
||||
: rule.stripDotZero
|
||||
? 0
|
||||
: rule.exponent;
|
||||
const auto valueDecimalSeparator = (decimal >= 0 || !zeros)
|
||||
? QString()
|
||||
: QString(symbol);
|
||||
const auto zeroString = QString(QChar('0'));
|
||||
const auto valueRightPart = (text.isEmpty() ? zeroString : QString())
|
||||
+ valueDecimalSeparator
|
||||
+ zeroString.repeated(zeros);
|
||||
const auto right = valueRightPart
|
||||
+ (rule.left ? QString() : state->currencyText);
|
||||
state->right->setText(right);
|
||||
state->right->setTextColorOverride(valueRightPart.isEmpty()
|
||||
? std::nullopt
|
||||
: std::make_optional(st::windowSubTextFg->c));
|
||||
state->right->move(
|
||||
(state->st.textMargins.left()
|
||||
+ width
|
||||
+ ((rule.left || !valueRightPart.isEmpty())
|
||||
? 0
|
||||
: state->currencySkip)),
|
||||
state->st.textMargins.top());
|
||||
};
|
||||
std::move(
|
||||
textPossiblyChanged
|
||||
) | rpl::start_with_next(updateRight, result->lifetime());
|
||||
if (state->left) {
|
||||
state->left->raise();
|
||||
}
|
||||
state->right->raise();
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] MaskedInputField *LookupMaskedField(
|
||||
not_null<RpWidget*> wrap,
|
||||
FieldConfig &config) {
|
||||
FieldConfig &config,
|
||||
rpl::producer<> textPossiblyChanged) {
|
||||
if (!UseMaskedField(config.type)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -96,7 +386,6 @@ namespace {
|
||||
case FieldType::CardExpireDate:
|
||||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::PriceAmount:
|
||||
return CreateChild<MaskedInputField>(
|
||||
wrap.get(),
|
||||
st::paymentsField,
|
||||
@@ -109,6 +398,11 @@ namespace {
|
||||
std::move(config.placeholder),
|
||||
ExtractPhonePrefix(config.defaultPhone),
|
||||
Parse(config));
|
||||
case FieldType::Money:
|
||||
return CreateMoneyField(
|
||||
wrap,
|
||||
config,
|
||||
std::move(textPossiblyChanged));
|
||||
}
|
||||
Unexpected("FieldType in Payments::Ui::LookupMaskedField.");
|
||||
}
|
||||
@@ -119,7 +413,10 @@ Field::Field(QWidget *parent, FieldConfig &&config)
|
||||
: _config(config)
|
||||
, _wrap(CreateWrap(parent, config))
|
||||
, _input(LookupInputField(_wrap.get(), config))
|
||||
, _masked(LookupMaskedField(_wrap.get(), config))
|
||||
, _masked(LookupMaskedField(
|
||||
_wrap.get(),
|
||||
config,
|
||||
_textPossiblyChanged.events_starting_with({})))
|
||||
, _countryIso2(config.value) {
|
||||
if (_masked) {
|
||||
setupMaskedGeometry();
|
||||
@@ -129,6 +426,8 @@ Field::Field(QWidget *parent, FieldConfig &&config)
|
||||
}
|
||||
if (const auto &validator = config.validator) {
|
||||
setupValidator(validator);
|
||||
} else if (config.type == FieldType::Money) {
|
||||
setupValidator(MoneyValidator(LookupCurrencyRule(config.currency)));
|
||||
}
|
||||
setupFrontBackspace();
|
||||
}
|
||||
@@ -210,7 +509,7 @@ void Field::setupValidator(Fn<ValidateResult(ValidateRequest)> validator) {
|
||||
const auto selectionStart = _masked->selectionStart();
|
||||
const auto selectionEnd = _masked->selectionEnd();
|
||||
return {
|
||||
.value = value(),
|
||||
.value = _masked->getLastText(),
|
||||
.position = position,
|
||||
.anchor = (selectionStart == selectionEnd
|
||||
? position
|
||||
@@ -221,7 +520,7 @@ void Field::setupValidator(Fn<ValidateResult(ValidateRequest)> validator) {
|
||||
}
|
||||
const auto cursor = _input->textCursor();
|
||||
return {
|
||||
.value = value(),
|
||||
.value = _input->getLastText(),
|
||||
.position = cursor.position(),
|
||||
.anchor = cursor.anchor(),
|
||||
};
|
||||
@@ -253,6 +552,7 @@ void Field::setupValidator(Fn<ValidateResult(ValidateRequest)> validator) {
|
||||
const auto guard = gsl::finally([&] {
|
||||
_validating = false;
|
||||
save();
|
||||
_textPossiblyChanged.fire({});
|
||||
});
|
||||
|
||||
const auto now = state();
|
||||
|
||||
@@ -29,7 +29,7 @@ enum class FieldType {
|
||||
Country,
|
||||
Phone,
|
||||
Email,
|
||||
PriceAmount,
|
||||
Money,
|
||||
};
|
||||
|
||||
struct FieldValidateRequest {
|
||||
@@ -83,6 +83,7 @@ struct FieldConfig {
|
||||
QString value;
|
||||
Fn<FieldValidateResult(FieldValidateRequest)> validator;
|
||||
Fn<void(object_ptr<BoxContent>)> showBox;
|
||||
QString currency;
|
||||
QString defaultPhone;
|
||||
QString defaultCountry;
|
||||
};
|
||||
@@ -124,6 +125,7 @@ private:
|
||||
const base::unique_qptr<RpWidget> _wrap;
|
||||
rpl::event_stream<> _frontBackspace;
|
||||
rpl::event_stream<> _finished;
|
||||
rpl::event_stream<> _textPossiblyChanged; // Must be above _masked.
|
||||
InputField *_input = nullptr;
|
||||
MaskedInputField *_masked = nullptr;
|
||||
QString _countryIso2;
|
||||
|
||||
@@ -279,7 +279,9 @@ void FormSummary::setupPrices(not_null<VerticalLayout*> layout) {
|
||||
add(tr::lng_payments_tips_label(tr::now), tips);
|
||||
}
|
||||
} else if (_invoice.tipsMax > 0) {
|
||||
const auto text = formatAmount(_invoice.tipsSelected);
|
||||
const auto text = _invoice.tipsSelected
|
||||
? formatAmount(_invoice.tipsSelected)
|
||||
: tr::lng_payments_tips_add(tr::now);
|
||||
const auto label = addRow(
|
||||
tr::lng_payments_tips_label(tr::now),
|
||||
Ui::Text::Link(text, "internal:edit_tips"));
|
||||
|
||||
@@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "payments/ui/payments_field.h"
|
||||
#include "ui/widgets/separate_panel.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -23,18 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Payments::Ui {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] auto PriceAmountValidator(int64 min, int64 max) {
|
||||
return [=](FieldValidateRequest request) {
|
||||
return FieldValidateResult{
|
||||
.value = request.nowValue,
|
||||
.position = request.nowPosition,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Panel::Panel(not_null<PanelDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
@@ -193,27 +182,52 @@ void Panel::chooseTips(const Invoice &invoice) {
|
||||
const auto min = invoice.tipsMin;
|
||||
const auto max = invoice.tipsMax;
|
||||
const auto now = invoice.tipsSelected;
|
||||
const auto currency = invoice.currency;
|
||||
showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(tr::lng_payments_tips_title());
|
||||
|
||||
box->setTitle(tr::lng_payments_tips_box_title());
|
||||
const auto row = box->lifetime().make_state<Field>(
|
||||
box,
|
||||
FieldConfig{
|
||||
.type = FieldType::PriceAmount,
|
||||
.placeholder = tr::lng_payments_tips_enter(),
|
||||
.type = FieldType::Money,
|
||||
.value = QString::number(now),
|
||||
.validator = PriceAmountValidator(min, max),
|
||||
.currency = ([&]() -> QString {
|
||||
static auto counter = 0;
|
||||
switch (++counter % 9) {
|
||||
case 0: return "USD";
|
||||
case 1: return "EUR";
|
||||
case 2: return "IRR";
|
||||
case 3: return "BRL";
|
||||
case 4: return "ALL";
|
||||
case 5: return "AZN";
|
||||
case 6: return "CHF";
|
||||
case 7: return "DKK";
|
||||
case 8: return "KZT";
|
||||
}
|
||||
return currency;
|
||||
})(), // #TODO payments currency,
|
||||
});
|
||||
box->setFocusCallback([=] {
|
||||
row->setFocusFast();
|
||||
});
|
||||
box->addRow(row->ownedWidget());
|
||||
box->addRow(object_ptr<FlatLabel>(box, "Min: " + QString::number(min), st::defaultFlatLabel));
|
||||
box->addRow(object_ptr<FlatLabel>(box, "Max: " + QString::number(max), st::defaultFlatLabel));
|
||||
const auto errorWrap = box->addRow(
|
||||
object_ptr<FadeWrap<FlatLabel>>(
|
||||
box,
|
||||
object_ptr<FlatLabel>(
|
||||
box,
|
||||
tr::lng_payments_tips_max(
|
||||
lt_amount,
|
||||
rpl::single(FillAmountAndCurrency(max, currency))),
|
||||
st::paymentTipsErrorLabel)),
|
||||
st::paymentTipsErrorPadding);
|
||||
errorWrap->hide(anim::type::instant);
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
const auto value = row->value().toLongLong();
|
||||
if (value < min || value > max) {
|
||||
if (value < min) {
|
||||
row->showError();
|
||||
} else if (value > max) {
|
||||
row->showError();
|
||||
errorWrap->show(anim::type::normal);
|
||||
} else {
|
||||
_delegate->panelChangeTips(value);
|
||||
box->closeBox();
|
||||
|
||||
Reference in New Issue
Block a user