mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support adding tips in payments.
This commit is contained in:
parent
00c915e58d
commit
8cac76931e
13 changed files with 355 additions and 33 deletions
|
@ -1889,6 +1889,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_payments_billing_zip_code" = "Zip Code";
|
||||
"lng_payments_save_payment_about" = "You can save your payment information for future use.";
|
||||
"lng_payments_save_information" = "Save Information";
|
||||
"lng_payments_tips_label" = "Tips";
|
||||
"lng_payments_tips_title" = "Tips";
|
||||
"lng_payments_tips_enter" = "Enter tips amount";
|
||||
|
||||
"lng_call_status_incoming" = "is calling you...";
|
||||
"lng_call_status_connecting" = "connecting...";
|
||||
|
|
|
@ -254,6 +254,8 @@ void CheckoutProcess::handleError(const Error &error) {
|
|||
|| id == u"PAYMENT_CREDENTIALS_INVALID"_q
|
||||
|| id == u"PAYMENT_CREDENTIALS_ID_INVALID"_q) {
|
||||
showToast({ "Error: " + id + ". Your card has not been billed." });
|
||||
} else {
|
||||
showToast({ "Error: " + id });
|
||||
}
|
||||
break;
|
||||
default: Unexpected("Error type in CheckoutProcess::handleError.");
|
||||
|
@ -284,6 +286,7 @@ void CheckoutProcess::panelCloseSure() {
|
|||
void CheckoutProcess::panelSubmit() {
|
||||
if (_form->invoice().receipt.paid) {
|
||||
panelCloseSure();
|
||||
return;
|
||||
} else if (_submitState == SubmitState::Validation
|
||||
|| _submitState == SubmitState::Finishing) {
|
||||
return;
|
||||
|
@ -437,6 +440,10 @@ void CheckoutProcess::chooseShippingOption() {
|
|||
_panel->chooseShippingOption(_form->shippingOptions());
|
||||
}
|
||||
|
||||
void CheckoutProcess::chooseTips() {
|
||||
_panel->chooseTips(_form->invoice());
|
||||
}
|
||||
|
||||
void CheckoutProcess::editPaymentMethod() {
|
||||
_panel->choosePaymentMethod(_form->paymentMethod().ui);
|
||||
}
|
||||
|
@ -453,6 +460,18 @@ void CheckoutProcess::panelChangeShippingOption(const QString &id) {
|
|||
showForm();
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelChooseTips() {
|
||||
if (_submitState != SubmitState::None) {
|
||||
return;
|
||||
}
|
||||
chooseTips();
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelChangeTips(int64 value) {
|
||||
_form->setTips(value);
|
||||
showForm();
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelValidateInformation(
|
||||
Ui::RequestedInformation data) {
|
||||
_form->validateInformation(data);
|
||||
|
|
|
@ -67,6 +67,7 @@ private:
|
|||
void showInformationError(Ui::InformationField field);
|
||||
void showCardError(Ui::CardField field);
|
||||
void chooseShippingOption();
|
||||
void chooseTips();
|
||||
void editPaymentMethod();
|
||||
|
||||
void performInitialSilentValidation();
|
||||
|
@ -84,6 +85,8 @@ private:
|
|||
void panelEditPhone() override;
|
||||
void panelChooseShippingOption() override;
|
||||
void panelChangeShippingOption(const QString &id) override;
|
||||
void panelChooseTips() override;
|
||||
void panelChangeTips(int64 value) override;
|
||||
|
||||
void panelValidateInformation(Ui::RequestedInformation data) override;
|
||||
void panelValidateCard(Ui::UncheckedCardDetails data) override;
|
||||
|
|
|
@ -45,6 +45,10 @@ namespace {
|
|||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] int64 ParsePriceAmount(uint64 value) {
|
||||
return *reinterpret_cast<const int64*>(&value);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<Ui::LabeledPrice> ParsePrices(
|
||||
const MTPVector<MTPLabeledPrice> &data) {
|
||||
return ranges::views::all(
|
||||
|
@ -53,7 +57,7 @@ namespace {
|
|||
return price.match([&](const MTPDlabeledPrice &data) {
|
||||
return Ui::LabeledPrice{
|
||||
.label = qs(data.vlabel()),
|
||||
.price = *reinterpret_cast<const int64*>(&data.vamount().v),
|
||||
.price = ParsePriceAmount(data.vamount().v),
|
||||
};
|
||||
});
|
||||
}) | ranges::to_vector;
|
||||
|
@ -290,6 +294,10 @@ void Form::processInvoice(const MTPDinvoice &data) {
|
|||
.cover = std::move(_invoice.cover),
|
||||
|
||||
.prices = ParsePrices(data.vprices()),
|
||||
.tipsMin = ParsePriceAmount(data.vmin_tip_amount().value_or_empty()),
|
||||
.tipsMax = ParsePriceAmount(data.vmax_tip_amount().value_or_empty()),
|
||||
.tipsSelected = ParsePriceAmount(
|
||||
data.vdefault_tip_amount().value_or_empty()),
|
||||
.currency = qs(data.vcurrency()),
|
||||
|
||||
.isNameRequested = data.is_name_requested(),
|
||||
|
@ -330,8 +338,7 @@ void Form::processDetails(const MTPDpayments_paymentForm &data) {
|
|||
void Form::processDetails(const MTPDpayments_paymentReceipt &data) {
|
||||
_invoice.receipt = Ui::Receipt{
|
||||
.date = data.vdate().v,
|
||||
.totalAmount = *reinterpret_cast<const int64*>(
|
||||
&data.vtotal_amount().v),
|
||||
.totalAmount = ParsePriceAmount(data.vtotal_amount().v),
|
||||
.currency = qs(data.vcurrency()),
|
||||
.paid = true,
|
||||
};
|
||||
|
@ -440,7 +447,8 @@ void Form::submit() {
|
|||
: Flag::f_requested_info_id)
|
||||
| (_shippingOptions.selectedId.isEmpty()
|
||||
? Flag(0)
|
||||
: Flag::f_shipping_option_id)),
|
||||
: Flag::f_shipping_option_id)
|
||||
| (_invoice.tipsSelected ? Flag::f_tip_amount : Flag(0))),
|
||||
MTP_long(_details.formId),
|
||||
_peer->input,
|
||||
MTP_int(_msgId),
|
||||
|
@ -449,7 +457,7 @@ void Form::submit() {
|
|||
MTP_inputPaymentCredentials(
|
||||
MTP_flags(0),
|
||||
MTP_dataJSON(MTP_bytes(_paymentMethod.newCredentials.data))),
|
||||
MTP_long(0) // #TODO payments tip_amount
|
||||
MTP_long(_invoice.tipsSelected)
|
||||
)).done([=](const MTPpayments_PaymentResult &result) {
|
||||
result.match([&](const MTPDpayments_paymentResult &data) {
|
||||
_updates.fire(PaymentFinished{ data.vupdates() });
|
||||
|
@ -668,6 +676,13 @@ void Form::setShippingOption(const QString &id) {
|
|||
_shippingOptions.selectedId = id;
|
||||
}
|
||||
|
||||
void Form::setTips(int64 value) {
|
||||
_invoice.tipsSelected = std::clamp(
|
||||
value,
|
||||
_invoice.tipsMin,
|
||||
_invoice.tipsMax);
|
||||
}
|
||||
|
||||
void Form::processShippingOptions(const QVector<MTPShippingOption> &data) {
|
||||
_shippingOptions = Ui::ShippingOptions{ ranges::views::all(
|
||||
data
|
||||
|
|
|
@ -173,6 +173,7 @@ public:
|
|||
void validateCard(const Ui::UncheckedCardDetails &details);
|
||||
void setPaymentCredentials(const NewCredentials &credentials);
|
||||
void setShippingOption(const QString &id);
|
||||
void setTips(int64 value);
|
||||
void submit();
|
||||
|
||||
private:
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace {
|
|||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::Phone:
|
||||
case FieldType::PriceAmount:
|
||||
return true;
|
||||
}
|
||||
Unexpected("FieldType in Payments::Ui::UseMaskedField.");
|
||||
|
@ -67,6 +68,7 @@ namespace {
|
|||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::Phone:
|
||||
case FieldType::PriceAmount:
|
||||
return base::make_unique_q<RpWidget>(parent);
|
||||
}
|
||||
Unexpected("FieldType in Payments::Ui::CreateWrap.");
|
||||
|
@ -94,6 +96,7 @@ namespace {
|
|||
case FieldType::CardExpireDate:
|
||||
case FieldType::CardCVC:
|
||||
case FieldType::Country:
|
||||
case FieldType::PriceAmount:
|
||||
return CreateChild<MaskedInputField>(
|
||||
wrap.get(),
|
||||
st::paymentsField,
|
||||
|
|
|
@ -29,6 +29,7 @@ enum class FieldType {
|
|||
Country,
|
||||
Phone,
|
||||
Email,
|
||||
PriceAmount,
|
||||
};
|
||||
|
||||
struct FieldValidateRequest {
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "data/data_countries.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "base/unixtime.h"
|
||||
|
@ -84,7 +85,7 @@ int64 FormSummary::computeTotalAmount() const {
|
|||
std::plus<>(),
|
||||
&LabeledPrice::price)
|
||||
: int64(0);
|
||||
return total + shipping;
|
||||
return total + shipping + _invoice.tipsSelected;
|
||||
}
|
||||
|
||||
void FormSummary::setupControls() {
|
||||
|
@ -193,12 +194,15 @@ void FormSummary::setupCover(not_null<VerticalLayout*> layout) {
|
|||
void FormSummary::setupPrices(not_null<VerticalLayout*> layout) {
|
||||
const auto addRow = [&](
|
||||
const QString &label,
|
||||
const QString &value,
|
||||
const TextWithEntities &value,
|
||||
bool full = false) {
|
||||
const auto &st = full
|
||||
? st::paymentsFullPriceAmount
|
||||
: st::paymentsPriceAmount;
|
||||
const auto right = CreateChild<FlatLabel>(layout.get(), value, st);
|
||||
const auto right = CreateChild<FlatLabel>(
|
||||
layout.get(),
|
||||
rpl::single(value),
|
||||
st);
|
||||
const auto &padding = st::paymentsPricePadding;
|
||||
const auto left = layout->add(
|
||||
object_ptr<FlatLabel>(
|
||||
|
@ -220,13 +224,14 @@ void FormSummary::setupPrices(not_null<VerticalLayout*> layout) {
|
|||
) | rpl::start_with_next([=](int top, int width) {
|
||||
right->moveToRight(st::paymentsPricePadding.right(), top, width);
|
||||
}, right->lifetime());
|
||||
return right;
|
||||
};
|
||||
|
||||
Settings::AddSkip(layout, st::paymentsPricesTopSkip);
|
||||
if (_invoice.receipt) {
|
||||
addRow(
|
||||
tr::lng_payments_date_label(tr::now),
|
||||
langDateTime(base::unixtime::parse(_invoice.receipt.date)),
|
||||
{ langDateTime(base::unixtime::parse(_invoice.receipt.date)) },
|
||||
true);
|
||||
Settings::AddSkip(layout, st::paymentsPricesBottomSkip);
|
||||
Settings::AddDivider(layout);
|
||||
|
@ -237,7 +242,7 @@ void FormSummary::setupPrices(not_null<VerticalLayout*> layout) {
|
|||
const QString &label,
|
||||
int64 amount,
|
||||
bool full = false) {
|
||||
addRow(label, formatAmount(amount), full);
|
||||
addRow(label, { formatAmount(amount) }, full);
|
||||
};
|
||||
for (const auto &price : _invoice.prices) {
|
||||
add(price.label, price.price);
|
||||
|
@ -251,7 +256,27 @@ void FormSummary::setupPrices(not_null<VerticalLayout*> layout) {
|
|||
add(price.label, price.price);
|
||||
}
|
||||
}
|
||||
add(tr::lng_payments_total_label(tr::now), computeTotalAmount(), true);
|
||||
|
||||
const auto computedTotal = computeTotalAmount();
|
||||
const auto total = _invoice.receipt.paid
|
||||
? _invoice.receipt.totalAmount
|
||||
: computedTotal;
|
||||
if (_invoice.receipt.paid) {
|
||||
if (const auto tips = total - computedTotal) {
|
||||
add(tr::lng_payments_tips_label(tr::now), tips);
|
||||
}
|
||||
} else if (_invoice.tipsMax > 0) {
|
||||
const auto text = formatAmount(_invoice.tipsSelected);
|
||||
const auto label = addRow(
|
||||
tr::lng_payments_tips_label(tr::now),
|
||||
Ui::Text::Link(text, "internal:edit_tips"));
|
||||
label->setClickHandlerFilter([=](auto&&...) {
|
||||
_delegate->panelChooseTips();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
add(tr::lng_payments_total_label(tr::now), total, true);
|
||||
Settings::AddSkip(layout, st::paymentsPricesBottomSkip);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "payments/ui/payments_edit_information.h"
|
||||
#include "payments/ui/payments_edit_card.h"
|
||||
#include "payments/ui/payments_panel_delegate.h"
|
||||
#include "payments/ui/payments_field.h"
|
||||
#include "ui/widgets/separate_panel.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -19,6 +20,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_passport.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)
|
||||
|
@ -127,6 +140,40 @@ void Panel::chooseShippingOption(const ShippingOptions &options) {
|
|||
}));
|
||||
}
|
||||
|
||||
void Panel::chooseTips(const Invoice &invoice) {
|
||||
const auto min = invoice.tipsMin;
|
||||
const auto max = invoice.tipsMax;
|
||||
const auto now = invoice.tipsSelected;
|
||||
showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(tr::lng_payments_tips_title());
|
||||
|
||||
const auto row = box->lifetime().make_state<Field>(
|
||||
box,
|
||||
FieldConfig{
|
||||
.type = FieldType::PriceAmount,
|
||||
.placeholder = tr::lng_payments_tips_enter(),
|
||||
.value = QString::number(now),
|
||||
.validator = PriceAmountValidator(min, max),
|
||||
});
|
||||
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));
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
const auto value = row->value().toLongLong();
|
||||
if (value < min || value > max) {
|
||||
row->showError();
|
||||
} else {
|
||||
_delegate->panelChangeTips(value);
|
||||
box->closeBox();
|
||||
}
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}));
|
||||
}
|
||||
|
||||
void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
|
||||
_widget->setTitle(tr::lng_payments_card_title());
|
||||
if (method.native.supported) {
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
const NativeMethodDetails &native,
|
||||
CardField field);
|
||||
void chooseShippingOption(const ShippingOptions &options);
|
||||
void chooseTips(const Invoice &invoice);
|
||||
void choosePaymentMethod(const PaymentMethodDetails &method);
|
||||
|
||||
bool showWebview(const QString &url, bool allowBack);
|
||||
|
|
|
@ -39,6 +39,9 @@ struct Invoice {
|
|||
Cover cover;
|
||||
|
||||
std::vector<LabeledPrice> prices;
|
||||
int64 tipsMin = 0;
|
||||
int64 tipsMax = 0;
|
||||
int64 tipsSelected = 0;
|
||||
QString currency;
|
||||
Receipt receipt;
|
||||
|
||||
|
@ -53,7 +56,7 @@ struct Invoice {
|
|||
bool emailSentToProvider = false;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return !currency.isEmpty() && !prices.empty();
|
||||
return !currency.isEmpty() && (!prices.empty() || tipsMax);
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return valid();
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
virtual void panelEditPhone() = 0;
|
||||
virtual void panelChooseShippingOption() = 0;
|
||||
virtual void panelChangeShippingOption(const QString &id) = 0;
|
||||
virtual void panelChooseTips() = 0;
|
||||
virtual void panelChangeTips(int64 value) = 0;
|
||||
|
||||
virtual void panelValidateInformation(RequestedInformation data) = 0;
|
||||
virtual void panelValidateCard(Ui::UncheckedCardDetails data) = 0;
|
||||
|
|
|
@ -10,6 +10,40 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
|
||||
#include <QtCore/QLocale>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
[[nodiscard]] QString FormatWithSeparators(
|
||||
double amount,
|
||||
char decimal,
|
||||
char thousands) {
|
||||
Expects(decimal != 0);
|
||||
|
||||
// Thanks https://stackoverflow.com/a/5058949
|
||||
struct FormattingHelper : std::numpunct<char> {
|
||||
FormattingHelper(char decimal, char thousands)
|
||||
: decimal(decimal)
|
||||
, thousands(thousands) {
|
||||
}
|
||||
|
||||
char do_decimal_point() const override { return decimal; }
|
||||
char do_thousands_sep() const override { return thousands; }
|
||||
|
||||
char decimal = '.';
|
||||
char thousands = ',';
|
||||
};
|
||||
|
||||
auto stream = std::ostringstream();
|
||||
auto helper = FormattingHelper(decimal, thousands ? thousands : '?');
|
||||
stream.imbue(std::locale(stream.getloc(), &helper));
|
||||
stream << std::fixed << amount;
|
||||
auto result = QString::fromStdString(stream.str());
|
||||
if (!thousands) {
|
||||
result.replace('?', QString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace Ui {
|
||||
|
||||
|
@ -126,13 +160,168 @@ QString FormatPlayedText(qint64 played, qint64 duration) {
|
|||
}
|
||||
|
||||
QString FillAmountAndCurrency(int64 amount, const QString ¤cy) {
|
||||
static const auto ShortCurrencyNames = QMap<QString, QString>{
|
||||
{ u"USD"_q, QString::fromUtf8("\x24") },
|
||||
{ u"GBP"_q, QString::fromUtf8("\xC2\xA3") },
|
||||
{ u"EUR"_q, QString::fromUtf8("\xE2\x82\xAC") },
|
||||
{ u"JPY"_q, QString::fromUtf8("\xC2\xA5") },
|
||||
struct Rule {
|
||||
//const char *name = "";
|
||||
//const char *native = "";
|
||||
const char *international = "";
|
||||
char thousands = ',';
|
||||
char decimal = '.';
|
||||
bool left = true;
|
||||
bool space = false;
|
||||
};
|
||||
static const auto Denominators = QMap<QString, int>{
|
||||
static const auto kRules = std::vector<std::pair<QString, Rule>>{
|
||||
{ u"AED"_q, { "", ',', '.', true, true } },
|
||||
{ u"AFN"_q, {} },
|
||||
{ u"ALL"_q, { "", '.', ',', false } },
|
||||
{ u"AMD"_q, { "", ',', '.', false, true } },
|
||||
{ u"ARS"_q, { "", '.', ',', true, true } },
|
||||
{ u"AUD"_q, { "AU$" } },
|
||||
{ u"AZN"_q, { "", ' ', ',', false, true } },
|
||||
{ u"BAM"_q, { "", '.', ',', false, true } },
|
||||
{ u"BDT"_q, { "", ',', '.', true, true } },
|
||||
{ u"BGN"_q, { "", ' ', ',', false, true } },
|
||||
{ u"BND"_q, { "", '.', ',', } },
|
||||
{ u"BOB"_q, { "", '.', ',', true, true } },
|
||||
{ u"BRL"_q, { "R$", '.', ',', true, true } },
|
||||
{ u"BHD"_q, { "", ',', '.', true, true } },
|
||||
{ u"BYR"_q, { "", ' ', ',', false, true } },
|
||||
{ u"CAD"_q, { "CA$" } },
|
||||
{ u"CHF"_q, { "", '\'', '.', false, true } },
|
||||
{ u"CLP"_q, { "", '.', ',', true, true } },
|
||||
{ u"CNY"_q, { "\x43\x4E\xC2\xA5" } },
|
||||
{ u"COP"_q, { "", '.', ',', true, true } },
|
||||
{ u"CRC"_q, { "", '.', ',', } },
|
||||
{ u"CZK"_q, { "", ' ', ',', false, true } },
|
||||
{ u"DKK"_q, { "", '\0', ',', false, true } },
|
||||
{ u"DOP"_q, {} },
|
||||
{ u"DZD"_q, { "", ',', '.', true, true } },
|
||||
{ u"EGP"_q, { "", ',', '.', true, true } },
|
||||
{ u"EUR"_q, { "\xE2\x82\xAC", ' ', ',', false, true } },
|
||||
{ u"GBP"_q, { "\xC2\xA3" } },
|
||||
{ u"GEL"_q, { "", ' ', ',', false, true } },
|
||||
{ u"GTQ"_q, {} },
|
||||
{ u"HKD"_q, { "HK$" } },
|
||||
{ u"HNL"_q, { "", ',', '.', true, true } },
|
||||
{ u"HRK"_q, { "", '.', ',', false, true } },
|
||||
{ u"HUF"_q, { "", ' ', ',', false, true } },
|
||||
{ u"IDR"_q, { "", '.', ',', } },
|
||||
{ u"ILS"_q, { "\xE2\x82\xAA", ',', '.', true, true } },
|
||||
{ u"INR"_q, { "\xE2\x82\xB9" } },
|
||||
{ u"ISK"_q, { "", '.', ',', false, true } },
|
||||
{ u"JMD"_q, {} },
|
||||
{ u"JPY"_q, { "\xC2\xA5" } },
|
||||
{ u"KES"_q, {} },
|
||||
{ u"KGS"_q, { "", ' ', '-', false, true } },
|
||||
{ u"KRW"_q, { "\xE2\x82\xA9" } },
|
||||
{ u"KZT"_q, { "", ' ', '-', } },
|
||||
{ u"LBP"_q, { "", ',', '.', true, true } },
|
||||
{ u"LKR"_q, { "", ',', '.', true, true } },
|
||||
{ u"MAD"_q, { "", ',', '.', true, true } },
|
||||
{ u"MDL"_q, { "", ',', '.', false, true } },
|
||||
{ u"MNT"_q, { "", ' ', ',', } },
|
||||
{ u"MUR"_q, {} },
|
||||
{ u"MVR"_q, { "", ',', '.', false, true } },
|
||||
{ u"MXN"_q, { "MX$" } },
|
||||
{ u"MYR"_q, {} },
|
||||
{ u"MZN"_q, {} },
|
||||
{ u"NGN"_q, {} },
|
||||
{ u"NIO"_q, { "", ',', '.', true, true } },
|
||||
{ u"NOK"_q, { "", ' ', ',', true, true } },
|
||||
{ u"NPR"_q, {} },
|
||||
{ u"NZD"_q, { "NZ$" } },
|
||||
{ u"PAB"_q, { "", ',', '.', true, true } },
|
||||
{ u"PEN"_q, { "", ',', '.', true, true } },
|
||||
{ u"PHP"_q, {} },
|
||||
{ u"PKR"_q, {} },
|
||||
{ u"PLN"_q, { "", ' ', ',', false, true } },
|
||||
{ u"PYG"_q, { "", '.', ',', true, true } },
|
||||
{ u"QAR"_q, { "", ',', '.', true, true } },
|
||||
{ u"RON"_q, { "", '.', ',', false, true } },
|
||||
{ u"RSD"_q, { "", '.', ',', false, true } },
|
||||
{ u"RUB"_q, { "", ' ', ',', false, true } },
|
||||
{ u"SAR"_q, { "", ',', '.', true, true } },
|
||||
{ u"SEK"_q, { "", '.', ',', false, true } },
|
||||
{ u"SGD"_q, {} },
|
||||
{ u"THB"_q, { "\xE0\xB8\xBF" } },
|
||||
{ u"TJS"_q, { "", ' ', ';', false, true } },
|
||||
{ u"TRY"_q, { "", '.', ',', false, true } },
|
||||
{ u"TTD"_q, {} },
|
||||
{ u"TWD"_q, { "NT$" } },
|
||||
{ u"TZS"_q, {} },
|
||||
{ u"UAH"_q, { "", ' ', ',', false } },
|
||||
{ u"UGX"_q, {} },
|
||||
{ u"USD"_q, { "$" } },
|
||||
{ u"UYU"_q, { "", '.', ',', true, true } },
|
||||
{ u"UZS"_q, { "", ' ', ',', false, true } },
|
||||
{ u"VND"_q, { "\xE2\x82\xAB", '.', ',', false, true } },
|
||||
{ u"YER"_q, { "", ',', '.', true, true } },
|
||||
{ u"ZAR"_q, { "", ',', '.', true, true } },
|
||||
{ u"IRR"_q, { "", ',', '/', false, true } },
|
||||
{ u"IQD"_q, { "", ',', '.', true, true } },
|
||||
{ u"VEF"_q, { "", '.', ',', true, true } },
|
||||
{ u"SYP"_q, { "", ',', '.', true, true } },
|
||||
|
||||
//{ u"VUV"_q, { "", ',', '.', false } },
|
||||
//{ u"WST"_q, {} },
|
||||
//{ u"XAF"_q, { "FCFA", ',', '.', false } },
|
||||
//{ u"XCD"_q, {} },
|
||||
//{ u"XOF"_q, { "CFA", ' ', ',', false } },
|
||||
//{ u"XPF"_q, { "", ',', '.', false } },
|
||||
//{ u"ZMW"_q, {} },
|
||||
//{ u"ANG"_q, {} },
|
||||
//{ u"RWF"_q, { "", ' ', ',', true, true } },
|
||||
//{ u"PGK"_q, {} },
|
||||
//{ u"TOP"_q, {} },
|
||||
//{ u"SBD"_q, {} },
|
||||
//{ u"SCR"_q, {} },
|
||||
//{ u"SHP"_q, {} },
|
||||
//{ u"SLL"_q, {} },
|
||||
//{ u"SOS"_q, {} },
|
||||
//{ u"SRD"_q, {} },
|
||||
//{ u"STD"_q, {} },
|
||||
//{ u"SVC"_q, {} },
|
||||
//{ u"SZL"_q, {} },
|
||||
//{ u"AOA"_q, {} },
|
||||
//{ u"AWG"_q, {} },
|
||||
//{ u"BBD"_q, {} },
|
||||
//{ u"BIF"_q, { "", ',', '.', false } },
|
||||
//{ u"BMD"_q, {} },
|
||||
//{ u"BSD"_q, {} },
|
||||
//{ u"BWP"_q, {} },
|
||||
//{ u"BZD"_q, {} },
|
||||
//{ u"CDF"_q, { "", ',', '.', false } },
|
||||
//{ u"CVE"_q, {} },
|
||||
//{ u"DJF"_q, { "", ',', '.', false } },
|
||||
//{ u"ETB"_q, {} },
|
||||
//{ u"FJD"_q, {} },
|
||||
//{ u"FKP"_q, {} },
|
||||
//{ u"GIP"_q, {} },
|
||||
//{ u"GMD"_q, { "", ',', '.', false } },
|
||||
//{ u"GNF"_q, { "", ',', '.', false } },
|
||||
//{ u"GYD"_q, {} },
|
||||
//{ u"HTG"_q, {} },
|
||||
//{ u"KHR"_q, { "", ',', '.', false } },
|
||||
//{ u"KMF"_q, { "", ',', '.', false } },
|
||||
//{ u"KYD"_q, {} },
|
||||
//{ u"LAK"_q, { "", ',', '.', false } },
|
||||
//{ u"LRD"_q, {} },
|
||||
//{ u"LSL"_q, { "", ',', '.', false } },
|
||||
//{ u"MGA"_q, {} },
|
||||
//{ u"MKD"_q, { "", '.', ',', false, true } },
|
||||
//{ u"MOP"_q, {} },
|
||||
//{ u"MWK"_q, {} },
|
||||
//{ u"NAD"_q, {} },
|
||||
};
|
||||
static const auto kRulesMap = [] {
|
||||
// flat_multi_map_pair_type lacks some required constructors :(
|
||||
auto &&pairs = kRules | ranges::views::transform([](auto &&pair) {
|
||||
return base::flat_multi_map_pair_type<QString, Rule>(
|
||||
pair.first,
|
||||
pair.second);
|
||||
});
|
||||
return base::flat_map<QString, Rule>(begin(pairs), end(pairs));
|
||||
}();
|
||||
static const auto kDenominators = base::flat_map<QString, int>{
|
||||
{ u"CLF"_q, 10000 },
|
||||
{ u"BHD"_q, 1000 },
|
||||
{ u"IQD"_q, 1000 },
|
||||
|
@ -163,21 +352,31 @@ QString FillAmountAndCurrency(int64 amount, const QString ¤cy) {
|
|||
{ u"XPF"_q, 1 },
|
||||
{ u"MRO"_q, 10 },
|
||||
};
|
||||
const auto currencyText = ShortCurrencyNames.value(currency, currency);
|
||||
const auto denominator = Denominators.value(currency, 100);
|
||||
const auto currencyValue = amount / float64(denominator);
|
||||
const auto digits = [&] {
|
||||
auto result = 0;
|
||||
for (auto test = 1; test < denominator; test *= 10) {
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
return QLocale::system().toCurrencyString(currencyValue, currencyText);
|
||||
//auto amountBucks = amount / 100;
|
||||
//auto amountCents = amount % 100;
|
||||
//auto amountText = u"%1,%2").arg(amountBucks).arg(amountCents, 2, 10, QChar('0'));
|
||||
//return currencyText + amountText;
|
||||
const auto denominatorIt = kDenominators.find(currency);
|
||||
const auto denominator = (denominatorIt != end(kDenominators))
|
||||
? denominatorIt->second
|
||||
: 100;
|
||||
const auto value = amount / float64(denominator);
|
||||
const auto ruleIt = kRulesMap.find(currency);
|
||||
if (ruleIt == end(kRulesMap)) {
|
||||
return QLocale::system().toCurrencyString(value, currency);
|
||||
}
|
||||
const auto &rule = ruleIt->second;
|
||||
const auto name = (*rule.international)
|
||||
? QString::fromUtf8(rule.international)
|
||||
: currency;
|
||||
auto result = QString();
|
||||
if (rule.left) {
|
||||
result.append(name);
|
||||
if (rule.space) result.append(' ');
|
||||
}
|
||||
result.append(
|
||||
FormatWithSeparators(value, rule.decimal, rule.thousands));
|
||||
if (!rule.left) {
|
||||
if (rule.space) result.append(' ');
|
||||
result.append(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ComposeNameString(
|
||||
|
|
Loading…
Add table
Reference in a new issue