diff --git a/src/qml/models/walletqmlmodel.h b/src/qml/models/walletqmlmodel.h index 340b351ada..d17b038cbb 100644 --- a/src/qml/models/walletqmlmodel.h +++ b/src/qml/models/walletqmlmodel.h @@ -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 wallet, QObject* parent = nullptr); @@ -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 m_wallet; @@ -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 diff --git a/src/qml/pages/main.qml b/src/qml/pages/main.qml index 60aa6c2705..43a94fad5e 100644 --- a/src/qml/pages/main.qml +++ b/src/qml/pages/main.qml @@ -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) } @@ -82,7 +84,7 @@ ApplicationWindow { id: desktopWallets DesktopWallets { onAddWallet: { - main.push(createWalletWizard) + main.push(createWalletWizard, { "launchContext": CreateWalletWizard.Context.Main }) } onSendTransaction: { main.push(sendReviewPage) diff --git a/src/qml/pages/wallet/CreateWalletWizard.qml b/src/qml/pages/wallet/CreateWalletWizard.qml index f275c9d37a..b6223d79b1 100644 --- a/src/qml/pages/wallet/CreateWalletWizard.qml +++ b/src/qml/pages/wallet/CreateWalletWizard.qml @@ -13,8 +13,11 @@ import "../wallet" PageStack { id: root + enum Context { Onboarding, Main } + signal finished() property string walletName: "" + property int launchContext: CreateWalletWizard.Context.Onboarding initialItem: Page { background: null @@ -22,7 +25,15 @@ PageStack { 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() } diff --git a/src/qml/pages/wallet/DesktopWallets.qml b/src/qml/pages/wallet/DesktopWallets.qml index d2bf0469b3..4763a901f9 100644 --- a/src/qml/pages/wallet/DesktopWallets.qml +++ b/src/qml/pages/wallet/DesktopWallets.qml @@ -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() + } + } } } @@ -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 @@ -79,6 +87,7 @@ Page { } NavigationTab { id: blockClockTabButton + checked: true Layout.preferredWidth: 30 Layout.rightMargin: 10 property int index: 3 diff --git a/src/qml/pages/wallet/WalletBadge.qml b/src/qml/pages/wallet/WalletBadge.qml index 1fca0b7105..39d5726043 100644 --- a/src/qml/pages/wallet/WalletBadge.qml +++ b/src/qml/pages/wallet/WalletBadge.qml @@ -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 @@ -32,6 +34,10 @@ Button { topPadding: 0 clip: true + HoverHandler{ + cursorShape: Qt.PointingHandCursor + } + contentItem: Item { RowLayout { visible: root.loading @@ -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 diff --git a/src/qml/walletqmlcontroller.cpp b/src/qml/walletqmlcontroller.cpp index a9eed57d0d..81065a5d86 100644 --- a/src/qml/walletqmlcontroller.cpp +++ b/src/qml/walletqmlcontroller.cpp @@ -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); @@ -94,6 +95,7 @@ void WalletQmlController::handleLoadWallet(std::unique_ptr w if (wallet_model->name() == name) { m_selected_wallet = wallet_model; Q_EMIT selectedWalletChanged(); + setWalletLoaded(true); return; } } @@ -104,6 +106,7 @@ void WalletQmlController::handleLoadWallet(std::unique_ptr w m_selected_wallet = wallet_model; m_wallets.push_back(m_selected_wallet); Q_EMIT selectedWalletChanged(); + setWalletLoaded(true); } void WalletQmlController::initialize() @@ -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(); + } +} diff --git a/src/qml/walletqmlcontroller.h b/src/qml/walletqmlcontroller.h index 4dd5acb211..56f082e7c4 100644 --- a/src/qml/walletqmlcontroller.h +++ b/src/qml/walletqmlcontroller.h @@ -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); @@ -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(); @@ -52,6 +60,8 @@ public Q_SLOTS: QMutex m_wallets_mutex; std::vector m_wallets; std::unique_ptr m_handler_load_wallet; + bool m_is_wallet_loaded{false}; + bool m_no_wallets_found{false}; bilingual_str m_error_message; std::vector m_warning_messages;