diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9d59b4eb53..96416c04c3 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -337,7 +337,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 @@ -361,6 +363,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 \ @@ -383,6 +386,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 0000000000..a9f17332b0 Binary files /dev/null and b/src/qml/res/icons/tooltip-arrow-dark.png differ diff --git a/src/qml/res/icons/tooltip-arrow-light.png b/src/qml/res/icons/tooltip-arrow-light.png new file mode 100644 index 0000000000..20f9a6d310 Binary files /dev/null and b/src/qml/res/icons/tooltip-arrow-light.png differ diff --git a/src/qml/res/src/tooltip-arrow-dark.svg b/src/qml/res/src/tooltip-arrow-dark.svg new file mode 100644 index 0000000000..91cd0c81be --- /dev/null +++ b/src/qml/res/src/tooltip-arrow-dark.svg @@ -0,0 +1,4 @@ + + + + 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 @@ + + + +