diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f371a5b5aa..31106bd1d7 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -335,6 +335,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/gear-outline.png \ diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc index 3d20c0109d..c745a9ce59 100644 --- a/src/qml/bitcoin_qml.qrc +++ b/src/qml/bitcoin_qml.qrc @@ -90,6 +90,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/gear-outline.png diff --git a/src/qml/components/BlockClock.qml b/src/qml/components/BlockClock.qml index dcb2d2d7b6..51b02afe51 100644 --- a/src/qml/components/BlockClock.qml +++ b/src/qml/components/BlockClock.qml @@ -32,6 +32,7 @@ Item { property var syncState: Utils.formatRemainingSyncTime(nodeModel.remainingSyncTime) property string syncTime: syncState.text property bool estimating: syncState.estimating + property bool faulted: nodeModel.faulted activeFocusOnTab: true @@ -50,7 +51,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 @@ -143,7 +144,7 @@ Item { maxNumOutboundPeers: nodeModel.maxNumOutboundPeers indicatorDimensions: dial.width * (3/200) indicatorSpacing: dial.width / 40 - paused: root.paused + paused: root.paused || root.faulted } NetworkIndicator { @@ -156,10 +157,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 @@ -175,6 +179,7 @@ Item { subText: root.syncTime } }, + State { name: "BLOCKCLOCK"; when: synced && !paused && connected PropertyChanges { @@ -186,7 +191,7 @@ Item { }, State { - name: "PAUSE"; when: paused + name: "PAUSE"; when: paused && !faulted PropertyChanges { target: root header: "Paused" @@ -204,6 +209,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 { @@ -224,6 +243,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 f00168acec..254df95ef7 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 0000000000..cf60fada2d Binary files /dev/null and b/src/qml/res/icons/error.png differ diff --git a/src/qml/res/src/error.svg b/src/qml/res/src/error.svg new file mode 100644 index 0000000000..c8bc7128f4 --- /dev/null +++ b/src/qml/res/src/error.svg @@ -0,0 +1,4 @@ + + + +