feat: [UI - Swap] Create tag error component
- created a new component (`ErrorTag`) based on the existing `InformationTag`, suitable for displaying a row of icon (optional), text and (optional) button in red/danger color - add ErrorTagPage.qml to StoryBook - add some basic QML tests - InformationTag: make more properties customizable, use the same `bgRadius` consistently - StatusSmartIdenticon: some fixes for the MouseArea hover/click behavior Fixes #14792
This commit is contained in:
parent
df3f9984a8
commit
a2e85bb3eb
|
@ -0,0 +1,95 @@
|
|||
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
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
|
||||
SplitView {
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
Pane {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.baseColor4
|
||||
}
|
||||
|
||||
ErrorTag {
|
||||
width: ctrlWidth.value || implicitWidth
|
||||
anchors.centerIn: parent
|
||||
text: ctrlText.text
|
||||
buttonText: ctrlButtonText.text
|
||||
asset.name: ctrlAssetName.text
|
||||
loading: ctrlLoading.checked
|
||||
onButtonClicked: logs.logEvent("ErrorTag::onButtonClicked", [], arguments)
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
SplitView.fillHeight: true
|
||||
SplitView.preferredWidth: 300
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Text:" }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlText
|
||||
text: "Insufficient funds to pay gas fees"
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Button text:" }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlButtonText
|
||||
text: "Buy ETH"
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Asset name:" }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id: ctrlAssetName
|
||||
text: "warning"
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label { text: "Width:" }
|
||||
SpinBox {
|
||||
id: ctrlWidth
|
||||
from: 0
|
||||
to: 400
|
||||
value: 0 // 0 == implicitWidth
|
||||
stepSize: 20
|
||||
textFromValue: function(value, locale) { return value === 0 ? "Implicit" : value }
|
||||
}
|
||||
}
|
||||
Switch {
|
||||
id: ctrlLoading
|
||||
text: "Loading"
|
||||
}
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// category: Controls
|
||||
|
||||
// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3413-311788&t=D3qGKqNjDBuLEEaD-0
|
|
@ -0,0 +1,68 @@
|
|||
import QtQuick 2.15
|
||||
import QtTest 1.15
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
ErrorTag {
|
||||
anchors.centerIn: parent
|
||||
text: "Insufficient funds to pay gas fees"
|
||||
}
|
||||
}
|
||||
|
||||
SignalSpy {
|
||||
id: signalSpy
|
||||
target: controlUnderTest
|
||||
signalName: "buttonClicked"
|
||||
}
|
||||
|
||||
property ErrorTag controlUnderTest: null
|
||||
|
||||
TestCase {
|
||||
name: "ErrorTag"
|
||||
when: windowShown
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
signalSpy.clear()
|
||||
}
|
||||
|
||||
function test_basicGeometry() {
|
||||
verify(!!controlUnderTest)
|
||||
verify(controlUnderTest.width > 0)
|
||||
verify(controlUnderTest.height > 0)
|
||||
}
|
||||
|
||||
function test_noDefaultButton() {
|
||||
verify(!!controlUnderTest)
|
||||
const button = findChild(controlUnderTest, "rightComponentButton")
|
||||
tryCompare(button, "visible", false)
|
||||
}
|
||||
|
||||
function test_buttonClick() {
|
||||
verify(!!controlUnderTest)
|
||||
controlUnderTest.buttonText = "Buy crypto"
|
||||
const button = findChild(controlUnderTest, "rightComponentButton")
|
||||
verify(!!button)
|
||||
tryCompare(button, "visible", true)
|
||||
mouseClick(button)
|
||||
tryCompare(signalSpy, "count", 1)
|
||||
}
|
||||
|
||||
function test_loadingNotClickable() {
|
||||
verify(!!controlUnderTest)
|
||||
controlUnderTest.loading = true
|
||||
const button = findChild(controlUnderTest, "rightComponentButton")
|
||||
verify(!!button)
|
||||
tryCompare(button, "visible", false)
|
||||
mouseClick(button)
|
||||
tryCompare(signalSpy, "count", 0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
/*!
|
||||
\qmltype LoadingComponent
|
||||
\inherits Control
|
||||
\inqmlmodule StatusQ.Components
|
||||
\since StatusQ.Components 0.1
|
||||
\brief A componet that can be used to adding a loading state to a widget
|
||||
\brief A component that can be used to adding a loading state to a widget
|
||||
Example:
|
||||
|
||||
\qml
|
||||
|
@ -48,6 +48,7 @@ Control {
|
|||
color: Theme.palette.statusLoadingHighlight
|
||||
radius: root.radius
|
||||
visible: false
|
||||
|
||||
LinearGradient {
|
||||
id: gradient
|
||||
width: 100
|
||||
|
@ -62,7 +63,7 @@ Control {
|
|||
GradientStop { position: 0.8; color: "transparent"}
|
||||
}
|
||||
rotation: 20
|
||||
NumberAnimation on x {
|
||||
XAnimator on x {
|
||||
id: animation
|
||||
easing.type: Easing.Linear
|
||||
loops: Animation.Infinite
|
||||
|
|
|
@ -38,6 +38,7 @@ Loader {
|
|||
property bool hoverEnabled: false
|
||||
readonly property bool hovered: (sourceComponent === roundedIcon && item) ?
|
||||
item.hovered : false
|
||||
|
||||
signal clicked(var mouse)
|
||||
|
||||
Component {
|
||||
|
@ -91,18 +92,15 @@ Loader {
|
|||
asset.bgBorderWidth: root.asset.bgBorderWidth
|
||||
asset.bgBorderColor: root.asset.bgBorderColor
|
||||
|
||||
signal clicked(var mouse)
|
||||
|
||||
property alias hovered: mouseArea.containsMouse
|
||||
readonly property alias hovered: mouseArea.containsMouse
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: root.hoverEnabled
|
||||
cursorShape: loading ? Qt.ArrowCursor
|
||||
: Qt.PointingHandCursor
|
||||
onClicked: parent.clicked(mouse)
|
||||
cursorShape: !loading && root.hoverEnabled ? Qt.PointingHandCursor : undefined
|
||||
onClicked: root.clicked(mouse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,14 +166,4 @@ Loader {
|
|||
width: root.asset.isImage ? root.asset.width : root.asset.bgWidth
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: item
|
||||
enabled: status === Loader.Ready
|
||||
ignoreUnknownSignals: true
|
||||
|
||||
function onClicked(mouse) {
|
||||
root.clicked(mouse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
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
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
InformationTag {
|
||||
id: root
|
||||
|
||||
property string text
|
||||
property string buttonText
|
||||
|
||||
signal buttonClicked()
|
||||
|
||||
implicitHeight: 33
|
||||
leftPadding: 10
|
||||
rightPadding: 4
|
||||
verticalPadding: 4
|
||||
spacing: 6
|
||||
|
||||
backgroundColor: Theme.palette.dangerColor3
|
||||
bgBorderColor: Theme.palette.dangerColor2
|
||||
|
||||
QtObject {
|
||||
id: priv
|
||||
|
||||
readonly property int fontPixelSize: Theme.tertiaryTextFontSize
|
||||
readonly property color foregroundColor: Theme.palette.dangerColor1
|
||||
}
|
||||
|
||||
asset {
|
||||
name: "warning"
|
||||
color: priv.foregroundColor
|
||||
}
|
||||
|
||||
tagPrimaryLabel.text: root.text
|
||||
tagPrimaryLabel.color: priv.foregroundColor
|
||||
tagPrimaryLabel.font.pixelSize: priv.fontPixelSize
|
||||
tagPrimaryLabel.elide: Text.ElideRight
|
||||
|
||||
// NB: regular binding won't work as `tagPrimaryLabel` is an alias
|
||||
Binding {
|
||||
target: tagPrimaryLabel
|
||||
property: "Layout.fillWidth"
|
||||
value: true
|
||||
}
|
||||
|
||||
rightComponent: StatusButton {
|
||||
objectName: "rightComponentButton"
|
||||
horizontalPadding: 8
|
||||
|
||||
width: visible || root.loading ? implicitWidth : 0
|
||||
visible: !!text
|
||||
|
||||
size: StatusBaseButton.Size.Tiny
|
||||
font.pixelSize: priv.fontPixelSize
|
||||
type: StatusBaseButton.Type.Danger
|
||||
normalColor: priv.foregroundColor
|
||||
hoverColor: Theme.palette.hoverColor(normalColor)
|
||||
textColor: Theme.palette.white
|
||||
radius: root.bgRadius
|
||||
text: root.buttonText
|
||||
onClicked: root.buttonClicked()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
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
|
||||
|
@ -18,20 +18,23 @@ Control {
|
|||
property alias rightComponent: rightComponent.sourceComponent
|
||||
property bool loading: false
|
||||
property int secondarylabelMaxWidth: 100
|
||||
|
||||
property color backgroundColor: "transparent"
|
||||
property color bgBorderColor: Theme.palette.baseColor2
|
||||
property real bgRadius: 36
|
||||
|
||||
property Component customBackground: Component {
|
||||
Rectangle {
|
||||
color: root.backgroundColor
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
radius: 36
|
||||
border.color: root.bgBorderColor
|
||||
radius: root.bgRadius
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var loadingComponent: Component { LoadingComponent {} }
|
||||
property var loadingComponent: Component { LoadingComponent { radius: root.bgRadius } }
|
||||
}
|
||||
|
||||
horizontalPadding: 12
|
||||
|
|
|
@ -12,6 +12,7 @@ CurrencyAmountInput 1.0 CurrencyAmountInput.qml
|
|||
EmojiHash 1.0 EmojiHash.qml
|
||||
EmptyShapeRectangleFooterListView 1.0 EmptyShapeRectangleFooterListView.qml
|
||||
ErrorDetails 1.0 ErrorDetails.qml
|
||||
ErrorTag 1.0 ErrorTag.qml
|
||||
FoldableHeader 1.0 FoldableHeader.qml
|
||||
FormGroup 1.0 FormGroup.qml
|
||||
GetSyncCodeDesktopInstructions 1.0 GetSyncCodeDesktopInstructions.qml
|
||||
|
|
Loading…
Reference in New Issue