Skip to content

Show "Select Wallet" or "Add Wallet" in the Wallet selector if a wallet isn't loaded #465

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

Merged
merged 3 commits into from
Jun 6, 2025
Merged
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
6 changes: 6 additions & 0 deletions src/qml/models/walletqmlmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class WalletQmlModel : public QObject
Q_PROPERTY(SendRecipient* sendRecipient READ sendRecipient CONSTANT)
Q_PROPERTY(WalletQmlModelTransaction* currentTransaction READ currentTransaction NOTIFY currentTransactionChanged)
Q_PROPERTY(unsigned int targetBlocks READ feeTargetBlocks WRITE setFeeTargetBlocks NOTIFY feeTargetBlocksChanged)
Q_PROPERTY(bool isWalletLoaded READ isWalletLoaded NOTIFY walletIsLoadedChanged)

public:
WalletQmlModel(std::unique_ptr<interfaces::Wallet> wallet, QObject* parent = nullptr);
Expand Down Expand Up @@ -67,11 +68,15 @@ class WalletQmlModel : public QObject
unsigned int feeTargetBlocks() const;
void setFeeTargetBlocks(unsigned int target_blocks);

bool isWalletLoaded() const { return m_is_wallet_loaded; }
void setWalletLoaded(bool loaded);

Q_SIGNALS:
void nameChanged();
void balanceChanged();
void currentTransactionChanged();
void feeTargetBlocksChanged();
void walletIsLoadedChanged();

private:
std::unique_ptr<interfaces::Wallet> m_wallet;
Expand All @@ -80,6 +85,7 @@ class WalletQmlModel : public QObject
SendRecipient* m_current_recipient{nullptr};
WalletQmlModelTransaction* m_current_transaction{nullptr};
wallet::CCoinControl m_coin_control;
bool m_is_wallet_loaded{false};
};

#endif // BITCOIN_QML_MODELS_WALLETQMLMODEL_H
8 changes: 5 additions & 3 deletions src/qml/pages/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ ApplicationWindow {
onFinished: {
optionsModel.onboard()
if (AppMode.walletEnabled && AppMode.isDesktop) {
main.push(desktopWallets)
main.push(createWalletWizard)
main.push([
desktopWallets, {},
createWalletWizard, { "launchContext": CreateWalletWizard.Context.Onboarding }
])
} else {
main.push(node)
}
Expand All @@ -82,7 +84,7 @@ ApplicationWindow {
id: desktopWallets
DesktopWallets {
onAddWallet: {
main.push(createWalletWizard)
main.push(createWalletWizard, { "launchContext": CreateWalletWizard.Context.Main })
}
onSendTransaction: {
main.push(sendReviewPage)
Expand Down
13 changes: 12 additions & 1 deletion src/qml/pages/wallet/CreateWalletWizard.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,27 @@ import "../wallet"
PageStack {
id: root

enum Context { Onboarding, Main }

signal finished()
property string walletName: ""
property int launchContext: CreateWalletWizard.Context.Onboarding

initialItem: Page {
background: null

header: NavigationBar2 {
id: navbar
rightItem: NavButton {
text: qsTr("Skip")
text: {
switch (root.launchContext) {
case CreateWalletWizard.Context.Main:
return qsTr("Cancel");
case CreateWalletWizard.Context.Onboarding:
default:
return qsTr("Skip");
}
}
onClicked: {
root.finished()
}
Expand Down
15 changes: 12 additions & 3 deletions src/qml/pages/wallet/DesktopWallets.qml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,20 @@ Page {
text: walletController.selectedWallet.name
balance: walletController.selectedWallet.balance
loading: !walletController.initialized
noWalletLoaded: !walletController.isWalletLoaded
noWalletsFound: walletController.noWalletsFound

MouseArea {
anchors.fill: parent
onClicked: {
walletListModel.listWalletDir()
walletSelect.opened ? walletSelect.close() : walletSelect.open()
if (walletController.initialized) {
walletListModel.listWalletDir()
if (walletController.noWalletsFound) {
root.addWallet()
} else {
walletSelect.opened ? walletSelect.close() : walletSelect.open()
}
}
}
}

Expand All @@ -52,9 +60,9 @@ Page {
}
}
centerItem: RowLayout {
visible: walletController.isWalletLoaded
NavigationTab {
id: activityTabButton
checked: true
text: qsTr("Activity")
property int index: 0
ButtonGroup.group: navigationTabs
Expand All @@ -79,6 +87,7 @@ Page {
}
NavigationTab {
id: blockClockTabButton
checked: true
Layout.preferredWidth: 30
Layout.rightMargin: 10
property int index: 3
Expand Down
41 changes: 40 additions & 1 deletion src/qml/pages/wallet/WalletBadge.qml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Button {
property bool showIcon: true
property string balance: "0.0 000 000"
property bool loading: false
property bool noWalletLoaded: false
property bool noWalletsFound: false

checkable: true
hoverEnabled: AppMode.isDesktop
Expand All @@ -32,6 +34,10 @@ Button {
topPadding: 0
clip: true

HoverHandler{
cursorShape: Qt.PointingHandCursor
}

contentItem: Item {
RowLayout {
visible: root.loading
Expand Down Expand Up @@ -65,7 +71,40 @@ Button {
}

RowLayout {
visible: !root.loading
visible: !root.loading && root.noWalletLoaded

opacity: visible ? 1 : 0

Behavior on opacity {
NumberAnimation { duration: 400 }
}

anchors.leftMargin: 5
anchors.rightMargin: 5
anchors.centerIn: parent
clip: true
spacing: 5
Icon {
visible: root.showIcon
source: root.noWalletsFound ? "image://images/plus" : "image://images/caret-down-medium-filled"
color: Theme.color.neutral8
size: 30
Layout.minimumWidth: 25
Layout.preferredWidth: 25
Layout.maximumWidth: 25
}
CoreText {
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
wrap: false
font.pixelSize: 15
text: root.noWalletsFound ? qsTr("Add Wallet") : qsTr("Select Wallet")
color: root.textColor
}
}

RowLayout {
visible: !root.loading && !root.noWalletLoaded

opacity: visible ? 1 : 0

Expand Down
26 changes: 26 additions & 0 deletions src/qml/walletqmlcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void WalletQmlController::createSingleSigWallet(const QString &name, const QStri
if (wallet) {
m_selected_wallet = new WalletQmlModel(std::move(*wallet));
m_wallets.push_back(m_selected_wallet);
setNoWalletsFound(false);
Q_EMIT selectedWalletChanged();
} else {
m_error_message = util::ErrorString(wallet);
Expand All @@ -94,6 +95,7 @@ void WalletQmlController::handleLoadWallet(std::unique_ptr<interfaces::Wallet> w
if (wallet_model->name() == name) {
m_selected_wallet = wallet_model;
Q_EMIT selectedWalletChanged();
setWalletLoaded(true);
return;
}
}
Expand All @@ -104,6 +106,7 @@ void WalletQmlController::handleLoadWallet(std::unique_ptr<interfaces::Wallet> w
m_selected_wallet = wallet_model;
m_wallets.push_back(m_selected_wallet);
Q_EMIT selectedWalletChanged();
setWalletLoaded(true);
}

void WalletQmlController::initialize()
Expand All @@ -118,9 +121,32 @@ void WalletQmlController::initialize()
}
if (!m_wallets.empty()) {
m_selected_wallet = m_wallets.front();
setWalletLoaded(true);
Q_EMIT selectedWalletChanged();
}

if (m_node.walletLoader().listWalletDir().size() == 0) {
setNoWalletsFound(true);
} else {
setNoWalletsFound(false);
}

m_initialized = true;
Q_EMIT initializedChanged();
}

void WalletQmlController::setWalletLoaded(bool loaded)
{
if (m_is_wallet_loaded != loaded) {
m_is_wallet_loaded = loaded;
Q_EMIT isWalletLoadedChanged();
}
}

void WalletQmlController::setNoWalletsFound(bool no_wallets_found)
{
if (m_no_wallets_found != no_wallets_found) {
m_no_wallets_found = no_wallets_found;
Q_EMIT noWalletsFoundChanged();
}
}
10 changes: 10 additions & 0 deletions src/qml/walletqmlcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class WalletQmlController : public QObject
Q_OBJECT
Q_PROPERTY(WalletQmlModel* selectedWallet READ selectedWallet NOTIFY selectedWalletChanged)
Q_PROPERTY(bool initialized READ initialized NOTIFY initializedChanged)
Q_PROPERTY(bool isWalletLoaded READ isWalletLoaded NOTIFY isWalletLoadedChanged)
Q_PROPERTY(bool noWalletsFound READ noWalletsFound NOTIFY noWalletsFoundChanged)

public:
explicit WalletQmlController(interfaces::Node& node, QObject *parent = nullptr);
Expand All @@ -33,10 +35,16 @@ class WalletQmlController : public QObject
WalletQmlModel* selectedWallet() const;
void unloadWallets();
bool initialized() const { return m_initialized; }
bool isWalletLoaded() const { return m_is_wallet_loaded; }
void setWalletLoaded(bool loaded);
bool noWalletsFound() const { return m_no_wallets_found; }
void setNoWalletsFound(bool no_wallets_found);

Q_SIGNALS:
void selectedWalletChanged();
void initializedChanged();
void isWalletLoadedChanged();
void noWalletsFoundChanged();

public Q_SLOTS:
void initialize();
Expand All @@ -52,6 +60,8 @@ public Q_SLOTS:
QMutex m_wallets_mutex;
std::vector<WalletQmlModel*> m_wallets;
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
bool m_is_wallet_loaded{false};
bool m_no_wallets_found{false};

bilingual_str m_error_message;
std::vector<bilingual_str> m_warning_messages;
Expand Down
Loading