Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce WalletModel and loadWallet functionality #417

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ QT_MOC_CPP = \
qml/models/moc_peerdetailsmodel.cpp \
qml/models/moc_peerlistsortproxy.cpp \
qml/models/moc_walletlistmodel.cpp \
qml/models/moc_walletqmlmodel.cpp \
qml/moc_appmode.cpp \
qml/moc_walletcontroller.cpp \
qml/moc_walletqmlcontroller.cpp \
qt/moc_addressbookpage.cpp \
qt/moc_addresstablemodel.cpp \
qt/moc_askpassphrasedialog.cpp \
Expand Down Expand Up @@ -126,12 +127,13 @@ BITCOIN_QT_H = \
qml/models/peerdetailsmodel.h \
qml/models/peerlistsortproxy.h \
qml/models/walletlistmodel.h \
qml/models/walletqmlmodel.h \
qml/appmode.h \
qml/bitcoin.h \
qml/guiconstants.h \
qml/imageprovider.h \
qml/util.h \
qml/walletcontroller.h \
qml/walletqmlcontroller.h \
qt/addressbookpage.h \
qt/addresstablemodel.h \
qt/askpassphrasedialog.h \
Expand Down Expand Up @@ -317,9 +319,10 @@ BITCOIN_QML_BASE_CPP = \
qml/models/peerdetailsmodel.cpp \
qml/models/peerlistsortproxy.cpp \
qml/models/walletlistmodel.cpp \
qml/models/walletqmlmodel.cpp \
qml/imageprovider.cpp \
qml/util.cpp \
qml/walletcontroller.cpp
qml/walletqmlcontroller.cpp

QML_RES_FONTS = \
qml/res/fonts/Inter-Regular.otf \
Expand Down
29 changes: 23 additions & 6 deletions src/qml/bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
#include <qml/models/peerdetailsmodel.h>
#include <qml/models/peerlistsortproxy.h>
#include <qml/models/walletlistmodel.h>
#include <qml/models/walletqmlmodel.h>
#include <qml/imageprovider.h>
#include <qml/util.h>
#include <qml/walletcontroller.h>
#include <qml/walletqmlcontroller.h>
#include <qt/guiutil.h>
#include <qt/initexecutor.h>
#include <qt/networkstyle.h>
Expand Down Expand Up @@ -259,8 +260,17 @@ int QmlGuiMain(int argc, char* argv[])

NodeModel node_model{*node};
InitExecutor init_executor{*node};
#ifdef ENABLE_WALLET
WalletQmlController wallet_controller(*node);
QObject::connect(&init_executor, &InitExecutor::initializeResult, &wallet_controller, &WalletQmlController::initialize);
#endif
QObject::connect(&node_model, &NodeModel::requestedInitialize, &init_executor, &InitExecutor::initialize);
QObject::connect(&node_model, &NodeModel::requestedShutdown, &init_executor, &InitExecutor::shutdown);
QObject::connect(&node_model, &NodeModel::requestedShutdown, [&] {
#ifdef ENABLE_WALLET
wallet_controller.unloadWallets();
#endif
init_executor.shutdown();
});
QObject::connect(&init_executor, &InitExecutor::initializeResult, &node_model, &NodeModel::initializeResult);
QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
// QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
Expand All @@ -277,8 +287,12 @@ int QmlGuiMain(int argc, char* argv[])
QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);


qGuiApp->setQuitOnLastWindowClosed(false);
QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
#ifdef ENABLE_WALLET
wallet_controller.unloadWallets();
#endif
node->startShutdown();
});

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

WalletController wallet_controller(*node);

QQmlApplicationEngine engine;

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

WalletListModel wallet_list_model{*node, nullptr};

engine.rootContext()->setContextProperty("networkTrafficTower", &network_traffic_tower);
engine.rootContext()->setContextProperty("nodeModel", &node_model);
engine.rootContext()->setContextProperty("chainModel", &chain_model);
engine.rootContext()->setContextProperty("peerTableModel", &peer_model);
engine.rootContext()->setContextProperty("peerListModelProxy", &peer_model_sort_proxy);
#ifdef ENABLE_WALLET
WalletListModel wallet_list_model{*node, nullptr};
engine.rootContext()->setContextProperty("walletController", &wallet_controller);
engine.rootContext()->setContextProperty("walletListModel", &wallet_list_model);
#endif

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

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

engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml")));
if (engine.rootObjects().isEmpty()) {
Expand Down
14 changes: 0 additions & 14 deletions src/qml/models/walletlistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ WalletListModel::WalletListModel(interfaces::Node& node, QObject *parent)
: QAbstractListModel(parent)
, m_node(node)
{
setSelectedWallet("Singlesig Wallet");
}

void WalletListModel::listWalletDir()
Expand All @@ -32,19 +31,6 @@ void WalletListModel::listWalletDir()
}
}

void WalletListModel::setSelectedWallet(QString wallet_name)
{
if (m_selected_wallet != wallet_name) {
m_selected_wallet = wallet_name;
Q_EMIT selectedWalletChanged();
}
}

QString WalletListModel::selectedWallet() const
{
return m_selected_wallet;
}

int WalletListModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
Expand Down
9 changes: 0 additions & 9 deletions src/qml/models/walletlistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class Node;
class WalletListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString selectedWallet READ selectedWallet WRITE setSelectedWallet NOTIFY selectedWalletChanged)

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

void setSelectedWallet(QString wallet_name);
QString selectedWallet() const;

public Q_SLOTS:
void listWalletDir();

Q_SIGNALS:
void selectedWalletChanged();

private:
struct Item {
QString name;
Expand All @@ -48,8 +41,6 @@ public Q_SLOTS:

QList<Item> m_items;
interfaces::Node& m_node;
QString m_selected_wallet;

};

#endif // BITCOIN_QML_MODELS_WALLETLISTMODEL_H
36 changes: 36 additions & 0 deletions src/qml/models/walletqmlmodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.

#include <qml/models/walletqmlmodel.h>

#include <qt/bitcoinunits.h>

#include <QTimer>

WalletQmlModel::WalletQmlModel(std::unique_ptr<interfaces::Wallet> wallet, QObject *parent)
: QObject(parent)
{
m_wallet = std::move(wallet);
}

WalletQmlModel::WalletQmlModel(QObject *parent)
: QObject(parent)
{
}

QString WalletQmlModel::balance() const
{
if (!m_wallet) {
return "0";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this leaves the wallet dropdown in a weird looking state, we'd want to revisit balance anyways on subsequent updates, just noting that this should all change.

}
return BitcoinUnits::format(BitcoinUnits::Unit::BTC, m_wallet->getBalance());
}

QString WalletQmlModel::name() const
{
if (!m_wallet) {
return QString();
}
return QString::fromStdString(m_wallet->getWalletName());
}
34 changes: 34 additions & 0 deletions src/qml/models/walletqmlmodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

#ifndef BITCOIN_QML_MODELS_WALLETQMLMODEL_H
#define BITCOIN_QML_MODELS_WALLETQMLMODEL_H

#include <interfaces/wallet.h>

#include <QObject>

class WalletQmlModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(QString balance READ balance NOTIFY balanceChanged)

public:
WalletQmlModel(std::unique_ptr<interfaces::Wallet> wallet, QObject *parent = nullptr);
WalletQmlModel(QObject *parent = nullptr);
~WalletQmlModel() = default;

QString name() const;
QString balance() const;

Q_SIGNALS:
void nameChanged();
void balanceChanged();

private:
std::unique_ptr<interfaces::Wallet> m_wallet;
};

#endif // BITCOIN_QML_MODELS_WALLETQMLMODEL_H
3 changes: 2 additions & 1 deletion src/qml/pages/wallet/DesktopWallets.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ Page {
leftItem: WalletBadge {
implicitWidth: 154
implicitHeight: 46
text: walletListModel.selectedWallet
text: walletController.selectedWallet.name
balance: walletController.selectedWallet.balance

MouseArea {
anchors.fill: parent
Expand Down
70 changes: 3 additions & 67 deletions src/qml/pages/wallet/WalletBadge.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,70 +13,6 @@ import "../../controls"
Button {
id: root

function formatSatoshis(satoshis) {
var highlightColor = Theme.color.neutral9
var zeroColor = Theme.color.neutral7

if (root.checked || root.hovered) {
highlightColor = zeroColor = Theme.color.orange
}

// Convert satoshis to bitcoins
var bitcoins = satoshis / 100000000;

// Format bitcoins to a fixed 8 decimal places string
var bitcoinStr = bitcoins.toFixed(8);

// Split the bitcoin string into integer and fractional parts
var parts = bitcoinStr.split('.');

// Add spaces for every 3 digits in the integer part
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ' ');

// Highlight the first significant digit and all following digits in the integer part
var significantFound = false;
parts[0] = parts[0].replace(/(\d)/g, function(match) {
if (!significantFound && match !== '0') {
significantFound = true;
}
if (significantFound) {
return '<font color="' + highlightColor + '">' + match + '</font>';
}
return match;
});

// Add spaces for every 3 digits in the decimal part
parts[1] = parts[1].replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
if (significantFound) {
parts[1] = '<font color="' + highlightColor + '">' + parts[1] + '</font>';
} else {
// Highlight the first significant digit and all following digits in the fractional part
significantFound = false;
parts[1] = parts[1].replace(/(\d)/g, function(match) {
if (!significantFound && match !== '0') {
significantFound = true;
}
if (significantFound) {
return '<font color="' + highlightColor + '">' + match + '</font>';
}
return match;
});
}

// Concatenate the parts back together
var formattedBitcoins = parts.join('.');

// Format the text with the Bitcoin symbol
var formattedText = `<font color="${highlightColor}">₿</font> ${formattedBitcoins}`;

// Highlight zero in a different color if satoshis are zero
if (satoshis === 0) {
formattedText = `<font color="${zeroColor}">₿ 0.00</font>`;
}

return formattedText;
}

property color bgActiveColor: Theme.color.neutral2
property color textColor: Theme.color.neutral7
property color textHoverColor: Theme.color.orange
Expand All @@ -85,17 +21,17 @@ Button {
property string iconSource: ""
property bool showBalance: true
property bool showIcon: true
property string balance: "0.0 000 000"

checkable: true
hoverEnabled: AppMode.isDesktop
implicitHeight: 60
implicitWidth: 220
implicitWidth: contentItem.width
bottomPadding: 0
topPadding: 0
clip: true

contentItem: RowLayout {
anchors.fill: parent
anchors.leftMargin: 5
anchors.rightMargin: 5
clip: true
Expand Down Expand Up @@ -126,7 +62,7 @@ Button {
CoreText {
id: balanceText
visible: root.showBalance
text: formatSatoshis(12300)
text: "₿ " + root.balance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll also need the sat symbol :P

color: Theme.color.neutral7
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/qml/pages/wallet/WalletSelect.qml
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ Popup {
width: 220
height: 32
text: name
checked: walletController.selectedWallet.name == name
ButtonGroup.group: buttonGroup
showBalance: false
showIcon: false
onClicked: {
walletListModel.selectedWallet = name
walletController.setSelectedWallet(name)
root.close()
}
}
Expand Down
Loading
Loading