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 2.15
|
||||||
import QtQuick.Controls 2.12
|
import QtQuick.Controls 2.15
|
||||||
|
import QtGraphicalEffects 1.15
|
||||||
|
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
import QtGraphicalEffects 1.12
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype LoadingComponent
|
\qmltype LoadingComponent
|
||||||
\inherits Control
|
\inherits Control
|
||||||
\inqmlmodule StatusQ.Components
|
\inqmlmodule StatusQ.Components
|
||||||
\since StatusQ.Components 0.1
|
\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:
|
Example:
|
||||||
|
|
||||||
\qml
|
\qml
|
||||||
|
@ -48,6 +48,7 @@ Control {
|
||||||
color: Theme.palette.statusLoadingHighlight
|
color: Theme.palette.statusLoadingHighlight
|
||||||
radius: root.radius
|
radius: root.radius
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
LinearGradient {
|
LinearGradient {
|
||||||
id: gradient
|
id: gradient
|
||||||
width: 100
|
width: 100
|
||||||
|
@ -62,7 +63,7 @@ Control {
|
||||||
GradientStop { position: 0.8; color: "transparent"}
|
GradientStop { position: 0.8; color: "transparent"}
|
||||||
}
|
}
|
||||||
rotation: 20
|
rotation: 20
|
||||||
NumberAnimation on x {
|
XAnimator on x {
|
||||||
id: animation
|
id: animation
|
||||||
easing.type: Easing.Linear
|
easing.type: Easing.Linear
|
||||||
loops: Animation.Infinite
|
loops: Animation.Infinite
|
||||||
|
|
|
@ -38,6 +38,7 @@ Loader {
|
||||||
property bool hoverEnabled: false
|
property bool hoverEnabled: false
|
||||||
readonly property bool hovered: (sourceComponent === roundedIcon && item) ?
|
readonly property bool hovered: (sourceComponent === roundedIcon && item) ?
|
||||||
item.hovered : false
|
item.hovered : false
|
||||||
|
|
||||||
signal clicked(var mouse)
|
signal clicked(var mouse)
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
@ -91,18 +92,15 @@ Loader {
|
||||||
asset.bgBorderWidth: root.asset.bgBorderWidth
|
asset.bgBorderWidth: root.asset.bgBorderWidth
|
||||||
asset.bgBorderColor: root.asset.bgBorderColor
|
asset.bgBorderColor: root.asset.bgBorderColor
|
||||||
|
|
||||||
signal clicked(var mouse)
|
readonly property alias hovered: mouseArea.containsMouse
|
||||||
|
|
||||||
property alias hovered: mouseArea.containsMouse
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: root.hoverEnabled
|
hoverEnabled: root.hoverEnabled
|
||||||
cursorShape: loading ? Qt.ArrowCursor
|
cursorShape: !loading && root.hoverEnabled ? Qt.PointingHandCursor : undefined
|
||||||
: Qt.PointingHandCursor
|
onClicked: root.clicked(mouse)
|
||||||
onClicked: parent.clicked(mouse)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,14 +166,4 @@ Loader {
|
||||||
width: root.asset.isImage ? root.asset.width : root.asset.bgWidth
|
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 2.15
|
||||||
import QtQuick.Layouts 1.13
|
import QtQuick.Layouts 1.15
|
||||||
import QtQuick.Controls 2.14
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
import StatusQ.Core 0.1
|
import StatusQ.Core 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
|
@ -18,20 +18,23 @@ Control {
|
||||||
property alias rightComponent: rightComponent.sourceComponent
|
property alias rightComponent: rightComponent.sourceComponent
|
||||||
property bool loading: false
|
property bool loading: false
|
||||||
property int secondarylabelMaxWidth: 100
|
property int secondarylabelMaxWidth: 100
|
||||||
|
|
||||||
property color backgroundColor: "transparent"
|
property color backgroundColor: "transparent"
|
||||||
|
property color bgBorderColor: Theme.palette.baseColor2
|
||||||
|
property real bgRadius: 36
|
||||||
|
|
||||||
property Component customBackground: Component {
|
property Component customBackground: Component {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: root.backgroundColor
|
color: root.backgroundColor
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: Theme.palette.baseColor2
|
border.color: root.bgBorderColor
|
||||||
radius: 36
|
radius: root.bgRadius
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
property var loadingComponent: Component { LoadingComponent {} }
|
property var loadingComponent: Component { LoadingComponent { radius: root.bgRadius } }
|
||||||
}
|
}
|
||||||
|
|
||||||
horizontalPadding: 12
|
horizontalPadding: 12
|
||||||
|
|
|
@ -12,6 +12,7 @@ CurrencyAmountInput 1.0 CurrencyAmountInput.qml
|
||||||
EmojiHash 1.0 EmojiHash.qml
|
EmojiHash 1.0 EmojiHash.qml
|
||||||
EmptyShapeRectangleFooterListView 1.0 EmptyShapeRectangleFooterListView.qml
|
EmptyShapeRectangleFooterListView 1.0 EmptyShapeRectangleFooterListView.qml
|
||||||
ErrorDetails 1.0 ErrorDetails.qml
|
ErrorDetails 1.0 ErrorDetails.qml
|
||||||
|
ErrorTag 1.0 ErrorTag.qml
|
||||||
FoldableHeader 1.0 FoldableHeader.qml
|
FoldableHeader 1.0 FoldableHeader.qml
|
||||||
FormGroup 1.0 FormGroup.qml
|
FormGroup 1.0 FormGroup.qml
|
||||||
GetSyncCodeDesktopInstructions 1.0 GetSyncCodeDesktopInstructions.qml
|
GetSyncCodeDesktopInstructions 1.0 GetSyncCodeDesktopInstructions.qml
|
||||||
|
|
Loading…
Reference in New Issue