mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-07-17 12:29:27 +00:00
feat(amm-ui): reshape liquidity position layout
Add responsive step navigation and a wider deposit workspace while preserving the shared create-pool and add-liquidity flow.
This commit is contained in:
parent
4a9ea6348d
commit
7c98ca7b42
@ -39,6 +39,9 @@ AmmActionCard {
|
||||
property string tokenResolutionMessage: ""
|
||||
property string confirmedPoolStatus: ""
|
||||
property var activePoolQuote: ({})
|
||||
property string headingText: qsTr("New position")
|
||||
property string headingDetail: ""
|
||||
property bool showRefreshAction: true
|
||||
|
||||
readonly property var quotePayload: root.flowState.quote || ({})
|
||||
readonly property bool contextLoading: root.flowState.contextLoading === true
|
||||
@ -101,7 +104,9 @@ AmmActionCard {
|
||||
signal draftChanged
|
||||
signal refreshRequested
|
||||
|
||||
implicitHeight: content.implicitHeight + 32
|
||||
readonly property int contentPadding: width >= 600 ? 24 : 16
|
||||
|
||||
implicitHeight: content.implicitHeight + root.contentPadding * 2
|
||||
implicitWidth: 480
|
||||
|
||||
Component.onCompleted: Qt.callLater(root.ensurePair)
|
||||
@ -148,7 +153,7 @@ AmmActionCard {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
anchors.margins: root.contentPadding
|
||||
spacing: 16
|
||||
|
||||
RowLayout {
|
||||
@ -160,7 +165,7 @@ AmmActionCard {
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
text: qsTr("New position")
|
||||
text: root.headingText
|
||||
color: root.theme.colors.textPrimary
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.DemiBold
|
||||
@ -168,7 +173,8 @@ AmmActionCard {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.contextStatusText()
|
||||
text: root.headingDetail.length > 0
|
||||
? root.headingDetail : root.contextStatusText()
|
||||
color: root.theme.colors.textSecondary
|
||||
font.pixelSize: 12
|
||||
elide: Text.ElideRight
|
||||
@ -190,6 +196,7 @@ AmmActionCard {
|
||||
Layout.preferredWidth: 36
|
||||
Layout.preferredHeight: 36
|
||||
enabled: !root.contextLoading && !root.submitting
|
||||
visible: root.showRefreshAction
|
||||
Accessible.name: qsTr("Refresh position data")
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: Accessible.name
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQml
|
||||
|
||||
import Logos.Controls
|
||||
import Logos.Icons
|
||||
import Logos.Wallet
|
||||
|
||||
import "../components/liquidity"
|
||||
@ -12,8 +17,11 @@ Item {
|
||||
property var runtime: null
|
||||
readonly property NewPositionFlow flow: newPositionFlow
|
||||
|
||||
readonly property int pageMargin: 16
|
||||
readonly property int preferredWidth: 480
|
||||
readonly property int pageMargin: width < 640 ? 16 : 24
|
||||
readonly property int contentMaxWidth: 1200
|
||||
readonly property bool wideLayout: width >= 760
|
||||
readonly property int stepRailWidth: Math.max(210, Math.min(330,
|
||||
(width - pageMargin * 2) * 0.30))
|
||||
|
||||
AmmTheme {
|
||||
id: theme
|
||||
@ -38,34 +46,194 @@ Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: Math.max(height, form.y + form.implicitHeight + root.pageMargin)
|
||||
contentHeight: Math.max(height, pageLayout.y + pageLayout.implicitHeight + root.pageMargin)
|
||||
enabled: !confirmationDialog.opened
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
NewPositionForm {
|
||||
id: form
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: pageLayout
|
||||
|
||||
x: Math.max(root.pageMargin, (scroll.width - width) / 2)
|
||||
y: root.pageMargin
|
||||
width: Math.max(0, Math.min(root.preferredWidth, scroll.width - root.pageMargin * 2))
|
||||
theme: theme
|
||||
newPositionContext: newPositionFlow.newPositionContext
|
||||
flowState: newPositionFlow.viewState
|
||||
y: root.wideLayout ? 32 : 16
|
||||
width: Math.max(0, Math.min(root.contentMaxWidth,
|
||||
scroll.width - root.pageMargin * 2))
|
||||
spacing: 24
|
||||
|
||||
onQuoteRequested: function(immediate, quoteRequest) {
|
||||
newPositionFlow.scheduleQuote(immediate, quoteRequest)
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
text: qsTr("New position")
|
||||
color: theme.colors.textPrimary
|
||||
font.pixelSize: 30
|
||||
font.weight: Font.Bold
|
||||
font.letterSpacing: 0
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: form.contextStatusText()
|
||||
color: theme.colors.textSecondary
|
||||
font.pixelSize: 12
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
LogosIconButton {
|
||||
objectName: "refreshPositionButton"
|
||||
iconSource: LogosIcons.refresh
|
||||
iconColor: theme.colors.textSecondary
|
||||
iconSize: 18
|
||||
Layout.preferredWidth: 40
|
||||
Layout.preferredHeight: 40
|
||||
enabled: !newPositionFlow.contextLoading && !newPositionFlow.submitting
|
||||
Accessible.name: qsTr("Refresh position data")
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: Accessible.name
|
||||
onClicked: newPositionFlow.refreshContext(true)
|
||||
}
|
||||
}
|
||||
|
||||
onConfirmationRequested: function(snapshot) {
|
||||
confirmationDialog.openWithSnapshot(snapshot)
|
||||
Rectangle {
|
||||
id: compactSteps
|
||||
|
||||
objectName: "compactPositionSteps"
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: compactStepRow.implicitHeight + 32
|
||||
visible: !root.wideLayout
|
||||
radius: 16
|
||||
color: theme.colors.cardBg
|
||||
border.color: theme.colors.border
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
id: compactStepRow
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 12
|
||||
|
||||
StepMarker {
|
||||
Layout.fillWidth: true
|
||||
colors: theme.colors
|
||||
stepNumber: 1
|
||||
label: qsTr("Select pair and fees")
|
||||
active: !form.hasPair
|
||||
complete: form.hasPair
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 1
|
||||
color: form.hasPair ? theme.colors.ctaBg : theme.colors.divider
|
||||
}
|
||||
|
||||
StepMarker {
|
||||
Layout.fillWidth: true
|
||||
colors: theme.colors
|
||||
stepNumber: 2
|
||||
label: form.missingPool
|
||||
? qsTr("Set price and deposit")
|
||||
: qsTr("Enter deposit amounts")
|
||||
active: form.hasPair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTokenResolveRequested: function(tokenId) {
|
||||
newPositionFlow.resolveToken(tokenId)
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: root.wideLayout ? 40 : 0
|
||||
|
||||
onDraftChanged: newPositionFlow.draftChanged()
|
||||
onRefreshRequested: newPositionFlow.refreshContext(true)
|
||||
Rectangle {
|
||||
id: positionStepRail
|
||||
|
||||
objectName: "positionStepRail"
|
||||
Layout.preferredWidth: root.stepRailWidth
|
||||
Layout.alignment: Qt.AlignTop
|
||||
implicitHeight: verticalSteps.implicitHeight + 40
|
||||
visible: root.wideLayout
|
||||
radius: 16
|
||||
color: theme.colors.cardBg
|
||||
border.color: theme.colors.border
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
id: verticalSteps
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 0
|
||||
|
||||
StepMarker {
|
||||
Layout.fillWidth: true
|
||||
colors: theme.colors
|
||||
stepNumber: 1
|
||||
label: qsTr("Select token pair and fees")
|
||||
active: !form.hasPair
|
||||
complete: form.hasPair
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.leftMargin: 17
|
||||
Layout.preferredWidth: 1
|
||||
Layout.preferredHeight: 28
|
||||
color: form.hasPair ? theme.colors.ctaBg : theme.colors.divider
|
||||
}
|
||||
|
||||
StepMarker {
|
||||
Layout.fillWidth: true
|
||||
colors: theme.colors
|
||||
stepNumber: 2
|
||||
label: form.missingPool
|
||||
? qsTr("Set price and deposit amounts")
|
||||
: qsTr("Enter deposit amounts")
|
||||
active: form.hasPair
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewPositionForm {
|
||||
id: form
|
||||
|
||||
objectName: "newPositionForm"
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
theme: theme
|
||||
headingText: form.hasPair ? qsTr("Deposit tokens") : qsTr("Select pair")
|
||||
headingDetail: form.hasPair
|
||||
? qsTr("Specify the token amounts for your liquidity contribution.")
|
||||
: qsTr("Choose two tokens and a fee tier for this position.")
|
||||
showRefreshAction: false
|
||||
newPositionContext: newPositionFlow.newPositionContext
|
||||
flowState: newPositionFlow.viewState
|
||||
|
||||
onQuoteRequested: function(immediate, quoteRequest) {
|
||||
newPositionFlow.scheduleQuote(immediate, quoteRequest)
|
||||
}
|
||||
|
||||
onConfirmationRequested: function(snapshot) {
|
||||
confirmationDialog.openWithSnapshot(snapshot)
|
||||
}
|
||||
|
||||
onTokenResolveRequested: function(tokenId) {
|
||||
newPositionFlow.resolveToken(tokenId)
|
||||
}
|
||||
|
||||
onDraftChanged: newPositionFlow.draftChanged()
|
||||
onRefreshRequested: newPositionFlow.refreshContext(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +255,6 @@ Item {
|
||||
function onQuoteRefreshRequested(immediate) {
|
||||
form.requestQuote(immediate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component {
|
||||
@ -108,4 +275,63 @@ Item {
|
||||
newPositionFlow.confirm(snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
component StepMarker: RowLayout {
|
||||
id: marker
|
||||
|
||||
required property var colors
|
||||
required property int stepNumber
|
||||
required property string label
|
||||
property bool active: false
|
||||
property bool complete: false
|
||||
|
||||
spacing: 12
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 36
|
||||
Layout.preferredHeight: 36
|
||||
radius: 18
|
||||
color: marker.active
|
||||
? marker.colors.ctaBg
|
||||
: marker.complete ? marker.colors.selection : marker.colors.inputBg
|
||||
border.color: marker.active || marker.complete
|
||||
? marker.colors.ctaBg : marker.colors.borderStrong
|
||||
border.width: 1
|
||||
Accessible.ignored: true
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: marker.stepNumber
|
||||
color: marker.active
|
||||
? marker.colors.background
|
||||
: marker.complete ? marker.colors.ctaBg : marker.colors.textPlaceholder
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Step %1").arg(marker.stepNumber)
|
||||
color: marker.active || marker.complete
|
||||
? marker.colors.textSecondary : marker.colors.textPlaceholder
|
||||
font.pixelSize: 11
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: marker.label
|
||||
color: marker.active || marker.complete
|
||||
? marker.colors.textPrimary : marker.colors.textSecondary
|
||||
font.pixelSize: 13
|
||||
font.weight: marker.active ? Font.DemiBold : Font.Normal
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,32 @@ TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
function test_positionLayoutUsesDesktopRailAndCompactProgress() {
|
||||
var page = createTemporaryObject(pageComponent, testCase)
|
||||
verify(page)
|
||||
page.visible = true
|
||||
wait(0)
|
||||
|
||||
var rail = findChild(page, "positionStepRail")
|
||||
var compactSteps = findChild(page, "compactPositionSteps")
|
||||
var form = findChild(page, "newPositionForm")
|
||||
verify(rail)
|
||||
verify(compactSteps)
|
||||
verify(form)
|
||||
|
||||
compare(page.wideLayout, true)
|
||||
verify(rail.width > 0)
|
||||
verify(form.width > rail.width)
|
||||
|
||||
page.width = 600
|
||||
wait(0)
|
||||
|
||||
compare(page.wideLayout, false)
|
||||
verify(compactSteps.implicitHeight > 0)
|
||||
verify(form.width > 0)
|
||||
verify(form.width <= page.width - 32)
|
||||
}
|
||||
|
||||
Component {
|
||||
id: runtimeComponent
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user