Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [UI - Swap] Create row radiobutton component with custom field #14887

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions storybook/pages/SlippageSelectorPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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 utils 1.0

import Storybook 1.0

SplitView {
orientation: Qt.Horizontal

Logs { id: logs }

Pane {
SplitView.fillWidth: true
SplitView.fillHeight: true

SlippageSelector {
id: slippageSelector
anchors.centerIn: parent
}
}

LogsAndControlsPanel {
SplitView.fillHeight: true
SplitView.preferredWidth: 300

logsView.logText: logs.logText

ColumnLayout {
anchors.fill: parent

Label {
Layout.fillWidth: true
font.weight: Font.Medium
text: "Value: %1".arg(slippageSelector.value)
}
Label {
Layout.fillWidth: true
font.weight: Font.Medium
text: "Valid: %1".arg(slippageSelector.valid ? "true" : "false")
}

ColumnLayout {
Repeater {
model: [0.1, 0.5, 0.24, 0.8, 120.84]

Button {
text: "set " + modelData
onClicked: slippageSelector.value = modelData
}
}
}

Button {
text: "Reset defaults"
onClicked: slippageSelector.reset()
}

Item { Layout.fillHeight: true }
}
}
}

// category: Controls

// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3409-257346&t=ENK93cK7GyTqEV8S-0
// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3410-262441&t=ENK93cK7GyTqEV8S-0
71 changes: 71 additions & 0 deletions storybook/pages/StatusButtonRowPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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 utils 1.0

import Storybook 1.0

SplitView {
orientation: Qt.Horizontal

Logs { id: logs }

QtObject {
id: d
readonly property var values: [0.1, 0.5, 0.7, 1] // predefined values
}

ListModel {
caybro marked this conversation as resolved.
Show resolved Hide resolved
id: valuesModel
}

Component.onCompleted: {
valuesModel.append(d.values.map(i => ({ text: "%L1".arg(i), value: i })))
}

Pane {
SplitView.fillWidth: true
SplitView.fillHeight: true

StatusButtonRow {
id: buttonRow
anchors.centerIn: parent
model: valuesModel
}
}

LogsAndControlsPanel {
SplitView.fillHeight: true
SplitView.preferredWidth: 300

logsView.logText: logs.logText

ColumnLayout {
anchors.fill: parent

Label {
Layout.fillWidth: true
font.weight: Font.Medium
text: "Raw model: %1".arg(d.values)
}

Label {
Layout.fillWidth: true
font.weight: Font.Medium
text: "Value: %1".arg(buttonRow.value)
}

Item { Layout.fillHeight: true }
}
}
}

// category: Controls

// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3409-257346&t=ENK93cK7GyTqEV8S-0
// https://www.figma.com/design/TS0eQX9dAZXqZtELiwKIoK/Swap---Milestone-1?node-id=3410-262441&t=ENK93cK7GyTqEV8S-0
131 changes: 131 additions & 0 deletions storybook/qmlTests/tests/tst_SlippageSelector.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import QtQuick 2.15
import QtTest 1.15

import StatusQ.Controls 0.1

import shared.controls 1.0

Item {
id: root
width: 600
height: 400

Component {
id: componentUnderTest
SlippageSelector {
anchors.centerIn: parent
}
}

property SlippageSelector controlUnderTest: null

TestCase {
name: "SlippageSelector"
when: windowShown

function init() {
controlUnderTest = createTemporaryObject(componentUnderTest, root)
}

function test_basicSetup() {
verify(!!controlUnderTest)
verify(controlUnderTest.width > 0)
verify(controlUnderTest.height > 0)
verify(controlUnderTest.valid)
}

function test_selectPresetValues() {
verify(!!controlUnderTest)
const buttonsRepeater = findChild(controlUnderTest, "buttonsRepeater")
verify(!!buttonsRepeater)
waitForRendering(buttonsRepeater)
for (let i = 0; i < buttonsRepeater.count; i++) {
const button = buttonsRepeater.itemAt(i)
verify(!!button)
mouseClick(button)
tryCompare(button, "checked", true)
tryCompare(button, "type", StatusBaseButton.Type.Primary)
tryCompare(controlUnderTest, "value", button.value)
verify(controlUnderTest.valid)
}
}

function test_setAndTypeCustomValue() {
verify(!!controlUnderTest)
const customButton = findChild(controlUnderTest, "customButton")
verify(!!customButton)
mouseClick(customButton)
const customInput = findChild(controlUnderTest, "customInput")
verify(!!customInput)
tryCompare(customInput, "cursorVisible", true)

// input "1.42"
keyClick(Qt.Key_1)
keyClick(Qt.Key_Period)
keyClick(Qt.Key_4)
keyClick(Qt.Key_2)

tryCompare(controlUnderTest, "value", 1.42)
verify(controlUnderTest.valid)

// delete contents (4x)
keyClick(Qt.Key_Backspace)
keyClick(Qt.Key_Backspace)
keyClick(Qt.Key_Backspace)
keyClick(Qt.Key_Backspace)

tryCompare(customInput, "text", "")
tryCompare(customInput, "valid", false)
tryCompare(controlUnderTest, "valid", false)

// click again the first button
const buttonsRepeater = findChild(controlUnderTest, "buttonsRepeater")
verify(!!buttonsRepeater)
waitForRendering(buttonsRepeater)
const firstButton = buttonsRepeater.itemAt(0)
verify(!!firstButton)
mouseClick(firstButton)
tryCompare(controlUnderTest, "value", firstButton.value)
verify(controlUnderTest.valid)
}

function test_setCustomValue() {
const theValue = 1.42

verify(!!controlUnderTest)
verify(controlUnderTest.valid)
controlUnderTest.value = theValue

const customInput = findChild(controlUnderTest, "customInput")
verify(!!customInput)
tryCompare(customInput, "cursorVisible", true)
tryCompare(customInput, "value", theValue)

verify(controlUnderTest.value, theValue)
verify(controlUnderTest.valid)
}

function test_resetDefaults() {
verify(!!controlUnderTest)
const initialValue = controlUnderTest.value
const buttonsRepeater = findChild(controlUnderTest, "buttonsRepeater")
verify(!!buttonsRepeater)
waitForRendering(buttonsRepeater)
const firstButton = buttonsRepeater.itemAt(0)
waitForRendering(firstButton)
tryCompare(firstButton, "visible", true)
mouseClick(firstButton)
tryCompare(controlUnderTest, "value", firstButton.value)
caybro marked this conversation as resolved.
Show resolved Hide resolved

controlUnderTest.reset()
tryCompare(controlUnderTest, "value", initialValue)
verify(controlUnderTest.valid)

const customButton = findChild(controlUnderTest, "customButton")
tryCompare(customButton, "visible", true)

const customInput = findChild(controlUnderTest, "customInput")
tryCompare(customInput, "visible", false)
}
}
}
40 changes: 40 additions & 0 deletions ui/StatusQ/src/StatusQ/Controls/StatusButtonRow.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

import StatusQ.Core 0.1
import StatusQ.Controls 0.1

RowLayout {
id: root

property string textRole: "text"
property string valueRole: "value"

property alias model: repeater.model
property var value: null

spacing: 8

Repeater {
id: repeater

objectName: "buttonsRepeater"

delegate: StatusButton {
readonly property var value: model[root.valueRole]

Layout.minimumWidth: 100
Layout.fillWidth: true

type: checked ? StatusBaseButton.Type.Primary
: StatusBaseButton.Type.Normal

checkable: true
checked: value === root.value
text: model[root.textRole]

onClicked: root.value = value
}
}
}
1 change: 1 addition & 0 deletions ui/StatusQ/src/StatusQ/Controls/qmldir
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ StatusTabBarIconButton 0.1 StatusTabBarIconButton.qml
StatusToolTip 0.1 StatusToolTip.qml
StatusBaseButton 0.1 StatusBaseButton.qml
StatusButton 0.1 StatusButton.qml
StatusButtonRow 0.1 StatusButtonRow.qml
StatusFlatButton 0.1 StatusFlatButton.qml
StatusRoundButton 0.1 StatusRoundButton.qml
StatusFlatRoundButton 0.1 StatusFlatRoundButton.qml
Expand Down
1 change: 1 addition & 0 deletions ui/StatusQ/src/statusq.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<file>StatusQ/Controls/StatusBaseInput.qml</file>
<file>StatusQ/Controls/StatusBlockProgressBar.qml</file>
<file>StatusQ/Controls/StatusButton.qml</file>
<file>StatusQ/Controls/StatusButtonRow.qml</file>
<file>StatusQ/Controls/StatusChatCommandButton.qml</file>
<file>StatusQ/Controls/StatusChatInfoButton.qml</file>
<file>StatusQ/Controls/StatusChatListCategoryItemButton.qml</file>
Expand Down
8 changes: 4 additions & 4 deletions ui/imports/shared/controls/CurrencyAmountInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import utils 1.0
/*!
\qmltype CurrencyAmountInput
\inherits TextField
\brief Provides a text input field that accepts a numeric value, with optional currency symbol ("USD").
\brief Provides a text input field that accepts a numeric value, with optional (currency) symbol (defaults to "USD").
Utilizes a builtin DoubleValidator to validate the user's input.
It accepts both the native decimal separator and optionally a period (`.`) for locales that don't use this.
\inqmlmodule shared.controls 1.0
Expand Down Expand Up @@ -91,11 +91,11 @@ TextField {
background: Rectangle {
radius: Style.current.radius
color: Theme.palette.statusAppNavBar.backgroundColor
border.width: root.cursorVisible || root.hovered || !root.valid ? 1 : 0
border.width: 1
border.color: {
if (!root.valid)
if (!root.valid && (root.focus || root.cursorVisible))
return Theme.palette.dangerColor1
if (root.cursorVisible)
if (root.cursorVisible || root.focus)
return Theme.palette.primaryColor1
if (root.hovered)
return Theme.palette.primaryColor2
Expand Down
Loading