Skip to content

Commit 5906e69

Browse files
committed
qml: Introduce the WalletBadge component
The WalletBadge is an Item that shows a wallet's name, type and balance. The WalletBadge balance shows all of the decimal places for a whole bitcoin and highlights the satoshis available. The component can be configured to not show the Icon or the Balance.
1 parent a73577b commit 5906e69

File tree

4 files changed

+171
-22
lines changed

4 files changed

+171
-22
lines changed

src/Makefile.qt.include

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ QML_RES_QML = \
423423
qml/pages/wallet/CreateIntro.qml \
424424
qml/pages/wallet/CreateName.qml \
425425
qml/pages/wallet/CreatePassword.qml \
426-
qml/pages/wallet/DesktopWallets.qml
426+
qml/pages/wallet/DesktopWallets.qml \
427+
qml/pages/wallet/WalletBadge.qml
427428

428429
if TARGET_ANDROID
429430
BITCOIN_QT_H += qml/androidnotifier.h

src/qml/bitcoin_qml.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
<file>pages/wallet/CreateName.qml</file>
7474
<file>pages/wallet/CreatePassword.qml</file>
7575
<file>pages/wallet/DesktopWallets.qml</file>
76+
<file>pages/wallet/WalletBadge.qml</file>
7677
</qresource>
7778
<qresource prefix="/icons">
7879
<file alias="add-wallet-dark">res/icons/add-wallet-dark.png</file>

src/qml/pages/wallet/DesktopWallets.qml

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,10 @@ Page {
2121

2222
header: NavigationBar2 {
2323
id: navBar
24-
leftItem: RowLayout {
25-
spacing: 5
26-
Icon {
27-
source: "image://images/singlesig-wallet"
28-
color: Theme.color.neutral8
29-
Layout.preferredWidth: 30
30-
Layout.preferredHeight: 30
31-
Layout.leftMargin: 10
32-
}
33-
Column {
34-
spacing: 2
35-
CoreText {
36-
text: "Singlesig Wallet"
37-
color: Theme.color.neutral7
38-
bold: true
39-
}
40-
CoreText {
41-
text: "<font color=\""+Theme.color.white+"\">₿</font> 0.00 <font color=\""+Theme.color.white+"\">167 599</font>"
42-
color: Theme.color.neutral7
43-
}
44-
}
24+
leftItem: WalletBadge {
25+
implicitWidth: 154
26+
implicitHeight: 46
27+
text: qsTr("Singlesig Wallet")
4528
}
4629
centerItem: RowLayout {
4730
NavigationTab {

src/qml/pages/wallet/WalletBadge.qml

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright (c) 2024 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
import QtQuick 2.15
6+
import QtQuick.Controls 2.15
7+
import QtQuick.Layouts 1.15
8+
9+
import org.bitcoincore.qt 1.0
10+
11+
import "../../controls"
12+
13+
Button {
14+
id: root
15+
16+
function formatSatoshis(satoshis) {
17+
var highlightColor = Theme.color.neutral9
18+
var zeroColor = Theme.color.neutral7
19+
20+
if (root.checked || root.hovered) {
21+
highlightColor = zeroColor = Theme.color.orange
22+
}
23+
24+
// Convert satoshis to bitcoins
25+
var bitcoins = satoshis / 100000000;
26+
27+
// Format bitcoins to a fixed 8 decimal places string
28+
var bitcoinStr = bitcoins.toFixed(8);
29+
30+
// Split the bitcoin string into integer and fractional parts
31+
var parts = bitcoinStr.split('.');
32+
33+
// Add spaces for every 3 digits in the integer part
34+
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
35+
36+
// Highlight the first significant digit and all following digits in the integer part
37+
var significantFound = false;
38+
parts[0] = parts[0].replace(/(\d)/g, function(match) {
39+
if (!significantFound && match !== '0') {
40+
significantFound = true;
41+
}
42+
if (significantFound) {
43+
return '<font color="' + highlightColor + '">' + match + '</font>';
44+
}
45+
return match;
46+
});
47+
48+
// Add spaces for every 3 digits in the decimal part
49+
parts[1] = parts[1].replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
50+
if (significantFound) {
51+
parts[1] = '<font color="' + highlightColor + '">' + parts[1] + '</font>';
52+
} else {
53+
// Highlight the first significant digit and all following digits in the fractional part
54+
significantFound = false;
55+
parts[1] = parts[1].replace(/(\d)/g, function(match) {
56+
if (!significantFound && match !== '0') {
57+
significantFound = true;
58+
}
59+
if (significantFound) {
60+
return '<font color="' + highlightColor + '">' + match + '</font>';
61+
}
62+
return match;
63+
});
64+
}
65+
66+
// Concatenate the parts back together
67+
var formattedBitcoins = parts.join('.');
68+
69+
// Format the text with the Bitcoin symbol
70+
var formattedText = `<font color="${highlightColor}">₿</font> ${formattedBitcoins}`;
71+
72+
// Highlight zero in a different color if satoshis are zero
73+
if (satoshis === 0) {
74+
formattedText = `<font color="${zeroColor}">₿ 0.00</font>`;
75+
}
76+
77+
return formattedText;
78+
}
79+
80+
property color bgActiveColor: Theme.color.neutral2
81+
property color textColor: Theme.color.neutral7
82+
property color textHoverColor: Theme.color.orange
83+
property color textActiveColor: Theme.color.orange
84+
property color iconColor: "transparent"
85+
property string iconSource: ""
86+
property bool showBalance: true
87+
property bool showIcon: true
88+
89+
checkable: true
90+
hoverEnabled: AppMode.isDesktop
91+
implicitHeight: 60
92+
implicitWidth: 220
93+
bottomPadding: 0
94+
topPadding: 0
95+
clip: true
96+
97+
contentItem: RowLayout {
98+
anchors.fill: parent
99+
anchors.leftMargin: 5
100+
anchors.rightMargin: 5
101+
clip: true
102+
spacing: 5
103+
Icon {
104+
id: icon
105+
visible: root.showIcon
106+
source: "image://images/singlesig-wallet"
107+
color: Theme.color.neutral8
108+
Layout.preferredWidth: 30
109+
Layout.preferredHeight: 30
110+
}
111+
ColumnLayout {
112+
spacing: 2
113+
CoreText {
114+
horizontalAlignment: Text.AlignLeft
115+
Layout.fillWidth: true
116+
wrap: false
117+
id: buttonText
118+
font.pixelSize: 13
119+
text: root.text
120+
color: root.textColor
121+
bold: true
122+
visible: root.text !== ""
123+
}
124+
CoreText {
125+
id: balanceText
126+
visible: root.showBalance
127+
text: formatSatoshis(12300)
128+
color: Theme.color.neutral7
129+
}
130+
}
131+
}
132+
133+
background: Rectangle {
134+
id: bg
135+
height: root.height
136+
width: root.width
137+
radius: 5
138+
color: Theme.color.neutral3
139+
visible: root.hovered || root.checked
140+
141+
FocusBorder {
142+
visible: root.visualFocus
143+
}
144+
145+
Behavior on color {
146+
ColorAnimation { duration: 150 }
147+
}
148+
}
149+
150+
states: [
151+
State {
152+
name: "CHECKED"; when: root.checked
153+
PropertyChanges { target: buttonText; color: root.textActiveColor }
154+
PropertyChanges { target: icon; color: root.textActiveColor }
155+
PropertyChanges { target: balanceText; color: root.textActiveColor }
156+
},
157+
State {
158+
name: "HOVER"; when: root.hovered
159+
PropertyChanges { target: buttonText; color: root.textHoverColor }
160+
PropertyChanges { target: icon; color: root.textHoverColor }
161+
PropertyChanges { target: balanceText; color: root.textHoverColor }
162+
}
163+
]
164+
}

0 commit comments

Comments
 (0)