233 lines
8.7 KiB
QML
233 lines
8.7 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Layouts 1.15
|
|
|
|
import StatusQ.Core 0.1
|
|
import StatusQ.Core.Theme 0.1
|
|
import StatusQ.Controls 0.1
|
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
|
import StatusQ.Components 0.1
|
|
import StatusQ.Controls.Validators 0.1
|
|
|
|
import "../controls"
|
|
|
|
import utils 1.0
|
|
|
|
ColumnLayout {
|
|
id: root
|
|
|
|
readonly property alias input: topAmountToSendInput
|
|
readonly property bool inputNumberValid: !!input.text && !isNaN(d.parsedInput) && input.valid
|
|
|
|
readonly property int minSendCryptoDecimals:
|
|
!inputIsFiat ? LocaleUtils.fractionalPartLength(d.inputNumber) : 0
|
|
readonly property int minReceiveCryptoDecimals:
|
|
!inputIsFiat ? minSendCryptoDecimals + 1 : 0
|
|
readonly property int minSendFiatDecimals:
|
|
inputIsFiat ? LocaleUtils.fractionalPartLength(d.inputNumber) : 0
|
|
readonly property int minReceiveFiatDecimals:
|
|
inputIsFiat ? minSendFiatDecimals + 1 : 0
|
|
|
|
property var selectedHolding // Crypto asset symbol like ETH
|
|
property string currentCurrency // Fiat currency symbol like USD
|
|
|
|
property int multiplierIndex // How divisible the token is, 18 for ETH
|
|
|
|
property double maxInputBalance
|
|
|
|
property bool isBridgeTx: false
|
|
property bool interactive: false
|
|
property bool inputIsFiat: false
|
|
|
|
property string caption: isBridgeTx ? qsTr("Amount to bridge") : qsTr("Amount to send")
|
|
|
|
property bool fiatInputInteractive: true
|
|
|
|
// Crypto value to send expressed in base units (like wei for ETH),
|
|
// as a string representing integer decimal
|
|
readonly property alias cryptoValueToSend: d.cryptoValueRawToSend
|
|
|
|
readonly property alias cryptoValueToSendFloat: d.cryptoValueToSend
|
|
|
|
property var formatCurrencyAmount:
|
|
(amount, symbol, options = null, locale = null) => {}
|
|
|
|
property bool mainInputLoading
|
|
property bool bottomTextLoading
|
|
|
|
signal reCalculateSuggestedRoute()
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
property double cryptoValueToSend
|
|
property double fiatValueToSend
|
|
|
|
Binding on cryptoValueToSend {
|
|
value: {
|
|
root.selectedHolding
|
|
if(!root.selectedHolding || !root.selectedHolding.marketDetails || !root.selectedHolding.marketDetails.currencyPrice) {
|
|
return 0
|
|
}
|
|
return root.inputIsFiat ? d.fiatValueToSend/root.selectedHolding.marketDetails.currencyPrice.amount
|
|
: d.inputNumber
|
|
}
|
|
delayed: true
|
|
}
|
|
|
|
Binding on fiatValueToSend {
|
|
value: {
|
|
root.selectedHolding
|
|
if(!root.selectedHolding || !root.selectedHolding.marketDetails || !root.selectedHolding.marketDetails.currencyPrice) {
|
|
return 0
|
|
}
|
|
return root.inputIsFiat ? d.inputNumber
|
|
: d.cryptoValueToSend * root.selectedHolding.marketDetails.currencyPrice.amount
|
|
}
|
|
delayed: true
|
|
}
|
|
|
|
readonly property string selectedSymbol: !!root.selectedHolding && !!root.selectedHolding.symbol ? root.selectedHolding.symbol: ""
|
|
|
|
readonly property string cryptoValueRawToSend: {
|
|
return SQUtils.AmountsArithmetic.fromNumber(
|
|
d.cryptoValueToSend, root.multiplierIndex).toString()
|
|
}
|
|
|
|
// Crypto value should be represented by 0 and fiat with 0.00
|
|
readonly property string zeroString: {
|
|
let decimals = root.inputIsFiat ? 2 : 0
|
|
LocaleUtils.numberToLocaleString(0, decimals, topAmountToSendInput.locale)
|
|
}
|
|
|
|
readonly property double parsedInput:
|
|
LocaleUtils.numberFromLocaleString(topAmountToSendInput.text,
|
|
topAmountToSendInput.locale)
|
|
|
|
readonly property double inputNumber:
|
|
// we should still calculate if value entered is greater than max safe value
|
|
!!input.text && !isNaN(d.parsedInput) && d.parsedInput >= 0 ? d.parsedInput : 0
|
|
|
|
readonly property Timer waitTimer: Timer {
|
|
interval: 1000
|
|
onTriggered: reCalculateSuggestedRoute()
|
|
}
|
|
}
|
|
|
|
onMaxInputBalanceChanged: {
|
|
input.validate()
|
|
}
|
|
|
|
onSelectedHoldingChanged: {
|
|
input.validate()
|
|
}
|
|
|
|
StatusBaseText {
|
|
text: root.caption
|
|
font.pixelSize: 13
|
|
lineHeight: 18
|
|
lineHeightMode: Text.FixedHeight
|
|
color: Theme.palette.directColor1
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
id: topItem
|
|
|
|
AmountInputWithCursor {
|
|
id: topAmountToSendInput
|
|
Layout.fillWidth: true
|
|
Layout.maximumWidth: 250
|
|
Layout.preferredWidth: !!text ? input.edit.paintedWidth + 2
|
|
: textMetrics.advanceWidth
|
|
placeholderText: d.zeroString
|
|
input.edit.color: input.valid ? Theme.palette.directColor1
|
|
: Theme.palette.dangerColor1
|
|
input.edit.readOnly: !root.interactive
|
|
validationMode: StatusInput.ValidationMode.Always
|
|
validators: [
|
|
StatusValidator {
|
|
errorMessage: ""
|
|
|
|
validate: (text) => {
|
|
const num = LocaleUtils.numberFromLocaleString(topAmountToSendInput.text,
|
|
topAmountToSendInput.locale)
|
|
if (isNaN(num) || num <= 0 || num > root.maxInputBalance) {
|
|
return false
|
|
}
|
|
if(!root.selectedHolding || !root.selectedHolding.marketDetails || !root.selectedHolding.marketDetails.currencyPrice) {
|
|
return false
|
|
}
|
|
const cryptoValueToSend = root.inputIsFiat ? num / root.selectedHolding.marketDetails.currencyPrice.amount : num
|
|
const cryptoValueToSendRaw = SQUtils.AmountsArithmetic.fromNumber(cryptoValueToSend, root.multiplierIndex).toString()
|
|
return cryptoValueToSendRaw >= 1
|
|
}
|
|
}
|
|
]
|
|
|
|
TextMetrics {
|
|
id: textMetrics
|
|
text: topAmountToSendInput.placeholderText
|
|
font: topAmountToSendInput.placeholderFont
|
|
}
|
|
|
|
Keys.onReleased: {
|
|
const amount = LocaleUtils.numberFromLocaleString(
|
|
topAmountToSendInput.text,
|
|
locale)
|
|
if (!isNaN(amount))
|
|
d.waitTimer.restart()
|
|
}
|
|
|
|
visible: !root.mainInputLoading
|
|
}
|
|
LoadingComponent {
|
|
objectName: "topAmountToSendInputLoadingComponent"
|
|
Layout.preferredWidth: topAmountToSendInput.width
|
|
Layout.preferredHeight: topAmountToSendInput.height
|
|
visible: root.mainInputLoading
|
|
}
|
|
}
|
|
|
|
StatusBaseText {
|
|
Layout.maximumWidth: parent.width
|
|
id: bottomItem
|
|
objectName: "bottomItemText"
|
|
|
|
readonly property double bottomAmountToSend: inputIsFiat ? d.cryptoValueToSend
|
|
: d.fiatValueToSend
|
|
readonly property string bottomAmountSymbol: inputIsFiat ? d.selectedSymbol
|
|
: root.currentCurrency
|
|
elide: Text.ElideMiddle
|
|
text: root.formatCurrencyAmount(bottomAmountToSend, bottomAmountSymbol)
|
|
font.pixelSize: 13
|
|
color: Theme.palette.directColor5
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: enabled ? Qt.PointingHandCursor : undefined
|
|
enabled: root.fiatInputInteractive && !!root.selectedHolding
|
|
|
|
onClicked: {
|
|
topAmountToSendInput.validate()
|
|
if(!!topAmountToSendInput.text) {
|
|
topAmountToSendInput.text = root.formatCurrencyAmount(
|
|
bottomItem.bottomAmountToSend,
|
|
bottomItem.bottomAmountSymbol,
|
|
{ noSymbol: true, rawAmount: true },
|
|
topAmountToSendInput.locale)
|
|
}
|
|
root.inputIsFiat = !root.inputIsFiat
|
|
d.waitTimer.restart()
|
|
}
|
|
}
|
|
visible: !root.bottomTextLoading
|
|
}
|
|
|
|
LoadingComponent {
|
|
objectName: "bottomItemTextLoadingComponent"
|
|
Layout.preferredWidth: bottomItem.width
|
|
Layout.preferredHeight: bottomItem.height
|
|
visible: root.bottomTextLoading
|
|
}
|
|
}
|