fix(airdrop): fix decimals validation

* set decimal for assets on AidropSettingsPanel and HoldingsDropdown test pages
* Disable amount length validation by default
* Input: Align validation error string to the left edge
* Update validation error copy

fixes #11918
This commit is contained in:
Andrey Bocharnikov 2024-03-05 18:12:03 +04:00
parent a2e85bb3eb
commit 2958a03c2c
8 changed files with 80 additions and 27 deletions

View File

@ -177,6 +177,10 @@ SplitView {
name: "chainName" name: "chainName"
expression: model.index ? "Ethereum Mainnet" : "Goerli" expression: model.index ? "Ethereum Mainnet" : "Goerli"
}, },
ExpressionRole {
name: "decimals"
expression: decimalsText.text
},
ExpressionRole { ExpressionRole {
readonly property string icon1: "network/Network=Ethereum" readonly property string icon1: "network/Network=Ethereum"
@ -192,7 +196,6 @@ SplitView {
value: TokenCategories.Category.Community value: TokenCategories.Category.Community
} }
Component.onCompleted: { Component.onCompleted: {
Qt.callLater(() => airdropsSettingsPanel.assetsModel = this) Qt.callLater(() => airdropsSettingsPanel.assetsModel = this)
} }
@ -250,6 +253,19 @@ SplitView {
text: "Owner and TMaster tokens deployed" text: "Owner and TMaster tokens deployed"
} }
Row {
Label {
anchors.verticalCenter: parent.verticalCenter
text: "Assets Decimals"
}
TextField {
id: decimalsText
text: "2"
width: 50
}
}
} }
} }
} }

View File

@ -119,7 +119,10 @@ SplitView {
expression: model.index ? "Ethereum Mainnet" : "Goerli" expression: model.index ? "Ethereum Mainnet" : "Goerli"
}, },
ExpressionRole { ExpressionRole {
name: "decimals"
expression: decimalsText.text
},
ExpressionRole {
readonly property string icon1: "network/Network=Ethereum" readonly property string icon1: "network/Network=Ethereum"
readonly property string icon2: "network/Network=Testnet" readonly property string icon2: "network/Network=Testnet"
@ -169,6 +172,16 @@ SplitView {
id: ctrlAllTokensMode id: ctrlAllTokensMode
text: "All tokens mode" text: "All tokens mode"
} }
Label {
text: "Assets Decimals"
}
TextField {
id: decimalsText
Layout.preferredWidth: 50
text: "2"
}
} }
} }
} }

View File

@ -24,28 +24,32 @@ SplitView {
icon: Style.svg(ModelsData.networks.optimism), icon: Style.svg(ModelsData.networks.optimism),
amount: "300", amount: "300",
multiplierIndex: 0, multiplierIndex: 0,
infiniteAmount: false infiniteAmount: false,
decimals: 6
}, },
{ {
name: "Arbitrum", name: "Arbitrum",
icon: Style.svg(ModelsData.networks.arbitrum), icon: Style.svg(ModelsData.networks.arbitrum),
amount: "400000", amount: "400000",
multiplierIndex: 3, multiplierIndex: 3,
infiniteAmount: false infiniteAmount: false,
decimals: 9
}, },
{ {
name: "Hermez", name: "Hermez",
icon: Style.svg(ModelsData.networks.hermez), icon: Style.svg(ModelsData.networks.hermez),
amount: "0", amount: "0",
multiplierIndex: 0, multiplierIndex: 0,
infiniteAmount: true infiniteAmount: true,
decimals: 0
}, },
{ {
name: "Ethereum", name: "Ethereum",
icon: Style.svg(ModelsData.networks.ethereum), icon: Style.svg(ModelsData.networks.ethereum),
amount: "12" + "0".repeat(18), amount: "12" + "0".repeat(18),
multiplierIndex: 18, multiplierIndex: 18,
infiniteAmount: false infiniteAmount: false,
decimals: 9
} }
] ]
@ -130,10 +134,24 @@ SplitView {
text: "∞" text: "∞"
} }
Label {
text: "Decimals:"
}
TextField {
id: decimalsTextField
text: "0"
}
} }
Label { RowLayout {
text: "amount: " + tokenPanel.amount Label {
text: "amount: " + tokenPanel.amount
}
Label {
text: "decimals: " + tokenPanel.decimals
}
} }
} }
} }

View File

@ -15,6 +15,7 @@ StatusComboBox {
readonly property string currentName: control.currentText readonly property string currentName: control.currentText
readonly property alias currentAmount: instantiator.amount readonly property alias currentAmount: instantiator.amount
readonly property alias decimals: instantiator.decimals
readonly property alias currentMultiplierIndex: instantiator.multiplierIndex readonly property alias currentMultiplierIndex: instantiator.multiplierIndex
readonly property alias currentInfiniteAmount: instantiator.infiniteAmount readonly property alias currentInfiniteAmount: instantiator.infiniteAmount
readonly property alias currentIcon: instantiator.icon readonly property alias currentIcon: instantiator.icon
@ -100,6 +101,7 @@ StatusComboBox {
property string amount property string amount
property int multiplierIndex property int multiplierIndex
property bool infiniteAmount property bool infiniteAmount
property int decimals
model: SortFilterProxyModel { model: SortFilterProxyModel {
sourceModel: root.model sourceModel: root.model
@ -113,6 +115,7 @@ StatusComboBox {
readonly property list<Binding> bindings: [ readonly property list<Binding> bindings: [
Bind { property: "icon"; value: model.icon }, Bind { property: "icon"; value: model.icon },
Bind { property: "amount"; value: model.amount }, Bind { property: "amount"; value: model.amount },
Bind { property: "decimals"; value: model.decimals },
Bind { property: "multiplierIndex"; value: model.multiplierIndex }, Bind { property: "multiplierIndex"; value: model.multiplierIndex },
Bind { property: "infiniteAmount"; value: model.infiniteAmount } Bind { property: "infiniteAmount"; value: model.infiniteAmount }
] ]

View File

@ -21,6 +21,7 @@ ColumnLayout {
property alias tokenImage: item.iconSource property alias tokenImage: item.iconSource
property alias amountText: amountInput.text property alias amountText: amountInput.text
property alias amount: amountInput.amount property alias amount: amountInput.amount
property alias decimals: amountInput.tokenDecimals
property alias multiplierIndex: amountInput.multiplierIndex property alias multiplierIndex: amountInput.multiplierIndex
property alias tokenCategoryText: tokenLabel.text property alias tokenCategoryText: tokenLabel.text
property alias networkLabelText: d.networkLabelText property alias networkLabelText: d.networkLabelText
@ -88,6 +89,7 @@ ColumnLayout {
spacing: 10 spacing: 10
property alias currentAmount: inlineNetworksComboBox.currentAmount property alias currentAmount: inlineNetworksComboBox.currentAmount
property alias decimals: inlineNetworksComboBox.decimals
property alias currentMultiplierIndex: property alias currentMultiplierIndex:
inlineNetworksComboBox.currentMultiplierIndex inlineNetworksComboBox.currentMultiplierIndex
property alias currentInfiniteAmount: property alias currentInfiniteAmount:
@ -128,7 +130,8 @@ ColumnLayout {
maximumAmount: !!networksComboBoxLoader.item maximumAmount: !!networksComboBoxLoader.item
? networksComboBoxLoader.item.currentAmount : "0" ? networksComboBoxLoader.item.currentAmount : "0"
tokenDecimals: !!networksComboBoxLoader.item
? networksComboBoxLoader.item.decimals : 0
multiplierIndex: !!networksComboBoxLoader.item multiplierIndex: !!networksComboBoxLoader.item
? networksComboBoxLoader.item.currentMultiplierIndex : 0 ? networksComboBoxLoader.item.currentMultiplierIndex : 0

View File

@ -425,6 +425,7 @@ StatusDropdown {
name: chainName, name: chainName,
icon: chainIcon, icon: chainIcon,
amount: asset.remainingSupply, amount: asset.remainingSupply,
decimals: asset.decimals,
multiplierIndex: asset.multiplierIndex, multiplierIndex: asset.multiplierIndex,
infiniteAmount: asset.infiniteSupply infiniteAmount: asset.infiniteSupply
}) })

View File

@ -10,7 +10,6 @@ import utils 1.0
Input { Input {
id: root id: root
property int maximumLength: 10
property var locale: LocaleUtils.userInputLocale property var locale: LocaleUtils.userInputLocale
readonly property alias amount: d.amount readonly property alias amount: d.amount
@ -18,6 +17,7 @@ Input {
readonly property bool valid: validationError.length === 0 readonly property bool valid: validationError.length === 0
property bool allowDecimals: true property bool allowDecimals: true
property int tokenDecimals: 0
property bool validateMaximumAmount: false property bool validateMaximumAmount: false
property string maximumAmount: "0" property string maximumAmount: "0"
@ -66,17 +66,12 @@ Input {
if (!root.allowDecimals) if (!root.allowDecimals)
root.text = root.text.replace(root.locale.decimalPoint, "") root.text = root.text.replace(root.locale.decimalPoint, "")
if(root.text.length === 0) { if (root.text.length === 0) {
d.amount = "0" d.amount = "0"
root.validationError = "" root.validationError = ""
return 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) const amountNumber = LocaleUtils.numberFromLocaleString(root.text, root.locale)
if (isNaN(amountNumber)) { if (isNaN(amountNumber)) {
d.amount = "0" d.amount = "0"
@ -84,23 +79,26 @@ Input {
return return
} }
const fractionalPartLength = LocaleUtils.fractionalPartLength(amountNumber)
if (fractionalPartLength > root.tokenDecimals) {
d.amount = "0"
root.validationError = qsTr("Max %n decimal place(s) for this asset", "", root.tokenDecimals)
return
}
if (!root.allowZero && amountNumber === 0) { if (!root.allowZero && amountNumber === 0) {
d.amount = "0" d.amount = "0"
root.validationError = qsTr("Amount must be greater than 0") root.validationError = qsTr("Amount must be greater than 0")
return return
} }
const amount = SQUtils.AmountsArithmetic.fromNumber( const amount = SQUtils.AmountsArithmetic.fromNumber(amountNumber, d.multiplierIndex)
amountNumber, d.multiplierIndex)
if (root.validateMaximumAmount) { if (root.validateMaximumAmount && root.maximumAmount && root.maximumAmount.length > 0) {
const maximumAmount = SQUtils.AmountsArithmetic.fromString( const maximumAmount = SQUtils.AmountsArithmetic.fromString(root.maximumAmount)
root.maximumAmount) const maxExceeded = SQUtils.AmountsArithmetic.cmp(amount, maximumAmount) === 1
const maxExceeded = SQUtils.AmountsArithmetic.cmp( if (maxExceeded) {
amount, maximumAmount) === 1
if (SQUtils.AmountsArithmetic.cmp(amount, maximumAmount) === 1) {
root.validationError = root.maximumExceededErrorText root.validationError = root.maximumExceededErrorText
return return
} }
@ -110,7 +108,7 @@ Input {
// As a target amount should be always integer number // As a target amount should be always integer number
if (!Number.isInteger(amountNumber) && d.multiplierIndex === 0) { if (!Number.isInteger(amountNumber) && d.multiplierIndex === 0) {
d.amount = amount.toString() d.amount = amount.toString()
} else { } else {
d.amount = amount.toFixed(0) d.amount = amount.toFixed(0)
} }

View File

@ -177,9 +177,10 @@ Item {
id: validationErrorText id: validationErrorText
visible: !!validationError visible: !!validationError
text: validationError text: validationError
anchors.left: inputField.left
anchors.leftMargin: 2
anchors.top: inputField.bottom anchors.top: inputField.bottom
anchors.topMargin: validationErrorTopMargin anchors.topMargin: validationErrorTopMargin
width: parent.width
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
font.pixelSize: 12 font.pixelSize: 12
height: 16 height: 16