Skip to content

Commit b41a0e4

Browse files
committed
qml: Introduce WalletModel and loadWallet functionality
When a user selects a wallet from the WalletSelect menu the wallet controller can now load the wallet data in and the name and balance will appear in the WalletBadge
1 parent 88ce525 commit b41a0e4

13 files changed

+225
-152
lines changed

src/Makefile.qt.include

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ QT_MOC_CPP = \
4444
qml/models/moc_peerdetailsmodel.cpp \
4545
qml/models/moc_peerlistsortproxy.cpp \
4646
qml/models/moc_walletlistmodel.cpp \
47+
qml/models/moc_walletqmlmodel.cpp \
4748
qml/moc_appmode.cpp \
48-
qml/moc_walletcontroller.cpp \
49+
qml/moc_walletqmlcontroller.cpp \
4950
qt/moc_addressbookpage.cpp \
5051
qt/moc_addresstablemodel.cpp \
5152
qt/moc_askpassphrasedialog.cpp \
@@ -126,12 +127,13 @@ BITCOIN_QT_H = \
126127
qml/models/peerdetailsmodel.h \
127128
qml/models/peerlistsortproxy.h \
128129
qml/models/walletlistmodel.h \
130+
qml/models/walletqmlmodel.h \
129131
qml/appmode.h \
130132
qml/bitcoin.h \
131133
qml/guiconstants.h \
132134
qml/imageprovider.h \
133135
qml/util.h \
134-
qml/walletcontroller.h \
136+
qml/walletqmlcontroller.h \
135137
qt/addressbookpage.h \
136138
qt/addresstablemodel.h \
137139
qt/askpassphrasedialog.h \
@@ -317,9 +319,10 @@ BITCOIN_QML_BASE_CPP = \
317319
qml/models/peerdetailsmodel.cpp \
318320
qml/models/peerlistsortproxy.cpp \
319321
qml/models/walletlistmodel.cpp \
322+
qml/models/walletqmlmodel.cpp \
320323
qml/imageprovider.cpp \
321324
qml/util.cpp \
322-
qml/walletcontroller.cpp
325+
qml/walletqmlcontroller.cpp
323326

324327
QML_RES_FONTS = \
325328
qml/res/fonts/Inter-Regular.otf \

src/qml/bitcoin.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
#include <qml/models/peerdetailsmodel.h>
2929
#include <qml/models/peerlistsortproxy.h>
3030
#include <qml/models/walletlistmodel.h>
31+
#include <qml/models/walletqmlmodel.h>
3132
#include <qml/imageprovider.h>
3233
#include <qml/util.h>
33-
#include <qml/walletcontroller.h>
34+
#include <qml/walletqmlcontroller.h>
3435
#include <qt/guiutil.h>
3536
#include <qt/initexecutor.h>
3637
#include <qt/networkstyle.h>
@@ -259,8 +260,17 @@ int QmlGuiMain(int argc, char* argv[])
259260

260261
NodeModel node_model{*node};
261262
InitExecutor init_executor{*node};
263+
#ifdef ENABLE_WALLET
264+
WalletQmlController wallet_controller(*node);
265+
QObject::connect(&init_executor, &InitExecutor::initializeResult, &wallet_controller, &WalletQmlController::initialize);
266+
#endif
262267
QObject::connect(&node_model, &NodeModel::requestedInitialize, &init_executor, &InitExecutor::initialize);
263-
QObject::connect(&node_model, &NodeModel::requestedShutdown, &init_executor, &InitExecutor::shutdown);
268+
QObject::connect(&node_model, &NodeModel::requestedShutdown, [&] {
269+
#ifdef ENABLE_WALLET
270+
wallet_controller.unloadWallets();
271+
#endif
272+
init_executor.shutdown();
273+
});
264274
QObject::connect(&init_executor, &InitExecutor::initializeResult, &node_model, &NodeModel::initializeResult);
265275
QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
266276
// QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
@@ -277,8 +287,12 @@ int QmlGuiMain(int argc, char* argv[])
277287
QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
278288
QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);
279289

290+
280291
qGuiApp->setQuitOnLastWindowClosed(false);
281292
QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
293+
#ifdef ENABLE_WALLET
294+
wallet_controller.unloadWallets();
295+
#endif
282296
node->startShutdown();
283297
});
284298

@@ -289,23 +303,22 @@ int QmlGuiMain(int argc, char* argv[])
289303
GUIUtil::LoadFont(":/fonts/inter/regular");
290304
GUIUtil::LoadFont(":/fonts/inter/semibold");
291305

292-
WalletController wallet_controller(*node);
293-
294306
QQmlApplicationEngine engine;
295307

296308
QScopedPointer<const NetworkStyle> network_style{NetworkStyle::instantiate(Params().GetChainType())};
297309
assert(!network_style.isNull());
298310
engine.addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()});
299311

300-
WalletListModel wallet_list_model{*node, nullptr};
301-
302312
engine.rootContext()->setContextProperty("networkTrafficTower", &network_traffic_tower);
303313
engine.rootContext()->setContextProperty("nodeModel", &node_model);
304314
engine.rootContext()->setContextProperty("chainModel", &chain_model);
305315
engine.rootContext()->setContextProperty("peerTableModel", &peer_model);
306316
engine.rootContext()->setContextProperty("peerListModelProxy", &peer_model_sort_proxy);
317+
#ifdef ENABLE_WALLET
318+
WalletListModel wallet_list_model{*node, nullptr};
307319
engine.rootContext()->setContextProperty("walletController", &wallet_controller);
308320
engine.rootContext()->setContextProperty("walletListModel", &wallet_list_model);
321+
#endif
309322

310323
OptionsQmlModel options_model(*node, !need_onboarding.toBool());
311324
engine.rootContext()->setContextProperty("optionsModel", &options_model);
@@ -318,6 +331,10 @@ int QmlGuiMain(int argc, char* argv[])
318331
qmlRegisterType<LineGraph>("org.bitcoincore.qt", 1, 0, "LineGraph");
319332
qmlRegisterUncreatableType<PeerDetailsModel>("org.bitcoincore.qt", 1, 0, "PeerDetailsModel", "");
320333

334+
#ifdef ENABLE_WALLET
335+
qmlRegisterUncreatableType<WalletQmlModel>("org.bitcoincore.qt", 1, 0, "WalletQmlModel",
336+
"WalletQmlModel cannot be instantiated from QML");
337+
#endif
321338

322339
engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml")));
323340
if (engine.rootObjects().isEmpty()) {

src/qml/models/walletlistmodel.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ WalletListModel::WalletListModel(interfaces::Node& node, QObject *parent)
1212
: QAbstractListModel(parent)
1313
, m_node(node)
1414
{
15-
setSelectedWallet("Singlesig Wallet");
1615
}
1716

1817
void WalletListModel::listWalletDir()
@@ -32,19 +31,6 @@ void WalletListModel::listWalletDir()
3231
}
3332
}
3433

35-
void WalletListModel::setSelectedWallet(QString wallet_name)
36-
{
37-
if (m_selected_wallet != wallet_name) {
38-
m_selected_wallet = wallet_name;
39-
Q_EMIT selectedWalletChanged();
40-
}
41-
}
42-
43-
QString WalletListModel::selectedWallet() const
44-
{
45-
return m_selected_wallet;
46-
}
47-
4834
int WalletListModel::rowCount(const QModelIndex &parent) const
4935
{
5036
Q_UNUSED(parent);

src/qml/models/walletlistmodel.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class Node;
1616
class WalletListModel : public QAbstractListModel
1717
{
1818
Q_OBJECT
19-
Q_PROPERTY(QString selectedWallet READ selectedWallet WRITE setSelectedWallet NOTIFY selectedWalletChanged)
2019

2120
public:
2221
WalletListModel(interfaces::Node& node, QObject *parent = nullptr);
@@ -30,15 +29,9 @@ class WalletListModel : public QAbstractListModel
3029
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
3130
QHash<int, QByteArray> roleNames() const override;
3231

33-
void setSelectedWallet(QString wallet_name);
34-
QString selectedWallet() const;
35-
3632
public Q_SLOTS:
3733
void listWalletDir();
3834

39-
Q_SIGNALS:
40-
void selectedWalletChanged();
41-
4235
private:
4336
struct Item {
4437
QString name;
@@ -48,8 +41,6 @@ public Q_SLOTS:
4841

4942
QList<Item> m_items;
5043
interfaces::Node& m_node;
51-
QString m_selected_wallet;
52-
5344
};
5445

5546
#endif // BITCOIN_QML_MODELS_WALLETLISTMODEL_H

src/qml/models/walletqmlmodel.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
#include <qml/models/walletqmlmodel.h>
6+
7+
#include <qt/bitcoinunits.h>
8+
9+
#include <QTimer>
10+
11+
WalletQmlModel::WalletQmlModel(std::unique_ptr<interfaces::Wallet> wallet, QObject *parent)
12+
: QObject(parent)
13+
{
14+
m_wallet = std::move(wallet);
15+
}
16+
17+
WalletQmlModel::WalletQmlModel(QObject *parent)
18+
: QObject(parent)
19+
{
20+
}
21+
22+
QString WalletQmlModel::balance() const
23+
{
24+
if (!m_wallet) {
25+
return "0";
26+
}
27+
return BitcoinUnits::format(BitcoinUnits::Unit::BTC, m_wallet->getBalance());
28+
}
29+
30+
QString WalletQmlModel::name() const
31+
{
32+
if (!m_wallet) {
33+
return QString();
34+
}
35+
return QString::fromStdString(m_wallet->getWalletName());
36+
}

src/qml/models/walletqmlmodel.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
#ifndef BITCOIN_QML_MODELS_WALLETQMLMODEL_H
6+
#define BITCOIN_QML_MODELS_WALLETQMLMODEL_H
7+
8+
#include <interfaces/wallet.h>
9+
10+
#include <QObject>
11+
12+
class WalletQmlModel : public QObject
13+
{
14+
Q_OBJECT
15+
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
16+
Q_PROPERTY(QString balance READ balance NOTIFY balanceChanged)
17+
18+
public:
19+
WalletQmlModel(std::unique_ptr<interfaces::Wallet> wallet, QObject *parent = nullptr);
20+
WalletQmlModel(QObject *parent = nullptr);
21+
~WalletQmlModel() = default;
22+
23+
QString name() const;
24+
QString balance() const;
25+
26+
Q_SIGNALS:
27+
void nameChanged();
28+
void balanceChanged();
29+
30+
private:
31+
std::unique_ptr<interfaces::Wallet> m_wallet;
32+
};
33+
34+
#endif // BITCOIN_QML_MODELS_WALLETQMLMODEL_H

src/qml/pages/wallet/DesktopWallets.qml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Page {
2424
leftItem: WalletBadge {
2525
implicitWidth: 154
2626
implicitHeight: 46
27-
text: walletListModel.selectedWallet
27+
text: walletController.selectedWallet.name
28+
balance: walletController.selectedWallet.balance
2829

2930
MouseArea {
3031
anchors.fill: parent

src/qml/pages/wallet/WalletBadge.qml

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,70 +13,6 @@ import "../../controls"
1313
Button {
1414
id: root
1515

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-
8016
property color bgActiveColor: Theme.color.neutral2
8117
property color textColor: Theme.color.neutral7
8218
property color textHoverColor: Theme.color.orange
@@ -85,17 +21,17 @@ Button {
8521
property string iconSource: ""
8622
property bool showBalance: true
8723
property bool showIcon: true
24+
property string balance: "0.0 000 000"
8825

8926
checkable: true
9027
hoverEnabled: AppMode.isDesktop
9128
implicitHeight: 60
92-
implicitWidth: 220
29+
implicitWidth: contentItem.width
9330
bottomPadding: 0
9431
topPadding: 0
9532
clip: true
9633

9734
contentItem: RowLayout {
98-
anchors.fill: parent
9935
anchors.leftMargin: 5
10036
anchors.rightMargin: 5
10137
clip: true
@@ -126,7 +62,7 @@ Button {
12662
CoreText {
12763
id: balanceText
12864
visible: root.showBalance
129-
text: formatSatoshis(12300)
65+
text: "" + root.balance
13066
color: Theme.color.neutral7
13167
}
13268
}

src/qml/pages/wallet/WalletSelect.qml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ Popup {
7878
width: 220
7979
height: 32
8080
text: name
81+
checked: walletController.selectedWallet.name == name
8182
ButtonGroup.group: buttonGroup
8283
showBalance: false
8384
showIcon: false
8485
onClicked: {
85-
walletListModel.selectedWallet = name
86+
walletController.setSelectedWallet(name)
8687
root.close()
8788
}
8889
}

0 commit comments

Comments
 (0)