diff --git a/apps/amm/qml/components/liquidity/AmmTokenAccessory.qml b/apps/amm/qml/components/liquidity/AmmTokenAccessory.qml index df3919e..4888c5b 100644 --- a/apps/amm/qml/components/liquidity/AmmTokenAccessory.qml +++ b/apps/amm/qml/components/liquidity/AmmTokenAccessory.qml @@ -1,6 +1,7 @@ pragma ComponentBehavior: Bound import QtQuick +import QtQuick.Controls import QtQuick.Layouts ColumnLayout { @@ -12,6 +13,9 @@ ColumnLayout { property string tokenLetter: "" property string tokenText: qsTr("Select token") property string balance: "" + property bool balanceUpdating: false + readonly property bool showBalanceLoadingIndicator: root.balance.length > 0 + && root.balanceUpdating property string accessibleName: qsTr("Select token") property bool invalid: false @@ -19,14 +23,31 @@ ColumnLayout { spacing: 2 - Text { + RowLayout { Layout.fillWidth: true visible: root.balance.length > 0 - text: qsTr("Balance %1").arg(root.balance) - color: root.theme.colors.textSecondary - font.pixelSize: 10 - horizontalAlignment: Text.AlignRight - elide: Text.ElideRight + spacing: 4 + + Text { + id: balanceText + + objectName: "tokenBalanceText" + Layout.fillWidth: true + text: qsTr("Balance %1").arg(root.balance) + color: root.theme.colors.textSecondary + font.pixelSize: 10 + horizontalAlignment: Text.AlignRight + elide: Text.ElideRight + } + + BusyIndicator { + objectName: "tokenBalanceLoadingIndicator" + Layout.preferredWidth: 12 + Layout.preferredHeight: 12 + visible: root.showBalanceLoadingIndicator + running: visible + Accessible.name: qsTr("Updating balance") + } } AmmTokenSelectButton { diff --git a/apps/amm/qml/components/liquidity/NewPositionForm.qml b/apps/amm/qml/components/liquidity/NewPositionForm.qml index 4c29614..abf4265 100644 --- a/apps/amm/qml/components/liquidity/NewPositionForm.qml +++ b/apps/amm/qml/components/liquidity/NewPositionForm.qml @@ -255,8 +255,8 @@ AmmActionCard { theme: root.theme text: root.amountA label: qsTr("Token A amount") - balance: root.contextLoading ? "" : root.holdingBalanceText(root.holdingA, - root.decimalsA) + balance: root.holdingBalanceText(root.holdingA, root.decimalsA) + balanceUpdating: root.contextLoading helperText: root.missingPool && !root.compact ? root.minimumAmountText("A") : "" errorText: root.formErrorText() @@ -312,8 +312,8 @@ AmmActionCard { theme: root.theme text: root.amountB label: qsTr("Token B amount") - balance: root.contextLoading ? "" : root.holdingBalanceText(root.holdingB, - root.decimalsB) + balance: root.holdingBalanceText(root.holdingB, root.decimalsB) + balanceUpdating: root.contextLoading helperText: root.missingPool && !root.compact ? root.minimumAmountText("B") : "" invalid: root.fieldHasError("amountB") diff --git a/apps/amm/qml/components/liquidity/TokenAmountInput.qml b/apps/amm/qml/components/liquidity/TokenAmountInput.qml index f46c2e6..3e8749e 100644 --- a/apps/amm/qml/components/liquidity/TokenAmountInput.qml +++ b/apps/amm/qml/components/liquidity/TokenAmountInput.qml @@ -11,6 +11,7 @@ AmmTokenAmountSurface { property string text: "" property string balance: "" + property bool balanceUpdating: false property string helperText: "" property bool showMaxButton: true property var tokenData: null @@ -79,6 +80,7 @@ AmmTokenAmountSurface { spacing: 4 AmmTokenAccessory { + objectName: "tokenAccessory" Layout.fillWidth: true theme: root.theme enabled: root.tokenSelectionEnabled @@ -88,6 +90,7 @@ AmmTokenAmountSurface { tokenLetter: root.tokenLetter(root.tokenData) tokenText: root.tokenText(root.tokenData) balance: root.balance + balanceUpdating: root.balanceUpdating accessibleName: qsTr("Select %1").arg(root.label) onClicked: tokenModal.open() } diff --git a/apps/amm/tests/qml/tst_NewPositionForm.qml b/apps/amm/tests/qml/tst_NewPositionForm.qml index 6dbc6c8..52959a8 100644 --- a/apps/amm/tests/qml/tst_NewPositionForm.qml +++ b/apps/amm/tests/qml/tst_NewPositionForm.qml @@ -221,6 +221,21 @@ TestCase { compare(fixedFee.text, "0.05%") } + function test_contextRefreshKeepsBalanceVisibleWhileUpdating() { + var form = createForm() + var amountInput = findChild(form, "tokenAAmountInput") + verify(amountInput) + compare(amountInput.balance, "1000") + + var state = flowState() + state.contextLoading = true + form.flowState = state + wait(0) + + compare(amountInput.balance, "1000") + compare(amountInput.balanceUpdating, true) + } + function test_contextRefreshSelectsSingleHoldingsBeforeQuote() { var form = createForm() form.selectedHoldingAId = "" diff --git a/apps/amm/tests/qml/tst_TokenAmountInput.qml b/apps/amm/tests/qml/tst_TokenAmountInput.qml index 27d7ae6..c01f6e2 100644 --- a/apps/amm/tests/qml/tst_TokenAmountInput.qml +++ b/apps/amm/tests/qml/tst_TokenAmountInput.qml @@ -119,6 +119,19 @@ TestCase { String(input.theme.colors.ctaBg).toLowerCase()) } + function test_balanceRefreshShowsLoadingIndicatorWithoutClearingBalance() { + var input = createTemporaryObject(inputComponent, testCase, { + "balance": "12", + "balanceUpdating": true + }) + verify(input) + + var accessory = findChild(input, "tokenAccessory") + verify(accessory) + compare(accessory.balance, "12") + compare(accessory.showBalanceLoadingIndicator, true) + } + function test_disabledTokenIsRejectedByTypedInput() { var input = createTemporaryObject(inputComponent, testCase) verify(input)