fix: existing ui bugs fixed + polished

This commit is contained in:
erhant 2026-06-18 18:31:51 +03:00
parent e77bf6153c
commit ec2ba77912
8 changed files with 96 additions and 6 deletions

View File

@ -20,7 +20,23 @@ Rectangle {
property int histIndex: -1
// --- Navigation API (pages call these via the injected `explorer`) ---
function sameDescriptor(a, b) {
if (!a || !b)
return false;
if (a.type !== b.type)
return false;
if (a.type === "home")
return true;
if (a.type === "search")
return a.query === b.query;
return a.param === b.param;
}
function navigateTo(desc) {
// Navigating to the page we're already on is a no-op don't grow the
// history (so e.g. Home-while-home doesn't wake the Back button).
var current = root.histIndex >= 0 ? root.history[root.histIndex] : null;
if (root.sameDescriptor(current, desc))
return;
var h = root.history.slice(0, root.histIndex + 1);
h.push(desc);
root.history = h;

View File

@ -0,0 +1,55 @@
import QtQuick
import Logos.Theme
// Tiny copy-to-clipboard button. Self-contained: writes `value` to the system
// clipboard via a hidden TextEdit (which runs in the host GUI process, so it
// reaches the real desktop clipboard), then flips to a check mark briefly as
// confirmation.
Item {
id: root
property string value: ""
property int size: 22
implicitWidth: size
implicitHeight: size
// Off-screen helper used purely to push text onto the clipboard.
TextEdit { id: clip; visible: false }
Rectangle {
anchors.fill: parent
radius: Theme.spacing.radiusSmall
color: hover.hovered ? Theme.palette.backgroundSecondary : "transparent"
HoverHandler { id: hover }
TapHandler {
onTapped: {
clip.text = root.value;
clip.selectAll();
clip.copy();
clip.text = "";
icon.source = icon.checkUrl;
resetTimer.restart();
}
}
Image {
id: icon
anchors.centerIn: parent
property url copyUrl: Qt.resolvedUrl("../icons/copy.svg")
property url checkUrl: Qt.resolvedUrl("../icons/check.svg")
source: copyUrl
sourceSize.width: Math.round(root.size * 0.72)
sourceSize.height: Math.round(root.size * 0.72)
width: Math.round(root.size * 0.72)
height: Math.round(root.size * 0.72)
fillMode: Image.PreserveAspectFit
}
Timer {
id: resetTimer
interval: 1200
onTriggered: icon.source = icon.copyUrl
}
}
}

View File

@ -12,6 +12,7 @@ RowLayout {
property string label: ""
property string value: ""
property bool mono: false
property bool copyable: false
property color valueColor: Theme.palette.text
spacing: Theme.spacing.medium
@ -36,4 +37,10 @@ RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
}
CopyButton {
visible: root.copyable && root.value.length > 0
value: root.value
Layout.alignment: Qt.AlignTop
}
}

3
src/qml/icons/check.svg Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#a6e3a1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"/>
</svg>

After

Width:  |  Height:  |  Size: 201 B

4
src/qml/icons/copy.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#cdd6f4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>

After

Width:  |  Height:  |  Size: 290 B

View File

@ -49,13 +49,13 @@ Item {
Layout.fillWidth: true
visible: page.loaded && Object.keys(page.account).length > 1
InfoRow { label: "Account ID"; value: page.account.accountId || ""; mono: true }
InfoRow { label: "Account ID"; value: page.account.accountId || ""; mono: true; copyable: true }
InfoRow {
label: "Balance"
value: page.account.balance || "0"
valueColor: Theme.palette.success
}
InfoRow { label: "Program Owner"; value: page.account.programOwner || ""; mono: true }
InfoRow { label: "Program Owner"; value: page.account.programOwner || ""; mono: true; copyable: true }
InfoRow { label: "Nonce"; value: page.account.nonce || "0" }
InfoRow {
label: "Data Size"

View File

@ -49,7 +49,7 @@ Item {
visible: page.loaded && Object.keys(page.block).length > 0
InfoRow { label: "Block ID"; value: String(page.block.blockId !== undefined ? page.block.blockId : "") }
InfoRow { label: "Hash"; value: page.block.hash || ""; mono: true }
InfoRow { label: "Hash"; value: page.block.hash || ""; mono: true; copyable: true }
// Previous hash a clickable link to the previous block when not genesis.
RowLayout {
@ -68,6 +68,11 @@ Item {
onTapped: page.explorer.navigateBlock(Number(page.blockId) - 1)
}
}
CopyButton {
visible: (page.block.prevBlockHash || "").length > 0
value: page.block.prevBlockHash || ""
Layout.alignment: Qt.AlignTop
}
}
InfoRow { label: "Timestamp"; value: page.block.timestampText || "" }
@ -80,7 +85,7 @@ Item {
Item { Layout.fillWidth: true }
}
InfoRow { label: "Signature"; value: page.block.signature || ""; mono: true }
InfoRow { label: "Signature"; value: page.block.signature || ""; mono: true; copyable: true }
InfoRow { label: "Transactions"; value: String(page.block.txCount !== undefined ? page.block.txCount : 0) }
}

View File

@ -48,7 +48,7 @@ Item {
Layout.fillWidth: true
visible: page.loaded && Object.keys(page.tx).length > 0
InfoRow { label: "Hash"; value: page.tx.hash || ""; mono: true }
InfoRow { label: "Hash"; value: page.tx.hash || ""; mono: true; copyable: true }
RowLayout {
Layout.fillWidth: true
spacing: Theme.spacing.medium
@ -60,7 +60,7 @@ Item {
// Public.
InfoRow {
visible: page.txType === "Public"
label: "Program ID"; value: page.tx.programId || ""; mono: true
label: "Program ID"; value: page.tx.programId || ""; mono: true; copyable: true
}
InfoRow {
visible: page.txType === "Public"