From 8f8341f6598afaa44e0370a67c7379fab78dd34c Mon Sep 17 00:00:00 2001
From: johnny9 <985648+johnny9@users.noreply.github.com>
Date: Wed, 1 May 2024 10:52:30 -0400
Subject: [PATCH] qml: Introduce Tooltip for the BlockClock navbar button
The Tooltip will appear when hovering over the BlockClock tab
button in the desktop navigation bar. It will show the current
state of IBD.
---
src/Makefile.qt.include | 6 +-
src/qml/bitcoin_qml.qrc | 4 ++
src/qml/components/BlockClock.qml | 64 +--------------------
src/qml/components/Tooltip.qml | 44 +++++++++++++++
src/qml/controls/CoreText.qml | 2 +-
src/qml/controls/Theme.qml | 3 +
src/qml/controls/utils.js | 66 ++++++++++++++++++++++
src/qml/imageprovider.cpp | 10 ++++
src/qml/pages/wallet/DesktopWallets.qml | 29 ++++++++++
src/qml/res/icons/tooltip-arrow-dark.png | Bin 0 -> 2096 bytes
src/qml/res/icons/tooltip-arrow-light.png | Bin 0 -> 1264 bytes
src/qml/res/src/tooltip-arrow-dark.svg | 4 ++
src/qml/res/src/tooltip-arrow-light.svg | 4 ++
13 files changed, 172 insertions(+), 64 deletions(-)
create mode 100644 src/qml/components/Tooltip.qml
create mode 100644 src/qml/controls/utils.js
create mode 100644 src/qml/res/icons/tooltip-arrow-dark.png
create mode 100644 src/qml/res/icons/tooltip-arrow-light.png
create mode 100644 src/qml/res/src/tooltip-arrow-dark.svg
create mode 100644 src/qml/res/src/tooltip-arrow-light.svg
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 67cedeeeec..e5ac06c98b 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -336,7 +336,9 @@ QML_RES_ICONS = \
qml/res/icons/shutdown.png \
qml/res/icons/singlesig-wallet.png \
qml/res/icons/storage-dark.png \
- qml/res/icons/storage-light.png
+ qml/res/icons/storage-light.png \
+ qml/res/icons/tooltip-arrow-dark.png \
+ qml/res/icons/tooltip-arrow-light.png
QML_QRC_CPP = qml/qrc_bitcoin.cpp
QML_QRC = qml/bitcoin_qml.qrc
@@ -360,6 +362,7 @@ QML_RES_QML = \
qml/components/StorageSettings.qml \
qml/components/ThemeSettings.qml \
qml/components/TotalBytesIndicator.qml \
+ qml/components/Tooltip.qml \
qml/controls/ContinueButton.qml \
qml/controls/CoreText.qml \
qml/controls/ExternalLink.qml \
@@ -381,6 +384,7 @@ QML_RES_QML = \
qml/controls/TextButton.qml \
qml/controls/Theme.qml \
qml/controls/ToggleButton.qml \
+ qml/controls/utils.js \
qml/controls/ValueInput.qml \
qml/pages/initerrormessage.qml \
qml/pages/main.qml \
diff --git a/src/qml/bitcoin_qml.qrc b/src/qml/bitcoin_qml.qrc
index 86372d3c4f..3f89b0dbf7 100644
--- a/src/qml/bitcoin_qml.qrc
+++ b/src/qml/bitcoin_qml.qrc
@@ -19,6 +19,7 @@
components/StorageSettings.qml
components/ThemeSettings.qml
components/TotalBytesIndicator.qml
+ components/Tooltip.qml
controls/ContinueButton.qml
controls/CoreText.qml
controls/ExternalLink.qml
@@ -41,6 +42,7 @@
controls/TextButton.qml
controls/Theme.qml
controls/ToggleButton.qml
+ controls/utils.js
controls/ValueInput.qml
pages/initerrormessage.qml
pages/main.qml
@@ -88,6 +90,8 @@
res/icons/singlesig-wallet.png
res/icons/storage-dark.png
res/icons/storage-light.png
+ res/icons/tooltip-arrow-dark.png
+ res/icons/tooltip-arrow-light.png
res/fonts/Inter-Regular.otf
diff --git a/src/qml/components/BlockClock.qml b/src/qml/components/BlockClock.qml
index 6e1c28f0a7..dcb2d2d7b6 100644
--- a/src/qml/components/BlockClock.qml
+++ b/src/qml/components/BlockClock.qml
@@ -10,6 +10,7 @@ import Qt.labs.settings 1.0
import org.bitcoincore.qt 1.0
import "../controls"
+import "../controls/utils.js" as Utils
Item {
id: root
@@ -28,7 +29,7 @@ Item {
property bool synced: nodeModel.verificationProgress > 0.999
property string syncProgress: formatProgressPercentage(nodeModel.verificationProgress * 100)
property bool paused: false
- property var syncState: formatRemainingSyncTime(nodeModel.remainingSyncTime)
+ property var syncState: Utils.formatRemainingSyncTime(nodeModel.remainingSyncTime)
property string syncTime: syncState.text
property bool estimating: syncState.estimating
@@ -234,65 +235,4 @@ Item {
return "0%"
}
}
-
- function formatRemainingSyncTime(milliseconds) {
- var minutes = Math.floor(milliseconds / 60000);
- var seconds = Math.floor((milliseconds % 60000) / 1000);
- var weeks = Math.floor(minutes / 10080);
- minutes %= 10080;
- var days = Math.floor(minutes / 1440);
- minutes %= 1440;
- var hours = Math.floor(minutes / 60);
- minutes %= 60;
- var result = "";
- var estimatingStatus = false;
-
- if (weeks > 0) {
- return {
- text: "~" + weeks + (weeks === 1 ? " week" : " weeks") + " left",
- estimating: false
- };
- }
- if (days > 0) {
- return {
- text: "~" + days + (days === 1 ? " day" : " days") + " left",
- estimating: false
- };
- }
- if (hours >= 5) {
- return {
- text: "~" + hours + (hours === 1 ? " hour" : " hours") + " left",
- estimating: false
- };
- }
- if (hours > 0) {
- return {
- text: "~" + hours + "h " + minutes + "m" + " left",
- estimating: false
- };
- }
- if (minutes >= 5) {
- return {
- text: "~" + minutes + (minutes === 1 ? " minute" : " minutes") + " left",
- estimating: false
- };
- }
- if (minutes > 0) {
- return {
- text: "~" + minutes + "m " + seconds + "s" + " left",
- estimating: false
- };
- }
- if (seconds > 0) {
- return {
- text: "~" + seconds + (seconds === 1 ? " second" : " seconds") + " left",
- estimating: false
- };
- } else {
- return {
- text: "Estimating",
- estimating: true
- };
- }
- }
}
diff --git a/src/qml/components/Tooltip.qml b/src/qml/components/Tooltip.qml
new file mode 100644
index 0000000000..4f00f4404d
--- /dev/null
+++ b/src/qml/components/Tooltip.qml
@@ -0,0 +1,44 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+import "../controls"
+
+Item {
+ id: root
+
+ property alias text: tooltipText.text
+
+ Rectangle {
+ id: tooltipBg
+ color: Theme.color.neutral0
+ border.color: Theme.color.neutral4
+ radius: 5
+ border.width: 1
+ width: tooltipText.width + 30
+ height: tooltipText.height + 20
+ anchors.top: arrow.bottom
+ anchors.right: arrow.right
+ anchors.rightMargin: -10
+ anchors.topMargin: -1
+ }
+
+ Image {
+ id: arrow
+ source: Theme.image.tooltipArrow
+ width: 22
+ height: 10
+ anchors.horizontalCenter: root.horizontalCenter
+ anchors.top: root.top
+ }
+
+ CoreText {
+ id: tooltipText
+ text: ""
+ wrapMode: Text.NoWrap
+ anchors.centerIn: tooltipBg
+ }
+}
diff --git a/src/qml/controls/CoreText.qml b/src/qml/controls/CoreText.qml
index 050f03b256..3857912614 100644
--- a/src/qml/controls/CoreText.qml
+++ b/src/qml/controls/CoreText.qml
@@ -8,7 +8,7 @@ import QtQuick.Controls 2.15
Text {
property bool bold: false
property bool wrap: true
- color: Theme.color.white
+ color: Theme.color.neutral9
font.family: "Inter"
font.styleName: bold ? "Semi Bold" : "Regular"
font.pixelSize: 13
diff --git a/src/qml/controls/Theme.qml b/src/qml/controls/Theme.qml
index df62e0a4ad..f57e152cbd 100644
--- a/src/qml/controls/Theme.qml
+++ b/src/qml/controls/Theme.qml
@@ -44,6 +44,7 @@ Control {
required property url blocktime
required property url network
required property url storage
+ required property url tooltipArrow
}
ColorSet {
@@ -115,6 +116,7 @@ Control {
blocktime: "image://images/blocktime-dark"
network: "image://images/network-dark"
storage: "image://images/storage-dark"
+ tooltipArrow: "qrc:/icons/tooltip-arrow-dark"
}
ImageSet {
@@ -122,6 +124,7 @@ Control {
blocktime: "image://images/blocktime-light"
network: "image://images/network-light"
storage: "image://images/storage-light"
+ tooltipArrow: "qrc:/icons/tooltip-arrow-light"
}
function toggleDark() {
diff --git a/src/qml/controls/utils.js b/src/qml/controls/utils.js
new file mode 100644
index 0000000000..bcbe9af35c
--- /dev/null
+++ b/src/qml/controls/utils.js
@@ -0,0 +1,66 @@
+// Copyright (c) 2024 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// utils.js
+
+function formatRemainingSyncTime(milliseconds) {
+ var minutes = Math.floor(milliseconds / 60000);
+ var seconds = Math.floor((milliseconds % 60000) / 1000);
+ var weeks = Math.floor(minutes / 10080);
+ minutes %= 10080;
+ var days = Math.floor(minutes / 1440);
+ minutes %= 1440;
+ var hours = Math.floor(minutes / 60);
+ minutes %= 60;
+ var result = "";
+ var estimatingStatus = false;
+
+ if (weeks > 0) {
+ return {
+ text: "~" + weeks + (weeks === 1 ? " week" : " weeks") + " left",
+ estimating: false
+ };
+ }
+ if (days > 0) {
+ return {
+ text: "~" + days + (days === 1 ? " day" : " days") + " left",
+ estimating: false
+ };
+ }
+ if (hours >= 5) {
+ return {
+ text: "~" + hours + (hours === 1 ? " hour" : " hours") + " left",
+ estimating: false
+ };
+ }
+ if (hours > 0) {
+ return {
+ text: "~" + hours + "h " + minutes + "m" + " left",
+ estimating: false
+ };
+ }
+ if (minutes >= 5) {
+ return {
+ text: "~" + minutes + (minutes === 1 ? " minute" : " minutes") + " left",
+ estimating: false
+ };
+ }
+ if (minutes > 0) {
+ return {
+ text: "~" + minutes + "m " + seconds + "s" + " left",
+ estimating: false
+ };
+ }
+ if (seconds > 0) {
+ return {
+ text: "~" + seconds + (seconds === 1 ? " second" : " seconds") + " left",
+ estimating: false
+ };
+ } else {
+ return {
+ text: "Estimating",
+ estimating: true
+ };
+ }
+}
diff --git a/src/qml/imageprovider.cpp b/src/qml/imageprovider.cpp
index 6a739a5aee..b3b041c9eb 100644
--- a/src/qml/imageprovider.cpp
+++ b/src/qml/imageprovider.cpp
@@ -132,5 +132,15 @@ QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize
return QIcon(":/icons/storage-light").pixmap(requested_size);
}
+ if (id == "tooltip-arrow-dark") {
+ *size = requested_size;
+ return QIcon(":/icons/tooltip-arrow-dark").pixmap(requested_size);
+ }
+
+ if (id == "tooltip-arrow-light") {
+ *size = requested_size;
+ return QIcon(":/icons/tooltip-arrow-light").pixmap(requested_size);
+ }
+
return {};
}
diff --git a/src/qml/pages/wallet/DesktopWallets.qml b/src/qml/pages/wallet/DesktopWallets.qml
index 3c5c20fc10..87b90e0166 100644
--- a/src/qml/pages/wallet/DesktopWallets.qml
+++ b/src/qml/pages/wallet/DesktopWallets.qml
@@ -5,8 +5,11 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
+
import org.bitcoincore.qt 1.0
+
import "../../controls"
+import "../../controls/utils.js" as Utils
import "../../components"
import "../node"
@@ -67,10 +70,36 @@ Page {
shorten: true
}
NavigationTab {
+ id: blockClockTabButton
Layout.preferredWidth: 30
Layout.rightMargin: 10
property int index: 3
ButtonGroup.group: navigationTabs
+
+ Tooltip {
+ id: blockClockTooltip
+ property var syncState: Utils.formatRemainingSyncTime(nodeModel.remainingSyncTime)
+ property bool synced: nodeModel.verificationProgress > 0.9999
+ property bool paused: nodeModel.pause
+ property bool connected: nodeModel.numOutboundPeers > 0
+
+ anchors.top: blockClockTabButton.bottom
+ anchors.topMargin: -5
+ anchors.horizontalCenter: blockClockTabButton.horizontalCenter
+
+ visible: blockClockTabButton.hovered
+ text: {
+ if (paused) {
+ qsTr("Paused")
+ } else if (connected && synced) {
+ qsTr("Blocktime\n" + Number(nodeModel.blockTipHeight).toLocaleString(Qt.locale(), 'f', 0))
+ } else if (connected){
+ qsTr("Downloading blocks\n" + syncState.text)
+ } else {
+ qsTr("Connecting")
+ }
+ }
+ }
}
NavigationTab {
iconSource: "image://images/gear-outline"
diff --git a/src/qml/res/icons/tooltip-arrow-dark.png b/src/qml/res/icons/tooltip-arrow-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9f17332b0e7aaf94ec22571a84406bbb2e92705
GIT binary patch
literal 2096
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
ah<^Y#Yc2hjRP?_90000
+
+
+
diff --git a/src/qml/res/src/tooltip-arrow-light.svg b/src/qml/res/src/tooltip-arrow-light.svg
new file mode 100644
index 0000000000..fe61055eff
--- /dev/null
+++ b/src/qml/res/src/tooltip-arrow-light.svg
@@ -0,0 +1,4 @@
+