status-desktop/ui/imports/shared/controls/AmountInput.qml

142 lines
4.5 KiB
QML
Raw Normal View History

import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import utils 1.0
Input {
id: root
property int maximumLength: 10
property var locale: LocaleUtils.userInputLocale
readonly property alias amount: d.amount
property alias multiplierIndex: d.multiplierIndex
readonly property bool valid: validationError.length === 0
property bool allowDecimals: true
property bool validateMaximumAmount: false
property string maximumAmount: "0"
property bool allowZero: true
property alias labelText: labelText.text
property string maximumExceededErrorText: qsTr("Amount exceeds balance")
validationErrorTopMargin: 8
fontPixelSize: 13
customHeight: 36
placeholderText: locale.zeroDigit
textField.rightPadding: labelText.implicitWidth + labelText.anchors.rightMargin
+ textField.leftPadding
function setAmount(amount, multiplierIndex = 0) {
console.assert(typeof amount === "string")
d.multiplierIndex = multiplierIndex
const amountNumber = SQUtils.AmountsArithmetic.toNumber(
amount, multiplierIndex)
root.text = LocaleUtils.numberToLocaleString(amountNumber, -1,
root.locale)
}
onTextChanged: d.validate()
onValidateMaximumAmountChanged: d.validate()
onMaximumAmountChanged: d.validate()
onMultiplierIndexChanged: d.validate()
QtObject {
id: d
property string amount: "0"
property int multiplierIndex: 0
function getEffectiveDigitsCount(str) {
const digits = LocaleUtils.getLocalizedDigitsCount(text, root.locale)
return str.startsWith(root.locale.decimalPoint) ? digits + 1 : digits
}
function validate() {
if (!root.allowDecimals)
root.text = root.text.replace(root.locale.decimalPoint, "")
if(root.text.length === 0) {
d.amount = "0"
root.validationError = ""
return
}
if (d.getEffectiveDigitsCount(text) > root.maximumLength) {
root.validationError = qsTr("The maximum number of characters is %1").arg(root.maximumLength)
return
}
const amountNumber = LocaleUtils.numberFromLocaleString(root.text, root.locale)
if (isNaN(amountNumber)) {
d.amount = "0"
root.validationError = qsTr("Invalid amount format")
return
}
if (!root.allowZero && amountNumber === 0) {
d.amount = "0"
root.validationError = qsTr("Amount must be greater than 0")
return
}
const amount = SQUtils.AmountsArithmetic.fromNumber(
amountNumber, d.multiplierIndex)
if (root.validateMaximumAmount) {
const maximumAmount = SQUtils.AmountsArithmetic.fromString(
root.maximumAmount)
const maxExceeded = SQUtils.AmountsArithmetic.cmp(
amount, maximumAmount) === 1
if (SQUtils.AmountsArithmetic.cmp(amount, maximumAmount) === 1) {
root.validationError = root.maximumExceededErrorText
return
}
}
// Fallback to handle float amounts for permissions
// As a target amount should be always integer number
if (!Number.isInteger(amountNumber) && d.multiplierIndex === 0) {
d.amount = amount.toString()
} else {
d.amount = amount.toFixed(0)
}
root.validationError = ""
}
}
validator: DoubleValidator {
decimals: root.allowDecimals ? 100 : 0
bottom: 0
notation: DoubleValidator.StandardNotation
locale: root.locale.name.split("_")[0] // For whatever reason, this doesn't work properly when being
// passed "language_country". We pass only the language part.
}
StatusBaseText {
id: labelText
parent: root.textField
anchors.right: parent.right
anchors.rightMargin: 13
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Amount")
color: Theme.palette.baseColor1
font.pixelSize: 13
}
}