Skip to content

Commit 8c19122

Browse files
committed
Merge #401: Introduce Wallet Select Dropdown
0939f2b qml: Introduce the WalletSelect component (johnny9) 5906e69 qml: Introduce the WalletBadge component (johnny9) Pull request description: WalletSelect is a Popup that appears after clicking the main WalletBadge in the DesktopNavigation bar. It contains a ListView that allows the user to select one of the wallets listed in the wallet directory. This PR uses the arrow icon that is shared with the Tooltip so it is based off of that commit. [![Build Artifacts](https://img.shields.io/badge/Build%20Artifacts-green )](https://github.com/bitcoin-core/gui-qml/actions/runs/9263281845) ACKs for top commit: D33r-Gee: tACK [0939f2b](0939f2b) on WSL Ubuntu 22.04 Tree-SHA512: 19b877ca1be7488c54e79dba28720818711ab9f9f8de34cdb4f540daa150dc6debb8d78d9e0ba14b8a246f88497f6a04b089bcd3e4dca433afe49990201439d9
2 parents a73577b + 0939f2b commit 8c19122

File tree

12 files changed

+458
-20
lines changed

12 files changed

+458
-20
lines changed

src/Makefile.qt.include

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ QT_MOC_CPP = \
4242
qml/models/moc_nodemodel.cpp \
4343
qml/models/moc_options_model.cpp \
4444
qml/models/moc_peerlistsortproxy.cpp \
45+
qml/models/moc_walletlistmodel.cpp \
4546
qml/moc_appmode.cpp \
4647
qml/moc_walletcontroller.cpp \
4748
qt/moc_addressbookpage.cpp \
@@ -122,6 +123,7 @@ BITCOIN_QT_H = \
122123
qml/models/nodemodel.h \
123124
qml/models/options_model.h \
124125
qml/models/peerlistsortproxy.h \
126+
qml/models/walletlistmodel.h \
125127
qml/appmode.h \
126128
qml/bitcoin.h \
127129
qml/guiconstants.h \
@@ -311,6 +313,7 @@ BITCOIN_QML_BASE_CPP = \
311313
qml/models/nodemodel.cpp \
312314
qml/models/options_model.cpp \
313315
qml/models/peerlistsortproxy.cpp \
316+
qml/models/walletlistmodel.cpp \
314317
qml/imageprovider.cpp \
315318
qml/util.cpp \
316319
qml/walletcontroller.cpp
@@ -339,6 +342,7 @@ QML_RES_ICONS = \
339342
qml/res/icons/info.png \
340343
qml/res/icons/network-dark.png \
341344
qml/res/icons/network-light.png \
345+
qml/res/icons/plus.png \
342346
qml/res/icons/shutdown.png \
343347
qml/res/icons/singlesig-wallet.png \
344348
qml/res/icons/storage-dark.png \
@@ -423,7 +427,9 @@ QML_RES_QML = \
423427
qml/pages/wallet/CreateIntro.qml \
424428
qml/pages/wallet/CreateName.qml \
425429
qml/pages/wallet/CreatePassword.qml \
426-
qml/pages/wallet/DesktopWallets.qml
430+
qml/pages/wallet/DesktopWallets.qml \
431+
qml/pages/wallet/WalletBadge.qml \
432+
qml/pages/wallet/WalletSelect.qml
427433

428434
if TARGET_ANDROID
429435
BITCOIN_QT_H += qml/androidnotifier.h

src/qml/bitcoin.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <qml/models/nodemodel.h>
2727
#include <qml/models/options_model.h>
2828
#include <qml/models/peerlistsortproxy.h>
29+
#include <qml/models/walletlistmodel.h>
2930
#include <qml/imageprovider.h>
3031
#include <qml/util.h>
3132
#include <qml/walletcontroller.h>
@@ -295,12 +296,15 @@ int QmlGuiMain(int argc, char* argv[])
295296
assert(!network_style.isNull());
296297
engine.addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()});
297298

299+
WalletListModel wallet_list_model{*node, nullptr};
300+
298301
engine.rootContext()->setContextProperty("networkTrafficTower", &network_traffic_tower);
299302
engine.rootContext()->setContextProperty("nodeModel", &node_model);
300303
engine.rootContext()->setContextProperty("chainModel", &chain_model);
301304
engine.rootContext()->setContextProperty("peerTableModel", &peer_model);
302305
engine.rootContext()->setContextProperty("peerListModelProxy", &peer_model_sort_proxy);
303306
engine.rootContext()->setContextProperty("walletController", &wallet_controller);
307+
engine.rootContext()->setContextProperty("walletListModel", &wallet_list_model);
304308

305309
OptionsQmlModel options_model(*node, !need_onboarding.toBool());
306310
engine.rootContext()->setContextProperty("optionsModel", &options_model);

src/qml/bitcoin_qml.qrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
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>
77+
<file>pages/wallet/WalletSelect.qml</file>
7678
</qresource>
7779
<qresource prefix="/icons">
7880
<file alias="add-wallet-dark">res/icons/add-wallet-dark.png</file>
@@ -95,6 +97,7 @@
9597
<file alias="info">res/icons/info.png</file>
9698
<file alias="network-dark">res/icons/network-dark.png</file>
9799
<file alias="network-light">res/icons/network-light.png</file>
100+
<file alias="plus">res/icons/plus.png</file>
98101
<file alias="shutdown">res/icons/shutdown.png</file>
99102
<file alias="singlesig-wallet">res/icons/singlesig-wallet.png</file>
100103
<file alias="storage-dark">res/icons/storage-dark.png</file>

src/qml/controls/Icon.qml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import QtQuick.Controls 2.15
77

88
Button {
99
id: root
10+
width: icon.width
11+
height: icon.height
1012
required property color color
1113
required property url source
1214
property int size: 32

src/qml/imageprovider.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,9 @@ QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize
162162
return QIcon(":/icons/hidden").pixmap(requested_size);
163163
}
164164

165+
if (id == "plus") {
166+
*size = requested_size;
167+
return QIcon(":/icons/plus").pixmap(requested_size);
168+
}
165169
return {};
166170
}

src/qml/models/walletlistmodel.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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/walletlistmodel.h>
6+
7+
#include <interfaces/node.h>
8+
9+
#include <QSet>
10+
11+
WalletListModel::WalletListModel(interfaces::Node& node, QObject *parent)
12+
: QAbstractListModel(parent)
13+
, m_node(node)
14+
{
15+
setSelectedWallet("Singlesig Wallet");
16+
}
17+
18+
void WalletListModel::listWalletDir()
19+
{
20+
QSet<QString> existing_names;
21+
for (int i = 0; i < rowCount(); ++i) {
22+
QModelIndex index = this->index(i, 0);
23+
QString name = data(index, NameRole).toString();
24+
existing_names.insert(name);
25+
}
26+
27+
for (const std::string &name : m_node.walletLoader().listWalletDir()) {
28+
QString qname = QString::fromStdString(name);
29+
if (!existing_names.contains(qname)) {
30+
addItem({ qname });
31+
}
32+
}
33+
}
34+
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+
48+
int WalletListModel::rowCount(const QModelIndex &parent) const
49+
{
50+
Q_UNUSED(parent);
51+
return m_items.size();
52+
}
53+
54+
QVariant WalletListModel::data(const QModelIndex &index, int role) const
55+
{
56+
if (!index.isValid() || index.row() < 0 || index.row() >= m_items.size())
57+
return QVariant();
58+
59+
const auto &item = m_items[index.row()];
60+
switch (role) {
61+
case Qt::DisplayRole:
62+
case NameRole:
63+
return item.name;
64+
default:
65+
return QVariant();
66+
}
67+
}
68+
69+
QHash<int, QByteArray> WalletListModel::roleNames() const
70+
{
71+
QHash<int, QByteArray> roles;
72+
roles[NameRole] = "name";
73+
return roles;
74+
}
75+
76+
void WalletListModel::addItem(const Item &item)
77+
{
78+
beginInsertRows(QModelIndex(), rowCount(), rowCount());
79+
m_items.append(item);
80+
endInsertRows();
81+
}

src/qml/models/walletlistmodel.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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_WALLETLISTMODEL_H
6+
#define BITCOIN_QML_MODELS_WALLETLISTMODEL_H
7+
8+
#include <interfaces/wallet.h>
9+
#include <QAbstractListModel>
10+
#include <QList>
11+
12+
namespace interfaces {
13+
class Node;
14+
}
15+
16+
class WalletListModel : public QAbstractListModel
17+
{
18+
Q_OBJECT
19+
Q_PROPERTY(QString selectedWallet READ selectedWallet WRITE setSelectedWallet NOTIFY selectedWalletChanged)
20+
21+
public:
22+
WalletListModel(interfaces::Node& node, QObject *parent = nullptr);
23+
~WalletListModel() = default;
24+
25+
enum Roles {
26+
NameRole = Qt::UserRole + 1
27+
};
28+
29+
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
30+
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
31+
QHash<int, QByteArray> roleNames() const override;
32+
33+
void setSelectedWallet(QString wallet_name);
34+
QString selectedWallet() const;
35+
36+
public Q_SLOTS:
37+
void listWalletDir();
38+
39+
Q_SIGNALS:
40+
void selectedWalletChanged();
41+
42+
private:
43+
struct Item {
44+
QString name;
45+
};
46+
47+
void addItem(const Item &item);
48+
49+
QList<Item> m_items;
50+
interfaces::Node& m_node;
51+
QString m_selected_wallet;
52+
53+
};
54+
55+
#endif // BITCOIN_QML_MODELS_WALLETLISTMODEL_H

src/qml/pages/wallet/DesktopWallets.qml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,26 @@ 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
24+
leftItem: WalletBadge {
25+
implicitWidth: 154
26+
implicitHeight: 46
27+
text: walletListModel.selectedWallet
28+
29+
MouseArea {
30+
anchors.fill: parent
31+
onClicked: {
32+
walletListModel.listWalletDir()
33+
walletSelect.opened ? walletSelect.close() : walletSelect.open()
4334
}
4435
}
36+
37+
WalletSelect {
38+
id: walletSelect
39+
model: walletListModel
40+
closePolicy: Popup.CloseOnPressOutside
41+
x: 0
42+
y: parent.height
43+
}
4544
}
4645
centerItem: RowLayout {
4746
NavigationTab {

0 commit comments

Comments
 (0)