From 2b61d228859af296a64f47977953f51cbedc42fc Mon Sep 17 00:00:00 2001 From: johnny9 <985648+johnny9@users.noreply.github.com> Date: Fri, 21 Apr 2023 19:39:28 -0500 Subject: [PATCH] qml: Put BlockClock into an Error state if init fails Co-authored-by: thebagmaster --- src/Makefile.qt.include | 1 + src/qml/bitcoin_qml.qrc | 1 + src/qml/components/BlockClock.qml | 32 ++++++++++++++++++++++++------ src/qml/imageprovider.cpp | 5 +++++ src/qml/models/nodemodel.cpp | 15 ++++++++++++-- src/qml/models/nodemodel.h | 5 +++++ src/qml/res/icons/error.png | Bin 0 -> 3492 bytes src/qml/res/src/error.svg | 4 ++++ 8 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/qml/res/icons/error.png create mode 100644 src/qml/res/src/error.svg diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9dcb95c1f8..cb2baa8189 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -327,6 +327,7 @@ QML_RES_ICONS = \ qml/res/icons/caret-right.png \ qml/res/icons/check.png \ qml/res/icons/cross.png \ + qml/res/icons/error.png \ qml/res/icons/export.png \ qml/res/icons/gear.png \ qml/res/icons/info.png \ diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc index 591615b1ca..91b7e7bd05 100644 --- a/src/qml/bitcoin_qml.qrc +++ b/src/qml/bitcoin_qml.qrc @@ -74,6 +74,7 @@ res/icons/caret-right.png res/icons/check.png res/icons/cross.png + res/icons/error.png res/icons/export.png res/icons/gear.png res/icons/info.png diff --git a/src/qml/components/BlockClock.qml b/src/qml/components/BlockClock.qml index f7210aa534..dd58cba8b9 100644 --- a/src/qml/components/BlockClock.qml +++ b/src/qml/components/BlockClock.qml @@ -30,6 +30,7 @@ Item { property var syncState: formatRemainingSyncTime(nodeModel.remainingSyncTime) property string syncTime: syncState.text property bool estimating: syncState.estimating + property bool faulted: nodeModel.faulted activeFocusOnTab: true @@ -47,7 +48,7 @@ Item { penWidth: dial.width / 50 timeRatioList: chainModel.timeRatioList verificationProgress: nodeModel.verificationProgress - paused: root.paused + paused: root.paused || root.faulted connected: root.connected synced: nodeModel.verificationProgress > 0.999 backgroundColor: Theme.color.neutral2 @@ -140,7 +141,7 @@ Item { maxNumOutboundPeers: nodeModel.maxNumOutboundPeers indicatorDimensions: dial.width * (3/200) indicatorSpacing: dial.width / 40 - paused: root.paused + paused: root.paused || root.faulted } NetworkIndicator { @@ -152,10 +153,13 @@ Item { MouseArea { anchors.fill: dial - cursorShape: Qt.PointingHandCursor + cursorShape: root.faulted ? Qt.ArrowCursor : Qt.PointingHandCursor + enabled: !root.faulted onClicked: { - root.paused = !root.paused - nodeModel.pause = root.paused + if (!root.faulted) { + root.paused = !root.paused + nodeModel.pause = root.paused + } } FocusBorder { visible: root.activeFocus @@ -171,6 +175,7 @@ Item { subText: root.syncTime } }, + State { name: "BLOCKCLOCK"; when: synced && !paused && connected PropertyChanges { @@ -182,7 +187,7 @@ Item { }, State { - name: "PAUSE"; when: paused + name: "PAUSE"; when: paused && !faulted PropertyChanges { target: root header: "Paused" @@ -200,6 +205,20 @@ Item { } }, + State { + name: "ERROR"; when: faulted + PropertyChanges { + target: root + header: "Error" + headerSize: dial.width * (3/25) + } + PropertyChanges { + target: bitcoinIcon + anchors.bottomMargin: dial.width / 40 + icon.source: "image://images/error" + } + }, + State { name: "CONNECTING"; when: !paused && !connected PropertyChanges { @@ -220,6 +239,7 @@ Item { } ] + function formatProgressPercentage(progress) { if (progress >= 1) { return Math.round(progress) + "%" diff --git a/src/qml/imageprovider.cpp b/src/qml/imageprovider.cpp index 26ffc102ea..10f70afcd2 100644 --- a/src/qml/imageprovider.cpp +++ b/src/qml/imageprovider.cpp @@ -82,6 +82,11 @@ QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize return QIcon(":/icons/cross").pixmap(requested_size); } + if (id == "error") { + *size = requested_size; + return QIcon(":/icons/error").pixmap(requested_size); + } + if (id == "export") { *size = requested_size; return QIcon(":/icons/export").pixmap(requested_size); diff --git a/src/qml/models/nodemodel.cpp b/src/qml/models/nodemodel.cpp index a699376d1a..521e5fa1c5 100644 --- a/src/qml/models/nodemodel.cpp +++ b/src/qml/models/nodemodel.cpp @@ -15,6 +15,7 @@ #include #include #include +#include NodeModel::NodeModel(interfaces::Node& node) : m_node{node} @@ -93,6 +94,14 @@ void NodeModel::setPause(bool new_pause) } } +void NodeModel::setErrorState(bool faulted) +{ + if (m_faulted != faulted) { + m_faulted = faulted; + Q_EMIT errorStateChanged(faulted); + } +} + void NodeModel::startNodeInitializionThread() { Q_EMIT requestedInitialize(); @@ -103,9 +112,11 @@ void NodeModel::requestShutdown() Q_EMIT requestedShutdown(); } -void NodeModel::initializeResult([[maybe_unused]] bool success, interfaces::BlockAndHeaderTipInfo tip_info) +void NodeModel::initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info) { - // TODO: Handle the `success` parameter, + if (!success) { + setErrorState(true); + } setBlockTipHeight(tip_info.block_height); setVerificationProgress(tip_info.verification_progress); diff --git a/src/qml/models/nodemodel.h b/src/qml/models/nodemodel.h index 442a0becf3..a17f9b0833 100644 --- a/src/qml/models/nodemodel.h +++ b/src/qml/models/nodemodel.h @@ -33,6 +33,7 @@ class NodeModel : public QObject Q_PROPERTY(int remainingSyncTime READ remainingSyncTime NOTIFY remainingSyncTimeChanged) Q_PROPERTY(double verificationProgress READ verificationProgress NOTIFY verificationProgressChanged) Q_PROPERTY(bool pause READ pause WRITE setPause NOTIFY pauseChanged) + Q_PROPERTY(bool faulted READ errorState WRITE setErrorState NOTIFY errorStateChanged) public: explicit NodeModel(interfaces::Node& node); @@ -49,6 +50,8 @@ class NodeModel : public QObject void setVerificationProgress(double new_progress); bool pause() const { return m_pause; } void setPause(bool new_pause); + bool errorState() const { return m_faulted; } + void setErrorState(bool new_error); Q_INVOKABLE float getTotalBytesReceived() const { return (float)m_node.getTotalBytesRecv(); } Q_INVOKABLE float getTotalBytesSent() const { return (float)m_node.getTotalBytesSent(); } @@ -70,6 +73,7 @@ public Q_SLOTS: void requestedShutdown(); void verificationProgressChanged(); void pauseChanged(bool new_pause); + void errorStateChanged(bool new_error_state); void setTimeRatioList(int new_time); void setTimeRatioListInitial(); @@ -85,6 +89,7 @@ public Q_SLOTS: int m_remaining_sync_time{0}; double m_verification_progress{0.0}; bool m_pause{false}; + bool m_faulted{false}; int m_shutdown_polling_timer_id{0}; diff --git a/src/qml/res/icons/error.png b/src/qml/res/icons/error.png new file mode 100644 index 0000000000000000000000000000000000000000..cf60fada2d32c1d5b1aa76d231fe77c2932ce9f5 GIT binary patch literal 3492 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 S4%t)y0000 + + +