fix(BurnTokensPopup): Handle non-integer values for assets

Closes: #11864
This commit is contained in:
Michał Cieślak 2023-08-30 10:25:32 +02:00 committed by Michał
parent 2de2393ec1
commit 1bc7eb374b
3 changed files with 110 additions and 79 deletions

View File

@ -28,9 +28,7 @@
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1573%3A296338" "https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1573%3A296338"
], ],
"BurnTokensPopup": [ "BurnTokensPopup": [
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?type=design&node-id=29528%3A588403&t=GUxMZEWcfRO7pXJb-1", "https://www.figma.com/file/qHfFm7C9LwtXpfdbxssCK3/Kuba%E2%8E%9CDesktop---Communities?type=design&node-id=35082-612599&mode=design&t=XTDQ4GeU1k9LPuVK-0"
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?type=design&node-id=29528%3A588563&t=GUxMZEWcfRO7pXJb-1",
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?type=design&node-id=29528%3A587660&t=GUxMZEWcfRO7pXJb-1"
], ],
"ChatAnchorButtonsPanel": [ "ChatAnchorButtonsPanel": [
"https://www.figma.com/file/Mr3rqxxgKJ2zMQ06UAKiWL/%F0%9F%92%AC-Chat%E2%8E%9CDesktop?node-id=14632-460085&t=SGTU2JeRA8ifbv2E-0" "https://www.figma.com/file/Mr3rqxxgKJ2zMQ06UAKiWL/%F0%9F%92%AC-Chat%E2%8E%9CDesktop?node-id=14632-460085&t=SGTU2JeRA8ifbv2E-0"

View File

@ -44,23 +44,49 @@ SplitView {
anchors.centerIn: parent anchors.centerIn: parent
text: "Reopen" text: "Reopen"
onClicked: dialog.open() onClicked: burnTokensPopup.open()
} }
BurnTokensPopup { BurnTokensPopup {
id: dialog id: burnTokensPopup
anchors.centerIn: parent anchors.centerIn: parent
visible: true
modal: false
closePolicy: Popup.NoAutoClose
communityName: editorCommunity.text communityName: editorCommunity.text
tokenName: editorToken.text tokenName: editorToken.text
remainingTokens: editorAmount.text remainingTokens: editorAmount.text
multiplierIndex: assetButton.checked ? 18 : 0
isAsset: assetButton.checked isAsset: assetButton.checked
tokenSource: assetButton.checked ? ModelsData.assets.socks : ModelsData.collectibles.kitty1Big tokenSource: assetButton.checked
? ModelsData.assets.socks
: ModelsData.collectibles.kitty1Big
accounts: accountsModel accounts: accountsModel
chainName: "Optimism" chainName: "Optimism"
onBurnClicked: logs.logEvent("BurnTokensPopup::onBurnClicked --> Burn amount: " + burnAmount) onBurnClicked: logs.logEvent("BurnTokensPopup::onBurnClicked --> Burn amount: " + burnAmount)
onCancelClicked: logs.logEvent("BurnTokensPopup::onCancelClicked") onCancelClicked: logs.logEvent("BurnTokensPopup::onCancelClicked")
onBurnFeesRequested: {
feeText = ""
feeErrorText = ""
isFeeLoading = true
feeCalculationTimer.restart()
}
}
Timer {
id: feeCalculationTimer
interval: 1000
onTriggered: {
burnTokensPopup.feeText = "0.0015 ETH ($75.43)"
burnTokensPopup.isFeeLoading = false
}
} }
} }
@ -79,6 +105,7 @@ SplitView {
SplitView.preferredWidth: 300 SplitView.preferredWidth: 300
ColumnLayout { ColumnLayout {
anchors.fill: parent
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
@ -87,8 +114,8 @@ SplitView {
TextField { TextField {
id: editorCommunity id: editorCommunity
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200 Layout.fillWidth: true
text: "Community lovers" text: "Community lovers"
} }
@ -101,8 +128,8 @@ SplitView {
TextField { TextField {
id: editorToken id: editorToken
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200 Layout.fillWidth: true
text: "Anniversary" text: "Anniversary"
} }
@ -115,8 +142,8 @@ SplitView {
TextField { TextField {
id: editorAmount id: editorAmount
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200 Layout.fillWidth: true
text: "123" text: "123"
} }
@ -139,6 +166,10 @@ SplitView {
text: "Collectible" text: "Collectible"
} }
Item {
Layout.fillHeight: true
}
} }
} }
} }

View File

@ -1,23 +1,20 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.14 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.15
import QtQml.Models 2.14 import QtQml.Models 2.15
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQml 2.15
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Utils 0.1 as SQUtils
import StatusQ.Controls.Validators 0.1
import StatusQ.Components 0.1
import AppLayouts.Communities.panels 1.0 import AppLayouts.Communities.panels 1.0
import AppLayouts.Communities.helpers 1.0
import utils 1.0 import utils 1.0
import SortFilterProxyModel 0.2 import shared.controls 1.0
StatusDialog { StatusDialog {
id: root id: root
@ -54,13 +51,16 @@ StatusDialog {
LocaleUtils.numberToLocaleString(remainingTokensFloat) LocaleUtils.numberToLocaleString(remainingTokensFloat)
property string accountAddress property string accountAddress
property alias amountToBurn: amountToBurnInput.text
readonly property bool isFeeError: root.feeErrorText !== "" readonly property bool isFeeError: root.feeErrorText !== ""
readonly property bool isFormValid: specificAmountButton.checked && amountToBurnInput.valid || allTokensButton.checked
readonly property bool isFormValid:
(specificAmountButton.checked && amountInput.valid && amountInput.text)
|| allTokensButton.checked
function initialize() { function initialize() {
specificAmountButton.checked = true specificAmountButton.checked = true
amountToBurnInput.forceActiveFocus() amountInput.forceActiveFocus()
} }
function getVerticalPadding() { function getVerticalPadding() {
@ -72,7 +72,7 @@ StatusDialog {
} }
} }
implicitWidth: 600 // by design width: 600 // by design
implicitHeight: content.implicitHeight + footer.height + header.height + d.getVerticalPadding() implicitHeight: content.implicitHeight + footer.height + header.height + d.getVerticalPadding()
contentItem: ColumnLayout { contentItem: ColumnLayout {
@ -83,22 +83,38 @@ StatusDialog {
StatusBaseText { StatusBaseText {
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("How many of %1s remaining %n %2 tokens would you like to burn?", "", d.remainingTokensFloat).arg(root.communityName).arg(root.tokenName) text: {
if (Number.isInteger(d.remainingTokensFloat))
return qsTr("How many of %1s remaining %Ln %2 token(s) would you like to burn?",
"", d.remainingTokensFloat).arg(root.communityName).arg(root.tokenName)
return qsTr("How many of %1s remaining %2 %3 tokens would you like to burn?")
.arg(root.communityName).arg(d.remainingTokensDisplayText).arg(root.tokenName)
}
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
lineHeight: 1.2 lineHeight: 1.2
font.pixelSize: Style.current.primaryTextFontSize font.pixelSize: Style.current.primaryTextFontSize
} }
RowLayout { Item {
Layout.bottomMargin: 12 Layout.bottomMargin: 12
Layout.leftMargin: -Style.current.halfPadding Layout.leftMargin: -Style.current.halfPadding
Layout.fillWidth: true
spacing: 26 implicitHeight: childrenRect.height
readonly property int spacing: 26
ColumnLayout { ColumnLayout {
id: specificAmountColumn
StatusRadioButton { StatusRadioButton {
id: specificAmountButton id: specificAmountButton
Layout.preferredWidth: amountInput.Layout.preferredWidth
+ amountInput.Layout.leftMargin
text: qsTr("Specific amount") text: qsTr("Specific amount")
font.pixelSize: Style.current.primaryTextFontSize font.pixelSize: Style.current.primaryTextFontSize
ButtonGroup.group: radioGroup ButtonGroup.group: radioGroup
@ -106,46 +122,33 @@ StatusDialog {
onToggled: if(checked) amountToBurnInput.forceActiveFocus() onToggled: if(checked) amountToBurnInput.forceActiveFocus()
} }
StatusInput { AmountInput {
id: amountToBurnInput id: amountInput
Layout.preferredWidth: 192 Layout.preferredWidth: 192
Layout.leftMargin: 30 Layout.leftMargin: 30
enabled: specificAmountButton.checked customHeight: 44
validationMode: StatusInput.ValidationMode.OnlyWhenDirty
validators: [
StatusValidator {
validate: (value) => {
const intAmount = parseInt(value)
if (!intAmount) allowDecimals: root.multiplierIndex > 0
return false maximumAmount: root.remainingTokens
multiplierIndex: root.multiplierIndex
const current = SQUtils.AmountsArithmetic.fromNumber( validateMaximumAmount: true
intAmount, root.multiplierIndex) allowZero: false
const remaining = SQUtils.AmountsArithmetic.fromString(
root.remainingTokens)
return SQUtils.AmountsArithmetic.cmp(current, remaining) <= 0 placeholderText: qsTr("Enter amount")
} labelText: ""
errorMessage: qsTr("Exceeds available remaining")
}, maximumExceededErrorText: qsTr("Exceeds available remaining")
StatusValidator {
validate: (value) => { return parseInt(value) !== 0 }
errorMessage: qsTr("Amount must be greater than 0")
},
StatusRegularExpressionValidator {
regularExpression: Constants.regularExpressions.numerical
errorMessage: qsTr("Invalid characters (0-9 only)")
}
]
} }
} }
StatusRadioButton { StatusRadioButton {
id: allTokensButton id: allTokensButton
Layout.alignment: Qt.AlignTop anchors.left: specificAmountColumn.right
anchors.right: parent.right
anchors.leftMargin: parent.spacing
text: qsTr("All available remaining (%1)").arg(d.remainingTokensDisplayText) text: qsTr("All available remaining (%1)").arg(d.remainingTokensDisplayText)
font.pixelSize: Style.current.primaryTextFontSize font.pixelSize: Style.current.primaryTextFontSize
@ -164,13 +167,12 @@ StatusDialog {
readonly property bool triggerFeeReevaluation: { readonly property bool triggerFeeReevaluation: {
specificAmountButton.checked specificAmountButton.checked
amountToBurnInput.text amountInput.amount
allTokensButton.checked
feesBox.accountsSelector.currentIndex feesBox.accountsSelector.currentIndex
if (root.opened) { if (root.opened)
requestFeeDelayTimer.restart() requestFeeDelayTimer.restart()
}
return true return true
} }
@ -186,7 +188,10 @@ StatusDialog {
if (accountsSelector.currentIndex < 0) if (accountsSelector.currentIndex < 0)
return return
const item = SQUtils.ModelUtils.get(accountsSelector.model, accountsSelector.currentIndex) const item = SQUtils.ModelUtils.get(
accountsSelector.model,
accountsSelector.currentIndex)
d.accountAddress = item.address d.accountAddress = item.address
} }
@ -195,17 +200,15 @@ StatusDialog {
interval: 500 interval: 500
onTriggered: { onTriggered: {
if(specificAmountButton.checked) { if (specificAmountButton.checked) {
if (!amountToBurnInput.text) if (!amountInput.valid)
return return
root.burnFeesRequested( root.burnFeesRequested(amountInput.amount,
SQUtils.AmountsArithmetic.fromNumber(
parseInt(amountToBurnInput.text),
root.multiplierIndex),
d.accountAddress) d.accountAddress)
} else { } else {
root.burnFeesRequested(root.remainingTokens, d.accountAddress) root.burnFeesRequested(root.remainingTokens,
d.accountAddress)
} }
} }
} }
@ -214,8 +217,8 @@ StatusDialog {
id: singleFeeModel id: singleFeeModel
readonly property string title: root.feeLabel readonly property string title: root.feeLabel
readonly property string feeText: root.isFeeLoading ? readonly property string feeText: root.isFeeLoading
"" : root.feeText ? "" : root.feeText
readonly property bool error: d.isFeeError readonly property bool error: d.isFeeError
} }
} }
@ -223,7 +226,9 @@ StatusDialog {
header: StatusDialogHeader { header: StatusDialogHeader {
headline.title: qsTr("Burn %1 tokens").arg(root.tokenName) headline.title: qsTr("Burn %1 tokens").arg(root.tokenName)
headline.subtitle: qsTr("%n %1 remaining in smart contract", "", d.remainingTokensFloat).arg(root.tokenName) headline.subtitle: qsTr("%1 %2 remaining in smart contract")
.arg(d.remainingTokensDisplayText).arg(root.tokenName)
leftComponent: Rectangle { leftComponent: Rectangle {
height: 40 height: 40
width: height width: height
@ -263,22 +268,19 @@ StatusDialog {
StatusButton { StatusButton {
enabled: d.isFormValid && !d.isFeeError && !root.isFeeLoading enabled: d.isFormValid && !d.isFeeError && !root.isFeeLoading
&& root.feeText !== ""
text: qsTr("Burn tokens") text: qsTr("Burn tokens")
type: StatusBaseButton.Type.Danger type: StatusBaseButton.Type.Danger
onClicked: { onClicked: {
if(specificAmountButton.checked) { if (specificAmountButton.checked)
root.burnClicked( root.burnClicked(amountInput.amount, d.accountAddress)
SQUtils.AmountsArithmetic.fromNumber( else
parseInt(amountToBurnInput.text),
root.multiplierIndex),
d.accountAddress)
} else {
root.burnClicked(root.remainingTokens, d.accountAddress) root.burnClicked(root.remainingTokens, d.accountAddress)
} }
} }
} }
} }
}
onOpened: d.initialize() onOpened: d.initialize()
} }