mirror of
https://github.com/logos-blockchain/lez-explorer-ui.git
synced 2026-07-30 03:13:25 +00:00
166 lines
6.0 KiB
QML
166 lines
6.0 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import Logos.Controls
|
|
import Logos.Theme
|
|
import "components"
|
|
|
|
Rectangle {
|
|
id: root
|
|
color: Theme.palette.background
|
|
|
|
// Typed replica of the backend; non-null once the plugin is registered,
|
|
// `ready` tracks the live connection.
|
|
readonly property var backend: logos.module("lez_explorer_ui")
|
|
property bool ready: false
|
|
|
|
// Self-managed navigation history (browser-style back/forward). Each entry
|
|
// is a descriptor { type, param?, query? }.
|
|
property var history: []
|
|
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;
|
|
root.histIndex = h.length - 1;
|
|
root.render();
|
|
}
|
|
function navigateBlock(id) { root.navigateTo({ type: "block", param: id }); }
|
|
function navigateTx(hash) { root.navigateTo({ type: "tx", param: hash }); }
|
|
function navigateAccount(id) { root.navigateTo({ type: "account", param: id }); }
|
|
function navigateSettings() { root.navigateTo({ type: "settings" }); }
|
|
function showSearchResults(results, query) {
|
|
root.navigateTo({ type: "search", param: results, query: query });
|
|
}
|
|
function goHome() { root.navigateTo({ type: "home" }); }
|
|
function goBack() { if (root.histIndex > 0) { root.histIndex--; root.render(); } }
|
|
function goForward() { if (root.histIndex < root.history.length - 1) { root.histIndex++; root.render(); } }
|
|
|
|
function render() {
|
|
if (root.histIndex < 0)
|
|
return;
|
|
var d = root.history[root.histIndex];
|
|
var props = { explorer: root };
|
|
var url = "pages/HomePage.qml";
|
|
if (d.type === "block") {
|
|
url = "pages/BlockPage.qml";
|
|
props.blockId = d.param;
|
|
} else if (d.type === "tx") {
|
|
url = "pages/TransactionPage.qml";
|
|
props.txHash = d.param;
|
|
} else if (d.type === "account") {
|
|
url = "pages/AccountPage.qml";
|
|
props.accountId = d.param;
|
|
} else if (d.type === "search") {
|
|
url = "pages/SearchResultsPage.qml";
|
|
props.results = d.param;
|
|
props.query = d.query || "";
|
|
} else if (d.type === "settings") {
|
|
url = "pages/SettingsPage.qml";
|
|
}
|
|
pageLoader.setSource(Qt.resolvedUrl(url), props);
|
|
navBar.canGoBack = root.histIndex > 0;
|
|
navBar.canGoForward = root.histIndex < root.history.length - 1;
|
|
}
|
|
|
|
Connections {
|
|
target: logos
|
|
function onViewModuleReadyChanged(moduleName, isReady) {
|
|
if (moduleName === "lez_explorer_ui")
|
|
root.ready = isReady && root.backend !== null;
|
|
}
|
|
}
|
|
Component.onCompleted: {
|
|
root.ready = root.backend !== null && logos.isViewModuleReady("lez_explorer_ui");
|
|
root.goHome();
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.spacing.large
|
|
spacing: Theme.spacing.medium
|
|
|
|
NavigationBar {
|
|
id: navBar
|
|
Layout.fillWidth: true
|
|
onBackClicked: root.goBack()
|
|
onForwardClicked: root.goForward()
|
|
onHomeClicked: root.goHome()
|
|
onSettingsClicked: root.navigateSettings()
|
|
}
|
|
|
|
SearchBar {
|
|
Layout.fillWidth: true
|
|
onSearchRequested: function (query) {
|
|
if (!root.backend || query.trim().length === 0)
|
|
return;
|
|
logos.watch(root.backend.search(query), function (results) {
|
|
var blocks = results && results.blocks ? results.blocks : [];
|
|
var txs = results && results.transactions ? results.transactions : [];
|
|
var accts = results && results.accounts ? results.accounts : [];
|
|
var total = blocks.length + txs.length + accts.length;
|
|
if (total === 1) {
|
|
if (blocks.length === 1)
|
|
root.navigateBlock(blocks[0].blockId);
|
|
else if (txs.length === 1)
|
|
root.navigateTx(txs[0].hash);
|
|
else
|
|
root.navigateAccount(accts[0].accountId);
|
|
} else {
|
|
root.showSearchResults(results, query);
|
|
}
|
|
}, function (err) {
|
|
root.showSearchResults({ blocks: [], transactions: [], accounts: [] }, query);
|
|
});
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: pageLoader
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
}
|
|
}
|
|
|
|
// Readiness overlay — covers the view until the backend connects.
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
visible: !root.ready
|
|
color: Theme.palette.background
|
|
|
|
ColumnLayout {
|
|
anchors.centerIn: parent
|
|
spacing: Theme.spacing.medium
|
|
|
|
BusyIndicator {
|
|
running: !root.ready
|
|
Layout.alignment: Qt.AlignHCenter
|
|
}
|
|
LogosText {
|
|
text: "Connecting to indexer backend…"
|
|
color: Theme.palette.textSecondary
|
|
font.pixelSize: Theme.typography.secondaryText
|
|
Layout.alignment: Qt.AlignHCenter
|
|
}
|
|
}
|
|
}
|
|
}
|