feat(StatusButton) Add support to show text when button is loading

- add a secondary "loading" state (`loadingWithText`), that is show the
loading indicator next to the text
- simplify the StatusBaseButton layout (esp. handling the overall
opacity/visibility)
- add a QML test suite; the code was becoming too complex and adding a
simple boolean prop was getting "dangerous"
- port the SwapModal to use the new `loadingWithText` property

Fixes #15313
This commit is contained in:
Lukáš Tinkl 2024-08-19 11:00:35 +02:00 committed by Lukáš Tinkl
parent 8dade32a39
commit e3dae7e1db
6 changed files with 377 additions and 91 deletions

View File

@ -55,6 +55,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -73,6 +74,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -92,6 +94,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -111,10 +114,10 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
isRoundIcon: true
radius: height/2
textFillWidth: ctrlFillWidth.checked
}
}
@ -137,6 +140,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -155,6 +159,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -174,6 +179,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
@ -193,6 +199,7 @@ SplitView {
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
loadingWithText: ctrlLoadingWithText.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
isRoundIcon: true
@ -284,6 +291,10 @@ SplitView {
id: ctrlLoading
text: "Loading"
}
Switch {
id: ctrlLoadingWithText
text: "Loading with text"
}
Switch {
id: ctrlInteractive
text: "Interactive"

View File

@ -0,0 +1,259 @@
import QtQuick 2.15
import QtTest 1.15
import StatusQ.Controls 0.1
import Models 1.0
Item {
id: root
width: 600
height: 400
Component {
id: componentUnderTest
StatusButton {
anchors.centerIn: parent
}
}
SignalSpy {
id: signalSpy
target: controlUnderTest
signalName: "clicked"
}
property StatusButton controlUnderTest: null
TestCase {
name: "StatusButton"
when: windowShown
function cleanup() {
if (!!controlUnderTest)
controlUnderTest.destroy()
signalSpy.clear()
}
function test_defaults() {
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: "Hello" })
verify(!!controlUnderTest)
verify(controlUnderTest.width > 0)
verify(controlUnderTest.height > 0)
verify(controlUnderTest.interactive)
verify(controlUnderTest.enabled)
verify(!controlUnderTest.loading)
verify(!controlUnderTest.loadingWithText)
verify(!controlUnderTest.isRoundIcon)
}
function test_text() {
const textToTest = "Hello"
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: textToTest })
verify(!!controlUnderTest)
const buttonText = findChild(controlUnderTest, "buttonText")
verify(!!buttonText)
verify(buttonText.visible)
compare(buttonText.text, textToTest)
// verify the icon is not visible
const buttonIcon = findChild(controlUnderTest, "buttonIcon")
verify(!!buttonIcon)
compare(buttonIcon.item, null)
}
function test_textLeftRight() {
const textToTest = "Hello"
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: textToTest, "icon.name": "gif" })
verify(!!controlUnderTest)
compare(controlUnderTest.textPosition, StatusBaseButton.TextPosition.Right)
const leftTextLoader = findChild(controlUnderTest, "leftTextLoader")
verify(!!leftTextLoader)
verify(!leftTextLoader.active)
const rightTextLoader = findChild(controlUnderTest, "rightTextLoader")
verify(!!rightTextLoader)
verify(rightTextLoader.active)
// set the text to appear on the right, verify the text position
controlUnderTest.textPosition = StatusBaseButton.TextPosition.Left
verify(leftTextLoader.active)
verify(!rightTextLoader.active)
}
function test_elideText() {
const textToTest = "This is a very long text that should be elided"
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: textToTest })
verify(!!controlUnderTest)
controlUnderTest.width = 100
// verify the text is visible and truncated (elided)
const buttonText = findChild(controlUnderTest, "buttonText")
verify(!!buttonText)
verify(buttonText.visible)
verify(buttonText.truncated)
}
function test_icon_data() {
return [
{ tag: "empty", name: "", iconVisible: false },
{ tag: "gif", name: "gif", iconVisible: true },
{ tag: "invalid", name: "bflmpsvz", iconVisible: false },
{ tag: "blob", name: ModelsData.icons.status, iconVisible: true },
{ tag: "fileUrl", name: ModelsData.assets.snt, iconVisible: true },
]
}
function test_icon(data) {
controlUnderTest = createTemporaryObject(componentUnderTest, root, { "icon.name": data.name })
verify(!!controlUnderTest)
const buttonIcon = findChild(controlUnderTest, "buttonIcon")
verify(!!buttonIcon)
if (data.iconVisible)
verify(buttonIcon.item.visible)
// verify the button is square with rounded edges
compare(controlUnderTest.width, controlUnderTest.height)
verify(controlUnderTest.radius != controlUnderTest.width/2)
// verify the text is not visible
const buttonText = findChild(controlUnderTest, "buttonText")
compare(buttonText, null)
}
function test_roundIcon() {
controlUnderTest = createTemporaryObject(componentUnderTest, root, { "icon.name": "gif", "isRoundIcon": true })
verify(!!controlUnderTest)
const buttonIcon = findChild(controlUnderTest, "buttonIcon")
verify(!!buttonIcon)
verify(buttonIcon.item.visible)
// verify that the button is rounded
compare(controlUnderTest.width, controlUnderTest.height)
compare(controlUnderTest.radius, controlUnderTest.width/2)
}
function test_emoji() {
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: "Hello" })
verify(!!controlUnderTest)
const buttonEmoji = findChild(controlUnderTest, "buttonEmoji")
verify(!!buttonEmoji)
verify(!buttonEmoji.visible)
// set some emoji, verify it's visible
controlUnderTest.asset.emoji = "💩"
verify(buttonEmoji.visible)
// unset the emoji, verify it's not visible
controlUnderTest.asset.emoji = ""
verify(!buttonEmoji.visible)
}
function test_textAndIcon_data() {
return test_icon_data()
}
function test_textAndIcon(data) {
const textToTest = "Hello"
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: textToTest, "icon.name": data.name })
verify(!!controlUnderTest)
const buttonIcon = findChild(controlUnderTest, "buttonIcon")
verify(!!buttonIcon)
if (data.iconVisible)
verify(buttonIcon.item.visible)
// verify the button is not square/round
verify(controlUnderTest.width > controlUnderTest.height)
// verify the text is visible too
const buttonText = findChild(controlUnderTest, "buttonText")
verify(!!buttonText)
verify(buttonText.visible)
compare(buttonText.text, textToTest)
}
function test_interactiveAndEnabled_data() {
return [
{ tag: "enabled", enabled: true, interactive: true, spyCount: 1, tooltip: true },
{ tag: "not enabled + interactive", enabled: false, interactive: true, spyCount: 0, tooltip: false },
{ tag: "enabled + not interactive", enabled: true, interactive: false, spyCount: 0, tooltip: true },
{ tag: "not enabled + not interactive", enabled: false, interactive: false, spyCount: 0, tooltip: false },
]
}
function test_interactiveAndEnabled(data) {
controlUnderTest = createTemporaryObject(componentUnderTest, root, { text: "Hello", "tooltip.text": "This is a tooltip" })
verify(!!controlUnderTest)
controlUnderTest.enabled = data.enabled
controlUnderTest.interactive = data.interactive
// verify the tooltip is visible in interactive or enabled when hovered
const buttonTooltip = findChild(controlUnderTest, "buttonTooltip")
verify(!!buttonTooltip)
mouseMove(controlUnderTest, controlUnderTest.width/2, controlUnderTest.height/2)
waitForItemPolished(buttonTooltip.contentItem)
tryCompare(buttonTooltip, "opened", data.tooltip)
// verify the click goes thru (or not) as expected
mouseClick(controlUnderTest)
compare(signalSpy.count, data.spyCount)
}
function test_loadingIndicators() {
controlUnderTest =
createTemporaryObject(componentUnderTest, root,
{ text: "Hello", "icon.name": "gif", "asset.emoji": "💩", "tooltip.text": "This is a tooltip" })
verify(!!controlUnderTest)
const buttonIcon = findChild(controlUnderTest, "buttonIcon")
verify(!!buttonIcon)
compare(buttonIcon.visible, true)
const buttonText = findChild(controlUnderTest, "buttonText")
verify(!!buttonText)
compare(buttonText.visible, true)
const buttonEmoji = findChild(controlUnderTest, "buttonEmoji")
verify(!!buttonEmoji)
compare(buttonEmoji.visible, true)
const loadingIndicator = findChild(controlUnderTest, "loadingIndicator")
verify(!!loadingIndicator)
compare(loadingIndicator.visible, false)
compare(controlUnderTest.contentItem.opacity, 1)
// verify when the overall indicator is running, nothing else is visible
controlUnderTest.loading = true
compare(loadingIndicator.visible, true)
compare(controlUnderTest.contentItem.opacity, 0) // the loading indicator is above the contentItem
// stop the loadingIndicator, verify icon, emoji and text are visible again
controlUnderTest.loading = false
compare(loadingIndicator.visible, false)
compare(controlUnderTest.contentItem.opacity, 1)
compare(buttonIcon.visible, true)
compare(buttonText.visible, true)
compare(buttonEmoji.visible, true)
// start the loadingWithText indicator, verify it and text are visible, icon and emoji not
const loadingWithTextIndicator = findChild(controlUnderTest, "loadingWithTextIndicator")
verify(!!loadingWithTextIndicator)
verify(!controlUnderTest.loadingWithText)
compare(loadingWithTextIndicator.visible, false)
controlUnderTest.loadingWithText = true
compare(loadingWithTextIndicator.visible, true)
compare(buttonIcon.visible, false)
compare(buttonText.visible, true)
compare(buttonEmoji.visible, false)
}
}
}

View File

@ -570,7 +570,7 @@ Item {
// Check max fees values and sign button state when nothing is set
compare(maxFeesText.text, qsTr("Max fees:"))
compare(maxFeesValue.text, "--")
verify(!signButton.enabled)
verify(!signButton.interactive)
verify(!errorTag.visible)
// set input values in the form correctly
@ -606,7 +606,7 @@ Item {
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("An error has occured, please try again"))
verify(!signButton.enabled)
verify(!signButton.interactive)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
@ -644,7 +644,7 @@ Item {
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Insufficient funds for swap"))
verify(!signButton.enabled)
verify(!signButton.interactive)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
@ -682,7 +682,7 @@ Item {
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Insufficient funds to pay gas fees"))
verify(!signButton.enabled)
verify(!signButton.interactive)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
@ -720,7 +720,7 @@ Item {
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Fetching the price took longer than expected. Please, try again later."))
verify(!signButton.enabled)
verify(!signButton.interactive)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
@ -758,7 +758,7 @@ Item {
compare(root.swapAdaptor.swapOutputData.hasError, true)
verify(errorTag.visible)
verify(errorTag.text, qsTr("Not enough liquidity. Lower token amount or try again later."))
verify(!signButton.enabled)
verify(!signButton.interactive)
compare(signButton.text, qsTr("Swap"))
// verfy input and output panels
@ -1487,7 +1487,7 @@ Item {
// Check max fees values and sign button state when nothing is set
compare(maxFeesValue.text, "--")
verify(!signButton.enabled)
verify(!signButton.interactive)
verify(!errorTag.visible)
// set input values in the form correctly
@ -1536,7 +1536,7 @@ Item {
verify(!errorTag.visible)
verify(signButton.enabled)
verify(!signButton.loading)
verify(!signButton.loadingWithText)
compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol))
// TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string.
compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
@ -1549,8 +1549,8 @@ Item {
verify(root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible)
verify(!signButton.enabled)
verify(signButton.loading)
verify(!signButton.interactive)
verify(signButton.loadingWithText)
compare(signButton.text, qsTr("Approving %1").arg(root.swapAdaptor.fromToken.symbol))
// TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string.
compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
@ -1564,7 +1564,7 @@ Item {
verify(!root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible)
verify(signButton.enabled)
verify(!signButton.loading)
verify(!signButton.loadingWithText)
compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol))
// TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string.
compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
@ -1578,8 +1578,8 @@ Item {
verify(root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible)
verify(!signButton.enabled)
verify(signButton.loading)
verify(!signButton.interactive)
verify(signButton.loadingWithText)
compare(signButton.text, qsTr("Approving %1").arg(root.swapAdaptor.fromToken.symbol))
// TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string.
compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
@ -1599,8 +1599,8 @@ Item {
verify(!root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible)
verify(!signButton.enabled)
verify(!signButton.loading)
verify(!signButton.interactive)
verify(!signButton.loadingWithText)
compare(signButton.text, qsTr("Swap"))
compare(maxFeesValue.text, Constants.dummyText)
@ -1612,7 +1612,7 @@ Item {
verify(!root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible)
verify(signButton.enabled)
verify(!signButton.loading)
verify(!signButton.loadingWithText)
compare(signButton.text, qsTr("Swap"))
compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
root.swapAdaptor.swapOutputData.totalFees,

View File

@ -1,6 +1,6 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.14
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@ -36,6 +36,7 @@ Button {
property alias tooltip: tooltip
property bool loading
property bool loadingWithText // loading indicator instead of icon, mutually exclusive with `loading`
property bool interactive: true
property color normalColor
@ -49,15 +50,12 @@ Button {
property int borderWidth: 0
property bool textFillWidth: false
property int radius: size === StatusBaseButton.Size.Tiny ? 6 : 8
property int radius: isRoundIcon ? height/2 : size === StatusBaseButton.Size.Tiny ? 6 : 8
property int size: StatusBaseButton.Size.Large
property int type: StatusBaseButton.Type.Normal
property int textPosition: StatusBaseButton.TextPosition.Right
// use Size.Small as default value to not change old behavior which had default size of 20x20
property int loadingIndicatorSize: StatusBaseButton.Size.Small
property bool isRoundIcon: false
QtObject {
@ -72,10 +70,8 @@ Button {
}
readonly property bool iconOnly: root.display === AbstractButton.IconOnly || root.text === ""
readonly property int iconSize: mapIconSize(root.size)
function mapIconSize(buttonSize) {
switch(buttonSize) {
readonly property int iconSize: {
switch(root.size) {
case StatusBaseButton.Size.Tiny:
return 16
case StatusBaseButton.Size.Small:
@ -136,86 +132,64 @@ Button {
color: {
if (!root.enabled || !root.interactive)
return disabledColor
return !root.loading && (root.hovered || root.highlighted) ? hoverColor : normalColor
return !root.loading && !root.loadingWithText && (root.hovered || root.highlighted) ? hoverColor : normalColor
}
}
contentItem: Item {
implicitWidth: layout.implicitWidth
implicitHeight: layout.implicitHeight
opacity: !root.loading
RowLayout {
id: layout
anchors.centerIn: parent
width: root.textFillWidth ? root.availableWidth : Math.min(root.availableWidth, implicitWidth)
width: root.textFillWidth && !d.iconOnly ? root.availableWidth : Math.min(root.availableWidth, implicitWidth)
height: Math.min(root.availableHeight, implicitHeight)
spacing: root.spacing
Component {
id: baseIcon
StatusIcon {
icon: root.icon.name
rotation: root.asset.rotation
mirror: root.asset.mirror
opacity: !root.loading && root.icon.name !== "" && root.display !== AbstractButton.TextOnly
color: root.icon.color
}
}
Component {
id: roundIcon
StatusRoundIcon {
opacity: !root.loading && root.icon.name !== "" && root.display !== AbstractButton.TextOnly
asset.name: root.icon.name
asset.width: d.iconSize
asset.height: d.iconSize
asset.color: root.icon.color
asset.bgColor: root.asset.bgColor
}
}
Component {
id: text
StatusBaseText {
opacity: !root.loading
font: root.font
text: root.text
color: d.textColor
elide: Text.ElideRight
maximumLineCount: 1
}
}
// text left
Loader {
objectName: "leftTextLoader"
Layout.fillWidth: true
active: root.textPosition === StatusBaseButton.TextPosition.Left && !d.iconOnly
visible: active
sourceComponent: text
}
// loading with text indicator
Loader {
id: iconLoader
objectName: "loadingWithTextIndicator"
active: root.loadingWithText
visible: active
sourceComponent: loadingComponent
}
Layout.preferredWidth: active ? root.icon.width : 0
Layout.preferredHeight: active ? root.icon.height : 0
// decoration
Loader {
objectName: "buttonIcon"
Layout.preferredWidth: root.icon.width
Layout.preferredHeight: root.icon.height
Layout.alignment: Qt.AlignCenter
active: root.icon.name !== ""
active: root.icon.name !== "" && root.display !== AbstractButton.TextOnly && !root.loadingWithText
visible: active
sourceComponent: root.isRoundIcon ? roundIcon : baseIcon
}
// emoji
StatusEmoji {
Layout.preferredWidth: visible ? root.icon.width : 0
Layout.preferredHeight: visible ? root.icon.height : 0
objectName: "buttonEmoji"
Layout.preferredWidth: root.icon.width
Layout.preferredHeight: root.icon.height
Layout.alignment: Qt.AlignCenter
opacity: !root.loading && root.display !== AbstractButton.TextOnly
visible: root.asset.emoji
visible: root.asset.emoji && root.display !== AbstractButton.TextOnly && !root.loadingWithText
emojiId: Emoji.iconId(root.asset.emoji, root.asset.emojiSize) || ""
opacity: !root.enabled || !root.interactive ? 0.4 : 1
}
// text right
Loader {
objectName: "rightTextLoader"
Layout.fillWidth: true
active: root.textPosition === StatusBaseButton.TextPosition.Right && !d.iconOnly
visible: active
@ -225,13 +199,11 @@ Button {
}
Loader {
objectName: "loadingIndicator"
anchors.centerIn: parent
active: root.loading
width: d.mapIconSize(root.loadingIndicatorSize)
height: width
sourceComponent: StatusLoadingIndicator {
color: d.textColor
}
visible: active
sourceComponent: loadingComponent
}
// stop the mouse clicks in the "loading" or non-interactive state w/o disabling the whole button
@ -240,15 +212,62 @@ Button {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.AllButtons
enabled: root.loading || !root.interactive
enabled: root.loading || root.loadingWithText || !root.interactive
onPressed: mouse.accepted = true
onWheel: wheel.accepted = true
cursorShape: root.interactive && !root.loading ? Qt.PointingHandCursor: undefined // always works; 'undefined' resets to default cursor
cursorShape: root.interactive && !root.loading && !root.loadingWithText ? Qt.PointingHandCursor: undefined // always works; 'undefined' resets to default cursor
}
StatusToolTip {
id: tooltip
objectName: "buttonTooltip"
visible: tooltip.text !== "" && root.hovered
offset: -(tooltip.x + tooltip.width/2 - root.width/2)
}
Component {
id: baseIcon
StatusIcon {
icon: root.icon.name
rotation: root.asset.rotation
mirror: root.asset.mirror
color: root.icon.color
}
}
Component {
id: roundIcon
StatusRoundIcon {
asset.name: root.icon.name
asset.width: root.icon.width
asset.height: root.icon.height
asset.color: root.icon.color
asset.bgColor: root.asset.bgColor
}
}
Component {
id: text
StatusBaseText {
objectName: "buttonText"
font: root.font
text: root.text
color: d.textColor
elide: Text.ElideRight
maximumLineCount: 1
horizontalAlignment: root.textFillWidth ? Text.AlignLeft : Text.AlignHCenter
}
}
Component {
id: loadingComponent
StatusLoadingIndicator {
width: root.icon.width
height: root.icon.height
color: d.textColor
}
}
}

View File

@ -86,7 +86,6 @@ Item {
StatusButton {
id: reloadButton
size: StatusBaseButton.Size.Tiny
loadingIndicatorSize: size
height: parent.height
width: height
borderColor: Theme.palette.directColor7

View File

@ -399,12 +399,10 @@ StatusDialog {
loading: root.swapAdaptor.swapProposalLoading
}
}
/* TODO: https://github.com/status-im/status-desktop/issues/15313
will introduce having loading button and showing text on the side*/
StatusButton {
objectName: "signButton"
readonly property string fromTokenSymbol: !!root.swapAdaptor.fromToken ? root.swapAdaptor.fromToken.symbol ?? "" : ""
loading: root.swapAdaptor.approvalPending
loadingWithText: root.swapAdaptor.approvalPending
icon.name: root.swapAdaptor.selectedAccount.migratedToKeycard ? Constants.authenticationIconByType[Constants.LoginType.Keycard]
: Constants.authenticationIconByType[root.loginType]
text: {
@ -421,10 +419,10 @@ StatusDialog {
root.swapAdaptor.swapOutputData.approvalNeeded ?
qsTr("Approve %1 spending cap to Swap").arg(fromTokenSymbol) : ""
disabledColor: Theme.palette.directColor8
enabled: root.swapAdaptor.validSwapProposalReceived &&
editSlippagePanel.valid &&
!d.isError &&
!root.swapAdaptor.approvalPending
interactive: root.swapAdaptor.validSwapProposalReceived &&
editSlippagePanel.valid &&
!d.isError &&
!root.swapAdaptor.approvalPending
onClicked: {
if (root.swapAdaptor.validSwapProposalReceived) {
if (root.swapAdaptor.swapOutputData.approvalNeeded)