diff --git a/storybook/pages/RouterErrorTagPage.qml b/storybook/pages/RouterErrorTagPage.qml new file mode 100644 index 0000000000..59694ab31b --- /dev/null +++ b/storybook/pages/RouterErrorTagPage.qml @@ -0,0 +1,80 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 + +import Storybook 1.0 + +import utils 1.0 + +import AppLayouts.Wallet.controls 1.0 + +SplitView { + id: root + + orientation: Qt.Vertical + + Rectangle { + SplitView.fillHeight: true + SplitView.fillWidth: true + color: Theme.palette.baseColor3 + RouterErrorTag { + anchors.centerIn: parent + width: 400 + + errorTitle: ctrlText.text + buttonText: ctrlButtonText.text + errorDetails: ctrlErrorDetails.text + expandable: expandableCheckBox.checked + } + } + + Pane { + ColumnLayout { + CheckBox { + id: expandableCheckBox + text: "expandable" + } + RowLayout { + Layout.fillWidth: true + Label { text: "Text:" } + TextField { + id: ctrlText + Layout.fillWidth: true + text: "Not enough ETH to pay gas fees" + } + } + RowLayout { + Layout.fillWidth: true + Label { text: "Button text:" } + TextField { + id: ctrlButtonText + Layout.fillWidth: true + text: "Add ETH" + } + } + RowLayout { + Layout.fillWidth: true + Label { text: "Asset name:" } + TextField { + id: ctrlAssetName + Layout.fillWidth: true + text: "warning" + } + } + RowLayout { + Layout.fillWidth: true + Label { text: "Error Details:" } + TextField { + id: ctrlErrorDetails + Layout.fillWidth: true + text: "Error Details will be displayed here" + } + } + } + } +} + +// category: Views diff --git a/storybook/pages/SendModalFooterPage.qml b/storybook/pages/SendModalFooterPage.qml index e0cafc69fd..a3fc91da66 100644 --- a/storybook/pages/SendModalFooterPage.qml +++ b/storybook/pages/SendModalFooterPage.qml @@ -1,11 +1,13 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 +import QtQml.Models 2.15 import StatusQ.Core.Theme 0.1 import Storybook 1.0 import AppLayouts.Wallet.views 1.0 +import AppLayouts.Wallet.controls 1.0 SplitView { orientation: Qt.Vertical @@ -25,6 +27,22 @@ SplitView { error: errorCheckbox.checked onReviewSendClicked: logs.logEvent("review send clicked") + + errorTags: errorCheckbox.checked ? errorTagsModel: null + } + } + + ObjectModel { + id: errorTagsModel + RouterErrorTag { + errorTitle: "Error 1" + buttonText: "Add ETH" + } + RouterErrorTag { + errorTitle: "Error 2" + buttonText: "Add ETH" + errorDetails: "Details will appear here" + expandable: true } } diff --git a/storybook/pages/StatusDialogPage.qml b/storybook/pages/StatusDialogPage.qml index 245cd41312..f413bee669 100644 --- a/storybook/pages/StatusDialogPage.qml +++ b/storybook/pages/StatusDialogPage.qml @@ -12,6 +12,8 @@ import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Popups.Dialog 0.1 +import AppLayouts.Wallet.controls 1.0 + SplitView { id: root @@ -138,10 +140,26 @@ SplitView { } } } + + errorTags: ctrlAddErrorTags.checked ? errorTagsModel: null } } } + ObjectModel { + id: errorTagsModel + RouterErrorTag { + errorTitle: "Error 1" + buttonText: "Add ETH" + } + RouterErrorTag { + errorTitle: "Error 2" + buttonText: "Add ETH" + errorDetails: "Details will appear here" + expandable: true + } + } + LogsAndControlsPanel { SplitView.preferredWidth: 320 SplitView.fillHeight: true @@ -238,6 +256,10 @@ SplitView { id: ctrlHeaderDropShadow text: "Header drop shadow" } + CheckBox { + id: ctrlAddErrorTags + text: "Add error tags" + } } } } diff --git a/storybook/qmlTests/tests/tst_RouterErrorTag.qml b/storybook/qmlTests/tests/tst_RouterErrorTag.qml new file mode 100644 index 0000000000..62095c4846 --- /dev/null +++ b/storybook/qmlTests/tests/tst_RouterErrorTag.qml @@ -0,0 +1,125 @@ +import QtQuick 2.15 +import QtTest 1.15 + +import AppLayouts.Wallet.controls 1.0 + +Item { + id: root + width: 600 + height: 400 + + Component { + id: componentUnderTest + RouterErrorTag { + anchors.centerIn: parent + errorTitle: "Not enough ETH to pay gas fees" + } + } + + SignalSpy { + id: signalSpy + target: controlUnderTest + signalName: "buttonClicked" + } + + property RouterErrorTag controlUnderTest: null + + TestCase { + name: "RouterErrorTag" + 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_DefaultState() { + verify(!!controlUnderTest) + const errorTitle = findChild(controlUnderTest, "errorTitle") + verify(!!errorTitle) + verify(errorTitle.visible) + const button = findChild(controlUnderTest, "addBalanceButton") + verify(!!button) + verify(!button.visible) + const expandButton = findChild(controlUnderTest, "expandButton") + verify(!!expandButton) + verify(!expandButton.visible) + const errorDetails = findChild(controlUnderTest, "errorDetails") + verify(!!errorDetails) + verify(!errorDetails.visible) + } + + function test_correctWidthWithButtonOrWithout() { + verify(!!controlUnderTest) + waitForRendering(controlUnderTest) + const origWidth = controlUnderTest.width + + controlUnderTest.buttonText = "Add assets" + waitForRendering(controlUnderTest) + const widthWithButton = controlUnderTest.width + verify(widthWithButton > origWidth) + + controlUnderTest.buttonText = "" + waitForRendering(controlUnderTest) + verify(controlUnderTest.width < widthWithButton) + } + + function test_addButtonClick() { + verify(!!controlUnderTest) + controlUnderTest.buttonText = "Add assets" + const button = findChild(controlUnderTest, "addBalanceButton") + verify(!!button) + verify(button.visible) + mouseClick(button) + tryCompare(signalSpy, "count", 1) + } + + function test_detailsVisibleOnceItHasValidText() { + verify(!!controlUnderTest) + const errorDetails = findChild(controlUnderTest, "errorDetails") + verify(!!errorDetails) + verify(!errorDetails.visible) + + controlUnderTest.errorDetails = "Added some details here" + verify(errorDetails.visible) + } + + function test_expandableOption() { + verify(!!controlUnderTest) + controlUnderTest.buttonText = "Add assets" + controlUnderTest.errorDetails = "Added some details here" + + const errorTitle = findChild(controlUnderTest, "errorTitle") + verify(!!errorTitle) + const button = findChild(controlUnderTest, "addBalanceButton") + verify(!!button) + const expandButton = findChild(controlUnderTest, "expandButton") + verify(!!expandButton) + const errorDetails = findChild(controlUnderTest, "errorDetails") + verify(!!errorDetails) + + controlUnderTest.expandable = true + verify(errorTitle.visible) + verify(!button.visible) + verify(expandButton.visible) + compare(expandButton.text, qsTr("+ Show details")) + verify(!errorDetails.visible) + + mouseClick(expandButton) + compare(expandButton.text, qsTr("- Hide details")) + verify(errorDetails.visible) + + controlUnderTest.expandable = false + verify(errorTitle.visible) + verify(button.visible) + verify(!expandButton.visible) + verify(errorDetails.visible) + } + } +} diff --git a/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialogFooter.qml b/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialogFooter.qml index be105ae1c2..ef1bf6118e 100644 --- a/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialogFooter.qml +++ b/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialogFooter.qml @@ -11,6 +11,7 @@ Rectangle { property ObjectModel leftButtons property ObjectModel rightButtons + property ObjectModel errorTags property int spacing: 5 property bool dropShadowEnabled @@ -34,34 +35,59 @@ Rectangle { visible: !root.dropShadowEnabled } - RowLayout { + ColumnLayout { id: layout - spacing: root.spacing - clip: true - anchors { fill: parent margins: 16 } + spacing: 8 + Repeater { - model: root.leftButtons + Layout.topMargin: 4 + model: root.errorTags onItemAdded: { item.Layout.fillHeight = true - item.Layout.fillWidth = Qt.binding(() => root.width < root.implicitWidth) + item.Layout.fillWidth = true } } - Item { + StatusDialogDivider { + Layout.topMargin: 12 Layout.fillWidth: true + + color: Theme.palette.directColor8 + + visible: !!root.errorTags && root.errorTags.count > 0 } - Repeater { - model: root.rightButtons - onItemAdded: { - item.Layout.fillHeight = true - item.Layout.fillWidth = Qt.binding(() => root.width < root.implicitWidth) + RowLayout { + + Layout.fillWidth: true + + spacing: root.spacing + clip: true + + Repeater { + model: root.leftButtons + onItemAdded: { + item.Layout.fillHeight = true + item.Layout.fillWidth = Qt.binding(() => root.width < root.implicitWidth) + } + } + + Item { + Layout.fillWidth: true + } + + Repeater { + model: root.rightButtons + onItemAdded: { + item.Layout.fillHeight = true + item.Layout.fillWidth = Qt.binding(() => root.width < root.implicitWidth) + } } } } diff --git a/ui/app/AppLayouts/Wallet/controls/RouterErrorTag.qml b/ui/app/AppLayouts/Wallet/controls/RouterErrorTag.qml new file mode 100644 index 0000000000..f11b9a0218 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/controls/RouterErrorTag.qml @@ -0,0 +1,108 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 + +Control { + id: root + + property alias errorTitle: errorTitle.text + property alias buttonText: addBalanceButton.text + property alias errorDetails: errorDetails.text + property alias icon: errorIcon.icon + property bool expandable + + signal buttonClicked() + + padding: Theme.halfPadding + leftPadding: 12 + + background: Rectangle { + radius: 8 + color: Theme.palette.dangerColor3 + border.width: 1 + border.color: Theme.palette.dangerColor2 + } + + contentItem: ColumnLayout { + RowLayout { + spacing: Theme.halfPadding + StatusIcon { + id: errorIcon + + objectName: "errorIcon" + + Layout.alignment: Qt.AlignVCenter + + icon: "warning" + color: Theme.palette.dangerColor1 + } + StatusBaseText { + id: errorTitle + + objectName: "errorTitle" + + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + + color: Theme.palette.dangerColor1 + font.pixelSize: Theme.additionalTextSize + } + StatusButton { + id: addBalanceButton + + objectName: "addBalanceButton" + + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + + size: StatusBaseButton.Size.Small + type: StatusBaseButton.Type.Danger + normalColor: Theme.palette.dangerColor1 + hoverColor: Theme.palette.hoverColor(normalColor) + textColor: Theme.palette.indirectColor1 + + onClicked: root.buttonClicked() + + visible: !root.expandable && !!text + } + StatusButton { + id: expandButton + + objectName: "expandButton" + + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + + checkable: true + size: StatusBaseButton.Size.Small + normalColor: Theme.palette.transparent + hoverColor: Theme.palette.transparent + textColor: Theme.palette.dangerColor1 + textHoverColor: Theme.palette.hoverColor(textColor) + font.pixelSize: Theme.tertiaryTextFontSize + font.weight: Font.Normal + text: checked ? qsTr("- Hide details") : qsTr("+ Show details") + + visible: root.expandable + } + } + StatusBaseText { + id: errorDetails + + objectName: "errorDetails" + + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.leftMargin: errorIcon.width + Theme.halfPadding + + color: Theme.palette.dangerColor1 + font.pixelSize: Theme.additionalTextSize + elide: Text.ElideRight + + visible: root.expandable ? expandButton.checked : !!text + } + } +} diff --git a/ui/app/AppLayouts/Wallet/controls/qmldir b/ui/app/AppLayouts/Wallet/controls/qmldir index e033e8ca1d..a57e419927 100644 --- a/ui/app/AppLayouts/Wallet/controls/qmldir +++ b/ui/app/AppLayouts/Wallet/controls/qmldir @@ -26,3 +26,4 @@ SwapProvidersTermsAndConditionsText 1.0 SwapProvidersTermsAndConditionsText.qml TokenSelector 1.0 TokenSelector.qml TokenSelectorButton 1.0 TokenSelectorButton.qml TokenSelectorCompactButton 1.0 TokenSelectorCompactButton.qml +RouterErrorTag 1.0 RouterErrorTag.qml diff --git a/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml index a7f066aac0..458e23333c 100644 --- a/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml +++ b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml @@ -22,7 +22,6 @@ StatusDialogFooter { // Signal to propogate Send clicked signal reviewSendClicked() - implicitHeight: 82 spacing: Theme.bigPadding color: Theme.palette.baseColor3 dropShadowEnabled: true