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:
parent
8dade32a39
commit
e3dae7e1db
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,6 @@ Item {
|
|||
StatusButton {
|
||||
id: reloadButton
|
||||
size: StatusBaseButton.Size.Tiny
|
||||
loadingIndicatorSize: size
|
||||
height: parent.height
|
||||
width: height
|
||||
borderColor: Theme.palette.directColor7
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue