mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-17 18:11:54 +00:00
613fa4d19f
In comparison to the previous version it provides simpler API and better validation based on AmountValidator. Old version will be removed after full integration of the new version.
256 lines
8.6 KiB
QML
256 lines
8.6 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
|
|
import StatusQ.Core 0.1
|
|
import StatusQ.Core.Theme 0.1
|
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
|
|
|
import StatusQ.Validators 0.1
|
|
|
|
import utils 1.0
|
|
import shared.controls 1.0
|
|
|
|
Control {
|
|
id: root
|
|
|
|
/* Crypto value in a base unit as a string integer, e.g. 1000000000000000000
|
|
* for 1 ETH */
|
|
readonly property alias amount: d.amountBaseUnit
|
|
|
|
/* In fiat mode the input value is meant to be a fiat value, conversely,
|
|
* crypto value otherwise. */
|
|
readonly property alias fiatMode: d.fiatMode
|
|
|
|
/* Indicates if input represent valid number. E.g. empty input or containing
|
|
* only decimal point is not valid. */
|
|
readonly property alias valid: textField.acceptableInput
|
|
readonly property bool empty: textField.length === 0
|
|
|
|
// TODO: remove, temporarily for backward compatibility. External components
|
|
// should not rely on formatted amount because formatting rules are internal
|
|
// detail of that component.
|
|
readonly property alias text: textField.text
|
|
|
|
/* Decimal point character to be dispalyed. Both "." and "," will be
|
|
* replaced by the provided decimal point on the fly */
|
|
property alias decimalPoint: validator.decimalPoint
|
|
|
|
/* Number of fiat decimal places used to limit allowed decimal places in
|
|
* fiatMode */
|
|
property int fiatDecimalPlaces: 2
|
|
|
|
/* Specifies how divisible given cryptocurrency is, e.g. 18 for ETH. Used
|
|
* for limiting allowed decimal places and computing final amout as an
|
|
* integer value */
|
|
property int multiplierIndex: 18
|
|
|
|
/* Price of one unit of given cryptocurrency (e.g. price for 1 ETH) */
|
|
property real price: 1.0
|
|
|
|
property alias caption: captionText.text
|
|
property bool interactive: true
|
|
|
|
/* Allows mark input as invalid when it's valid number but doesn't satisfy
|
|
* arbitrary external criteria, e.g. is higher than maximum expected value. */
|
|
property bool markAsInvalid: false
|
|
|
|
/* Methods for formatting crypto and fiat value expecting double values,
|
|
e.g. 1.0 for 1 ETH or 1.0 for 1 USD. */
|
|
property var formatFiat: balance =>
|
|
`${balance.toLocaleString(Qt.locale())} FIAT`
|
|
property var formatBalance: balance =>
|
|
`${balance.toLocaleString(Qt.locale())} CRYPTO`
|
|
|
|
/* Allows to set value to be displayed. The value is expected to be a not
|
|
localized string like "1", "1.1" or "0.000000023400234222". Provided
|
|
value will be formatted and displayed. Depending on the fiatMode flag
|
|
it will affect output amount appropriately. */
|
|
function setValue(valueString) {
|
|
if (!valueString)
|
|
valueString = "0"
|
|
|
|
const decimalPlaces = d.fiatMode ? root.fiatDecimalPlaces
|
|
: root.multiplierIndex
|
|
|
|
const stringNumber = SQUtils.AmountsArithmetic.fromString(
|
|
valueString).toFixed(decimalPlaces)
|
|
|
|
const trimmed = d.fiatMode
|
|
? stringNumber
|
|
: d.removeDecimalTrailingZeros(stringNumber)
|
|
|
|
textField.text = d.localize(trimmed)
|
|
}
|
|
|
|
function clear() {
|
|
textField.clear()
|
|
}
|
|
|
|
function forceActiveFocus() {
|
|
textField.forceActiveFocus()
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
property bool fiatMode: false
|
|
|
|
readonly property string inputDelocalized:
|
|
root.valid && textField.length !== 0
|
|
? textField.text.replace(",", ".") : "0"
|
|
|
|
function removeDecimalTrailingZeros(num) {
|
|
if (!num.includes("."))
|
|
return num
|
|
|
|
return num.replace(/\.?0*$/g, "")
|
|
}
|
|
|
|
function localize(num) {
|
|
return num.replace(".", root.decimalPoint)
|
|
}
|
|
|
|
readonly property string amountBaseUnit: {
|
|
if (d.fiatMode)
|
|
return secondaryValue
|
|
|
|
const multiplier = SQUtils.AmountsArithmetic.fromExponent(
|
|
root.multiplierIndex)
|
|
|
|
return SQUtils.AmountsArithmetic.times(
|
|
SQUtils.AmountsArithmetic.fromString(inputDelocalized),
|
|
multiplier).toFixed()
|
|
}
|
|
|
|
readonly property string secondaryValue: {
|
|
const price = isNaN(root.price) ? 0 : root.price
|
|
|
|
if (!d.fiatMode)
|
|
return SQUtils.AmountsArithmetic.times(
|
|
SQUtils.AmountsArithmetic.fromString(inputDelocalized),
|
|
SQUtils.AmountsArithmetic.fromNumber(
|
|
price * (10 ** root.fiatDecimalPlaces))).round().toFixed()
|
|
|
|
const multiplier = SQUtils.AmountsArithmetic.fromExponent(
|
|
root.multiplierIndex)
|
|
|
|
return SQUtils.AmountsArithmetic.div(
|
|
SQUtils.AmountsArithmetic.times(
|
|
SQUtils.AmountsArithmetic.fromString(inputDelocalized),
|
|
multiplier),
|
|
SQUtils.AmountsArithmetic.fromNumber(price)).round().toFixed()
|
|
}
|
|
}
|
|
|
|
contentItem: ColumnLayout {
|
|
StatusBaseText {
|
|
id: captionText
|
|
|
|
Layout.fillWidth: true
|
|
|
|
visible: text.length > 0
|
|
|
|
font.pixelSize: 13
|
|
lineHeight: 18
|
|
lineHeightMode: Text.FixedHeight
|
|
color: Theme.palette.directColor1
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
RowLayout {
|
|
StyledTextField {
|
|
id: textField
|
|
|
|
objectName: "amountToSend_textField"
|
|
|
|
Layout.fillWidth: true
|
|
|
|
implicitHeight: 44
|
|
padding: 0
|
|
background: null
|
|
|
|
readOnly: !root.interactive
|
|
|
|
color: text.length === 0 || (root.valid && !root.markAsInvalid)
|
|
? Theme.palette.directColor1
|
|
: Theme.palette.dangerColor1
|
|
|
|
placeholderText: {
|
|
if (!d.fiatMode || root.fiatDecimalPlaces === 0)
|
|
return "0"
|
|
|
|
return "0" + root.decimalPoint
|
|
+ "0".repeat(root.fiatDecimalPlaces)
|
|
}
|
|
|
|
font.pixelSize: Utils.getFontSizeBasedOnLetterCount(text)
|
|
|
|
validator: AmountValidator {
|
|
id: validator
|
|
|
|
maxDecimalDigits: d.fiatMode ? root.fiatDecimalPlaces
|
|
: root.multiplierIndex
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusBaseText {
|
|
id: bottomItem
|
|
|
|
objectName: "bottomItemText"
|
|
|
|
Layout.fillWidth: true
|
|
|
|
text: {
|
|
const divisor = SQUtils.AmountsArithmetic.fromExponent(
|
|
d.fiatMode ? root.multiplierIndex
|
|
: root.fiatDecimalPlaces)
|
|
const divided = SQUtils.AmountsArithmetic.div(
|
|
SQUtils.AmountsArithmetic.fromString(
|
|
d.secondaryValue), divisor)
|
|
const asNumber = SQUtils.AmountsArithmetic.toNumber(divided)
|
|
|
|
return d.fiatMode ? root.formatBalance(asNumber)
|
|
: root.formatFiat(asNumber)
|
|
}
|
|
|
|
elide: Text.ElideMiddle
|
|
font.pixelSize: 13
|
|
color: Theme.palette.directColor5
|
|
|
|
MouseArea {
|
|
objectName: "amountToSend_mouseArea"
|
|
|
|
anchors.fill: parent
|
|
cursorShape: enabled ? Qt.PointingHandCursor : undefined
|
|
enabled: root.interactive
|
|
|
|
onClicked: {
|
|
const secondaryValue = d.secondaryValue
|
|
|
|
d.fiatMode = !d.fiatMode
|
|
|
|
if (textField.length === 0)
|
|
return
|
|
|
|
const decimalPlaces = d.fiatMode ? root.fiatDecimalPlaces
|
|
: root.multiplierIndex
|
|
const divisor = SQUtils.AmountsArithmetic.fromExponent(
|
|
decimalPlaces)
|
|
|
|
const stringNumber = SQUtils.AmountsArithmetic.div(
|
|
SQUtils.AmountsArithmetic.fromString(secondaryValue),
|
|
divisor).toFixed(decimalPlaces)
|
|
|
|
const trimmed = d.fiatMode
|
|
? stringNumber
|
|
: d.removeDecimalTrailingZeros(stringNumber)
|
|
|
|
textField.text = d.localize(trimmed)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|