Skip to content
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
30 changes: 0 additions & 30 deletions amm-ui/Main.qml

This file was deleted.

2 changes: 1 addition & 1 deletion amm-ui/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "ui_qml",
"category": "amm",
"description": "UI module for the AMM program",
"view": "Main.qml",
"view": "qml/Main.qml",
"icon": "icons/amm.png",
"dependencies": [],

Expand Down
152 changes: 152 additions & 0 deletions amm-ui/qml/Main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Item {
id: root

property var tokenData: [
{ symbol: "TOK1", name: "Token 1", color: "#627eea", letter: "E", address: "0x0000000000000000000000000000000000000000", usdPrice: 2392.70 },
{ symbol: "TOK2", name: "Token 2", color: "#2775ca", letter: "$", address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", usdPrice: 1.00 },
{ symbol: "TOK3", name: "Token 3", color: "#26a17b", letter: "T", address: "0xdac17f958d2ee523a2206206994597c13d831ec7", usdPrice: 1.00 },
{ symbol: "TOK4", name: "Token 4", color: "#f7931a", letter: "B", address: "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", usdPrice: 63500 },
{ symbol: "TOK5", name: "Token 5", color: "#627eea", letter: "E", address: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", usdPrice: 2392.70 },
{ symbol: "TOK6", name: "Token 6", color: "#9b59b6", letter: "L", address: "0x1337000000000000000000000000000000000cafe", usdPrice: 0.42 }
]

// ── Theme ─────────────────────────────────────────────────────────────────
QtObject {
id: theme
property bool isDark: false
property var colors: isDark ? dark : light

readonly property var light: ({
background: "#f7f7f5",
cardBg: "#ffffff",
inputBg: "#f0f0ee",
panelBg: "#e8e8e4",
panelHoverBg: "#ddddd8",
textPrimary: "#111111",
textSecondary: "#777770",
textPlaceholder: "#bbbbb5",
border: Qt.rgba(0,0,0,0.08),
borderStrong: Qt.rgba(0,0,0,0.10),
divider: Qt.rgba(0,0,0,0.06),
ctaBg: "#111111",
ctaHoverBg: "#2a2a28",
selection: "#b5c4a5",
noTokenCircle: "#c8c8c4",
orb1: "#7a8c6a",
orb2: "#b5c4a5",
orb3: "#7a8c6a",
orb4: "#c8d4b8"
})

readonly property var dark: ({
background: "#0d0d12",
cardBg: "#1a1a22",
inputBg: "#222230",
panelBg: "#2a2a38",
panelHoverBg: "#363650",
textPrimary: "#ffffff",
textSecondary: "#888899",
textPlaceholder: "#444455",
border: Qt.rgba(1,1,1,0.08),
borderStrong: Qt.rgba(1,1,1,0.10),
divider: Qt.rgba(1,1,1,0.06),
ctaBg: "#2d1530",
ctaHoverBg: "#3d1f40",
selection: "#4c1d4b",
noTokenCircle: "#444455",
orb1: "#627eea",
orb2: "#9b59b6",
orb3: "#fc72ff",
orb4: "#26a17b"
})
}

// ── Root background ───────────────────────────────────────────────────────
Rectangle {
anchors.fill: parent
color: theme.colors.background
Behavior on color { ColorAnimation { duration: 300 } }

// Theme toggle
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 16
width: 44; height: 24; radius: 12
color: theme.colors.panelBg
border.color: theme.colors.border
border.width: 1
Text {
anchors.centerIn: parent
text: theme.isDark ? "☀" : "☾"
font.pixelSize: 13
color: theme.colors.textSecondary
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: theme.isDark = !theme.isDark
}
}

// Decorative orbs
Rectangle { x: -180; y: -120; width: 560; height: 560; radius: 280; color: theme.colors.orb1; opacity: 0.07 }
Rectangle { x: parent.width - 280; y: parent.height - 320; width: 480; height: 480; radius: 240; color: theme.colors.orb2; opacity: 0.09 }
Rectangle { x: parent.width - 200; y: -80; width: 380; height: 380; radius: 190; color: theme.colors.orb3; opacity: 0.05 }
Rectangle { x: 40; y: parent.height - 260; width: 320; height: 320; radius: 160; color: theme.colors.orb4; opacity: 0.08 }

ColumnLayout {
anchors.centerIn: parent
spacing: 28

Text {
Layout.alignment: Qt.AlignHCenter
text: "Logos AMM"
color: theme.colors.textPrimary
font.pixelSize: 48
font.weight: Font.Bold
}

SwapCard {
id: swapCard
Layout.alignment: Qt.AlignHCenter
theme: theme
tokens: root.tokenData
width: Math.min(480, root.width - 32)

onRequestTokenSelect: function(side) {
tokenModal.targetSide = side
tokenModal.open()
}
}

Text {
Layout.alignment: Qt.AlignHCenter
text: "Buy and sell crypto on <font color='" + theme.colors.textPrimary + "'>LEZ</font>."
textFormat: Text.RichText
color: theme.colors.textSecondary
font.pixelSize: 15
horizontalAlignment: Text.AlignHCenter
}
}

TokenSelectorModal {
id: tokenModal
anchors.fill: parent
z: 10
theme: theme
tokens: root.tokenData

property string targetSide: "sell"

onTokenSelected: function(tok) {
swapCard.setToken(targetSide, tok)
tokenModal.close()
}
}
}
}
153 changes: 153 additions & 0 deletions amm-ui/qml/SwapCard.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Rectangle {
id: root

property var theme
property var tokens: []
property var sellToken: null
property var buyToken: null
property string sellAmount: ""

signal requestTokenSelect(string side)

function setToken(side, token) {
if (side === "sell") root.sellToken = token
else root.buyToken = token
}

readonly property string buyAmount: {
if (!sellToken || !buyToken || sellAmount === "") return ""
var amt = parseFloat(sellAmount)
if (isNaN(amt) || amt <= 0) return ""
var result = amt * sellToken.usdPrice / buyToken.usdPrice
return result >= 1 ? result.toFixed(2) : result.toFixed(6)
}

readonly property string sellUsd: {
if (!sellToken || sellAmount === "") return ""
var amt = parseFloat(sellAmount)
if (isNaN(amt)) return ""
var val = amt * sellToken.usdPrice
return "~$" + val.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}

readonly property string buyUsd: {
if (!buyToken || buyAmount === "") return ""
var amt = parseFloat(buyAmount)
if (isNaN(amt)) return ""
var val = amt * buyToken.usdPrice
return "~$" + val.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}

radius: 24
color: theme.colors.cardBg
border.color: theme.colors.border
border.width: 1
implicitWidth: 480
implicitHeight: cardLayout.implicitHeight + 16

Behavior on color { ColorAnimation { duration: 300 } }

ColumnLayout {
id: cardLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 8
spacing: 0

TokenInput {
Layout.fillWidth: true
theme: root.theme
label: "Sell"
amount: root.sellAmount
usdValue: root.sellUsd
token: root.sellToken
readOnly: false
onInputEdited: function(v) { root.sellAmount = v }
onTokenClicked: root.requestTokenSelect("sell")
}

Item {
Layout.fillWidth: true
Layout.preferredHeight: 40

Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: theme.colors.divider
}

Rectangle {
anchors.centerIn: parent
width: 36; height: 36; radius: 18
color: swapHover.containsMouse ? theme.colors.panelHoverBg : theme.colors.panelBg
border.color: theme.colors.borderStrong
border.width: 1
Behavior on color { ColorAnimation { duration: 120 } }

Text {
anchors.centerIn: parent
text: "↓"
color: theme.colors.textPrimary
font.pixelSize: 16
}

MouseArea {
id: swapHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
var tmp = root.sellToken
root.sellToken = root.buyToken
root.buyToken = tmp
}
}
}
}

TokenInput {
Layout.fillWidth: true
theme: root.theme
label: "Buy"
amount: root.buyAmount
usdValue: root.buyUsd
token: root.buyToken
readOnly: true
onTokenClicked: root.requestTokenSelect("buy")
}

Rectangle {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.bottomMargin: 8
Layout.leftMargin: 8
Layout.rightMargin: 8
Layout.preferredHeight: 56
radius: 20
color: ctaHover.containsMouse ? theme.colors.ctaHoverBg : theme.colors.ctaBg
Behavior on color { ColorAnimation { duration: 120 } }

Text {
anchors.centerIn: parent
text: "Swap"
color: "#ffffff"
font.pixelSize: 17
font.weight: Font.Medium
}

MouseArea {
id: ctaHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
}
}
}
}
Loading
Loading