From b9995c44ec7ba8e8438f61807b6cc2c7ffcf2b03 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 10 May 2021 15:20:33 +0200 Subject: [PATCH 01/62] Fix misc compiler warnings --- src/api/LocalMoneroApi.h | 2 +- src/appcontext.cpp | 3 +-- src/coinswidget.h | 2 +- src/dialog/UpdateDialog.h | 4 ++-- src/dialog/WalletCacheDebugDialog.cpp | 2 +- src/dialog/aboutdialog.h | 2 +- src/dialog/broadcasttxdialog.cpp | 2 +- src/dialog/broadcasttxdialog.h | 2 +- src/dialog/debuginfodialog.h | 4 ++-- src/dialog/restoredialog.h | 2 +- src/dialog/signverifydialog.cpp | 2 +- src/dialog/transactioninfodialog.h | 4 ++-- src/dialog/tximportdialog.cpp | 2 +- src/dialog/tximportdialog.h | 3 ++- src/dialog/verifyproofdialog.cpp | 2 +- src/dialog/verifyproofdialog.h | 6 +++--- src/libwalletqt/WalletManager.cpp | 2 +- src/main.cpp | 3 +-- src/mainwindow.cpp | 2 -- src/mainwindow.h | 4 ++-- src/model/NodeModel.h | 2 +- src/model/SubaddressProxyModel.cpp | 10 +++++----- src/receivewidget.cpp | 1 + src/utils/FeatherSeed.h | 4 ++-- src/utils/brute.h | 4 ++-- src/utils/nodes.cpp | 6 ++---- src/utils/txfiathistory.cpp | 11 ++++++----- src/utils/txfiathistory.h | 2 +- src/utils/utils.cpp | 2 +- src/widgets/ccsprogressdelegate.cpp | 5 ++--- src/widgets/tickerwidget.h | 2 +- src/widgets/xmrigwidget.h | 4 ++-- src/wizard/PageHardwareDevice.h | 2 +- src/wizard/PageMenu.h | 2 +- src/wizard/PageNetwork.h | 2 +- src/wizard/PageNetworkTor.h | 2 +- src/wizard/PageOpenWallet.h | 2 +- src/wizard/PageSetPassword.h | 3 ++- src/wizard/PageSetRestoreHeight.h | 2 +- src/wizard/PageWalletFile.h | 2 +- src/wizard/PageWalletRestoreKeys.h | 2 +- src/wizard/PageWalletRestoreSeed.h | 2 +- 42 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/api/LocalMoneroApi.h b/src/api/LocalMoneroApi.h index 14b6c82b..60145b89 100644 --- a/src/api/LocalMoneroApi.h +++ b/src/api/LocalMoneroApi.h @@ -45,8 +45,8 @@ private slots: private: QString getBuySellUrl(bool buy, const QString ¤cyCode, const QString &countryCode="", const QString &paymentMethod="", const QString &amount = "", int page = 0); - QString m_baseUrl; UtilsNetworking *m_network; + QString m_baseUrl; }; diff --git a/src/appcontext.cpp b/src/appcontext.cpp index de5c2e16..422df1c6 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -145,7 +145,6 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con return; } - auto balance = this->currentWallet->balance(); auto unlocked_balance = this->currentWallet->unlockedBalance(); if(!all && amount > unlocked_balance) { emit createTransactionError("Not enough money to spend"); @@ -549,7 +548,7 @@ void AppContext::donateBeg() { config()->set(Config::donateBeg, donationCounter); } -AppContext::~AppContext() {} +AppContext::~AppContext() = default; // ############################################## LIBWALLET QT ######################################################### diff --git a/src/coinswidget.h b/src/coinswidget.h index a2f3e5b1..0550c5d2 100644 --- a/src/coinswidget.h +++ b/src/coinswidget.h @@ -56,9 +56,9 @@ private: Ui::CoinsWidget *ui; QMenu *m_contextMenu; + QMenu *m_headerMenu; QMenu *m_copyMenu; QAction *m_showSpentAction; - QMenu *m_headerMenu; QAction *m_freezeOutputAction; QAction *m_freezeAllSelectedAction; QAction *m_thawOutputAction; diff --git a/src/dialog/UpdateDialog.h b/src/dialog/UpdateDialog.h index 70fe3134..86d959a6 100644 --- a/src/dialog/UpdateDialog.h +++ b/src/dialog/UpdateDialog.h @@ -34,6 +34,8 @@ signals: private: void setStatus(const QString &msg, bool success = false); + Ui::UpdateDialog *ui; + QString m_version; QString m_downloadUrl; QString m_hash; @@ -44,8 +46,6 @@ private: std::string m_updateZipArchive; QNetworkReply *m_reply = nullptr; - - Ui::UpdateDialog *ui; }; #endif //FEATHER_UPDATEDIALOG_H diff --git a/src/dialog/WalletCacheDebugDialog.cpp b/src/dialog/WalletCacheDebugDialog.cpp index b3b9dc87..d02fbb6d 100644 --- a/src/dialog/WalletCacheDebugDialog.cpp +++ b/src/dialog/WalletCacheDebugDialog.cpp @@ -9,8 +9,8 @@ WalletCacheDebugDialog::WalletCacheDebugDialog(AppContext *ctx, QWidget *parent) : QDialog(parent) - , m_ctx(ctx) , ui(new Ui::WalletCacheDebugDialog) + , m_ctx(ctx) { ui->setupUi(this); diff --git a/src/dialog/aboutdialog.h b/src/dialog/aboutdialog.h index e7ce12cb..5f082906 100644 --- a/src/dialog/aboutdialog.h +++ b/src/dialog/aboutdialog.h @@ -21,8 +21,8 @@ public: ~AboutDialog() override; private: - QStringListModel *m_model; Ui::AboutDialog *ui; + QStringListModel *m_model; }; #endif // ABOUT_H diff --git a/src/dialog/broadcasttxdialog.cpp b/src/dialog/broadcasttxdialog.cpp index 9d1ed711..3bb1173e 100644 --- a/src/dialog/broadcasttxdialog.cpp +++ b/src/dialog/broadcasttxdialog.cpp @@ -9,8 +9,8 @@ BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex) : QDialog(parent) - , m_ctx(ctx) , ui(new Ui::BroadcastTxDialog) + , m_ctx(ctx) { ui->setupUi(this); diff --git a/src/dialog/broadcasttxdialog.h b/src/dialog/broadcasttxdialog.h index bc2f5e38..a9a5e340 100644 --- a/src/dialog/broadcasttxdialog.h +++ b/src/dialog/broadcasttxdialog.h @@ -26,8 +26,8 @@ private slots: private: Ui::BroadcastTxDialog *ui; - UtilsNetworking *m_network; AppContext *m_ctx; + UtilsNetworking *m_network; DaemonRpc *m_rpc; }; diff --git a/src/dialog/debuginfodialog.h b/src/dialog/debuginfodialog.h index 1f9821be..44c1c5ed 100644 --- a/src/dialog/debuginfodialog.h +++ b/src/dialog/debuginfodialog.h @@ -25,10 +25,10 @@ private: void copyToClipboad(); void updateInfo(); - QTimer m_updateTimer; + Ui::DebugInfoDialog *ui; AppContext *m_ctx; - Ui::DebugInfoDialog *ui; + QTimer m_updateTimer; }; #endif //FEATHER_DEBUGINFODIALOG_H diff --git a/src/dialog/restoredialog.h b/src/dialog/restoredialog.h index 065cc907..d7f119dd 100644 --- a/src/dialog/restoredialog.h +++ b/src/dialog/restoredialog.h @@ -32,8 +32,8 @@ signals: void rejected(); private: - AppContext *m_ctx; Ui::RestoreDialog *ui; + AppContext *m_ctx; }; #endif // RESTOREDIALOG_H diff --git a/src/dialog/signverifydialog.cpp b/src/dialog/signverifydialog.cpp index f60dbdb8..283c33b4 100644 --- a/src/dialog/signverifydialog.cpp +++ b/src/dialog/signverifydialog.cpp @@ -9,8 +9,8 @@ SignVerifyDialog::SignVerifyDialog(Wallet *wallet, QWidget *parent) : QDialog(parent) - , m_wallet(wallet) , ui(new Ui::SignVerifyDialog) + , m_wallet(wallet) { ui->setupUi(this); diff --git a/src/dialog/transactioninfodialog.h b/src/dialog/transactioninfodialog.h index 02908dc6..575a1815 100644 --- a/src/dialog/transactioninfodialog.h +++ b/src/dialog/transactioninfodialog.h @@ -35,9 +35,9 @@ private: Ui::TransactionInfoDialog *ui; - TxProofDialog *m_txProofDialog; - TransactionInfo *m_txInfo; Wallet *m_wallet; + TransactionInfo *m_txInfo; + TxProofDialog *m_txProofDialog; QString m_txKey; QString m_txid; QTimer m_updateTimer; diff --git a/src/dialog/tximportdialog.cpp b/src/dialog/tximportdialog.cpp index 2dcc5f97..6cffd96f 100644 --- a/src/dialog/tximportdialog.cpp +++ b/src/dialog/tximportdialog.cpp @@ -9,9 +9,9 @@ TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx) : QDialog(parent) + , ui(new Ui::TxImportDialog) , m_ctx(ctx) , m_loadTimer(new QTimer(this)) - , ui(new Ui::TxImportDialog) { ui->setupUi(this); ui->resp->hide(); diff --git a/src/dialog/tximportdialog.h b/src/dialog/tximportdialog.h index 13294f40..4fdcb702 100644 --- a/src/dialog/tximportdialog.h +++ b/src/dialog/tximportdialog.h @@ -27,8 +27,9 @@ private slots: private: Ui::TxImportDialog *ui; - UtilsNetworking *m_network; AppContext *m_ctx; + + UtilsNetworking *m_network; DaemonRpc *m_rpc; QTimer *m_loadTimer; diff --git a/src/dialog/verifyproofdialog.cpp b/src/dialog/verifyproofdialog.cpp index 77493ed8..98b4fa8b 100644 --- a/src/dialog/verifyproofdialog.cpp +++ b/src/dialog/verifyproofdialog.cpp @@ -11,8 +11,8 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent) : QDialog(parent) - , m_wallet(wallet) , ui(new Ui::VerifyProofDialog) + , m_wallet(wallet) { ui->setupUi(this); diff --git a/src/dialog/verifyproofdialog.h b/src/dialog/verifyproofdialog.h index 89e44e33..9159decb 100644 --- a/src/dialog/verifyproofdialog.h +++ b/src/dialog/verifyproofdialog.h @@ -31,11 +31,11 @@ private: void checkFormattedProof(); void proofStatus(bool success, const QString &message); - QPixmap m_success; - QPixmap m_failure; - Ui::VerifyProofDialog *ui; Wallet *m_wallet; + + QPixmap m_success; + QPixmap m_failure; }; #endif //FEATHER_VERIFYPROOFDIALOG_H diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp index d1feb23d..76220145 100644 --- a/src/libwalletqt/WalletManager.cpp +++ b/src/libwalletqt/WalletManager.cpp @@ -455,9 +455,9 @@ bool WalletManager::clearWalletCache(const QString &wallet_path) const WalletManager::WalletManager(QObject *parent) : QObject(parent) + , m_currentWallet(nullptr) , m_passphraseReceiver(nullptr) , m_scheduler(this) - , m_currentWallet(nullptr) { m_pimpl = Monero::WalletManagerFactory::getWalletManager(); } diff --git a/src/main.cpp b/src/main.cpp index 97dc1914..b73f8ed7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -94,7 +94,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { } const QStringList args = parser.positionalArguments(); - bool localTor = parser.isSet(useLocalTorOption); bool stagenet = parser.isSet(stagenetOption); bool testnet = parser.isSet(testnetOption); bool quiet = parser.isSet(quietModeOption); @@ -167,6 +166,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { qInstallMessageHandler(Utils::applicationLogHandler); qRegisterMetaType>(); - auto *mainWindow = new MainWindow(ctx); + new MainWindow(ctx); return QApplication::exec(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 228c4bcd..7b0b72d9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -636,8 +636,6 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { qDebug() << Q_FUNC_INFO; bool hide = config()->get(Config::hideBalance).toBool(); - int amountPrecision = config()->get(Config::amountPrecision).toInt(); - QString balance_str = WalletManager::displayAmount(spendable); balance_str.remove(QRegExp("0+$")); diff --git a/src/mainwindow.h b/src/mainwindow.h index 9faa7d3e..807a4033 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -181,8 +181,6 @@ private: void startupWarning(); bool autoOpenWallet(); - AppContext *m_ctx; - static MainWindow * pMainWindow; void closeEvent(QCloseEvent *event) override; void cleanupBeforeClose(); @@ -210,6 +208,8 @@ private: WalletWizard *createWizard(WalletWizard::Page startPage); Ui::MainWindow *ui; + AppContext *m_ctx; + Settings *m_windowSettings = nullptr; CalcWindow *m_windowCalc = nullptr; RestoreDialog *m_restoreDialog = nullptr; diff --git a/src/model/NodeModel.h b/src/model/NodeModel.h index 5b79a5ea..f7509eab 100644 --- a/src/model/NodeModel.h +++ b/src/model/NodeModel.h @@ -32,9 +32,9 @@ public: private: QList m_nodes; + int m_nodeSource; QIcon m_offline; QIcon m_online; - int m_nodeSource; }; #endif //FEATHER_NODEMODEL_H diff --git a/src/model/SubaddressProxyModel.cpp b/src/model/SubaddressProxyModel.cpp index a984e398..b14802e6 100644 --- a/src/model/SubaddressProxyModel.cpp +++ b/src/model/SubaddressProxyModel.cpp @@ -4,11 +4,11 @@ #include "SubaddressProxyModel.h" SubaddressProxyModel::SubaddressProxyModel(QObject *parent, Subaddress *subaddress, bool hidePrimary) - : QSortFilterProxyModel(parent), - m_searchRegExp(""), - m_searchCaseSensitiveRegExp(""), - m_subaddress(subaddress), - m_hidePrimary(hidePrimary) + : QSortFilterProxyModel(parent) + , m_subaddress(subaddress) + , m_searchRegExp("") + , m_searchCaseSensitiveRegExp("") + , m_hidePrimary(hidePrimary) { m_searchRegExp.setCaseSensitivity(Qt::CaseInsensitive); m_searchRegExp.setPatternSyntax(QRegExp::FixedString); diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index b86517cf..f40b8816 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -146,6 +146,7 @@ void ReceiveWidget::setSearchFilter(const QString &filter) { void ReceiveWidget::showHeaderMenu(const QPoint& position) { + Q_UNUSED(position); m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses()); m_headerMenu->exec(QCursor::pos()); } diff --git a/src/utils/FeatherSeed.h b/src/utils/FeatherSeed.h index bf501019..47d6780d 100644 --- a/src/utils/FeatherSeed.h +++ b/src/utils/FeatherSeed.h @@ -16,6 +16,8 @@ enum SeedType { struct FeatherSeed { // TODO: this is spaghetti, needs refactor + NetworkType::Type netType; + QString coin; QString language; SeedType seedType; @@ -24,8 +26,6 @@ struct FeatherSeed { QString spendKey; QString correction; - NetworkType::Type netType; - time_t time; int restoreHeight = 0; diff --git a/src/utils/brute.h b/src/utils/brute.h index dddab97d..16801b6b 100644 --- a/src/utils/brute.h +++ b/src/utils/brute.h @@ -40,8 +40,8 @@ private: std::string m_word; strategy m_currentStrategy; - int iword = 0; - int ichar = 0; + size_t iword = 0; + size_t ichar = 0; }; #endif //FEATHER_BRUTE_H diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index 2d7b08c4..76b6e45a 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -5,16 +5,14 @@ #include "nodes.h" #include "utils/utils.h" -#include "utils/WebsocketClient.h" #include "appcontext.h" - Nodes::Nodes(AppContext *ctx, QObject *parent) : QObject(parent) - , m_ctx(ctx) - , m_connection(FeatherNode()) , modelWebsocket(new NodeModel(NodeSource::websocket, this)) , modelCustom(new NodeModel(NodeSource::custom, this)) + , m_ctx(ctx) + , m_connection(FeatherNode()) { this->loadConfig(); connect(m_ctx, &AppContext::walletRefreshed, this, &Nodes::onWalletRefreshed); diff --git a/src/utils/txfiathistory.cpp b/src/utils/txfiathistory.cpp index 6a4eaab7..b0f9fb83 100644 --- a/src/utils/txfiathistory.cpp +++ b/src/utils/txfiathistory.cpp @@ -7,10 +7,11 @@ #include "txfiathistory.h" #include "utils/utils.h" -TxFiatHistory::TxFiatHistory(int genesis_timestamp, const QString &configDirectory, QObject *parent) : - QObject(parent), - m_genesis_timestamp(genesis_timestamp), - m_configDirectory(configDirectory) { +TxFiatHistory::TxFiatHistory(int genesis_timestamp, const QString &configDirectory, QObject *parent) + : QObject(parent) + , m_genesis_timestamp(genesis_timestamp) + , m_configDirectory(configDirectory) +{ m_databasePath = QString("%1/fiatHistory.db").arg(configDirectory); this->loadDatabase(); } @@ -70,7 +71,7 @@ void TxFiatHistory::onUpdateDatabase() { } // keep local fiatTxHistory database up to date, loop for missing dates - for(year; year != yearCurrent + 1; year += 1){ + for(; year != yearCurrent + 1; year += 1){ for(int month = 1; month != 13; month++) { if(year == yearCurrent && month == now.month() && now.day() == 1) break; QDateTime _now; diff --git a/src/utils/txfiathistory.h b/src/utils/txfiathistory.h index 5587b7f9..cbb7d80d 100644 --- a/src/utils/txfiathistory.h +++ b/src/utils/txfiathistory.h @@ -23,11 +23,11 @@ signals: private: void loadDatabase(); void writeDatabase(); + int m_genesis_timestamp; QString m_databasePath; QString m_configDirectory; bool m_initialized = false; QMap m_database; - int m_genesis_timestamp; }; #endif //FEATHER_TXFIATHISTORY_H diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 97e38c9e..5ca76771 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -142,7 +142,7 @@ void Utils::desktopNotify(const QString &title, const QString &message, int dura QString stderr = process.readAllStandardError(); #elif defined(Q_OS_MACOS) QProcess process; - // @TODO: need to escape special chars with \ + // @TODO: need to escape special chars with "\" process.start("osascript", macos); process.waitForFinished(-1); QString stdout = process.readAllStandardOutput(); diff --git a/src/widgets/ccsprogressdelegate.cpp b/src/widgets/ccsprogressdelegate.cpp index 51044acf..18c39b36 100644 --- a/src/widgets/ccsprogressdelegate.cpp +++ b/src/widgets/ccsprogressdelegate.cpp @@ -6,10 +6,9 @@ #include CCSProgressDelegate::CCSProgressDelegate(CCSModel *model, QWidget *parent) - : m_model(model) - , QStyledItemDelegate(parent) + : QStyledItemDelegate(parent) + , m_model(model) { - } void CCSProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, diff --git a/src/widgets/tickerwidget.h b/src/widgets/tickerwidget.h index e6464ebb..74386a1a 100644 --- a/src/widgets/tickerwidget.h +++ b/src/widgets/tickerwidget.h @@ -29,10 +29,10 @@ public slots: private: Ui::TickerWidget *ui; + AppContext *m_ctx; QString m_symbol; bool m_convertBalance; bool m_hidePercent; - AppContext *m_ctx; }; #endif // TICKERWIDGET_H diff --git a/src/widgets/xmrigwidget.h b/src/widgets/xmrigwidget.h index aa5d7e7d..b38efb83 100644 --- a/src/widgets/xmrigwidget.h +++ b/src/widgets/xmrigwidget.h @@ -50,11 +50,11 @@ signals: private: void showContextMenu(const QPoint &pos); - AppContext *m_ctx; Ui::XMRigWidget *ui; + AppContext *m_ctx; + XmRig * m_XMRig; QStandardItemModel *m_model; QMenu *m_contextMenu; - XmRig * m_XMRig; int m_threads; QStringList m_urls; diff --git a/src/wizard/PageHardwareDevice.h b/src/wizard/PageHardwareDevice.h index 9267c354..d20a6b95 100644 --- a/src/wizard/PageHardwareDevice.h +++ b/src/wizard/PageHardwareDevice.h @@ -28,8 +28,8 @@ public: bool isComplete() const override; private: - AppContext *m_ctx; Ui::PageHardwareDevice *ui; + AppContext *m_ctx; WizardFields *m_fields; }; diff --git a/src/wizard/PageMenu.h b/src/wizard/PageMenu.h index c755a98d..49e19577 100644 --- a/src/wizard/PageMenu.h +++ b/src/wizard/PageMenu.h @@ -28,9 +28,9 @@ signals: void enableDarkMode(bool enable); private: + Ui::PageMenu *ui; AppContext *m_ctx; WalletKeysFilesModel *m_walletKeysFilesModel; - Ui::PageMenu *ui; WizardFields *m_fields; }; diff --git a/src/wizard/PageNetwork.h b/src/wizard/PageNetwork.h index 502f3497..7c2aafe3 100644 --- a/src/wizard/PageNetwork.h +++ b/src/wizard/PageNetwork.h @@ -26,8 +26,8 @@ public: bool isComplete() const override; private: - AppContext *m_ctx; Ui::PageNetwork *ui; + AppContext *m_ctx; }; #endif //FEATHER_WIZARDNETWORK_H diff --git a/src/wizard/PageNetworkTor.h b/src/wizard/PageNetworkTor.h index 9863b58b..48056abe 100644 --- a/src/wizard/PageNetworkTor.h +++ b/src/wizard/PageNetworkTor.h @@ -26,8 +26,8 @@ signals: void initialNetworkConfigured(); private: - AppContext *m_ctx; Ui::PageNetworkTor *ui; + AppContext *m_ctx; }; #endif //FEATHER_PAGENETWORKTOR_H diff --git a/src/wizard/PageOpenWallet.h b/src/wizard/PageOpenWallet.h index 73309d6a..5342b473 100644 --- a/src/wizard/PageOpenWallet.h +++ b/src/wizard/PageOpenWallet.h @@ -31,10 +31,10 @@ signals: private: void updatePath(); + Ui::PageOpenWallet *ui; AppContext *m_ctx; WalletKeysFilesModel *m_walletKeysFilesModel; WalletKeysFilesProxyModel *m_keysProxy; - Ui::PageOpenWallet *ui; QStandardItemModel *m_model; }; diff --git a/src/wizard/PageSetPassword.h b/src/wizard/PageSetPassword.h index aa89c5c7..263ae1ff 100644 --- a/src/wizard/PageSetPassword.h +++ b/src/wizard/PageSetPassword.h @@ -29,9 +29,10 @@ signals: void createWallet(); private: + Ui::PageSetPassword *ui; + AppContext *m_ctx; WizardFields *m_fields; - Ui::PageSetPassword *ui; }; diff --git a/src/wizard/PageSetRestoreHeight.h b/src/wizard/PageSetRestoreHeight.h index 155406bb..4ab90b3d 100644 --- a/src/wizard/PageSetRestoreHeight.h +++ b/src/wizard/PageSetRestoreHeight.h @@ -33,9 +33,9 @@ private: void showScanWarning(const QDateTime &date); void showWalletAgeWarning(const QDateTime &date); + Ui::PageSetRestoreHeight *ui; AppContext *m_ctx; WizardFields *m_fields; - Ui::PageSetRestoreHeight *ui; }; #endif //FEATHER_PAGESETRESTOREHEIGHT_H diff --git a/src/wizard/PageWalletFile.h b/src/wizard/PageWalletFile.h index 3d2b495a..3f9c2ba4 100644 --- a/src/wizard/PageWalletFile.h +++ b/src/wizard/PageWalletFile.h @@ -34,8 +34,8 @@ private: bool walletPathExists(const QString &walletName); bool validateWidgets(); - AppContext *m_ctx; Ui::PageWalletFile *ui; + AppContext *m_ctx; WizardFields *m_fields; bool m_validated; }; diff --git a/src/wizard/PageWalletRestoreKeys.h b/src/wizard/PageWalletRestoreKeys.h index ff20301f..3be83b92 100644 --- a/src/wizard/PageWalletRestoreKeys.h +++ b/src/wizard/PageWalletRestoreKeys.h @@ -27,9 +27,9 @@ public: int nextId() const override; private: + Ui::PageWalletRestoreKeys *ui; AppContext *m_ctx; WizardFields *m_fields; - Ui::PageWalletRestoreKeys *ui; }; #endif diff --git a/src/wizard/PageWalletRestoreSeed.h b/src/wizard/PageWalletRestoreSeed.h index d29c7b23..9b792835 100644 --- a/src/wizard/PageWalletRestoreSeed.h +++ b/src/wizard/PageWalletRestoreSeed.h @@ -50,8 +50,8 @@ private: void onSeedTypeToggled(); - AppContext *m_ctx; Ui::PageWalletRestoreSeed *ui; + AppContext *m_ctx; WizardFields *m_fields; seedType m_tevador; From cc0192485895f30445adc2e0f98a011e8e7a4c67 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 10 May 2021 17:05:10 +0200 Subject: [PATCH 02/62] non-static mainwindow --- src/coinswidget.cpp | 4 +-- src/coinswidget.h | 4 +-- src/contactswidget.cpp | 35 ++++++++++++++---------- src/contactswidget.h | 4 +-- src/libwalletqt/Subaddress.cpp | 4 ++- src/libwalletqt/Wallet.h | 4 +-- src/mainwindow.cpp | 38 ++++++++++++-------------- src/mainwindow.h | 8 +++--- src/mainwindow.ui | 49 +++++++++------------------------- src/sendwidget.cpp | 4 +-- src/sendwidget.h | 2 +- src/sendwidget.ui | 6 +++++ src/settings.cpp | 8 +++--- src/settings.h | 4 +-- 14 files changed, 82 insertions(+), 92 deletions(-) diff --git a/src/coinswidget.cpp b/src/coinswidget.cpp index 507da8b6..78d80a45 100644 --- a/src/coinswidget.cpp +++ b/src/coinswidget.cpp @@ -11,14 +11,14 @@ #include #include -CoinsWidget::CoinsWidget(QWidget *parent) +CoinsWidget::CoinsWidget(AppContext *ctx, QWidget *parent) : QWidget(parent) , ui(new Ui::CoinsWidget) + , m_ctx(ctx) , m_headerMenu(new QMenu(this)) , m_copyMenu(new QMenu("Copy",this)) { ui->setupUi(this); - m_ctx = MainWindow::getContext(); // header context menu ui->coins->header()->setContextMenuPolicy(Qt::CustomContextMenu); diff --git a/src/coinswidget.h b/src/coinswidget.h index 0550c5d2..38c17774 100644 --- a/src/coinswidget.h +++ b/src/coinswidget.h @@ -22,7 +22,7 @@ class CoinsWidget : public QWidget Q_OBJECT public: - explicit CoinsWidget(QWidget *parent = nullptr); + explicit CoinsWidget(AppContext *ctx, QWidget *parent = nullptr); void setModel(CoinsModel * model, Coins * coins); ~CoinsWidget() override; @@ -54,6 +54,7 @@ private: }; Ui::CoinsWidget *ui; + AppContext *m_ctx; QMenu *m_contextMenu; QMenu *m_headerMenu; @@ -68,7 +69,6 @@ private: Coins *m_coins; CoinsModel * m_model; CoinsProxyModel * m_proxyModel; - AppContext *m_ctx; void showContextMenu(const QPoint & point); void copy(copyField field); diff --git a/src/contactswidget.cpp b/src/contactswidget.cpp index a7a7bc3d..e7d9c014 100644 --- a/src/contactswidget.cpp +++ b/src/contactswidget.cpp @@ -11,12 +11,11 @@ #include -ContactsWidget::ContactsWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::ContactsWidget) +ContactsWidget::ContactsWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::ContactsWidget) { ui->setupUi(this); - m_ctx = MainWindow::getContext(); // header context menu ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu); @@ -69,9 +68,10 @@ void ContactsWidget::payTo() { emit fillAddress(address); } -void ContactsWidget::setModel(AddressBookModel *model) +void ContactsWidget::setModel(AddressBookModel *model, Wallet *wallet) { m_model = model; + m_wallet = wallet; m_proxyModel = new AddressBookProxyModel; m_proxyModel->setSourceModel(m_model); ui->contacts->setModel(m_proxyModel); @@ -104,24 +104,31 @@ void ContactsWidget::showHeaderMenu(const QPoint& position) void ContactsWidget::newContact(QString address, QString name) { - auto * dialog = new ContactsDialog(this, address, name); - int ret = dialog->exec(); - if (!ret) return; + if (!m_wallet) { + QMessageBox::warning(this, "Error", "No wallet opened."); + return; + } - address = dialog->getAddress(); - name = dialog->getName(); + ContactsDialog dialog{this, address, name}; + int ret = dialog.exec(); + if (ret != QDialog::Accepted) { + return; + } - bool addressValid = WalletManager::addressValid(address, m_ctx->currentWallet->nettype()); + address = dialog.getAddress(); + name = dialog.getName(); + + bool addressValid = WalletManager::addressValid(address, m_wallet->nettype()); if (!addressValid) { QMessageBox::warning(this, "Invalid address", "Invalid address"); return; } - int num_addresses = m_ctx->currentWallet->addressBook()->count(); + int num_addresses = m_wallet->addressBook()->count(); QString address_entry; QString name_entry; for (int i=0; icurrentWallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){ + m_wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){ address_entry = entry.address(); name_entry = entry.description(); }); @@ -138,7 +145,7 @@ void ContactsWidget::newContact(QString address, QString name) } } - m_ctx->currentWallet->addressBook()->addRow(address, "", name); + m_wallet->addressBook()->addRow(address, "", name); } void ContactsWidget::deleteContact() diff --git a/src/contactswidget.h b/src/contactswidget.h index 40357735..cf9a3a5d 100644 --- a/src/contactswidget.h +++ b/src/contactswidget.h @@ -21,7 +21,7 @@ class ContactsWidget : public QWidget public: explicit ContactsWidget(QWidget *parent = nullptr); - void setModel(AddressBookModel * model); + void setModel(AddressBookModel *model, Wallet *wallet); ~ContactsWidget() override; public slots: @@ -42,7 +42,6 @@ private slots: private: Ui::ContactsWidget *ui; - AppContext *m_ctx; QAction *m_showFullAddressesAction; QMenu *m_rowMenu; @@ -50,6 +49,7 @@ private: QMenu *m_headerMenu; AddressBookModel * m_model; AddressBookProxyModel * m_proxyModel; + Wallet *m_wallet; }; #endif // CONTACTSWIDGET_H diff --git a/src/libwalletqt/Subaddress.cpp b/src/libwalletqt/Subaddress.cpp index 308eb4aa..dc683577 100644 --- a/src/libwalletqt/Subaddress.cpp +++ b/src/libwalletqt/Subaddress.cpp @@ -5,7 +5,9 @@ #include Subaddress::Subaddress(Monero::Subaddress *subaddressImpl, QObject *parent) - : QObject(parent), m_subaddressImpl(subaddressImpl), m_unusedLookahead(0) + : QObject(parent) + , m_subaddressImpl(subaddressImpl) + , m_unusedLookahead(0) { getAll(); } diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index a3b96121..84311d95 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -423,7 +423,7 @@ public: // Passphrase entry for hardware wallets void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false); - virtual void onWalletPassphraseNeeded(bool on_device) override; + void onWalletPassphraseNeeded(bool on_device) override; quint64 getBytesReceived() const; quint64 getBytesSent() const; @@ -466,7 +466,7 @@ signals: private: Wallet(QObject * parent = nullptr); - Wallet(Monero::Wallet *w, QObject * parent = 0); + Wallet(Monero::Wallet *w, QObject * parent = nullptr); ~Wallet(); //! initializes wallet diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7b0b72d9..7c1e0e45 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -32,17 +32,14 @@ #include "utils/WebsocketNotifier.h" #include "utils/Updater.h" -MainWindow * MainWindow::pMainWindow = nullptr; - MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_ctx(ctx) { - pMainWindow = this; ui->setupUi(this); - m_windowSettings = new Settings(this); + m_windowSettings = new Settings(m_ctx, this); m_windowCalc = new CalcWindow(this); m_splashDialog = new SplashDialog(this); @@ -71,7 +68,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, tickerWidget, &TickerWidget::init); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceWidget, &TickerWidget::init); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged); - connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, ui->sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged)); + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged)); connect(m_windowSettings, &Settings::amountPrecisionChanged, m_ctx, &AppContext::onAmountPrecisionChanged); connect(m_windowSettings, &Settings::skinChanged, this, &MainWindow::skinChanged); @@ -192,13 +189,20 @@ void MainWindow::initWidgets() { connect(ui->historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer); connect(ui->historyWidget, &HistoryWidget::resendTransaction, this, &MainWindow::onResendTransaction); + // [Send] + m_sendWidget = new SendWidget(m_ctx, this); + ui->sendWidgetLayout->addWidget(m_sendWidget); + // [Receive] connect(ui->receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) { ui->historyWidget->setSearchText(text); ui->tabWidget->setCurrentIndex(Tabs::HISTORY); }); - connect(ui->contactWidget, &ContactsWidget::fillAddress, ui->sendWidget, &SendWidget::fillAddress); + connect(ui->contactWidget, &ContactsWidget::fillAddress, m_sendWidget, &SendWidget::fillAddress); + // [Coins] + m_coinsWidget = new CoinsWidget(m_ctx, this); + ui->coinsWidgetLayout->addWidget(m_coinsWidget); #ifdef HAS_LOCALMONERO m_localMoneroWidget = new LocalMoneroWidget(this, m_ctx); @@ -618,11 +622,11 @@ void MainWindow::onWalletOpened() { ui->historyWidget->setModel(m_ctx->currentWallet->historyModel(), m_ctx->currentWallet); // contacts widget - ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel()); + ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel(), m_ctx->currentWallet); // coins page m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); - ui->coinsWidget->setModel(m_ctx->currentWallet->coinsModel(), m_ctx->currentWallet->coins()); + m_coinsWidget->setModel(m_ctx->currentWallet->coinsModel(), m_ctx->currentWallet->coins()); this->touchbarShowWallet(); this->updatePasswordIcon(); @@ -784,7 +788,7 @@ void MainWindow::onTransactionCommitted(bool status, PendingTransaction *tx, con if (status) { // success QString body = QString("Successfully sent %1 transaction(s).").arg(txid.count()); QMessageBox::information(this, "Transactions sent", body); - ui->sendWidget->clearFields(); + m_sendWidget->clearFields(); } else { auto err = tx->errorString(); QString body = QString("Error committing transaction: %1").arg(err); @@ -994,7 +998,7 @@ void MainWindow::donateButtonClicked() { if (donation <= 0) donation = 0.1337; - ui->sendWidget->fill(globals::donationAddress, "Donation to the Feather development team", donation); + m_sendWidget->fill(globals::donationAddress, "Donation to the Feather development team", donation); ui->tabWidget->setCurrentIndex(Tabs::SEND); } @@ -1014,7 +1018,7 @@ void MainWindow::showCalcWindow() { void MainWindow::payToMany() { ui->tabWidget->setCurrentIndex(Tabs::SEND); - ui->sendWidget->payToMany(); + m_sendWidget->payToMany(); QMessageBox::information(this, "Pay to many", "Enter a list of outputs in the 'Pay to' field.\n" "One output per line.\n" "Format: address, amount\n" @@ -1022,7 +1026,7 @@ void MainWindow::payToMany() { } void MainWindow::showSendScreen(const CCSEntry &entry) { - ui->sendWidget->fill(entry); + m_sendWidget->fill(entry); ui->tabWidget->setCurrentIndex(Tabs::SEND); } @@ -1064,14 +1068,6 @@ void MainWindow::importContacts() { QMessageBox::information(this, "Contacts imported", QString("Total contacts imported: %1").arg(inserts)); } -MainWindow *MainWindow::getInstance() { - return pMainWindow; -} - -AppContext *MainWindow::getContext(){ - return pMainWindow->m_ctx; -} - QString MainWindow::loadStylesheet(const QString &resource) { QFile f(resource); if (!f.exists()) { @@ -1481,7 +1477,7 @@ void MainWindow::onWalletAboutToClose() { ui->historyWidget->resetModel(); ui->contactWidget->resetModel(); ui->receiveWidget->resetModel(); - ui->coinsWidget->resetModel(); + m_coinsWidget->resetModel(); } void MainWindow::onExportHistoryCSV(bool checked) { diff --git a/src/mainwindow.h b/src/mainwindow.h index 807a4033..a32e2ad8 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -36,6 +36,9 @@ #include "widgets/tickerwidget.h" #include "wizard/WalletWizard.h" +#include "sendwidget.h" +#include "coinswidget.h" + #ifdef HAS_LOCALMONERO #include "widgets/LocalMoneroWidget.h" #endif @@ -68,8 +71,6 @@ Q_OBJECT public: explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr); - static MainWindow *getInstance(); - static AppContext *getContext(); ~MainWindow() override; enum Tabs { @@ -181,7 +182,6 @@ private: void startupWarning(); bool autoOpenWallet(); - static MainWindow * pMainWindow; void closeEvent(QCloseEvent *event) override; void cleanupBeforeClose(); QString loadStylesheet(const QString &resource); @@ -216,6 +216,8 @@ private: XMRigWidget *m_xmrig = nullptr; SplashDialog *m_splashDialog = nullptr; + SendWidget *m_sendWidget = nullptr; + CoinsWidget *m_coinsWidget = nullptr; #ifdef HAS_LOCALMONERO LocalMoneroWidget *m_localMoneroWidget = nullptr; #endif diff --git a/src/mainwindow.ui b/src/mainwindow.ui index be1b3814..0b385454 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -188,29 +188,11 @@ 11 - - - - 0 - 0 - + + + 0 - - - 0 - 100 - - - - - 16777215 - 16777215 - - - - - - + @@ -226,7 +208,14 @@ - + + + + 0 + 0 + + + @@ -254,7 +243,7 @@ - + @@ -735,12 +724,6 @@ - - SendWidget - QWidget -
sendwidget.h
- 1 -
ContactsWidget QWidget @@ -753,12 +736,6 @@
receivewidget.h
1
- - CoinsWidget - QWidget -
coinswidget.h
- 1 -
HistoryWidget QWidget diff --git a/src/sendwidget.cpp b/src/sendwidget.cpp index cc09f9cf..7c6eb3ba 100644 --- a/src/sendwidget.cpp +++ b/src/sendwidget.cpp @@ -8,12 +8,12 @@ #include "globals.h" #include "utils/AppData.h" -SendWidget::SendWidget(QWidget *parent) +SendWidget::SendWidget(AppContext *ctx, QWidget *parent) : QWidget(parent) , ui(new Ui::SendWidget) + , m_ctx(ctx) { ui->setupUi(this); - m_ctx = MainWindow::getContext(); QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)"; QRegExp rx; diff --git a/src/sendwidget.h b/src/sendwidget.h index 056fb404..94b4163e 100644 --- a/src/sendwidget.h +++ b/src/sendwidget.h @@ -17,7 +17,7 @@ class SendWidget : public QWidget Q_OBJECT public: - explicit SendWidget(QWidget *parent = nullptr); + explicit SendWidget(AppContext *ctx, QWidget *parent = nullptr); void fill(const CCSEntry &entry); void fill(const QString &address, const QString& description, double amount = 0); void fill(double amount); diff --git a/src/sendwidget.ui b/src/sendwidget.ui index 566459da..5de09348 100644 --- a/src/sendwidget.ui +++ b/src/sendwidget.ui @@ -10,6 +10,12 @@ 231 + + + 0 + 0 + + Form diff --git a/src/settings.cpp b/src/settings.cpp index bf73847a..4be0ae2b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -7,12 +7,12 @@ #include -Settings::Settings(QWidget *parent) : - QDialog(parent), - ui(new Ui::Settings) +Settings::Settings(AppContext *ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::Settings) + , m_ctx(ctx) { ui->setupUi(this); - m_ctx = MainWindow::getContext(); this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); diff --git a/src/settings.h b/src/settings.h index 65b9078f..e02c3b03 100644 --- a/src/settings.h +++ b/src/settings.h @@ -20,7 +20,7 @@ class Settings : public QDialog Q_OBJECT public: - explicit Settings(QWidget *parent = nullptr); + explicit Settings(AppContext *ctx, QWidget *parent = nullptr); ~Settings() override; signals: @@ -49,8 +49,8 @@ private: void setupSkinCombobox(); void setupLocalMoneroFrontendCombobox(); - AppContext *m_ctx; Ui::Settings *ui; + AppContext *m_ctx; QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"}; From f43949a346f6b676ce3124a153697b2ba1eb6929 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 18 May 2021 17:59:18 +0200 Subject: [PATCH 03/62] Allow opening multiple windows --- CMakeLists.txt | 8 +- src/WindowManager.cpp | 444 +++++++++++++++++ src/WindowManager.h | 79 +++ src/api/LocalMoneroApi.cpp | 15 - src/appcontext.cpp | 465 +++-------------- src/appcontext.h | 65 +-- src/calcwidget.cpp | 6 +- src/calcwindow.cpp | 6 +- src/cli.cpp | 132 ++--- src/cli.h | 37 +- src/coinswidget.cpp | 22 +- src/coinswidget.h | 4 +- src/{globals.h => constants.h} | 17 +- src/contactswidget.cpp | 40 +- src/contactswidget.h | 5 +- src/dialog/TxProofDialog.cpp | 18 +- src/dialog/TxProofDialog.h | 6 +- src/dialog/WalletCacheDebugDialog.cpp | 38 +- src/dialog/WalletCacheDebugDialog.h | 4 +- src/dialog/broadcasttxdialog.cpp | 4 +- src/dialog/broadcasttxdialog.h | 4 +- src/dialog/debuginfodialog.cpp | 39 +- src/dialog/debuginfodialog.h | 4 +- src/dialog/keysdialog.cpp | 19 +- src/dialog/keysdialog.h | 2 +- src/dialog/passworddialog.cpp | 2 +- src/dialog/passworddialog.h | 2 +- src/dialog/restoredialog.cpp | 10 +- src/dialog/restoredialog.h | 4 +- src/dialog/seeddialog.cpp | 15 +- src/dialog/seeddialog.h | 5 +- src/dialog/splashdialog.cpp | 3 + src/dialog/torinfodialog.cpp | 5 +- src/dialog/torinfodialog.h | 4 +- src/dialog/transactioninfodialog.cpp | 23 +- src/dialog/transactioninfodialog.h | 8 +- src/dialog/txconfadvdialog.cpp | 22 +- src/dialog/txconfadvdialog.h | 4 +- src/dialog/txconfdialog.cpp | 16 +- src/dialog/txconfdialog.h | 4 +- src/dialog/tximportdialog.cpp | 6 +- src/dialog/tximportdialog.h | 4 +- src/dialog/viewonlydialog.cpp | 17 +- src/dialog/viewonlydialog.h | 4 +- src/dialog/walletinfodialog.cpp | 33 +- src/dialog/walletinfodialog.h | 4 +- src/historywidget.cpp | 51 +- src/historywidget.h | 8 +- src/libwalletqt/Wallet.cpp | 12 +- src/libwalletqt/Wallet.h | 14 +- src/libwalletqt/WalletManager.cpp | 130 +---- src/libwalletqt/WalletManager.h | 33 +- src/main.cpp | 106 ++-- src/mainwindow.cpp | 685 ++++++++++---------------- src/mainwindow.h | 164 +++--- src/mainwindow.ui | 62 +-- src/model/CoinsModel.cpp | 6 +- src/model/TransactionHistoryModel.cpp | 6 +- src/receivewidget.cpp | 64 ++- src/receivewidget.h | 7 +- src/sendwidget.cpp | 26 +- src/sendwidget.h | 5 +- src/settings.cpp | 15 +- src/settings.h | 4 +- src/utils/RestoreHeightLookup.h | 4 +- src/utils/TorManager.cpp | 1 + src/utils/WebsocketClient.h | 4 +- src/utils/WebsocketNotifier.cpp | 10 +- src/utils/WebsocketNotifier.h | 4 +- src/utils/config.cpp | 55 ++- src/utils/config.h | 46 +- src/utils/keysfiles.cpp | 22 +- src/utils/keysfiles.h | 3 +- src/utils/nodes.cpp | 170 ++++--- src/utils/nodes.h | 23 +- src/utils/utils.cpp | 4 +- src/utils/xmrig.cpp | 1 + src/widgets/LocalMoneroWidget.cpp | 4 +- src/widgets/LocalMoneroWidget.h | 4 +- src/widgets/nodewidget.cpp | 2 +- src/widgets/nodewidget.h | 4 +- src/widgets/restoreheightwidget.cpp | 6 +- src/widgets/tickerwidget.cpp | 21 +- src/widgets/tickerwidget.h | 4 +- src/widgets/xmrigwidget.cpp | 47 +- src/widgets/xmrigwidget.h | 5 +- src/wizard/PageHardwareDevice.cpp | 3 +- src/wizard/PageHardwareDevice.h | 3 +- src/wizard/PageMenu.cpp | 3 +- src/wizard/PageMenu.h | 3 +- src/wizard/PageNetwork.cpp | 10 +- src/wizard/PageNetwork.h | 3 +- src/wizard/PageNetworkTor.cpp | 3 +- src/wizard/PageNetworkTor.h | 3 +- src/wizard/PageOpenWallet.cpp | 32 +- src/wizard/PageOpenWallet.h | 3 +- src/wizard/PageSetPassword.cpp | 3 +- src/wizard/PageSetPassword.h | 3 +- src/wizard/PageSetRestoreHeight.cpp | 8 +- src/wizard/PageSetRestoreHeight.h | 3 +- src/wizard/PageWalletFile.cpp | 9 +- src/wizard/PageWalletFile.h | 3 +- src/wizard/PageWalletRestoreKeys.cpp | 17 +- src/wizard/PageWalletRestoreKeys.h | 4 +- src/wizard/PageWalletRestoreSeed.cpp | 7 +- src/wizard/PageWalletRestoreSeed.h | 3 +- src/wizard/PageWalletSeed.cpp | 7 +- src/wizard/PageWalletSeed.h | 4 +- src/wizard/WalletWizard.cpp | 71 +-- src/wizard/WalletWizard.h | 14 +- 110 files changed, 1839 insertions(+), 1903 deletions(-) create mode 100644 src/WindowManager.cpp create mode 100644 src/WindowManager.h rename src/{globals.h => constants.h} (67%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a77d0d8..bc3e7ad4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,15 +9,17 @@ set(VERSION_MINOR "1") set(VERSION_REVISION "0") set(VERSION "beta-6") +option(STATIC "Link libraries statically, requires static Qt") + option(FETCH_DEPS "Download dependencies if they are not found" ON) + option(LOCALMONERO "Include LocalMonero module" ON) option(XMRIG "Include XMRig module" ON) option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF) option(CHECK_UPDATES "Enable checking for application updates" OFF) - -option(STATIC "Link libraries statically, requires static Qt") option(USE_DEVICE_TREZOR "Trezor support compilation" OFF) option(DONATE_BEG "Prompt donation window every once in a while" ON) + list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake") include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) @@ -33,7 +35,7 @@ endif() set(MONERO_HEAD "36fb05da3394505f8033ceb8806b28909617696f") set(BUILD_GUI_DEPS ON) -set(ARCH "x86-64") +set(ARCH "x86-64" CACHE STRING "Target architecture") set(BUILD_64 ON) set(INSTALL_VENDORED_LIBUNBOUND ${STATIC}) set(USE_SINGLE_BUILDDIR ON) diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp new file mode 100644 index 00000000..fca665bc --- /dev/null +++ b/src/WindowManager.cpp @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "WindowManager.h" +#include "constants.h" +#include "dialog/passworddialog.h" +#include "dialog/splashdialog.h" +#include "utils/WebsocketNotifier.h" +#include "utils/tails.h" +#include "utils/Icons.h" +#include "utils/NetworkManager.h" +#include "utils/TorManager.h" + +#include + +WindowManager::WindowManager() { + m_walletManager = WalletManager::instance(); + m_splashDialog = new SplashDialog; + + connect(m_walletManager, &WalletManager::walletOpened, this, &WindowManager::onWalletOpened); + connect(m_walletManager, &WalletManager::walletCreated, this, &WindowManager::onWalletCreated); + connect(m_walletManager, &WalletManager::deviceButtonRequest, this, &WindowManager::onDeviceButtonRequest); + connect(m_walletManager, &WalletManager::deviceError, this, &WindowManager::onDeviceError); + + connect(qApp, &QGuiApplication::lastWindowClosed, this, &WindowManager::quitAfterLastWindow); + + m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png")); + m_tray->setToolTip("Feather Wallet"); + this->buildTrayMenu(); + m_tray->show(); + + this->initSkins(); + + if (!config()->get(Config::firstRun).toBool()) { + this->onInitialNetworkConfigured(); + } + + if (!this->autoOpenWallet()) { + this->initWizard(); + } +} + +// ######################## APPLICATION LIFECYCLE ######################## + +void WindowManager::quitAfterLastWindow() { + if (m_windows.length() > 0 || m_openingWallet) { + return; + } + + qDebug() << "No wizards in progress and no wallets open, quitting application."; + QApplication::quit(); +} + +void WindowManager::close() { + qDebug() << Q_FUNC_INFO; + for (const auto &window: m_windows) { + window->close(); + } + torManager()->stop(); + QApplication::quit(); +} + +void WindowManager::closeWindow(MainWindow *window) { + m_windows.removeOne(window); +} + +void WindowManager::restartApplication(const QString &binaryFilename) { + QProcess::startDetached(binaryFilename, qApp->arguments()); + this->close(); +} + +// ######################## WALLET OPEN ######################## + +void WindowManager::tryOpenWallet(const QString &path, const QString &password) { + // Path : path to .keys file + + QString absolutePath = path; + if (absolutePath.startsWith("~")) { + absolutePath.replace(0, 1, QDir::homePath()); + } + + // If the wallet is already open, just bring window to front + for (const auto &window : m_windows) { + if (absolutePath == window->walletKeysPath() || absolutePath == window->walletCachePath()) { + window->bringToFront(); + return; + } + } + + if (!Utils::fileExists(path)) { + this->handleWalletError(QString("Wallet not found: %1").arg(path)); + return; + } + + m_openingWallet = true; + m_walletManager->openWalletAsync(path, password, constants::networkType, 1); +} + +void WindowManager::onWalletOpened(Wallet *wallet) { + if (wallet->status() != Wallet::Status_Ok) { + QString errMsg = wallet->errorString(); + if (wallet->status() == Wallet::Status_BadPassword) { + // Don't show incorrect password when we try with empty password for the first time + bool showIncorrectPassword = m_openWalletTriedOnce; + m_openWalletTriedOnce = true; + this->onWalletOpenPasswordRequired(showIncorrectPassword, wallet->cachePath()); + } + else if (errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc")) { + qCritical() << errMsg; + WalletManager::clearWalletCache(wallet->cachePath()); // TODO: check this + errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart Feather.").arg(errMsg); + this->handleWalletError(errMsg); + } else { + this->handleWalletError(errMsg); + } + return; + } + + // Create new mainwindow with wallet + + m_splashDialog->hide(); + m_openWalletTriedOnce = false; + auto *window = new MainWindow(this, wallet); + m_windows.append(window); + this->buildTrayMenu(); + m_openingWallet = false; +} + +void WindowManager::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) { + QFileInfo fileInfo(path); + + PasswordDialog dialog{fileInfo.fileName(), invalidPassword}; + switch (dialog.exec()) { + case QDialog::Rejected: + { + m_openWalletTriedOnce = false; + this->showWizard(WalletWizard::Page_OpenWallet); + return; + } + } + + this->tryOpenWallet(path, dialog.password); +} + +bool WindowManager::autoOpenWallet() { + QString autoPath = config()->get(Config::autoOpenWalletPath).toString(); + if (!autoPath.isEmpty() && autoPath.startsWith(QString::number(constants::networkType))) { + autoPath.remove(0, 1); + } + if (!autoPath.isEmpty() && Utils::fileExists(autoPath)) { + this->tryOpenWallet(autoPath, ""); // TODO: get password from --password + return true; + } + return false; +} + +// ######################## WALLET CREATION ######################## + +void WindowManager::tryCreateWallet(FeatherSeed seed, const QString &path, const QString &password, + const QString &seedOffset) { + if(Utils::fileExists(path)) { + auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); + this->handleWalletError(err); + return; + } + + if (seed.mnemonic.isEmpty()) { + this->handleWalletError("Mnemonic seed error. Failed to write wallet."); + return; + } + + Wallet *wallet = nullptr; + if (seed.seedType == SeedType::TEVADOR) { + wallet = m_walletManager->createDeterministicWalletFromSpendKey(path, password, seed.language, constants::networkType, seed.spendKey, seed.restoreHeight, constants::kdfRounds, seedOffset); + wallet->setCacheAttribute("feather.seed", seed.mnemonic.join(" ")); + wallet->setCacheAttribute("feather.seedoffset", seedOffset); + } + if (seed.seedType == SeedType::MONERO) { + wallet = m_walletManager->recoveryWallet(path, password, seed.mnemonic.join(" "), seedOffset, constants::networkType, seed.restoreHeight, constants::kdfRounds); + } + + if (!wallet) { + this->handleWalletError("Failed to write wallet"); + return; + } + + this->onWalletOpened(wallet); +} + +void WindowManager::tryCreateWalletFromDevice(const QString &path, const QString &password, int restoreHeight) +{ + if (Utils::fileExists(path)) { + auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); + this->handleWalletError(err); + return; + } + + m_openingWallet = true; + m_walletManager->createWalletFromDeviceAsync(path, password, constants::networkType, "Ledger", restoreHeight); +} + +void WindowManager::tryCreateWalletFromKeys(const QString &path, const QString &password, const QString &address, + const QString &viewkey, const QString &spendkey, quint64 restoreHeight) { + if (Utils::fileExists(path)) { + auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); + this->handleWalletError(err); + return; + } + + if (!WalletManager::addressValid(address, constants::networkType)) { + auto err = QString("Failed to create wallet. Invalid address provided.").arg(path); + this->handleWalletError(err); + return; + } + + if (!WalletManager::keyValid(viewkey, address, true, constants::networkType)) { + auto err = QString("Failed to create wallet. Invalid viewkey provided.").arg(path); + this->handleWalletError(err); + return; + } + + if (!spendkey.isEmpty() && !WalletManager::keyValid(spendkey, address, false, constants::networkType)) { + auto err = QString("Failed to create wallet. Invalid spendkey provided.").arg(path); + this->handleWalletError(err); + return; + } + + Wallet *wallet = m_walletManager->createWalletFromKeys(path, password, constants::seedLanguage, constants::networkType, address, viewkey, spendkey, restoreHeight); + m_openingWallet = true; + m_walletManager->walletOpened(wallet); +} + +void WindowManager::onWalletCreated(Wallet *wallet) { + // Currently only called when a wallet is created from device. + auto state = wallet->status(); + if (state != Wallet::Status_Ok) { + qDebug() << Q_FUNC_INFO << QString("Wallet open error: %1").arg(wallet->errorString()); + this->displayWalletErrorMessage(wallet->errorString()); + m_splashDialog->hide(); + this->showWizard(WalletWizard::Page_Menu); + return; + } + + this->onWalletOpened(wallet); +} + +// ######################## ERROR HANDLING ######################## + +void WindowManager::handleWalletError(const QString &message) { + qCritical() << message; + this->displayWalletErrorMessage(message); + this->initWizard(); +} + +void WindowManager::displayWalletErrorMessage(const QString &message) { + QString errMsg = message; + if (message.contains("No device found")) { + errMsg += "\n\nThis wallet is backed by a hardware device. Make sure the Monero app is opened on the device.\n" + "You may need to restart Feather before the device can get detected."; + } + if (message.contains("Unable to open device")) { + errMsg += "\n\nThe device might be in use by a different application."; + } + + if (message.contains("SW_CLIENT_NOT_SUPPORTED")) { + errMsg += "\n\nIncompatible version: you may need to upgrade the Monero app on the Ledger device to the latest version."; + } + else if (message.contains("Wrong Device Status")) { + errMsg += "\n\nThe device may need to be unlocked."; + } + else if (message.contains("Wrong Channel")) { + errMsg += "\n\nRestart the hardware device and try again."; + } + + QMessageBox msgBox; + msgBox.setWindowIcon(icons()->icon("appicons/64x64.png")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(errMsg); + msgBox.setWindowTitle("Wallet error"); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.exec(); +} + +// ######################## DEVICE ######################## + +void WindowManager::onDeviceButtonRequest(quint64 code) { + m_splashDialog->setMessage("Action required on device: Export the view key to open the wallet."); + m_splashDialog->setIcon(QPixmap(":/assets/images/key.png")); + m_splashDialog->show(); + m_splashDialog->setEnabled(true); +} + +void WindowManager::onDeviceError(const QString &errorMessage) { + // TODO: when does this get called? + qCritical() << Q_FUNC_INFO << errorMessage; +} + +// ######################## TRAY ######################## + +void WindowManager::buildTrayMenu() { + QMenu *menu; + if (!m_tray->contextMenu()) { + menu = new QMenu(); + m_tray->setContextMenu(menu); + } else { + menu = m_tray->contextMenu(); + menu->clear(); + } + + for (const auto &window : m_windows) { + QString name = window->walletName(); + QMenu *submenu = menu->addMenu(name); + submenu->addAction("Show/Hide", window, &MainWindow::showOrHide); + submenu->addAction("Close", window, &MainWindow::close); + } + menu->addSeparator(); + menu->addAction("Exit Feather", this, &WindowManager::close); +} + +// ######################## NETWORKING ######################## + +void WindowManager::onInitialNetworkConfigured() { + this->initTor(); + this->initWS(); +} + +void WindowManager::initTor() { + torManager()->init(); + torManager()->start(); + + connect(torManager(), &TorManager::connectionStateChanged, &websocketNotifier()->websocketClient, &WebsocketClient::onToggleConnect); + + this->onTorSettingsChanged(); +} + +void WindowManager::onTorSettingsChanged() { + if (Utils::isTorsocks()) { + return; + } + + // use local tor -> bundled tor + QString host = config()->get(Config::socks5Host).toString(); + quint16 port = config()->get(Config::socks5Port).toString().toUShort(); + if (!torManager()->isLocalTor()) { + host = torManager()->featherTorHost; + port = torManager()->featherTorPort; + } + + QNetworkProxy proxy{QNetworkProxy::Socks5Proxy, host, port}; + getNetworkTor()->setProxy(proxy); + websocketNotifier()->websocketClient.webSocket.setProxy(proxy); + + emit torSettingsChanged(); +} + +void WindowManager::initWS() { + websocketNotifier()->websocketClient.start(); +} + +// ######################## WIZARD ######################## + +WalletWizard* WindowManager::createWizard(WalletWizard::Page startPage) const { + auto *wizard = new WalletWizard; + connect(wizard, &WalletWizard::initialNetworkConfigured, this, &WindowManager::onInitialNetworkConfigured); + connect(wizard, &WalletWizard::skinChanged, this, &WindowManager::changeSkin); + connect(wizard, &WalletWizard::openWallet, this, &WindowManager::tryOpenWallet); + connect(wizard, &WalletWizard::createWallet, this, &WindowManager::tryCreateWallet); + connect(wizard, &WalletWizard::createWalletFromKeys, this, &WindowManager::tryCreateWalletFromKeys); + connect(wizard, &WalletWizard::createWalletFromDevice, this, &WindowManager::tryCreateWalletFromDevice); + return wizard; +} + +void WindowManager::initWizard() { + auto startPage = WalletWizard::Page_Menu; + if (config()->get(Config::firstRun).toBool() && !(TailsOS::detect() || WhonixOS::detect())) { + startPage = WalletWizard::Page_Network; + } + + this->showWizard(startPage); +} + +void WindowManager::showWizard(WalletWizard::Page startPage) { + if (!m_wizard) { + m_wizard = this->createWizard(startPage); + } + + m_wizard->setStartId(startPage); + m_wizard->restart(); + m_wizard->setEnabled(true); + m_wizard->show(); +} + +void WindowManager::wizardOpenWallet() { + this->showWizard(WalletWizard::Page_OpenWallet); +} + +// ######################## SKINS ######################## + +void WindowManager::initSkins() { + m_skins.insert("Native", ""); + + QString qdarkstyle = this->loadStylesheet(":qdarkstyle/style.qss"); + if (!qdarkstyle.isEmpty()) + m_skins.insert("QDarkStyle", qdarkstyle); + + QString breeze_dark = this->loadStylesheet(":/dark.qss"); + if (!breeze_dark.isEmpty()) + m_skins.insert("Breeze/Dark", breeze_dark); + + QString breeze_light = this->loadStylesheet(":/light.qss"); + if (!breeze_light.isEmpty()) + m_skins.insert("Breeze/Light", breeze_light); + + QString skin = config()->get(Config::skin).toString(); + qApp->setStyleSheet(m_skins[skin]); +} + +QString WindowManager::loadStylesheet(const QString &resource) { + QFile f(resource); + if (!f.exists()) { + printf("Unable to set stylesheet, file not found\n"); + f.close(); + return ""; + } + + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + QString data = ts.readAll(); + f.close(); + + return data; +} + +void WindowManager::changeSkin(const QString &skinName) { + if (!m_skins.contains(skinName)) { + qWarning() << QString("No such skin %1").arg(skinName); + return; + } + + config()->set(Config::skin, skinName); + qApp->setStyleSheet(m_skins[skinName]); + qDebug() << QString("Skin changed to %1").arg(skinName); +} diff --git a/src/WindowManager.h b/src/WindowManager.h new file mode 100644 index 00000000..3d99c6d9 --- /dev/null +++ b/src/WindowManager.h @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_WINDOWMANAGER_H +#define FEATHER_WINDOWMANAGER_H + +#include +#include "libwalletqt/WalletManager.h" +#include "libwalletqt/Wallet.h" +#include "wizard/WalletWizard.h" +#include "dialog/torinfodialog.h" +#include "mainwindow.h" + +class MainWindow; +class WindowManager : public QObject { +Q_OBJECT + +public: + explicit WindowManager(); + + void wizardOpenWallet(); + void close(); + void closeWindow(MainWindow *window); + void showWizard(WalletWizard::Page startPage); + void changeSkin(const QString &skinName); + void restartApplication(const QString &binaryFilename); + +signals: + void torSettingsChanged(); + +public slots: + void onTorSettingsChanged(); + void tryOpenWallet(const QString &path, const QString &password); + +private slots: + void onWalletOpened(Wallet *wallet); + void onWalletCreated(Wallet *wallet); + void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); + void onInitialNetworkConfigured(); + void onDeviceButtonRequest(quint64 code); + void onDeviceError(const QString &errorMessage); + +private: + void tryCreateWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset); + void tryCreateWalletFromDevice(const QString &path, const QString &password, int restoreHeight); + void tryCreateWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight); + + bool autoOpenWallet(); + + void initWizard(); + WalletWizard* createWizard(WalletWizard::Page startPage) const; + + void handleWalletError(const QString &message); + void displayWalletErrorMessage(const QString &message); + + void initTor(); + void initWS(); + void initSkins(); + QString loadStylesheet(const QString &resource); + void buildTrayMenu(); + + void quitAfterLastWindow(); + + QVector m_windows; + + WalletManager *m_walletManager; + WalletWizard *m_wizard = nullptr; + SplashDialog *m_splashDialog = nullptr; + + QSystemTrayIcon *m_tray; + + QMap m_skins; + + bool m_openWalletTriedOnce = false; + bool m_openingWallet = false; +}; + + +#endif //FEATHER_WINDOWMANAGER_H diff --git a/src/api/LocalMoneroApi.cpp b/src/api/LocalMoneroApi.cpp index a047a87f..1e494d89 100644 --- a/src/api/LocalMoneroApi.cpp +++ b/src/api/LocalMoneroApi.cpp @@ -60,21 +60,6 @@ void LocalMoneroApi::onResponse(QNetworkReply *reply, LocalMoneroApi::Endpoint e const QString err = reply->errorString(); QByteArray data = reply->readAll(); - - qDebug() << "Response"; - qDebug() << data; - for (const auto header : reply->rawHeaderList()) { - qDebug() << header << ": " << reply->rawHeader(header); - } - - qDebug() << reply->rawHeaderPairs(); - - qDebug() << "Request"; - for (const auto header : reply->request().rawHeaderList()) { - qDebug() << "header: " << header << ": " << reply->request().rawHeader(header); - } - qDebug() << reply->request().url(); - reply->deleteLater(); QJsonObject obj; diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 422df1c6..75588a46 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -5,7 +5,7 @@ #include #include "appcontext.h" -#include "globals.h" +#include "constants.h" // libwalletqt #include "libwalletqt/TransactionHistory.h" @@ -17,44 +17,32 @@ #include "utils/WebsocketClient.h" #include "utils/WebsocketNotifier.h" -WalletKeysFilesModel *AppContext::wallets = nullptr; -QMap AppContext::txCache; +// This class serves as a business logic layer between MainWindow and libwalletqt. +// This way we don't clutter the GUI with wallet logic, +// and keep libwalletqt (mostly) clean of Feather specific implementation details -AppContext::AppContext(QCommandLineParser *cmdargs) { - this->cmdargs = cmdargs; +AppContext::AppContext(Wallet *wallet) + : wallet(wallet) + , nodes(new Nodes(this, this)) + , networkType(constants::networkType) + , m_rpc(new DaemonRpc{this, getNetworkTor(), ""}) +{ + connect(this->wallet.get(), &Wallet::moneySpent, this, &AppContext::onMoneySpent); + connect(this->wallet.get(), &Wallet::moneyReceived, this, &AppContext::onMoneyReceived); + connect(this->wallet.get(), &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived); + connect(this->wallet.get(), &Wallet::newBlock, this, &AppContext::onWalletNewBlock); + connect(this->wallet.get(), &Wallet::updated, this, &AppContext::onWalletUpdate); + connect(this->wallet.get(), &Wallet::refreshed, this, &AppContext::onWalletRefreshed); + connect(this->wallet.get(), &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted); + connect(this->wallet.get(), &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed); + connect(this->wallet.get(), &Wallet::transactionCreated, this, &AppContext::onTransactionCreated); + connect(this->wallet.get(), &Wallet::deviceError, this, &AppContext::onDeviceError); + connect(this->wallet.get(), &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest); + connect(this->wallet.get(), &Wallet::connectionStatusChanged, [this]{ + this->nodes->autoConnect(); + }); - this->isTails = TailsOS::detect(); - this->isWhonix = WhonixOS::detect(); - - // ----------------- Setup Paths ----------------- - - QString configDir = Config::defaultConfigDir().path(); - createConfigDirectory(configDir); - - QString walletDir = config()->get(Config::walletDirectory).toString(); - if (walletDir.isEmpty()) { - walletDir = Utils::defaultWalletDir(); - } - this->defaultWalletDir = walletDir; - if (!QDir().mkpath(defaultWalletDir)) - qCritical() << "Unable to create dir: " << defaultWalletDir; - - // ----------------- Network Type ----------------- - - if (this->cmdargs->isSet("stagenet")) { - this->networkType = NetworkType::STAGENET; - config()->set(Config::networkType, NetworkType::STAGENET); - } - else if (this->cmdargs->isSet("testnet")) { - this->networkType = NetworkType::TESTNET; - config()->set(Config::networkType, NetworkType::TESTNET); - } - else { - this->networkType = NetworkType::MAINNET; - config()->set(Config::networkType, NetworkType::MAINNET); - } - - this->nodes = new Nodes(this, this); + connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError); // Store the wallet every 2 minutes m_storeTimer.start(2 * 60 * 1000); @@ -62,71 +50,26 @@ AppContext::AppContext(QCommandLineParser *cmdargs) { this->storeWallet(); }); - this->walletManager = WalletManager::instance(); - QString logPath = QString("%1/daemon.log").arg(configDir); - Monero::Utils::onStartup(); - Monero::Wallet::init("", "feather", logPath.toStdString(), true); + this->updateBalance(); - bool logLevelFromEnv; - int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv); - if (this->cmdargs->isSet("quiet")) - this->walletManager->setLogLevel(-1); - else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max) - Monero::WalletManagerFactory::setLogLevel(logLevel); - - connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError); - - // libwallet connects - connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened); - connect(this->walletManager, &WalletManager::walletCreated, this, &AppContext::onWalletCreated); - connect(this->walletManager, &WalletManager::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest); - connect(this->walletManager, &WalletManager::deviceError, this, &AppContext::onDeviceError); - - // TODO: move me - connect(websocketNotifier(), &WebsocketNotifier::NodesReceived, this->nodes, &Nodes::onWSNodesReceived); - - m_rpc = new DaemonRpc{this, getNetworkTor(), ""}; -} - -void AppContext::initTor() { - if (this->cmdargs->isSet("tor-host")) - config()->set(Config::socks5Host, this->cmdargs->value("tor-host")); - if (this->cmdargs->isSet("tor-port")) - config()->set(Config::socks5Port, this->cmdargs->value("tor-port")); - if (this->cmdargs->isSet("use-local-tor")) - config()->set(Config::useLocalTor, true); - - torManager()->init(); - torManager()->start(); - - connect(torManager(), &TorManager::connectionStateChanged, &websocketNotifier()->websocketClient, &WebsocketClient::onToggleConnect); - - this->onTorSettingsChanged(); -} - -void AppContext::initWS() { - websocketNotifier()->websocketClient.start(); + // force trigger preferredFiat signal for history model + this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString()); } void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector &address) { // tx cancelled by user - double amount = tx->amount() / globals::cdiv; + double amount = tx->amount() / constants::cdiv; emit createTransactionCancelled(address, amount); - this->currentWallet->disposeTransaction(tx); + this->wallet->disposeTransaction(tx); } void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) { - if(this->currentWallet == nullptr){ - qCritical() << "Cannot create transaction; no wallet loaded"; - return; - } - if (churn) { - address = this->currentWallet->address(0, 0); // primary address + address = this->wallet->address(0, 0); // primary address } qCritical() << "Creating transaction"; - this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); + this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); emit initiateTransaction(); } @@ -135,17 +78,12 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con // tx creation this->tmpTxDescription = description; - if(this->currentWallet == nullptr) { - emit createTransactionError("Cannot create transaction; no wallet loaded"); - return; - } - if (!all && amount == 0) { emit createTransactionError("Cannot send nothing"); return; } - auto unlocked_balance = this->currentWallet->unlockedBalance(); + auto unlocked_balance = this->wallet->unlockedBalance(); if(!all && amount > unlocked_balance) { emit createTransactionError("Not enough money to spend"); return; @@ -154,11 +92,11 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con return; } - qDebug() << "creating tx"; + qDebug() << "Creating tx"; if (all) - this->currentWallet->createTransactionAllAsync(address, "", globals::mixin, this->tx_priority); + this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority); else - this->currentWallet->createTransactionAsync(address, "", amount, globals::mixin, this->tx_priority); + this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority); emit initiateTransaction(); } @@ -166,23 +104,18 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con void AppContext::onCreateTransactionMultiDest(const QVector &addresses, const QVector &amounts, const QString &description) { this->tmpTxDescription = description; - if (this->currentWallet == nullptr) { - emit createTransactionError("Cannot create transaction; no wallet loaded"); - return; - } - quint64 total_amount = 0; for (auto &amount : amounts) { total_amount += amount; } - auto unlocked_balance = this->currentWallet->unlockedBalance(); + auto unlocked_balance = this->wallet->unlockedBalance(); if (total_amount > unlocked_balance) { emit createTransactionError("Not enough money to spend"); } qDebug() << "Creating tx"; - this->currentWallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority); + this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority); emit initiateTransaction(); } @@ -192,68 +125,15 @@ void AppContext::onCreateTransactionError(const QString &msg) { emit endTransaction(); } -void AppContext::closeWallet(bool emitClosedSignal, bool storeWallet) { - if (this->currentWallet == nullptr) - return; - - emit walletAboutToClose(); - - if (storeWallet) { - this->storeWallet(); - } - - this->currentWallet->disconnect(); - this->walletManager->closeWallet(); - this->currentWallet = nullptr; - - if (emitClosedSignal) - emit walletClosed(); -} - -void AppContext::onOpenWallet(const QString &path, const QString &password){ - if(this->currentWallet != nullptr){ - emit walletOpenedError("There is an active wallet opened."); - return; - } - - if(!Utils::fileExists(path)) { - emit walletOpenedError(QString("Wallet not found: %1").arg(path)); - return; - } - - if (password.isEmpty()) { - this->walletPassword = ""; - } - - config()->set(Config::firstRun, false); - - this->walletPath = path; - this->walletManager->openWalletAsync(path, password, this->networkType, 1); -} - -void AppContext::onWalletCreated(Wallet * wallet) { - // Currently only called when a wallet is created from device. - auto state = wallet->status(); - if (state != Wallet::Status_Ok) { - emit walletCreatedError(wallet->errorString()); - return; - } - - this->onWalletOpened(wallet); -} - void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) { - if(this->currentWallet) { - auto *model = this->currentWallet->transactionHistoryModel(); - if(model != nullptr) { - model->preferredFiatSymbol = symbol; - } + auto *model = this->wallet->transactionHistoryModel(); + if (model != nullptr) { + model->preferredFiatSymbol = symbol; } } void AppContext::onAmountPrecisionChanged(int precision) { - if (!this->currentWallet) return; - auto *model = this->currentWallet->transactionHistoryModel(); + auto *model = this->wallet->transactionHistoryModel(); if (!model) return; model->amountPrecision = precision; } @@ -265,12 +145,12 @@ void AppContext::commitTransaction(PendingTransaction *tx) { this->onMultiBroadcast(tx); } - this->currentWallet->commitTransactionAsync(tx); + this->wallet->commitTransactionAsync(tx); } void AppContext::onMultiBroadcast(PendingTransaction *tx) { - int count = tx->txCount(); - for (int i = 0; i < count; i++) { + quint64 count = tx->txCount(); + for (quint64 i = 0; i < count; i++) { QString txData = tx->signedTxToHex(i); for (const auto& node: this->nodes->websocketNodes()) { @@ -294,205 +174,37 @@ void AppContext::onDeviceError(const QString &message) { } void AppContext::onTorSettingsChanged() { - if (WhonixOS::detect() || Utils::isTorsocks()) { + if (Utils::isTorsocks()) { return; } - // use local tor -> bundled tor - QString host = config()->get(Config::socks5Host).toString(); - quint16 port = config()->get(Config::socks5Port).toString().toUShort(); - if (!torManager()->isLocalTor()) { - host = torManager()->featherTorHost; - port = torManager()->featherTorPort; - } - - QNetworkProxy proxy{QNetworkProxy::Socks5Proxy, host, port}; - getNetworkTor()->setProxy(proxy); - websocketNotifier()->websocketClient.webSocket.setProxy(proxy); - this->nodes->connectToNode(); auto privacyLevel = config()->get(Config::torPrivacyLevel).toInt(); qDebug() << "Changed privacyLevel to " << privacyLevel; } -void AppContext::onInitialNetworkConfigured() { - this->initTor(); - this->initWS(); -} - -void AppContext::onWalletOpened(Wallet *wallet) { - auto state = wallet->status(); - if (state != Wallet::Status_Ok) { - auto errMsg = wallet->errorString(); - if (state == Wallet::Status_BadPassword) { - this->closeWallet(false); - // Don't show incorrect password when we try with empty password for the first time - bool showIncorrectPassword = m_openWalletTriedOnce; - m_openWalletTriedOnce = true; - emit walletOpenPasswordNeeded(showIncorrectPassword, wallet->path()); - } - else if (errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc")) { - qCritical() << errMsg; - this->walletManager->clearWalletCache(this->walletPath); - errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart Feather.").arg(errMsg); - this->closeWallet(false); - emit walletOpenedError(errMsg); - } else { - this->closeWallet(false); - emit walletOpenedError(errMsg); - } - - return; - } - - m_openWalletTriedOnce = false; - this->refreshed = false; - this->currentWallet = wallet; - this->walletPath = this->currentWallet->path() + ".keys"; - this->walletPassword = this->currentWallet->getPassword(); - config()->set(Config::walletPath, this->walletPath); - - connect(this->currentWallet, &Wallet::moneySpent, this, &AppContext::onMoneySpent); - connect(this->currentWallet, &Wallet::moneyReceived, this, &AppContext::onMoneyReceived); - connect(this->currentWallet, &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived); - connect(this->currentWallet, &Wallet::newBlock, this, &AppContext::onWalletNewBlock); - connect(this->currentWallet, &Wallet::updated, this, &AppContext::onWalletUpdate); - connect(this->currentWallet, &Wallet::refreshed, this, &AppContext::onWalletRefreshed); - connect(this->currentWallet, &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted); - connect(this->currentWallet, &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed); - connect(this->currentWallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated); - connect(this->currentWallet, &Wallet::deviceError, this, &AppContext::onDeviceError); - connect(this->currentWallet, &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest); - - emit walletOpened(); - - connect(this->currentWallet, &Wallet::connectionStatusChanged, [this]{ - this->nodes->autoConnect(); - }); - this->nodes->connectToNode(); - this->updateBalance(); - -#ifdef DONATE_BEG - this->donateBeg(); -#endif - - // force trigger preferredFiat signal for history model - this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString()); -} - -void AppContext::createConfigDirectory(const QString &dir) { - QString config_dir_tor = QString("%1/%2").arg(dir).arg("tor"); - QString config_dir_tordata = QString("%1/%2").arg(dir).arg("tor/data"); - - QStringList createDirs({dir, config_dir_tor, config_dir_tordata}); - for(const auto &d: createDirs) { - if(!Utils::dirExists(d)) { - qDebug() << QString("Creating directory: %1").arg(d); - if (!QDir().mkpath(d)) { - qCritical() << "Could not create directory " << d; - } - } - } -} - -void AppContext::createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset) { - if(Utils::fileExists(path)) { - auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - if(seed.mnemonic.isEmpty()) { - emit walletCreatedError("Mnemonic seed error. Failed to write wallet."); - return; - } - - Wallet *wallet = nullptr; - if (seed.seedType == SeedType::TEVADOR) { - wallet = this->walletManager->createDeterministicWalletFromSpendKey(path, password, seed.language, this->networkType, seed.spendKey, seed.restoreHeight, globals::kdfRounds, seedOffset); - wallet->setCacheAttribute("feather.seed", seed.mnemonic.join(" ")); - wallet->setCacheAttribute("feather.seedoffset", seedOffset); - } - if (seed.seedType == SeedType::MONERO) { - wallet = this->walletManager->recoveryWallet(path, password, seed.mnemonic.join(" "), seedOffset, this->networkType, seed.restoreHeight, globals::kdfRounds); - } - - this->currentWallet = wallet; - if(this->currentWallet == nullptr) { - emit walletCreatedError("Failed to write wallet"); - return; - } - - this->onWalletOpened(wallet); -} - -void AppContext::createWalletFromDevice(const QString &path, const QString &password, int restoreHeight) { - if(Utils::fileExists(path)) { - auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - this->walletManager->createWalletFromDeviceAsync(path, password, this->networkType, "Ledger", restoreHeight); -} - -void AppContext::createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic) { - if(Utils::fileExists(path)) { - auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - if(!WalletManager::addressValid(address, this->networkType)) { - auto err = QString("Failed to create wallet. Invalid address provided.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - if(!this->walletManager->keyValid(viewkey, address, true, this->networkType)) { - auto err = QString("Failed to create wallet. Invalid viewkey provided.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - if(!spendkey.isEmpty() && !this->walletManager->keyValid(spendkey, address, false, this->networkType)) { - auto err = QString("Failed to create wallet. Invalid spendkey provided.").arg(path); - qCritical() << err; - emit walletCreatedError(err); - return; - } - - Wallet *wallet = this->walletManager->createWalletFromKeys(path, password, this->seedLanguage, this->networkType, address, viewkey, spendkey, restoreHeight); - this->walletManager->walletOpened(wallet); -} - void AppContext::onSetRestoreHeight(quint64 height){ - auto seed = this->currentWallet->getCacheAttribute("feather.seed"); + auto seed = this->wallet->getCacheAttribute("feather.seed"); if(!seed.isEmpty()) { const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; emit setRestoreHeightError(msg); return; } - this->currentWallet->setWalletCreationHeight(height); - this->currentWallet->setPassword(this->currentWallet->getPassword()); // trigger .keys write + this->wallet->setWalletCreationHeight(height); + this->wallet->setPassword(this->wallet->getPassword()); // trigger .keys write // nuke wallet cache - const auto fn = this->currentWallet->path(); - this->walletManager->clearWalletCache(fn); + const auto fn = this->wallet->cachePath(); + WalletManager::clearWalletCache(fn); emit customRestoreHeightSet(height); } void AppContext::onOpenAliasResolve(const QString &openAlias) { // @TODO: calling this freezes for about 1-2 seconds :/ - const auto result = this->walletManager->resolveOpenAlias(openAlias); + const auto result = WalletManager::instance()->resolveOpenAlias(openAlias);; // TODO: async call const auto spl = result.split("|"); auto msg = QString(""); if(spl.count() != 2) { @@ -503,7 +215,7 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) { const auto &status = spl.at(0); const auto &address = spl.at(1); - const auto valid = this->walletManager->addressValid(address, this->networkType); + const auto valid = WalletManager::addressValid(address, constants::networkType); if(status == "false"){ if(valid){ msg = "Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"; @@ -532,50 +244,32 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) { emit openAliasResolveError(msg); } -void AppContext::donateBeg() { - if (this->currentWallet == nullptr) return; - if (this->networkType != NetworkType::Type::MAINNET) return; - if (this->currentWallet->viewOnly()) return; - - auto donationCounter = config()->get(Config::donateBeg).toInt(); - if (donationCounter == -1) - return; // previously donated - - donationCounter += 1; - if (donationCounter % globals::donationBoundary == 0) { - emit donationNag(); - } - config()->set(Config::donateBeg, donationCounter); -} - -AppContext::~AppContext() = default; - -// ############################################## LIBWALLET QT ######################################################### +// ########################################## LIBWALLET QT SIGNALS #################################################### void AppContext::onMoneySpent(const QString &txId, quint64 amount) { - auto amount_num = amount / globals::cdiv; + auto amount_num = amount / constants::cdiv; qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); } void AppContext::onMoneyReceived(const QString &txId, quint64 amount) { // Incoming tx included in a block. - auto amount_num = amount / globals::cdiv; + auto amount_num = amount / constants::cdiv; qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); } void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) { // Incoming transaction in pool - auto amount_num = amount / globals::cdiv; + auto amount_num = amount / constants::cdiv; qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); - if(this->currentWallet->synchronized()) { + if(this->wallet->synchronized()) { auto notify = QString("%1 XMR (pending)").arg(amount_num); Utils::desktopNotify("Payment received", notify, 5000); } } void AppContext::onWalletUpdate() { - if (this->currentWallet->synchronized()) { + if (this->wallet->synchronized()) { this->refreshModels(); this->storeWallet(); } @@ -595,7 +289,7 @@ void AppContext::onWalletRefreshed(bool success, const QString &message) { this->refreshed = true; emit walletRefreshed(); // store wallet immediately upon finishing synchronization - this->currentWallet->store(); + this->wallet->store(); } qDebug() << "Wallet refresh status: " << success; @@ -605,10 +299,9 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) { // Called whenever a new block gets scanned by the wallet this->syncStatusUpdated(blockheight, targetHeight); - if (!this->currentWallet) return; - if (this->currentWallet->isSynchronized()) { - this->currentWallet->coins()->refreshUnlocked(); - this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); + if (this->wallet->isSynchronized()) { + this->wallet->coins()->refreshUnlocked(); + this->wallet->history()->refresh(this->wallet->currentSubaddressAccount()); // Todo: only refresh tx confirmations } } @@ -616,7 +309,7 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) { void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) { qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight; - if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) + if (this->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) return; if (daemonHeight < targetHeight) { @@ -631,7 +324,7 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVectordonationSending = true; } } @@ -646,16 +339,16 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVectorcurrentWallet->setUserNote(entry, this->tmpTxDescription); + this->wallet->setUserNote(entry, this->tmpTxDescription); } this->tmpTxDescription = ""; } // Store wallet immediately so we don't risk losing tx key if wallet crashes - this->currentWallet->store(); + this->wallet->store(); - this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); - this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); + this->wallet->history()->refresh(this->wallet->currentSubaddressAccount()); + this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount()); this->updateBalance(); @@ -670,19 +363,16 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con void AppContext::storeWallet() { // Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet - if (this->currentWallet == nullptr || !this->currentWallet->isSynchronized()) + if (!this->wallet->isSynchronized()) return; qDebug() << "Storing wallet"; - this->currentWallet->store(); + this->wallet->store(); } void AppContext::updateBalance() { - if (!this->currentWallet) - return; - - quint64 balance = this->currentWallet->balance(); - quint64 spendable = this->currentWallet->unlockedBalance(); + quint64 balance = this->wallet->balance(); + quint64 spendable = this->wallet->unlockedBalance(); emit balanceUpdated(balance, spendable); } @@ -698,11 +388,8 @@ void AppContext::syncStatusUpdated(quint64 height, quint64 target) { } void AppContext::refreshModels() { - if (!this->currentWallet) - return; - - this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount()); - this->currentWallet->subaddress()->refresh(this->currentWallet->currentSubaddressAccount()); - this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); + this->wallet->history()->refresh(this->wallet->currentSubaddressAccount()); + this->wallet->subaddress()->refresh(this->wallet->currentSubaddressAccount()); + this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount()); // Todo: set timer for refreshes } diff --git a/src/appcontext.h b/src/appcontext.h index 35435b7c..646457de 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -7,22 +7,15 @@ #include #include -#include "utils/tails.h" #include "utils/whonix.h" -#include "utils/prices.h" #include "utils/networking.h" -#include "utils/TorManager.h" #include "utils/wsclient.h" -#include "utils/txfiathistory.h" #include "utils/FeatherSeed.h" #include "utils/daemonrpc.h" -#include "widgets/RedditPost.h" -#include "widgets/CCSEntry.h" #include "utils/RestoreHeightLookup.h" #include "utils/nodes.h" #include "libwalletqt/WalletManager.h" -#include "utils/keysfiles.h" #include "PendingTransaction.h" class AppContext : public QObject @@ -30,55 +23,30 @@ class AppContext : public QObject Q_OBJECT public: - explicit AppContext(QCommandLineParser *cmdargs); - ~AppContext() override; + explicit AppContext(Wallet *wallet); - QCommandLineParser *cmdargs; - - bool isTails = false; - bool isWhonix = false; + QScopedPointer wallet; + Nodes *nodes; bool donationSending = false; - QString defaultWalletDir; - QString tmpTxDescription; + QString tmpTxDescription; // TODO: remove the need for this var - QString walletPath; - QString walletPassword = ""; NetworkType::Type networkType; - PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low; - QString seedLanguage = "English"; // 14 word `monero-seed` only has English - - Nodes *nodes; // TODO: move this to mainwindow (?) - - static WalletKeysFilesModel *wallets; - static QMap txCache; - - static void createConfigDirectory(const QString &dir); + QMap txCache; // libwalletqt bool refreshed = false; - WalletManager *walletManager; - Wallet *currentWallet = nullptr; - void createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset = ""); - void createWalletFromDevice(const QString &path, const QString &password, int restoreHeight); - void createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic = false); + void commitTransaction(PendingTransaction *tx); void syncStatusUpdated(quint64 height, quint64 target); void updateBalance(); - void initTor(); - void initWS(); - void donateBeg(); void refreshModels(); - // Closes the currently opened wallet - void closeWallet(bool emitClosedSignal = true, bool storeWallet = false); void storeWallet(); public slots: - void onOpenWallet(const QString& path, const QString &password); - void onWalletCreated(Wallet * wallet); void onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all); void onCreateTransactionMultiDest(const QVector &addresses, const QVector &amounts, const QString &description); void onCancelTransaction(PendingTransaction *tx, const QVector &address); @@ -90,39 +58,28 @@ public slots: void onAmountPrecisionChanged(int precision); void onMultiBroadcast(PendingTransaction *tx); void onDeviceButtonRequest(quint64 code); - void onTorSettingsChanged(); - void onInitialNetworkConfigured(); void onDeviceError(const QString &message); + void onTorSettingsChanged(); // should not be here + private slots: void onMoneySpent(const QString &txId, quint64 amount); void onMoneyReceived(const QString &txId, quint64 amount); void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount); void onWalletUpdate(); void onWalletRefreshed(bool success, const QString &message); - void onWalletOpened(Wallet *wallet); + void onWalletNewBlock(quint64 blockheight, quint64 targetHeight); void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight); void onTransactionCreated(PendingTransaction *tx, const QVector &address); void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); signals: - // Emitted just before the wallet is closed - void walletAboutToClose(); - - // Emitted after a wallet has been closed - void walletClosed(); - void balanceUpdated(quint64 balance, quint64 spendable); void blockchainSync(int height, int target); void refreshSync(int height, int target); void synchronized(); void walletRefreshed(); - void walletOpened(); - void walletCreatedError(const QString &msg); - void walletCreated(Wallet *wallet); - void walletOpenedError(QString msg); - void walletOpenPasswordNeeded(bool invalidPassword, QString path); void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); void createTransactionError(QString message); void createTransactionCancelled(const QVector &address, double amount); @@ -131,18 +88,14 @@ signals: void openAliasResolved(const QString &address, const QString &openAlias); void setRestoreHeightError(const QString &msg); void customRestoreHeightSet(int height); - void closeApplication(); - void donationNag(); void initiateTransaction(); void endTransaction(); void deviceButtonRequest(quint64 code); - void updatesAvailable(const QJsonObject &updates); void deviceError(const QString &message); private: DaemonRpc *m_rpc; QTimer m_storeTimer; - bool m_openWalletTriedOnce = false; }; #endif //FEATHER_APPCONTEXT_H diff --git a/src/calcwidget.cpp b/src/calcwidget.cpp index 48e85744..b4ce187d 100644 --- a/src/calcwidget.cpp +++ b/src/calcwidget.cpp @@ -9,9 +9,9 @@ #include "utils/AppData.h" #include "utils/config.h" -CalcWidget::CalcWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::CalcWidget) +CalcWidget::CalcWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::CalcWidget) { ui->setupUi(this); diff --git a/src/calcwindow.cpp b/src/calcwindow.cpp index f4ccbfc0..3a363e73 100644 --- a/src/calcwindow.cpp +++ b/src/calcwindow.cpp @@ -8,9 +8,9 @@ #include "ui_calcwindow.h" -CalcWindow::CalcWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::CalcWindow) +CalcWindow::CalcWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::CalcWindow) { Qt::WindowFlags flags = this->windowFlags(); this->setWindowFlags(flags|Qt::WindowStaysOnTopHint); // on top diff --git a/src/cli.cpp b/src/cli.cpp index 6f236dc7..a0e7a63d 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -9,48 +9,59 @@ #include "model/AddressBookModel.h" #include "model/TransactionHistoryModel.h" #include "utils/brute.h" +#include "constants.h" -CLI::CLI(AppContext *ctx, QObject *parent) : - QObject(parent), - ctx(ctx) { - connect(this->ctx, &AppContext::walletOpened, this, &CLI::onWalletOpened); - connect(this->ctx, &AppContext::walletOpenedError, this, &CLI::onWalletOpenedError); - connect(this->ctx, &AppContext::walletOpenPasswordNeeded, this, &CLI::onWalletOpenPasswordRequired); -} +CLI::CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent) + : QObject(parent) + , m_mode(mode) + , m_cmdargs(cmdargs) +{ + m_walletManager = WalletManager::instance(); + connect(m_walletManager, &WalletManager::walletOpened, this, &CLI::onWalletOpened); -void CLI::run() { - if (mode == CLIMode::ExportContacts || mode == CLIMode::ExportTxHistory) + if (m_mode == Mode::ExportContacts || m_mode == Mode::ExportTxHistory) { - if(!ctx->cmdargs->isSet("wallet-file")) - return this->finishedError("--wallet-file argument missing"); - if(!ctx->cmdargs->isSet("password")) - return this->finishedError("--password argument missing"); - ctx->onOpenWallet(ctx->cmdargs->value("wallet-file"), ctx->cmdargs->value("password")); + if (!cmdargs->isSet("wallet-file")) { + this->finished("--wallet-file argument missing"); + return; + } + if (!cmdargs->isSet("password")) { + this->finished("--password argument missing"); + return; + } + + QString walletFile = cmdargs->value("wallet-file"); + QString password = cmdargs->value("password"); + + + m_walletManager->openWalletAsync(walletFile, password, constants::networkType); } - else if (mode == CLIMode::BruteforcePassword) + else if (mode == Mode::BruteforcePassword) { - QString keys_file = ctx->cmdargs->value("bruteforce-password"); + QString keys_file = m_cmdargs->value("bruteforce-password"); if (!keys_file.endsWith(".keys")) { - return this->finishedError("Wallet file does not end with .keys"); + this->finished("Wallet file does not end with .keys"); + return; } QStringList words; - if (ctx->cmdargs->isSet("bruteforce-dict")) { - QString data = Utils::barrayToString(Utils::fileOpen(ctx->cmdargs->value("bruteforce-dict"))); + if (m_cmdargs->isSet("bruteforce-dict")) { + QString data = Utils::barrayToString(Utils::fileOpen(m_cmdargs->value("bruteforce-dict"))); words = data.split("\n"); } - if (!ctx->cmdargs->isSet("bruteforce-chars")) { - return this->finishedError("--bruteforce-chars argument missing"); + if (!m_cmdargs->isSet("bruteforce-chars")) { + this->finished("--bruteforce-chars argument missing"); + return; } - QString chars = ctx->cmdargs->value("bruteforce-chars"); + QString chars = m_cmdargs->value("bruteforce-chars"); brute b(chars.toStdString()); if (words.isEmpty()) { qDebug() << "No dictionairy specified, bruteforcing all chars"; while (true) { QString pass = QString::fromStdString(b.next()); - if (ctx->walletManager->verifyWalletPassword(keys_file, pass, false)) { + if (m_walletManager->verifyWalletPassword(keys_file, pass, false)) { this->finished(QString("Found password: %1").arg(pass)); break; } @@ -60,7 +71,7 @@ void CLI::run() { else { bruteword bb(chars.toStdString()); bool foundPass = false; - for (auto word: words) { + for (const auto& word: words) { if (word.isEmpty()) { continue; } @@ -71,7 +82,7 @@ void CLI::run() { if (pass == "") { break; } - if (ctx->walletManager->verifyWalletPassword(keys_file, pass, false)) { + if (m_walletManager->verifyWalletPassword(keys_file, pass, false)) { this->finished(QString("Found password: %1").arg(pass)); foundPass = true; break; @@ -88,50 +99,39 @@ void CLI::run() { } } } -} - -void CLI::onWalletOpened() { - if(mode == CLIMode::ExportContacts){ - auto *model = ctx->currentWallet->addressBookModel(); - auto fn = ctx->cmdargs->value("export-contacts"); - if(model->writeCSV(fn)) - this->finished(QString("Address book exported to %1").arg(fn)); - else - this->finishedError("Address book export failure"); - } else if(mode == ExportTxHistory) { - ctx->currentWallet->history()->refresh(ctx->currentWallet->currentSubaddressAccount()); - auto *model = ctx->currentWallet->history(); - auto fn = ctx->cmdargs->value("export-txhistory"); - if(model->writeCSV(fn)) - this->finished(QString("Transaction history exported to %1").arg(fn)); - else - this->finishedError("Transaction history export failure"); + else { + this->finished("Invalid mode"); } } -void CLI::onWalletOpenedError(const QString &err) { - if(mode == CLIMode::ExportContacts || - mode == CLIMode::ExportTxHistory) - return this->finishedError(err); +void CLI::onWalletOpened(Wallet *w) { + QScopedPointer wallet{w}; + + if (wallet->status() != Wallet::Status_Ok) { + this->finished(wallet->errorString()); + return; + } + + if (m_mode == Mode::ExportContacts) { + auto *model = wallet->addressBookModel(); + QString fileName = m_cmdargs->value("export-contacts"); + if (model->writeCSV(fileName)) + this->finished(QString("Contacts exported to %1").arg(fileName)); + else + this->finished("Failed to export contacts"); + } + else if (m_mode == Mode::ExportTxHistory) { + wallet->history()->refresh(wallet->currentSubaddressAccount()); + auto *model = wallet->history(); + QString fileName = m_cmdargs->value("export-txhistory"); + if (model->writeCSV(fileName)) + this->finished(QString("Transaction history exported to %1").arg(fileName)); + else + this->finished("Failed to export transaction history"); + } } -void CLI::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) { - if(mode == CLIMode::ExportContacts || - mode == CLIMode::ExportTxHistory) - return this->finishedError("invalid password"); -} - -void CLI::finished(const QString &msg){ - qInfo() << msg; - emit closeApplication(); -} - -void CLI::finishedError(const QString &err) { - qCritical() << err; - emit closeApplication(); -} - -CLI::~CLI() { - ctx->disconnect(); - delete ctx; +void CLI::finished(const QString &message) { + qInfo() << message; + QApplication::quit(); } diff --git a/src/cli.h b/src/cli.h index 38271cdc..dc04a9ae 100644 --- a/src/cli.h +++ b/src/cli.h @@ -7,37 +7,28 @@ #include #include "appcontext.h" -enum CLIMode { - ExportContacts, - ExportTxHistory, - BruteforcePassword -}; - class CLI : public QObject { Q_OBJECT + public: - CLIMode mode; - explicit CLI(AppContext *ctx, QObject *parent = nullptr); - ~CLI() override; + enum Mode { + ExportContacts, + ExportTxHistory, + BruteforcePassword + }; -public slots: - void run(); - - //libwalletqt - void onWalletOpened(); - void onWalletOpenedError(const QString& err); - void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); - -private: - AppContext *ctx; + explicit CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent = nullptr); private slots: - void finished(const QString &msg); - void finishedError(const QString &err); + void onWalletOpened(Wallet *wallet); -signals: - void closeApplication(); +private: + void finished(const QString &message); + + Mode m_mode; + QCommandLineParser *m_cmdargs; + WalletManager *m_walletManager; }; #endif //FEATHER_CLI_H diff --git a/src/coinswidget.cpp b/src/coinswidget.cpp index 78d80a45..74a534b2 100644 --- a/src/coinswidget.cpp +++ b/src/coinswidget.cpp @@ -11,12 +11,12 @@ #include #include -CoinsWidget::CoinsWidget(AppContext *ctx, QWidget *parent) - : QWidget(parent) - , ui(new Ui::CoinsWidget) - , m_ctx(ctx) - , m_headerMenu(new QMenu(this)) - , m_copyMenu(new QMenu("Copy",this)) +CoinsWidget::CoinsWidget(QSharedPointer ctx, QWidget *parent) + : QWidget(parent) + , ui(new Ui::CoinsWidget) + , m_ctx(std::move(ctx)) + , m_headerMenu(new QMenu(this)) + , m_copyMenu(new QMenu("Copy",this)) { ui->setupUi(this); @@ -69,7 +69,7 @@ void CoinsWidget::setModel(CoinsModel * model, Coins * coins) { ui->coins->setColumnHidden(CoinsModel::SpentHeight, true); ui->coins->setColumnHidden(CoinsModel::Frozen, true); - if (!m_ctx->currentWallet->viewOnly()) { + if (!m_ctx->wallet->viewOnly()) { ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, true); } else { ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, false); @@ -233,17 +233,17 @@ CoinsInfo* CoinsWidget::currentEntry() { void CoinsWidget::freezeCoins(const QVector& indexes) { for (int i : indexes) { - m_ctx->currentWallet->coins()->freeze(i); + m_ctx->wallet->coins()->freeze(i); } - m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount()); m_ctx->updateBalance(); } void CoinsWidget::thawCoins(const QVector &indexes) { for (int i : indexes) { - m_ctx->currentWallet->coins()->thaw(i); + m_ctx->wallet->coins()->thaw(i); } - m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); + m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount()); m_ctx->updateBalance(); } diff --git a/src/coinswidget.h b/src/coinswidget.h index 38c17774..9939d4ce 100644 --- a/src/coinswidget.h +++ b/src/coinswidget.h @@ -22,7 +22,7 @@ class CoinsWidget : public QWidget Q_OBJECT public: - explicit CoinsWidget(AppContext *ctx, QWidget *parent = nullptr); + explicit CoinsWidget(QSharedPointer ctx, QWidget *parent = nullptr); void setModel(CoinsModel * model, Coins * coins); ~CoinsWidget() override; @@ -54,7 +54,7 @@ private: }; Ui::CoinsWidget *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; QMenu *m_contextMenu; QMenu *m_headerMenu; diff --git a/src/globals.h b/src/constants.h similarity index 67% rename from src/globals.h rename to src/constants.h index fd9b67e4..76c79e1a 100644 --- a/src/globals.h +++ b/src/constants.h @@ -1,24 +1,31 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. -#ifndef FEATHER_GLOBALS_H -#define FEATHER_GLOBALS_H +#ifndef FEATHER_CONSTANTS_H +#define FEATHER_CONSTANTS_H #include #include -namespace globals +#include "networktype.h" + +namespace constants { + // application constants + static NetworkType::Type networkType; // TODO: compiler moans, also not really a const + // coin constants const std::string coinName = "monero"; const qreal cdiv = 1e12; const quint32 mixin = 10; const quint64 kdfRounds = 1; + const QString seedLanguage = "English"; // todo: move me + // donation constants const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f"; const int donationAmount = 25; // euro - const int donationBoundary = 15; + const int donationBoundary = 25; // websocket constants const QUrl websocketUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws")); @@ -27,4 +34,4 @@ namespace globals const QString websiteUrl = "https://featherwallet.org"; } -#endif //FEATHER_GLOBALS_H +#endif //FEATHER_CONSTANTS_H diff --git a/src/contactswidget.cpp b/src/contactswidget.cpp index e7d9c014..f031c579 100644 --- a/src/contactswidget.cpp +++ b/src/contactswidget.cpp @@ -11,12 +11,23 @@ #include -ContactsWidget::ContactsWidget(QWidget *parent) +ContactsWidget::ContactsWidget(QSharedPointer ctx, QWidget *parent) : QWidget(parent) , ui(new Ui::ContactsWidget) + , m_ctx(std::move(ctx)) { ui->setupUi(this); + m_model = m_ctx->wallet->addressBookModel(); + m_proxyModel = new AddressBookProxyModel; + m_proxyModel->setSourceModel(m_model); + ui->contacts->setModel(m_proxyModel); + + ui->contacts->setSortingEnabled(true); + ui->contacts->header()->setSectionResizeMode(AddressBookModel::Address, QHeaderView::Stretch); + ui->contacts->header()->setSectionResizeMode(AddressBookModel::Description, QHeaderView::ResizeToContents); + ui->contacts->header()->setMinimumSectionSize(200); + // header context menu ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu); m_headerMenu = new QMenu(this); @@ -68,20 +79,6 @@ void ContactsWidget::payTo() { emit fillAddress(address); } -void ContactsWidget::setModel(AddressBookModel *model, Wallet *wallet) -{ - m_model = model; - m_wallet = wallet; - m_proxyModel = new AddressBookProxyModel; - m_proxyModel->setSourceModel(m_model); - ui->contacts->setModel(m_proxyModel); - - ui->contacts->setSortingEnabled(true); - ui->contacts->header()->setSectionResizeMode(AddressBookModel::Address, QHeaderView::Stretch); - ui->contacts->header()->setSectionResizeMode(AddressBookModel::Description, QHeaderView::ResizeToContents); - ui->contacts->header()->setMinimumSectionSize(200); -} - void ContactsWidget::setShowFullAddresses(bool show) { m_model->setShowFullAddresses(show); } @@ -104,11 +101,6 @@ void ContactsWidget::showHeaderMenu(const QPoint& position) void ContactsWidget::newContact(QString address, QString name) { - if (!m_wallet) { - QMessageBox::warning(this, "Error", "No wallet opened."); - return; - } - ContactsDialog dialog{this, address, name}; int ret = dialog.exec(); if (ret != QDialog::Accepted) { @@ -118,17 +110,17 @@ void ContactsWidget::newContact(QString address, QString name) address = dialog.getAddress(); name = dialog.getName(); - bool addressValid = WalletManager::addressValid(address, m_wallet->nettype()); + bool addressValid = WalletManager::addressValid(address, m_ctx->wallet->nettype()); if (!addressValid) { QMessageBox::warning(this, "Invalid address", "Invalid address"); return; } - int num_addresses = m_wallet->addressBook()->count(); + int num_addresses = m_ctx->wallet->addressBook()->count(); QString address_entry; QString name_entry; for (int i=0; iaddressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){ + m_ctx->wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){ address_entry = entry.address(); name_entry = entry.description(); }); @@ -145,7 +137,7 @@ void ContactsWidget::newContact(QString address, QString name) } } - m_wallet->addressBook()->addRow(address, "", name); + m_ctx->wallet->addressBook()->addRow(address, "", name); } void ContactsWidget::deleteContact() diff --git a/src/contactswidget.h b/src/contactswidget.h index cf9a3a5d..17395ff7 100644 --- a/src/contactswidget.h +++ b/src/contactswidget.h @@ -20,8 +20,7 @@ class ContactsWidget : public QWidget Q_OBJECT public: - explicit ContactsWidget(QWidget *parent = nullptr); - void setModel(AddressBookModel *model, Wallet *wallet); + explicit ContactsWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~ContactsWidget() override; public slots: @@ -42,6 +41,7 @@ private slots: private: Ui::ContactsWidget *ui; + QSharedPointer m_ctx; QAction *m_showFullAddressesAction; QMenu *m_rowMenu; @@ -49,7 +49,6 @@ private: QMenu *m_headerMenu; AddressBookModel * m_model; AddressBookProxyModel * m_proxyModel; - Wallet *m_wallet; }; #endif // CONTACTSWIDGET_H diff --git a/src/dialog/TxProofDialog.cpp b/src/dialog/TxProofDialog.cpp index 811ddbc9..ef7b3e0d 100644 --- a/src/dialog/TxProofDialog.cpp +++ b/src/dialog/TxProofDialog.cpp @@ -9,15 +9,15 @@ #include "libwalletqt/Transfer.h" #include "utils/utils.h" -TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txInfo) - : QDialog(parent) - , ui(new Ui::TxProofDialog) - , m_wallet(wallet) +TxProofDialog::TxProofDialog(QWidget *parent, QSharedPointer ctx, TransactionInfo *txInfo) + : QDialog(parent) + , ui(new Ui::TxProofDialog) + , m_ctx(std::move(ctx)) { ui->setupUi(this); m_txid = txInfo->hash(); - m_txKey = m_wallet->getTxKey(m_txid); + m_txKey = m_ctx->wallet->getTxKey(m_txid); m_direction = txInfo->direction(); for (auto const &t: txInfo->transfers()) { @@ -25,7 +25,7 @@ TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *t } for (auto const &s: txInfo->subaddrIndex()) { - m_InDestinations.push_back(wallet->address(txInfo->subaddrAccount(), s)); + m_InDestinations.push_back(m_ctx->wallet->address(txInfo->subaddrAccount(), s)); } // Due to some logic in core we can't create OutProofs @@ -127,7 +127,7 @@ void TxProofDialog::showWarning(const QString &message) { void TxProofDialog::getFormattedProof() { QString message = ui->message->toPlainText(); QString address = ui->combo_address->currentText(); - QString nettype = Utils::QtEnumToString(m_wallet->nettype()).toLower(); + QString nettype = Utils::QtEnumToString(m_ctx->wallet->nettype()).toLower(); nettype = nettype.replace(0, 1, nettype[0].toUpper()); // Capitalize first letter TxProof proof = this->getProof(); @@ -208,12 +208,12 @@ TxProof TxProofDialog::getProof() { TxProof proof = [this, message, address]{ switch (m_mode) { case Mode::SpendProof: { - return m_wallet->getSpendProof(m_txid, message); + return m_ctx->wallet->getSpendProof(m_txid, message); } case Mode::OutProof: case Mode::InProof: default: { // Todo: split this into separate functions - return m_wallet->getTxProof(m_txid, address, message); + return m_ctx->wallet->getTxProof(m_txid, address, message); } } }(); diff --git a/src/dialog/TxProofDialog.h b/src/dialog/TxProofDialog.h index 1ad53ce0..d0102480 100644 --- a/src/dialog/TxProofDialog.h +++ b/src/dialog/TxProofDialog.h @@ -6,8 +6,8 @@ #include -#include "libwalletqt/Wallet.h" #include "libwalletqt/TransactionInfo.h" +#include "appcontext.h" namespace Ui { class TxProofDialog; @@ -18,7 +18,7 @@ class TxProofDialog : public QDialog Q_OBJECT public: - explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txid); + explicit TxProofDialog(QWidget *parent, QSharedPointer ctx, TransactionInfo *txid); ~TxProofDialog() override; void setTxId(const QString &txid); @@ -50,7 +50,7 @@ private: TransactionInfo::Direction m_direction; Ui::TxProofDialog *ui; - Wallet *m_wallet; + QSharedPointer m_ctx; }; #endif //FEATHER_TXPROOFDIALOG_H diff --git a/src/dialog/WalletCacheDebugDialog.cpp b/src/dialog/WalletCacheDebugDialog.cpp index d02fbb6d..3f1d2d7c 100644 --- a/src/dialog/WalletCacheDebugDialog.cpp +++ b/src/dialog/WalletCacheDebugDialog.cpp @@ -7,81 +7,81 @@ #include -WalletCacheDebugDialog::WalletCacheDebugDialog(AppContext *ctx, QWidget *parent) +WalletCacheDebugDialog::WalletCacheDebugDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) , ui(new Ui::WalletCacheDebugDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); ui->output->setFont(ModelUtils::getMonospaceFont()); connect(ui->m_blockchain, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printBlockchain()); + this->setOutput(m_ctx->wallet->printBlockchain()); }); connect(ui->m_transfers, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printTransfers()); + this->setOutput(m_ctx->wallet->printTransfers()); }); connect(ui->m_unconfirmed_payments, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printUnconfirmedPayments()); + this->setOutput(m_ctx->wallet->printUnconfirmedPayments()); }); connect(ui->m_confirmed_txs, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printConfirmedTransferDetails()); + this->setOutput(m_ctx->wallet->printConfirmedTransferDetails()); }); connect(ui->m_unconfirmed_txs, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printUnconfirmedTransferDetails()); + this->setOutput(m_ctx->wallet->printUnconfirmedTransferDetails()); }); connect(ui->m_payments, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printPayments()); + this->setOutput(m_ctx->wallet->printPayments()); }); connect(ui->m_pub_keys, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printPubKeys()); + this->setOutput(m_ctx->wallet->printPubKeys()); }); connect(ui->m_tx_notes, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printTxNotes()); + this->setOutput(m_ctx->wallet->printTxNotes()); }); connect(ui->m_subaddresses, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printSubaddresses()); + this->setOutput(m_ctx->wallet->printSubaddresses()); }); connect(ui->m_subaddress_labels, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printSubaddressLabels()); + this->setOutput(m_ctx->wallet->printSubaddressLabels()); }); connect(ui->m_additional_tx_keys, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printAdditionalTxKeys()); + this->setOutput(m_ctx->wallet->printAdditionalTxKeys()); }); connect(ui->m_attributes, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printAttributes()); + this->setOutput(m_ctx->wallet->printAttributes()); }); connect(ui->m_key_images, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printKeyImages()); + this->setOutput(m_ctx->wallet->printKeyImages()); }); connect(ui->m_account_tags, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printAccountTags()); + this->setOutput(m_ctx->wallet->printAccountTags()); }); connect(ui->m_tx_keys, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printTxKeys()); + this->setOutput(m_ctx->wallet->printTxKeys()); }); connect(ui->m_address_book, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printAddressBook()); + this->setOutput(m_ctx->wallet->printAddressBook()); }); connect(ui->m_scanned_pool_txs, &QRadioButton::pressed, [this]{ - this->setOutput(m_ctx->currentWallet->printScannedPoolTxs()); + this->setOutput(m_ctx->wallet->printScannedPoolTxs()); }); this->adjustSize(); diff --git a/src/dialog/WalletCacheDebugDialog.h b/src/dialog/WalletCacheDebugDialog.h index 54a5f67b..e2ba3c72 100644 --- a/src/dialog/WalletCacheDebugDialog.h +++ b/src/dialog/WalletCacheDebugDialog.h @@ -16,13 +16,13 @@ class WalletCacheDebugDialog : public QDialog Q_OBJECT public: - explicit WalletCacheDebugDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit WalletCacheDebugDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~WalletCacheDebugDialog() override; private: void setOutput(const QString &output); Ui::WalletCacheDebugDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; }; diff --git a/src/dialog/broadcasttxdialog.cpp b/src/dialog/broadcasttxdialog.cpp index 3bb1173e..7ab90d1f 100644 --- a/src/dialog/broadcasttxdialog.cpp +++ b/src/dialog/broadcasttxdialog.cpp @@ -7,10 +7,10 @@ #include -BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex) +BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, QSharedPointer ctx, const QString &transactionHex) : QDialog(parent) , ui(new Ui::BroadcastTxDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); diff --git a/src/dialog/broadcasttxdialog.h b/src/dialog/broadcasttxdialog.h index a9a5e340..0f32c7df 100644 --- a/src/dialog/broadcasttxdialog.h +++ b/src/dialog/broadcasttxdialog.h @@ -17,7 +17,7 @@ class BroadcastTxDialog : public QDialog Q_OBJECT public: - explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex = ""); + explicit BroadcastTxDialog(QWidget *parent, QSharedPointer ctx, const QString &transactionHex = ""); ~BroadcastTxDialog() override; private slots: @@ -26,7 +26,7 @@ private slots: private: Ui::BroadcastTxDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; UtilsNetworking *m_network; DaemonRpc *m_rpc; }; diff --git a/src/dialog/debuginfodialog.cpp b/src/dialog/debuginfodialog.cpp index 28544df1..7fcab2ef 100644 --- a/src/dialog/debuginfodialog.cpp +++ b/src/dialog/debuginfodialog.cpp @@ -7,11 +7,12 @@ #include "utils/WebsocketClient.h" #include "utils/TorManager.h" #include "utils/WebsocketNotifier.h" +#include "utils/tails.h" -DebugInfoDialog::DebugInfoDialog(AppContext *ctx, QWidget *parent) +DebugInfoDialog::DebugInfoDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) , ui(new Ui::DebugInfoDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); @@ -28,7 +29,7 @@ void DebugInfoDialog::updateInfo() { QString torStatus; // Special case for Tails because we know the status of the daemon by polling tails-tor-has-bootstrapped.target - if(m_ctx->isTails) { + if (TailsOS::detect()) { if(torManager()->torConnected) torStatus = "Connected"; else @@ -46,32 +47,32 @@ void DebugInfoDialog::updateInfo() { ui->label_featherVersion->setText(QString("%1-%2").arg(FEATHER_VERSION, FEATHER_BRANCH)); ui->label_moneroVersion->setText(QString("%1-%2").arg(MONERO_VERSION, MONERO_BRANCH)); - ui->label_walletHeight->setText(QString::number(m_ctx->currentWallet->blockChainHeight())); - ui->label_daemonHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainHeight())); - ui->label_targetHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainTargetHeight())); - ui->label_restoreHeight->setText(QString::number(m_ctx->currentWallet->getWalletCreationHeight())); - ui->label_synchronized->setText(m_ctx->currentWallet->isSynchronized() ? "True" : "False"); + ui->label_walletHeight->setText(QString::number(m_ctx->wallet->blockChainHeight())); + ui->label_daemonHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainHeight())); + ui->label_targetHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainTargetHeight())); + ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight())); + ui->label_synchronized->setText(m_ctx->wallet->isSynchronized() ? "True" : "False"); auto node = m_ctx->nodes->connection(); ui->label_remoteNode->setText(node.toAddress()); - ui->label_walletStatus->setText(this->statusToString(m_ctx->currentWallet->connectionStatus())); + ui->label_walletStatus->setText(this->statusToString(m_ctx->wallet->connectionStatus())); ui->label_torStatus->setText(torStatus); ui->label_websocketStatus->setText(Utils::QtEnumToString(websocketNotifier()->websocketClient.webSocket.state()).remove("State")); QString seedType = [this](){ - if (m_ctx->currentWallet->isHwBacked()) + if (m_ctx->wallet->isHwBacked()) return "Hardware"; - if (m_ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty()) + if (m_ctx->wallet->getCacheAttribute("feather.seed").isEmpty()) return "25 word"; else return "14 word"; }(); QString deviceType = [this](){ - if (m_ctx->currentWallet->isHwBacked()) { - if (m_ctx->currentWallet->isLedger()) + if (m_ctx->wallet->isHwBacked()) { + if (m_ctx->wallet->isLedger()) return "Ledger"; - else if (m_ctx->currentWallet->isTrezor()) + else if (m_ctx->wallet->isTrezor()) return "Trezor"; else return "Unknown"; @@ -81,17 +82,17 @@ void DebugInfoDialog::updateInfo() { } }(); - ui->label_netType->setText(Utils::QtEnumToString(m_ctx->currentWallet->nettype())); + ui->label_netType->setText(Utils::QtEnumToString(m_ctx->wallet->nettype())); ui->label_seedType->setText(seedType); ui->label_deviceType->setText(deviceType); - ui->label_viewOnly->setText(m_ctx->currentWallet->viewOnly() ? "True" : "False"); - ui->label_primaryOnly->setText(m_ctx->currentWallet->balance(0) == m_ctx->currentWallet->balanceAll() ? "True" : "False"); + ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False"); + ui->label_primaryOnly->setText(m_ctx->wallet->balance(0) == m_ctx->wallet->balanceAll() ? "True" : "False"); QString os = QSysInfo::prettyProductName(); - if (m_ctx->isTails) { + if (TailsOS::detect()) { os = QString("Tails %1").arg(TailsOS::version()); } - if (m_ctx->isWhonix) { + if (WhonixOS::detect()) { os = QString("Whonix %1").arg(WhonixOS::version()); } ui->label_OS->setText(os); diff --git a/src/dialog/debuginfodialog.h b/src/dialog/debuginfodialog.h index 44c1c5ed..80a53918 100644 --- a/src/dialog/debuginfodialog.h +++ b/src/dialog/debuginfodialog.h @@ -17,7 +17,7 @@ class DebugInfoDialog : public QDialog Q_OBJECT public: - explicit DebugInfoDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit DebugInfoDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~DebugInfoDialog() override; private: @@ -26,7 +26,7 @@ private: void updateInfo(); Ui::DebugInfoDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; QTimer m_updateTimer; }; diff --git a/src/dialog/keysdialog.cpp b/src/dialog/keysdialog.cpp index 73533495..56184814 100644 --- a/src/dialog/keysdialog.cpp +++ b/src/dialog/keysdialog.cpp @@ -4,21 +4,20 @@ #include "keysdialog.h" #include "ui_keysdialog.h" -KeysDialog::KeysDialog(AppContext *ctx, QWidget *parent) - : QDialog(parent) - , ui(new Ui::KeysDialog) +KeysDialog::KeysDialog(QSharedPointer ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::KeysDialog) { ui->setupUi(this); - auto w = ctx->currentWallet; QString unavailable = "Unavailable: Key is stored on hardware device"; - ui->label_restoreHeight->setText(QString::number(w->getWalletCreationHeight())); - ui->label_primaryAddress->setText(w->address(0, 0)); - ui->label_secretSpendKey->setText(w->isHwBacked() ? unavailable : w->getSecretSpendKey()); - ui->label_secretViewKey->setText(w->getSecretViewKey()); - ui->label_publicSpendKey->setText(w->getPublicSpendKey()); - ui->label_publicViewKey->setText(w->getPublicViewKey()); + ui->label_restoreHeight->setText(QString::number(ctx->wallet->getWalletCreationHeight())); + ui->label_primaryAddress->setText(ctx->wallet->address(0, 0)); + ui->label_secretSpendKey->setText(ctx->wallet->isHwBacked() ? unavailable : ctx->wallet->getSecretSpendKey()); + ui->label_secretViewKey->setText(ctx->wallet->getSecretViewKey()); + ui->label_publicSpendKey->setText(ctx->wallet->getPublicSpendKey()); + ui->label_publicViewKey->setText(ctx->wallet->getPublicViewKey()); this->adjustSize(); } diff --git a/src/dialog/keysdialog.h b/src/dialog/keysdialog.h index e0fe0c0e..84df75d5 100644 --- a/src/dialog/keysdialog.h +++ b/src/dialog/keysdialog.h @@ -16,7 +16,7 @@ class KeysDialog : public QDialog Q_OBJECT public: - explicit KeysDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit KeysDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~KeysDialog() override; private: diff --git a/src/dialog/passworddialog.cpp b/src/dialog/passworddialog.cpp index 7f7d0f73..a576929e 100644 --- a/src/dialog/passworddialog.cpp +++ b/src/dialog/passworddialog.cpp @@ -4,7 +4,7 @@ #include "passworddialog.h" #include "ui_passworddialog.h" -PasswordDialog::PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword) +PasswordDialog::PasswordDialog(const QString &walletName, bool incorrectPassword, QWidget *parent) : QDialog(parent) , ui(new Ui::PasswordDialog) { diff --git a/src/dialog/passworddialog.h b/src/dialog/passworddialog.h index 060de72a..a204cea1 100644 --- a/src/dialog/passworddialog.h +++ b/src/dialog/passworddialog.h @@ -15,7 +15,7 @@ class PasswordDialog : public QDialog Q_OBJECT public: - explicit PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword); + explicit PasswordDialog(const QString &walletName, bool incorrectPassword, QWidget *parent = nullptr); ~PasswordDialog() override; QString password = ""; diff --git a/src/dialog/restoredialog.cpp b/src/dialog/restoredialog.cpp index 49edce02..fa9679a4 100644 --- a/src/dialog/restoredialog.cpp +++ b/src/dialog/restoredialog.cpp @@ -4,21 +4,23 @@ #include "restoredialog.h" #include "ui_restoredialog.h" -RestoreDialog::RestoreDialog(AppContext *ctx, QWidget *parent) +#include "constants.h" + +RestoreDialog::RestoreDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) , ui(new Ui::RestoreDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RestoreDialog::accepted); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RestoreDialog::rejected); - if(m_ctx->networkType == NetworkType::Type::TESTNET) { + if(constants::networkType == NetworkType::Type::TESTNET) { ui->restoreHeightWidget->hideSlider(); } else { // load restoreHeight lookup db - ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[m_ctx->networkType]); + ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[constants::networkType]); } } diff --git a/src/dialog/restoredialog.h b/src/dialog/restoredialog.h index d7f119dd..e6118c81 100644 --- a/src/dialog/restoredialog.h +++ b/src/dialog/restoredialog.h @@ -22,7 +22,7 @@ class RestoreDialog : public QDialog Q_OBJECT public: - explicit RestoreDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit RestoreDialog(QSharedPointer ctx, QWidget *parent = nullptr); void initRestoreHeights(RestoreHeightLookup *lookup); int getHeight(); ~RestoreDialog() override; @@ -33,7 +33,7 @@ signals: private: Ui::RestoreDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; }; #endif // RESTOREDIALOG_H diff --git a/src/dialog/seeddialog.cpp b/src/dialog/seeddialog.cpp index 63f46a26..123dcaee 100644 --- a/src/dialog/seeddialog.cpp +++ b/src/dialog/seeddialog.cpp @@ -4,18 +4,19 @@ #include "ui_seeddialog.h" #include "seeddialog.h" -SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent) - : QDialog(parent) - , ui(new Ui::SeedDialog) +SeedDialog::SeedDialog(QSharedPointer ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::SeedDialog) + , m_ctx(std::move(ctx)) { ui->setupUi(this); ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation)); - ui->label_restoreHeight->setText(QString::number(wallet->getWalletCreationHeight())); + ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight())); - QString seedOffset = wallet->getCacheAttribute("feather.seedoffset"); - QString seed_14_words = wallet->getCacheAttribute("feather.seed"); - QString seed_25_words = wallet->getSeed(seedOffset); + QString seedOffset = m_ctx->wallet->getCacheAttribute("feather.seedoffset"); + QString seed_14_words = m_ctx->wallet->getCacheAttribute("feather.seed"); + QString seed_25_words = m_ctx->wallet->getSeed(seedOffset); if (seed_14_words.isEmpty()) { ui->check_toggleSeedType->hide(); diff --git a/src/dialog/seeddialog.h b/src/dialog/seeddialog.h index 52793e46..b1e211b3 100644 --- a/src/dialog/seeddialog.h +++ b/src/dialog/seeddialog.h @@ -5,7 +5,7 @@ #define FEATHER_SEEDDIALOG_H #include -#include "libwalletqt/Wallet.h" +#include "appcontext.h" namespace Ui { class SeedDialog; @@ -16,13 +16,14 @@ class SeedDialog : public QDialog Q_OBJECT public: - explicit SeedDialog(Wallet *wallet, QWidget *parent = nullptr); + explicit SeedDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~SeedDialog() override; private: void setSeed(const QString &seed); Ui::SeedDialog *ui; + QSharedPointer m_ctx; }; diff --git a/src/dialog/splashdialog.cpp b/src/dialog/splashdialog.cpp index ded389f3..06b2481e 100644 --- a/src/dialog/splashdialog.cpp +++ b/src/dialog/splashdialog.cpp @@ -3,6 +3,7 @@ #include "splashdialog.h" #include "ui_splashdialog.h" +#include "utils/Icons.h" SplashDialog::SplashDialog(QWidget *parent) : QDialog(parent) @@ -10,6 +11,8 @@ SplashDialog::SplashDialog(QWidget *parent) { ui->setupUi(this); + this->setWindowIcon(icons()->icon("appicon/64x64")); + QPixmap pixmap = QPixmap(":/assets/images/key.png"); ui->icon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation)); diff --git a/src/dialog/torinfodialog.cpp b/src/dialog/torinfodialog.cpp index 48528765..0c9ab787 100644 --- a/src/dialog/torinfodialog.cpp +++ b/src/dialog/torinfodialog.cpp @@ -9,11 +9,12 @@ #include #include "utils/TorManager.h" +#include "utils/tails.h" -TorInfoDialog::TorInfoDialog(QWidget *parent, AppContext *ctx) +TorInfoDialog::TorInfoDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) , ui(new Ui::TorInfoDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); diff --git a/src/dialog/torinfodialog.h b/src/dialog/torinfodialog.h index 60b5b864..1ca07448 100644 --- a/src/dialog/torinfodialog.h +++ b/src/dialog/torinfodialog.h @@ -18,7 +18,7 @@ class TorInfoDialog : public QDialog Q_OBJECT public: - explicit TorInfoDialog(QWidget *parent, AppContext *ctx); + explicit TorInfoDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~TorInfoDialog() override; public slots: @@ -38,7 +38,7 @@ private: void initPrivacyLevel(); Ui::TorInfoDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; }; diff --git a/src/dialog/transactioninfodialog.cpp b/src/dialog/transactioninfodialog.cpp index 048b3fbf..433acd16 100644 --- a/src/dialog/transactioninfodialog.cpp +++ b/src/dialog/transactioninfodialog.cpp @@ -17,18 +17,18 @@ #include #include -TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent) - : QDialog(parent) - , ui(new Ui::TransactionInfoDialog) - , m_wallet(wallet) - , m_txInfo(txInfo) +TransactionInfoDialog::TransactionInfoDialog(QSharedPointer ctx, TransactionInfo *txInfo, QWidget *parent) + : QDialog(parent) + , ui(new Ui::TransactionInfoDialog) + , m_ctx(std::move(ctx)) + , m_txInfo(txInfo) { ui->setupUi(this); m_txid = txInfo->hash(); ui->label_txid->setText(m_txid); - m_txKey = m_wallet->getTxKey(txInfo->hash()); + m_txKey = m_ctx->wallet->getTxKey(txInfo->hash()); if (m_txKey.isEmpty()) { ui->btn_CopyTxKey->setEnabled(false); ui->btn_CopyTxKey->setToolTip("Transaction key unknown"); @@ -37,11 +37,11 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey); connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof); - connect(m_wallet, &Wallet::newBlock, this, &TransactionInfoDialog::updateData); + connect(m_ctx->wallet.get(), &Wallet::newBlock, this, &TransactionInfoDialog::updateData); this->setData(txInfo); - if (AppContext::txCache.contains(txInfo->hash()) && (txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) { + if (m_ctx->txCache.contains(txInfo->hash()) && (txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) { connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{ emit resendTranscation(m_txid); }); @@ -53,7 +53,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx for (const auto& transfer : txInfo->transfers()) { auto address = transfer->address(); auto amount = WalletManager::displayAmount(transfer->amount()); - auto index = m_wallet->subaddressIndex(address); + auto index = m_ctx->wallet->subaddressIndex(address); cursor.insertText(address, Utils::addressTextFormat(index)); cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertBlock(); @@ -63,7 +63,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx ui->frameDestinations->hide(); } - m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo); + m_txProofDialog = new TxProofDialog(this, m_ctx, txInfo); QCoreApplication::processEvents(); @@ -121,8 +121,7 @@ void TransactionInfoDialog::setData(TransactionInfo* tx) { } void TransactionInfoDialog::updateData() { - if (!m_wallet) return; - TransactionInfo* tx = m_wallet->history()->transaction(m_txid); + TransactionInfo* tx = m_ctx->wallet->history()->transaction(m_txid); if (!tx) return; this->setData(tx); } diff --git a/src/dialog/transactioninfodialog.h b/src/dialog/transactioninfodialog.h index 575a1815..6cb2960d 100644 --- a/src/dialog/transactioninfodialog.h +++ b/src/dialog/transactioninfodialog.h @@ -7,9 +7,7 @@ #include #include #include -#include "libwalletqt/Coins.h" -#include "libwalletqt/TransactionInfo.h" -#include "libwalletqt/Wallet.h" +#include "appcontext.h" #include "dialog/TxProofDialog.h" namespace Ui { @@ -21,7 +19,7 @@ class TransactionInfoDialog : public QDialog Q_OBJECT public: - explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr); + explicit TransactionInfoDialog(QSharedPointer ctx, TransactionInfo *txInfo, QWidget *parent = nullptr); ~TransactionInfoDialog() override; signals: @@ -35,7 +33,7 @@ private: Ui::TransactionInfoDialog *ui; - Wallet *m_wallet; + QSharedPointer m_ctx; TransactionInfo *m_txInfo; TxProofDialog *m_txProofDialog; QString m_txKey; diff --git a/src/dialog/txconfadvdialog.cpp b/src/dialog/txconfadvdialog.cpp index 98fbc8d6..2f27c557 100644 --- a/src/dialog/txconfadvdialog.cpp +++ b/src/dialog/txconfadvdialog.cpp @@ -12,12 +12,12 @@ #include #include -TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent) - : QDialog(parent) - , ui(new Ui::TxConfAdvDialog) - , m_ctx(ctx) - , m_exportUnsignedMenu(new QMenu(this)) - , m_exportSignedMenu(new QMenu(this)) +TxConfAdvDialog::TxConfAdvDialog(QSharedPointer ctx, const QString &description, QWidget *parent) + : QDialog(parent) + , ui(new Ui::TxConfAdvDialog) + , m_ctx(std::move(ctx)) + , m_exportUnsignedMenu(new QMenu(this)) + , m_exportSignedMenu(new QMenu(this)) { ui->setupUi(this); @@ -30,7 +30,7 @@ TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QW m_exportSignedMenu->addAction("Save to file", this, &TxConfAdvDialog::signedSaveFile); ui->btn_exportSigned->setMenu(m_exportSignedMenu); - if (m_ctx->currentWallet->viewOnly()) { + if (m_ctx->wallet->viewOnly()) { ui->btn_exportSigned->hide(); ui->btn_send->hide(); } @@ -61,7 +61,7 @@ void TxConfAdvDialog::setTransaction(PendingTransaction *tx) { ui->total->setText(WalletManager::displayAmount(tx->amount() + ptx->fee())); auto size_str = [this]{ - if (m_ctx->currentWallet->viewOnly()) { + if (m_ctx->wallet->viewOnly()) { return QString("Size: %1 bytes (unsigned)").arg(QString::number(m_tx->unsignedTxToBin().size())); } else { auto size = m_tx->signedTxToHex(0).size() / 2; @@ -108,7 +108,7 @@ void TxConfAdvDialog::setupConstructionData(ConstructionInfo *ci) { for (const auto& o: outputs) { auto address = o->address(); auto amount = WalletManager::displayAmount(o->amount()); - auto index = m_ctx->currentWallet->subaddressIndex(address); + auto index = m_ctx->wallet->subaddressIndex(address); cursor.insertText(address, Utils::addressTextFormat(index)); cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertBlock(); @@ -177,9 +177,9 @@ void TxConfAdvDialog::broadcastTransaction() { void TxConfAdvDialog::closeDialog() { if (m_tx != nullptr) - m_ctx->currentWallet->disposeTransaction(m_tx); + m_ctx->wallet->disposeTransaction(m_tx); if (m_utx != nullptr) - m_ctx->currentWallet->disposeTransaction(m_utx); + m_ctx->wallet->disposeTransaction(m_utx); QDialog::reject(); } diff --git a/src/dialog/txconfadvdialog.h b/src/dialog/txconfadvdialog.h index bd687972..e59a7666 100644 --- a/src/dialog/txconfadvdialog.h +++ b/src/dialog/txconfadvdialog.h @@ -22,7 +22,7 @@ class TxConfAdvDialog : public QDialog Q_OBJECT public: - explicit TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent = nullptr); + explicit TxConfAdvDialog(QSharedPointer ctx, const QString &description, QWidget *parent = nullptr); ~TxConfAdvDialog() override; void setTransaction(PendingTransaction *tx); @@ -43,7 +43,7 @@ private: void signedSaveFile(); Ui::TxConfAdvDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; PendingTransaction *m_tx = nullptr; UnsignedTransaction *m_utx = nullptr; QMenu *m_exportUnsignedMenu; diff --git a/src/dialog/txconfdialog.cpp b/src/dialog/txconfdialog.cpp index 47d959a2..dbf9f236 100644 --- a/src/dialog/txconfdialog.cpp +++ b/src/dialog/txconfdialog.cpp @@ -5,16 +5,16 @@ #include "ui_txconfdialog.h" #include "model/ModelUtils.h" #include "txconfadvdialog.h" -#include "globals.h" +#include "constants.h" #include "utils/AppData.h" #include "utils/ColorScheme.h" #include -TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent) +TxConfDialog::TxConfDialog(QSharedPointer ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent) : QDialog(parent) , ui(new Ui::TxConfDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) , m_tx(tx) , m_address(address) , m_description(description) @@ -37,9 +37,9 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin int maxLength = Utils::maxLength(amounts); std::for_each(amounts.begin(), amounts.end(), [maxLength](QString& amount){amount = amount.rightJustified(maxLength, ' ');}); - QString amount_fiat = convert(tx->amount() / globals::cdiv); - QString fee_fiat = convert(tx->fee() / globals::cdiv); - QString total_fiat = convert((tx->amount() + tx->fee()) / globals::cdiv); + QString amount_fiat = convert(tx->amount() / constants::cdiv); + QString fee_fiat = convert(tx->fee() / constants::cdiv); + QString total_fiat = convert((tx->amount() + tx->fee()) / constants::cdiv); QVector amounts_fiat = {amount_fiat, fee_fiat, total_fiat}; int maxLengthFiat = Utils::maxLength(amounts_fiat); std::for_each(amounts_fiat.begin(), amounts_fiat.end(), [maxLengthFiat](QString& amount){amount = amount.rightJustified(maxLengthFiat, ' ');}); @@ -52,7 +52,7 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin ui->label_fee->setText(QString("%1 (%2 %3)").arg(amounts[1], amounts_fiat[1], preferredCur)); ui->label_total->setText(QString("%1 (%2 %3)").arg(amounts[2], amounts_fiat[2], preferredCur)); - auto subaddressIndex = m_ctx->currentWallet->subaddressIndex(address); + auto subaddressIndex = m_ctx->wallet->subaddressIndex(address); QString addressExtra; ui->label_address->setText(ModelUtils::displayAddress(address, 2)); @@ -76,7 +76,7 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced); - AppContext::txCache[tx->txid()[0]] = tx->signedTxToHex(0); + m_ctx->txCache[tx->txid()[0]] = tx->signedTxToHex(0); this->adjustSize(); } diff --git a/src/dialog/txconfdialog.h b/src/dialog/txconfdialog.h index 0fdd95a1..1057df88 100644 --- a/src/dialog/txconfdialog.h +++ b/src/dialog/txconfdialog.h @@ -18,7 +18,7 @@ class TxConfDialog : public QDialog Q_OBJECT public: - explicit TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr); + explicit TxConfDialog(QSharedPointer ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr); ~TxConfDialog() override; bool showAdvanced = false; @@ -27,7 +27,7 @@ private: void setShowAdvanced(); Ui::TxConfDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; PendingTransaction *m_tx; QString m_address; QString m_description; diff --git a/src/dialog/tximportdialog.cpp b/src/dialog/tximportdialog.cpp index 6cffd96f..f3843b86 100644 --- a/src/dialog/tximportdialog.cpp +++ b/src/dialog/tximportdialog.cpp @@ -7,10 +7,10 @@ #include -TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx) +TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer ctx) : QDialog(parent) , ui(new Ui::TxImportDialog) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) , m_loadTimer(new QTimer(this)) { ui->setupUi(this); @@ -88,7 +88,7 @@ void TxImportDialog::onImport() { bool pool = tx.value("in_pool").toBool(); bool double_spend_seen = tx.value("double_spend_seen").toBool(); - if (m_ctx->currentWallet->importTransaction(tx.value("tx_hash").toString(), output_indices, height, timestamp, false, pool, double_spend_seen)) { + if (m_ctx->wallet->importTransaction(tx.value("tx_hash").toString(), output_indices, height, timestamp, false, pool, double_spend_seen)) { QMessageBox::information(this, "Import transaction", "Transaction imported successfully."); } else { QMessageBox::warning(this, "Import transaction", "Transaction import failed."); diff --git a/src/dialog/tximportdialog.h b/src/dialog/tximportdialog.h index 4fdcb702..6b6992c9 100644 --- a/src/dialog/tximportdialog.h +++ b/src/dialog/tximportdialog.h @@ -17,7 +17,7 @@ class TxImportDialog : public QDialog Q_OBJECT public: - explicit TxImportDialog(QWidget *parent, AppContext *ctx); + explicit TxImportDialog(QWidget *parent, QSharedPointer ctx); ~TxImportDialog() override; private slots: @@ -27,7 +27,7 @@ private slots: private: Ui::TxImportDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; UtilsNetworking *m_network; DaemonRpc *m_rpc; diff --git a/src/dialog/viewonlydialog.cpp b/src/dialog/viewonlydialog.cpp index 3a551ff0..8aead695 100644 --- a/src/dialog/viewonlydialog.cpp +++ b/src/dialog/viewonlydialog.cpp @@ -8,20 +8,21 @@ #include "viewonlydialog.h" #include "ui_viewonlydialog.h" -ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent) - : QDialog(parent) - , ui(new Ui::ViewOnlyDialog), m_ctx(ctx) +ViewOnlyDialog::ViewOnlyDialog(QSharedPointer ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::ViewOnlyDialog) + , m_ctx(std::move(ctx)) { ui->setupUi(this); - ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight())); - ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0)); - ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey()); + ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight())); + ui->label_primaryAddress->setText(m_ctx->wallet->address(0, 0)); + ui->label_secretViewKey->setText(m_ctx->wallet->getSecretViewKey()); connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad); connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet); - ui->btn_Save->setEnabled(!m_ctx->currentWallet->viewOnly()); + ui->btn_Save->setEnabled(!m_ctx->wallet->viewOnly()); this->adjustSize(); } @@ -40,7 +41,7 @@ void ViewOnlyDialog::onWriteViewOnlyWallet(){ if((bool)passwordDialog.exec()) passwd = passwordDialog.textValue(); - m_ctx->currentWallet->createViewOnly(fn, passwd); + m_ctx->wallet->createViewOnly(fn, passwd); QMessageBox::information(this, "Information", "View-only wallet successfully written to disk."); } diff --git a/src/dialog/viewonlydialog.h b/src/dialog/viewonlydialog.h index ccc9c2e2..50caa387 100644 --- a/src/dialog/viewonlydialog.h +++ b/src/dialog/viewonlydialog.h @@ -16,7 +16,7 @@ class ViewOnlyDialog : public QDialog Q_OBJECT public: - explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit ViewOnlyDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~ViewOnlyDialog() override; private slots: @@ -24,7 +24,7 @@ private slots: private: Ui::ViewOnlyDialog *ui; - AppContext *m_ctx = nullptr; + QSharedPointer m_ctx; void copyToClipboad(); }; diff --git a/src/dialog/walletinfodialog.cpp b/src/dialog/walletinfodialog.cpp index 991cce7a..57ae5c46 100644 --- a/src/dialog/walletinfodialog.cpp +++ b/src/dialog/walletinfodialog.cpp @@ -6,21 +6,20 @@ #include -WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent) - : QDialog(parent) - , ui(new Ui::WalletInfoDialog) - , m_ctx(ctx) +WalletInfoDialog::WalletInfoDialog(QSharedPointer ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::WalletInfoDialog) + , m_ctx(std::move(ctx)) { ui->setupUi(this); - QFileInfo keys(ctx->walletPath); - QFileInfo cache(ctx->currentWallet->path()); + QFileInfo cache(m_ctx->wallet->cachePath()); - ui->label_walletName->setText(keys.fileName().replace(".keys", "")); - ui->label_netType->setText(Utils::QtEnumToString(ctx->currentWallet->nettype())); - ui->label_seedType->setText(ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word"); - ui->label_viewOnly->setText(ctx->currentWallet->viewOnly() ? "True" : "False"); - ui->label_path->setText(ctx->walletPath); + ui->label_walletName->setText(QFileInfo(m_ctx->wallet->cachePath()).fileName()); + ui->label_netType->setText(Utils::QtEnumToString(m_ctx->wallet->nettype())); + ui->label_seedType->setText(m_ctx->wallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word"); + ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False"); + ui->label_path->setText(m_ctx->wallet->keysPath()); ui->label_cacheSize->setText(QString("%1 MB").arg(QString::number(cache.size() / 1e6, 'f', 2))); connect(ui->btn_openWalletDir, &QPushButton::clicked, this, &WalletInfoDialog::openWalletDir); @@ -28,12 +27,12 @@ WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent) this->adjustSize(); } -void WalletInfoDialog::openWalletDir() { - QFileInfo file(m_ctx->walletPath); - - QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode)); -} - WalletInfoDialog::~WalletInfoDialog() { delete ui; } + +void WalletInfoDialog::openWalletDir() { + QFileInfo file(m_ctx->wallet->keysPath()); + + QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode)); +} \ No newline at end of file diff --git a/src/dialog/walletinfodialog.h b/src/dialog/walletinfodialog.h index 9697475b..37647323 100644 --- a/src/dialog/walletinfodialog.h +++ b/src/dialog/walletinfodialog.h @@ -17,14 +17,14 @@ class WalletInfoDialog : public QDialog Q_OBJECT public: - explicit WalletInfoDialog(AppContext *ctx, QWidget *parent = nullptr); + explicit WalletInfoDialog(QSharedPointer ctx, QWidget *parent = nullptr); ~WalletInfoDialog() override; private: void openWalletDir(); Ui::WalletInfoDialog *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; }; #endif //FEATHER_WALLETINFODIALOG_H diff --git a/src/historywidget.cpp b/src/historywidget.cpp index c74f8bbc..22416824 100644 --- a/src/historywidget.cpp +++ b/src/historywidget.cpp @@ -11,11 +11,13 @@ #include -HistoryWidget::HistoryWidget(QWidget *parent) - : QWidget(parent) - , ui(new Ui::HistoryWidget) - , m_contextMenu(new QMenu(this)) - , m_copyMenu(new QMenu("Copy", this)) +HistoryWidget::HistoryWidget(QSharedPointer ctx, QWidget *parent) + : QWidget(parent) + , ui(new Ui::HistoryWidget) + , m_ctx(std::move(ctx)) + , m_contextMenu(new QMenu(this)) + , m_copyMenu(new QMenu("Copy", this)) + , m_model(m_ctx->wallet->historyModel()) { ui->setupUi(this); m_contextMenu->addMenu(m_copyMenu); @@ -45,6 +47,18 @@ HistoryWidget::HistoryWidget(QWidget *parent) config()->set(Config::showHistorySyncNotice, false); ui->syncNotice->hide(); }); + + connect(m_ctx.get(), &AppContext::walletRefreshed, this, &HistoryWidget::onWalletRefreshed); + + ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool()); + ui->history->setHistoryModel(m_model); + m_ctx->wallet->transactionHistoryModel()->amountPrecision = config()->get(Config::amountPrecision).toInt(); + + // Load view state + QByteArray historyViewState = QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray()); + if (!historyViewState.isEmpty()) { + ui->history->setViewState(historyViewState); + } } void HistoryWidget::showContextMenu(const QPoint &point) { @@ -59,7 +73,7 @@ void HistoryWidget::showContextMenu(const QPoint &point) { if (!tx) return; bool unconfirmed = tx->isFailed() || tx->isPending(); - if (AppContext::txCache.contains(tx->hash()) && unconfirmed && tx->direction() != TransactionInfo::Direction_In) { + if (m_ctx->txCache.contains(tx->hash()) && unconfirmed && tx->direction() != TransactionInfo::Direction_In) { menu.addAction(icons()->icon("info2.svg"), "Resend transaction", this, &HistoryWidget::onResendTransaction); } @@ -79,22 +93,6 @@ void HistoryWidget::onResendTransaction() { } } -void HistoryWidget::setModel(TransactionHistoryProxyModel *model, Wallet *wallet) -{ - m_model = model; - m_wallet = wallet; - m_txHistory = m_wallet->history(); - ui->history->setHistoryModel(m_model); - m_wallet->transactionHistoryModel()->amountPrecision = config()->get(Config::amountPrecision).toInt(); - - // Load view state - QByteArray historyViewState = QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray()); - - if (!historyViewState.isEmpty()) { - ui->history->setViewState(historyViewState); - } -} - void HistoryWidget::resetModel() { // Save view state @@ -108,7 +106,7 @@ void HistoryWidget::showTxDetails() { auto *tx = ui->history->currentEntry(); if (!tx) return; - auto *dialog = new TransactionInfoDialog(m_wallet, tx, this); + auto *dialog = new TransactionInfoDialog(m_ctx, tx, this); connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){ emit resendTransaction(txid); }); @@ -128,7 +126,6 @@ void HistoryWidget::setSearchText(const QString &text) { } void HistoryWidget::setSearchFilter(const QString &filter) { - if (!m_model) return; m_model->setSearchFilter(filter); ui->history->setSearchMode(!filter.isEmpty()); } @@ -137,7 +134,7 @@ void HistoryWidget::createTxProof() { auto *tx = ui->history->currentEntry(); if (!tx) return; - auto *dialog = new TxProofDialog(this, m_wallet, tx); + auto *dialog = new TxProofDialog(this, m_ctx, tx); dialog->exec(); dialog->deleteLater(); } @@ -162,10 +159,6 @@ void HistoryWidget::copy(copyField field) { Utils::copyToClipboard(data); } -void HistoryWidget::onWalletOpened() { - ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool()); -} - void HistoryWidget::onWalletRefreshed() { ui->syncNotice->hide(); } diff --git a/src/historywidget.h b/src/historywidget.h index 197d0531..82d2cf86 100644 --- a/src/historywidget.h +++ b/src/historywidget.h @@ -8,6 +8,7 @@ #include "model/TransactionHistoryProxyModel.h" #include "libwalletqt/Coins.h" #include "libwalletqt/Wallet.h" +#include "appcontext.h" #include #include @@ -21,15 +22,13 @@ class HistoryWidget : public QWidget Q_OBJECT public: - explicit HistoryWidget(QWidget *parent = nullptr); - void setModel(TransactionHistoryProxyModel *model, Wallet *wallet); + explicit HistoryWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~HistoryWidget() override; public slots: void setSearchText(const QString &text); void resetModel(); void onWalletRefreshed(); - void onWalletOpened(); signals: void viewOnBlockExplorer(QString txid); @@ -55,11 +54,10 @@ private: void showSyncNoticeMsg(); Ui::HistoryWidget *ui; + QSharedPointer m_ctx; QMenu *m_contextMenu; QMenu *m_copyMenu; - TransactionHistory *m_txHistory; TransactionHistoryProxyModel *m_model; - Wallet *m_wallet = nullptr; }; #endif //FEATHER_HISTORYWIDGET_H diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 2079519e..6edffa22 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -3,6 +3,9 @@ #include "Wallet.h" +#include +#include + #include "TransactionHistory.h" #include "AddressBook.h" #include "Subaddress.h" @@ -174,9 +177,14 @@ SubaddressIndex Wallet::subaddressIndex(const QString &address) const return SubaddressIndex(i.first, i.second); } -QString Wallet::path() const +QString Wallet::cachePath() const { - return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->path())); + return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->filename())); +} + +QString Wallet::keysPath() const +{ + return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->keysFilename()));; } //void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */) diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 84311d95..94dcc25a 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -76,6 +76,9 @@ class Wallet : public QObject, public PassprasePrompter Q_OBJECT public: + Wallet(QObject * parent = nullptr); + Wallet(Monero::Wallet *w, QObject * parent = nullptr); + ~Wallet(); enum Status { Status_Ok = Monero::Wallet::Status_Ok, @@ -138,8 +141,11 @@ public: //! returns the subaddress index of the address SubaddressIndex subaddressIndex(const QString &address) const; - //! returns wallet file's path - QString path() const; + //! returns wallet cache file path + QString cachePath() const; + + //! returns wallet keys file path + QString keysPath() const; //! saves wallet to the file by given path //! empty path stores in current location @@ -465,10 +471,6 @@ signals: void refreshingChanged() const; private: - Wallet(QObject * parent = nullptr); - Wallet(Monero::Wallet *w, QObject * parent = nullptr); - ~Wallet(); - //! initializes wallet bool init( const QString &daemonAddress, diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp index 76220145..aa34a533 100644 --- a/src/libwalletqt/WalletManager.cpp +++ b/src/libwalletqt/WalletManager.cpp @@ -68,14 +68,10 @@ Wallet *WalletManager::createWallet(const QString &path, const QString &password const QString &language, NetworkType::Type nettype, quint64 kdfRounds) { QMutexLocker locker(&m_mutex); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - } + Monero::Wallet * w = m_pimpl->createWallet(path.toStdString(), password.toStdString(), language.toStdString(), static_cast(nettype), kdfRounds); - m_currentWallet = new Wallet(w); - return m_currentWallet; + return new Wallet(w); } Wallet *WalletManager::openWallet(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds) @@ -90,24 +86,20 @@ Wallet *WalletManager::openWallet(const QString &path, const QString &password, this->m_passphraseReceiver = nullptr; }); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - } qDebug() << QString("%1: opening wallet at %2, nettype = %3 ").arg(__PRETTY_FUNCTION__).arg(qPrintable(path)).arg(nettype); Monero::Wallet * w = m_pimpl->openWallet(path.toStdString(), password.toStdString(), static_cast(nettype), kdfRounds, &tmpListener); w->setListener(nullptr); qDebug() << QString("%1: opened wallet: %2, status: %3").arg(__PRETTY_FUNCTION__).arg(w->address(0, 0).c_str()).arg(w->status()); - m_currentWallet = new Wallet(w); + auto wallet = new Wallet(w); // move wallet to the GUI thread. Otherwise it wont be emitting signals - if (m_currentWallet->thread() != qApp->thread()) { - m_currentWallet->moveToThread(qApp->thread()); + if (wallet->thread() != qApp->thread()) { + wallet->moveToThread(qApp->thread()); } - return m_currentWallet; + return wallet; } void WalletManager::openWalletAsync(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds) @@ -121,13 +113,9 @@ void WalletManager::openWalletAsync(const QString &path, const QString &password Wallet *WalletManager::recoveryWallet(const QString &path, const QString &password, const QString &seed, const QString &seed_offset, NetworkType::Type nettype, quint64 restoreHeight, quint64 kdfRounds) { QMutexLocker locker(&m_mutex); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - } + Monero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), password.toStdString(), seed.toStdString(), static_cast(nettype), restoreHeight, kdfRounds, seed_offset.toStdString()); - m_currentWallet = new Wallet(w); - return m_currentWallet; + return new Wallet(w); } Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &password, const QString &language, @@ -135,30 +123,18 @@ Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString & const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds) { QMutexLocker locker(&m_mutex); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - m_currentWallet = nullptr; - } Monero::Wallet * w = m_pimpl->createWalletFromKeys(path.toStdString(), password.toStdString(), language.toStdString(), static_cast(nettype), restoreHeight, address.toStdString(), viewkey.toStdString(), spendkey.toStdString(), kdfRounds); - m_currentWallet = new Wallet(w); - return m_currentWallet; + return new Wallet(w); } Wallet *WalletManager::createDeterministicWalletFromSpendKey(const QString &path, const QString &password, const QString &language, NetworkType::Type nettype, const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds, const QString &offset_passphrase) { QMutexLocker locker(&m_mutex); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - m_currentWallet = nullptr; - } Monero::Wallet * w = m_pimpl->createDeterministicWalletFromSpendKey(path.toStdString(), password.toStdString(), language.toStdString(), static_cast(nettype), restoreHeight, spendkey.toStdString(), kdfRounds, offset_passphrase.toStdString()); - m_currentWallet = new Wallet(w); - return m_currentWallet; + return new Wallet(w); } Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString &password, NetworkType::Type nettype, @@ -174,26 +150,20 @@ Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString this->m_passphraseReceiver = nullptr; }); - if (m_currentWallet) { - qDebug() << "Closing open m_currentWallet" << m_currentWallet; - delete m_currentWallet; - m_currentWallet = nullptr; - } Monero::Wallet * w = m_pimpl->createWalletFromDevice(path.toStdString(), password.toStdString(), static_cast(nettype), deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener); w->setListener(nullptr); - m_currentWallet = new Wallet(w); + auto wallet = new Wallet(w); // move wallet to the GUI thread. Otherwise it wont be emitting signals - if (m_currentWallet->thread() != qApp->thread()) { - m_currentWallet->moveToThread(qApp->thread()); + if (wallet->thread() != qApp->thread()) { + wallet->moveToThread(qApp->thread()); } - return m_currentWallet; + return wallet; } - void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype, const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead) { @@ -203,30 +173,6 @@ void WalletManager::createWalletFromDeviceAsync(const QString &path, const QStri }); } -QString WalletManager::closeWallet() -{ - QMutexLocker locker(&m_mutex); - qDebug() << Q_FUNC_INFO ; - QString result; - if (m_currentWallet) { - result = m_currentWallet->address(0, 0); - delete m_currentWallet; - m_currentWallet = nullptr; - } else { - qCritical() << "Trying to close non existing wallet " << m_currentWallet; - result = "0"; - } - return result; -} - -// @TODO: fix -//void WalletManager::closeWalletAsync(const QJSValue& callback) -//{ -// m_scheduler.run([this] { -// return QJSValueList({closeWallet()}); -// }, callback); -//} - bool WalletManager::walletExists(const QString &path) const { return m_pimpl->walletExists(path.toStdString()); @@ -287,7 +233,7 @@ bool WalletManager::addressValid(const QString &address, NetworkType::Type netty return Monero::Wallet::addressValid(address.toStdString(), static_cast(nettype)); } -bool WalletManager::keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) const +bool WalletManager::keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) { std::string error; if(!Monero::Wallet::keyValid(key.toStdString(), address.toStdString(), isViewKey, static_cast(nettype), error)){ @@ -329,43 +275,6 @@ quint64 WalletManager::blockchainTargetHeight() const return m_pimpl->blockchainTargetHeight(); } -double WalletManager::miningHashRate() const -{ - return m_pimpl->miningHashRate(); -} - -bool WalletManager::isMining() const -{ - { - QMutexLocker locker(&m_mutex); - if (m_currentWallet == nullptr || !m_currentWallet->connectionStatus()) - { - return false; - } - } - - return m_pimpl->isMining(); -} - -void WalletManager::miningStatusAsync() -{ - m_scheduler.run([this] { - emit miningStatus(isMining()); - }); -} - -bool WalletManager::startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery) -{ - if(threads == 0) - threads = 1; - return m_pimpl->startMining(address.toStdString(), threads, backgroundMining, ignoreBattery); -} - -bool WalletManager::stopMining() -{ - return m_pimpl->stopMining(); -} - bool WalletManager::localDaemonSynced() const { return blockchainHeight() > 1 && blockchainHeight() >= blockchainTargetHeight(); @@ -386,8 +295,9 @@ QString WalletManager::resolveOpenAlias(const QString &address) const bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error) const { QMutexLocker locker(&m_mutex); - if (m_currentWallet) - return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); + // TODO: FIXME +// if (m_currentWallet) +// return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); return false; } @@ -435,9 +345,8 @@ QUrl WalletManager::localPathToUrl(const QString &path) const return QUrl::fromLocalFile(path); } -bool WalletManager::clearWalletCache(const QString &wallet_path) const +bool WalletManager::clearWalletCache(const QString &wallet_path) { - QString fileName = wallet_path; // Make sure wallet file is not .keys fileName.replace(".keys",""); @@ -455,7 +364,6 @@ bool WalletManager::clearWalletCache(const QString &wallet_path) const WalletManager::WalletManager(QObject *parent) : QObject(parent) - , m_currentWallet(nullptr) , m_passphraseReceiver(nullptr) , m_scheduler(this) { diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h index 0f4e58e2..1a02d456 100644 --- a/src/libwalletqt/WalletManager.h +++ b/src/libwalletqt/WalletManager.h @@ -93,16 +93,7 @@ public: const QString &deviceName, quint64 restoreHeight = 0, const QString &subaddressLookahead = ""); - /*! - * \brief closeWallet - closes current open wallet and frees memory - * \return wallet address - */ - Q_INVOKABLE QString closeWallet(); - /*! - * \brief closeWalletAsync - asynchronous version of "closeWallet" - */ - //Q_INVOKABLE void closeWalletAsync(const QJSValue& callback); //! checks is given filename is a wallet; Q_INVOKABLE bool walletExists(const QString &path) const; @@ -127,7 +118,7 @@ public: Q_INVOKABLE bool paymentIdValid(const QString &payment_id) const; Q_INVOKABLE static bool addressValid(const QString &address, NetworkType::Type nettype); - Q_INVOKABLE bool keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) const; + Q_INVOKABLE static bool keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype); Q_INVOKABLE QString paymentIdFromAddress(const QString &address, NetworkType::Type nettype) const; @@ -136,14 +127,9 @@ public: Q_INVOKABLE quint64 networkDifficulty() const; Q_INVOKABLE quint64 blockchainHeight() const; Q_INVOKABLE quint64 blockchainTargetHeight() const; - Q_INVOKABLE double miningHashRate() const; Q_INVOKABLE bool localDaemonSynced() const; Q_INVOKABLE bool isDaemonLocal(const QString &daemon_address) const; - Q_INVOKABLE void miningStatusAsync(); - Q_INVOKABLE bool startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery); - Q_INVOKABLE bool stopMining(); - // QML missing such functionality, implementing these helpers here Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const; Q_INVOKABLE QUrl localPathToUrl(const QString &path) const; @@ -159,10 +145,9 @@ public: Q_INVOKABLE QString resolveOpenAlias(const QString &address) const; Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector &unknown_parameters, QString &error) const; Q_INVOKABLE QVariantMap parse_uri_to_object(const QString &uri) const; -// Q_INVOKABLE bool saveQrCode(const QString &, const QString &) const; // clear/rename wallet cache - Q_INVOKABLE bool clearWalletCache(const QString &fileName) const; + Q_INVOKABLE static bool clearWalletCache(const QString &fileName); Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false); virtual void onWalletPassphraseNeeded(bool on_device) override; @@ -171,7 +156,6 @@ public: void setProxyAddress(QString address); signals: - void walletOpened(Wallet * wallet); void walletCreated(Wallet * wallet); void walletPassphraseNeeded(bool onDevice); @@ -185,16 +169,13 @@ public slots: private: friend class WalletPassphraseListenerImpl; - explicit WalletManager(QObject *parent = 0); - ~WalletManager(); + explicit WalletManager(QObject *parent = nullptr); + ~WalletManager() override; - bool isMining() const; - - static WalletManager * m_instance; - Monero::WalletManager * m_pimpl; + static WalletManager *m_instance; + Monero::WalletManager *m_pimpl; mutable QMutex m_mutex; - QPointer m_currentWallet; - PassphraseReceiver * m_passphraseReceiver; + PassphraseReceiver *m_passphraseReceiver; QMutex m_mutex_passphraseReceiver; QString m_proxyAddress; mutable QMutex m_proxyMutex; diff --git a/src/main.cpp b/src/main.cpp index b73f8ed7..a62ae807 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,8 +7,10 @@ #include #include "config-feather.h" +#include "constants.h" #include "mainwindow.h" #include "cli.h" +#include "WindowManager.h" #if defined(Q_OS_WIN) #include @@ -87,8 +89,8 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { QCommandLineOption bruteforceDictionairy(QStringList() << "bruteforce-dict", "Bruteforce dictionairy", "file"); parser.addOption(bruteforceDictionairy); - auto parsed = parser.parse(argv_); - if(!parsed) { + bool parsed = parser.parse(argv_); + if (!parsed) { qCritical() << parser.errorText(); exit(1); } @@ -102,33 +104,15 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { bool bruteforcePassword = parser.isSet(bruteforcePasswordOption); bool cliMode = exportContacts || exportTxHistory || bruteforcePassword; - if(cliMode) { - QCoreApplication cli_app(argc, argv); - QCoreApplication::setApplicationName("FeatherWallet"); - - auto *ctx = new AppContext(&parser); - - auto *cli = new CLI(ctx, &cli_app); - QObject::connect(cli, &CLI::closeApplication, &cli_app, &QCoreApplication::quit); - - if(exportContacts) { - if(!quiet) - qInfo() << "CLI mode: Address book export"; - cli->mode = CLIMode::ExportContacts; - QTimer::singleShot(0, cli, &CLI::run); - } else if(exportTxHistory) { - if(!quiet) - qInfo() << "CLI mode: Transaction history export"; - cli->mode = CLIMode::ExportTxHistory; - QTimer::singleShot(0, cli, &CLI::run); - } else if(bruteforcePassword) { - cli->mode = CLIMode::BruteforcePassword; - QTimer::singleShot(0, cli, &CLI::run); - } - - return QCoreApplication::exec(); - } + // Setup networkType + if (stagenet) + constants::networkType = NetworkType::STAGENET; + else if (testnet) + constants::networkType = NetworkType::TESTNET; + else + constants::networkType = NetworkType::MAINNET; + // Setup QApplication QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); QApplication::setDesktopSettingsAware(true); // use system font @@ -136,11 +120,70 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { QApplication app(argc, argv); + QApplication::setQuitOnLastWindowClosed(false); QApplication::setApplicationName("FeatherWallet"); + // Setup config directories + QString configDir = Config::defaultConfigDir().path(); + QString config_dir_tor = QString("%1/%2").arg(configDir).arg("tor"); + QString config_dir_tordata = QString("%1/%2").arg(configDir).arg("tor/data"); + QStringList createDirs({configDir, config_dir_tor, config_dir_tordata}); + for (const auto &d: createDirs) { + if (!Utils::dirExists(d)) { + qDebug() << QString("Creating directory: %1").arg(d); + if (!QDir().mkpath(d)) { + qCritical() << "Could not create directory " << d; + } + } + } + + // Setup logging + QString logPath = QString("%1/daemon.log").arg(configDir); + Monero::Utils::onStartup(); + Monero::Wallet::init("", "feather", logPath.toStdString(), true); + + bool logLevelFromEnv; + int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv); + + if (parser.isSet("quiet")) + WalletManager::instance()->setLogLevel(-1); + else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max) + Monero::WalletManagerFactory::setLogLevel(logLevel); + + // Setup wallet directory + QString walletDir = config()->get(Config::walletDirectory).toString(); + if (walletDir.isEmpty()) { + walletDir = Utils::defaultWalletDir(); + config()->set(Config::walletDirectory, walletDir); + } + if (!QDir().mkpath(walletDir)) + qCritical() << "Unable to create dir: " << walletDir; + + // Setup Tor config + if (parser.isSet("tor-host")) + config()->set(Config::socks5Host, parser.value("tor-host")); + if (parser.isSet("tor-port")) + config()->set(Config::socks5Port, parser.value("tor-port")); + if (parser.isSet("use-local-tor")) + config()->set(Config::useLocalTor, true); + + if (cliMode) { + CLI::Mode mode = [&]{ + if (exportContacts) + return CLI::Mode::ExportContacts; + if (exportTxHistory) + return CLI::Mode::ExportTxHistory; + if (bruteforcePassword) + return CLI::Mode::BruteforcePassword; + }(); + + CLI cli{mode, &parser, &app}; + return QCoreApplication::exec(); + } + parser.process(app); // Parse again for --help and --version - if(!quiet) { + if (!quiet) { QMap info; info["Qt"] = QT_VERSION_STR; info["Feather"] = FEATHER_VERSION; @@ -153,8 +196,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]); } - auto *ctx = new AppContext(&parser); - #if defined(Q_OS_MAC) // For some odd reason, if we don't do this, QPushButton's // need to be clicked *twice* in order to fire ?! @@ -166,6 +207,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { qInstallMessageHandler(Utils::applicationLogHandler); qRegisterMetaType>(); - new MainWindow(ctx); + WindowManager windowManager; + return QApplication::exec(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7c1e0e45..0850dedc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2,7 +2,6 @@ // Copyright (c) 2020-2021, The Monero Project. #include -#include #include #include "mainwindow.h" @@ -21,7 +20,7 @@ #include "dialog/balancedialog.h" #include "dialog/WalletCacheDebugDialog.h" #include "dialog/UpdateDialog.h" -#include "globals.h" +#include "constants.h" #include "libwalletqt/AddressBook.h" #include "utils/AsyncTask.h" #include "utils/AppData.h" @@ -31,14 +30,20 @@ #include "utils/Icons.h" #include "utils/WebsocketNotifier.h" #include "utils/Updater.h" +#include "utils/tails.h" +#include "utils/TorManager.h" -MainWindow::MainWindow(AppContext *ctx, QWidget *parent) +MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) - , m_ctx(ctx) + , m_windowManager(windowManager) + , m_ctx(new AppContext(wallet)) { ui->setupUi(this); + // Ensure the destructor is called after closeEvent() + setAttribute(Qt::WA_DeleteOnClose); + m_windowSettings = new Settings(m_ctx, this); m_windowCalc = new CalcWindow(this); m_splashDialog = new SplashDialog(this); @@ -46,13 +51,10 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) this->restoreGeo(); this->startupWarning(); - this->initSkins(); this->initStatusBar(); this->initWidgets(); this->initMenu(); - this->initTray(); this->initHome(); - this->initTouchBar(); this->initWalletContext(); // Websocket notifier @@ -62,64 +64,34 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) #ifdef HAS_XMRIG connect(websocketNotifier(), &WebsocketNotifier::XMRigDownloadsReceived, m_xmrig, &XMRigWidget::onDownloads); #endif + websocketNotifier()->emitCache(); // Get cached data // Settings for (auto tickerWidget: m_tickerWidgets) connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, tickerWidget, &TickerWidget::init); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceWidget, &TickerWidget::init); - connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx, &AppContext::onPreferredFiatCurrencyChanged); + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx.get(), &AppContext::onPreferredFiatCurrencyChanged); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged)); - connect(m_windowSettings, &Settings::amountPrecisionChanged, m_ctx, &AppContext::onAmountPrecisionChanged); + connect(m_windowSettings, &Settings::amountPrecisionChanged, m_ctx.get(), &AppContext::onAmountPrecisionChanged); connect(m_windowSettings, &Settings::skinChanged, this, &MainWindow::skinChanged); - // Wizard - connect(this, &MainWindow::closed, [=]{ - if (m_wizard) - m_wizard->close(); - }); + connect(m_windowManager, &WindowManager::torSettingsChanged, m_ctx.get(), &AppContext::onTorSettingsChanged); + connect(torManager(), &TorManager::connectionStateChanged, this, &MainWindow::onTorConnectionStateChanged); + this->onTorConnectionStateChanged(torManager()->torConnected); - // History - // TODO: move this - connect(m_ctx, &AppContext::walletRefreshed, ui->historyWidget, &HistoryWidget::onWalletRefreshed); - connect(m_ctx, &AppContext::walletOpened, ui->historyWidget, &HistoryWidget::onWalletOpened); - - if (!config()->get(Config::firstRun).toBool() || TailsOS::detect() || WhonixOS::detect()) { - this->onInitialNetworkConfigured(); - } - - this->setEnabled(true); - this->show(); ColorScheme::updateFromWidget(this); - if (!this->autoOpenWallet()) { - this->initWizard(); - } - // Timers connect(&m_updateBytes, &QTimer::timeout, this, &MainWindow::updateNetStats); connect(&m_txTimer, &QTimer::timeout, [this]{ m_statusLabelStatus->setText("Constructing transaction" + this->statusDots()); }); -} -void MainWindow::initSkins() { - m_skins.insert("Native", ""); + this->onWalletOpened(); - QString qdarkstyle = this->loadStylesheet(":qdarkstyle/style.qss"); - if (!qdarkstyle.isEmpty()) - m_skins.insert("QDarkStyle", qdarkstyle); - - QString breeze_dark = this->loadStylesheet(":/dark.qss"); - if (!breeze_dark.isEmpty()) - m_skins.insert("Breeze/Dark", breeze_dark); - - QString breeze_light = this->loadStylesheet(":/light.qss"); - if (!breeze_light.isEmpty()) - m_skins.insert("Breeze/Light", breeze_light); - - QString skin = config()->get(Config::skin).toString(); - qApp->setStyleSheet(m_skins[skin]); - ColorScheme::updateFromWidget(this); +#ifdef DONATE_BEG + this->donationNag(); +#endif } void MainWindow::initStatusBar() { @@ -186,19 +158,26 @@ void MainWindow::initWidgets() { }); // [History] - connect(ui->historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer); - connect(ui->historyWidget, &HistoryWidget::resendTransaction, this, &MainWindow::onResendTransaction); + m_historyWidget = new HistoryWidget(m_ctx, this); + ui->historyWidgetLayout->addWidget(m_historyWidget); + connect(m_historyWidget, &HistoryWidget::viewOnBlockExplorer, this, &MainWindow::onViewOnBlockExplorer); + connect(m_historyWidget, &HistoryWidget::resendTransaction, this, &MainWindow::onResendTransaction); // [Send] m_sendWidget = new SendWidget(m_ctx, this); ui->sendWidgetLayout->addWidget(m_sendWidget); + // -------------- + m_contactsWidget = new ContactsWidget(m_ctx, this); + ui->contactsWidgetLayout->addWidget(m_contactsWidget); // [Receive] - connect(ui->receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) { - ui->historyWidget->setSearchText(text); + m_receiveWidget = new ReceiveWidget(m_ctx, this); + ui->receiveWidgetLayout->addWidget(m_receiveWidget); + connect(m_receiveWidget, &ReceiveWidget::showTransactions, [this](const QString &text) { + m_historyWidget->setSearchText(text); ui->tabWidget->setCurrentIndex(Tabs::HISTORY); }); - connect(ui->contactWidget, &ContactsWidget::fillAddress, m_sendWidget, &SendWidget::fillAddress); + connect(m_contactsWidget, &ContactsWidget::fillAddress, m_sendWidget, &SendWidget::fillAddress); // [Coins] m_coinsWidget = new CoinsWidget(m_ctx, this); @@ -225,9 +204,11 @@ void MainWindow::initWidgets() { void MainWindow::initMenu() { // TODO: Rename actions to follow style // [File] - connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked); // Close current wallet - connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::menuQuitClicked); // Quit application - connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::menuSettingsClicked); + connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::menuOpenClicked); + connect(ui->actionNew_Restore, &QAction::triggered, this, &MainWindow::menuNewRestoreClicked); + connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked); // Close current wallet + connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::menuQuitClicked); // Quit application + connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::menuSettingsClicked); // [Wallet] connect(ui->actionInformation, &QAction::triggered, this, &MainWindow::showWalletInfoDialog); @@ -237,7 +218,7 @@ void MainWindow::initMenu() { connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog); // [Wallet] -> [Advanced] - connect(ui->actionStore_wallet, &QAction::triggered, [this]{m_ctx->currentWallet->store();}); + connect(ui->actionStore_wallet, &QAction::triggered, [this]{m_ctx->wallet->store();}); connect(ui->actionUpdate_balance, &QAction::triggered, [this]{m_ctx->updateBalance();}); connect(ui->actionRefresh_tabs, &QAction::triggered, [this]{m_ctx->refreshModels();}); connect(ui->actionRescan_spent, &QAction::triggered, this, &MainWindow::rescanSpent); @@ -332,45 +313,14 @@ void MainWindow::initMenu() { // Setup shortcuts ui->actionStore_wallet->setShortcut(QKeySequence("Ctrl+S")); ui->actionRefresh_tabs->setShortcut(QKeySequence("Ctrl+R")); + ui->actionOpen->setShortcut(QKeySequence("Ctrl+O")); + ui->actionNew_Restore->setShortcut(QKeySequence("Ctrl+N")); ui->actionClose->setShortcut(QKeySequence("Ctrl+W")); ui->actionShow_debug_info->setShortcut(QKeySequence("Ctrl+D")); ui->actionSettings->setShortcut(QKeySequence("Ctrl+Alt+S")); ui->actionUpdate_balance->setShortcut(QKeySequence("Ctrl+U")); } -void MainWindow::initTray() { - // TODO: Add tray support on Windows and Mac - -#if defined(Q_OS_LINUX) - // system tray - m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/images/appicons/64x64.png")); - m_trayIcon->show(); - - m_trayActionCalc = new QAction("Calc", this); - m_trayActionCalc->setStatusTip("Calculator"); - - m_trayActionSend = new QAction("Send", this); - m_trayActionSend->setStatusTip("Send XMR payment"); - - m_trayActionHistory = new QAction("History", this); - m_trayActionHistory->setStatusTip("View incoming transfers"); - - m_trayActionExit = new QAction("Quit", this); - m_trayActionExit->setStatusTip("Exit application"); - - m_trayMenu.addAction(m_trayActionSend); - m_trayMenu.addAction(m_trayActionHistory); - m_trayMenu.addAction(m_trayActionCalc); - m_trayMenu.addAction(m_trayActionExit); - m_trayIcon->setContextMenu(&m_trayMenu); - - connect(m_trayActionCalc, &QAction::triggered, this, &MainWindow::showCalcWindow); - connect(m_trayActionSend, &QAction::triggered, this, &MainWindow::showSendTab); - connect(m_trayActionHistory, &QAction::triggered, this, &MainWindow::showHistoryTab); - connect(m_trayActionExit, &QAction::triggered, this, &QMainWindow::close); -#endif -} - void MainWindow::initHome() { // Ticker widgets m_tickerWidgets.append(new TickerWidget(this, m_ctx, "XMR")); @@ -385,64 +335,37 @@ void MainWindow::initHome() { connect(ui->redditWidget, &RedditWidget::setStatusText, this, &MainWindow::setStatusText); } -void MainWindow::initTouchBar() { -#ifdef Q_OS_MAC - m_touchbar = new KDMacTouchBar(this); - m_touchbarActionWelcome = new QAction(QIcon(":/assets/images/feather.png"), "Welcome to Feather!"); - m_touchbarWalletItems = {ui->actionSettings, ui->actionCalculator, ui->actionKeys, ui->actionDonate_to_Feather}; - m_touchbarWizardItems = {m_touchbarActionWelcome}; -#endif -} - void MainWindow::initWalletContext() { - connect(m_ctx, &AppContext::walletClosed, [this](){this->onWalletClosed();}); - connect(m_ctx, &AppContext::balanceUpdated, this, &MainWindow::onBalanceUpdated); - connect(m_ctx, &AppContext::walletOpened, this, &MainWindow::onWalletOpened); - connect(m_ctx, &AppContext::walletOpenedError, this, &MainWindow::onWalletOpenedError); - connect(m_ctx, &AppContext::walletCreatedError, this, &MainWindow::onWalletCreatedError); - connect(m_ctx, &AppContext::synchronized, this, &MainWindow::onSynchronized); - connect(m_ctx, &AppContext::blockchainSync, this, &MainWindow::onBlockchainSync); - connect(m_ctx, &AppContext::refreshSync, this, &MainWindow::onRefreshSync); - connect(m_ctx, &AppContext::createTransactionError, this, &MainWindow::onCreateTransactionError); - connect(m_ctx, &AppContext::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess); - connect(m_ctx, &AppContext::transactionCommitted, this, &MainWindow::onTransactionCommitted); - connect(m_ctx, &AppContext::walletOpenPasswordNeeded, this, &MainWindow::onWalletOpenPasswordRequired); - connect(m_ctx, &AppContext::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest); - connect(m_ctx, &AppContext::deviceError, this, &MainWindow::onDeviceError); - connect(m_ctx, &AppContext::donationNag, this, &MainWindow::onShowDonationNag); - connect(m_ctx, &AppContext::initiateTransaction, this, &MainWindow::onInitiateTransaction); - connect(m_ctx, &AppContext::endTransaction, this, &MainWindow::onEndTransaction); - connect(m_ctx, &AppContext::customRestoreHeightSet, this, &MainWindow::onCustomRestoreHeightSet); - connect(m_ctx, &AppContext::walletAboutToClose, this, &MainWindow::onWalletAboutToClose); + connect(m_ctx.get(), &AppContext::balanceUpdated, this, &MainWindow::onBalanceUpdated); + connect(m_ctx.get(), &AppContext::synchronized, this, &MainWindow::onSynchronized); + connect(m_ctx.get(), &AppContext::blockchainSync, this, &MainWindow::onBlockchainSync); + connect(m_ctx.get(), &AppContext::refreshSync, this, &MainWindow::onRefreshSync); + connect(m_ctx.get(), &AppContext::createTransactionError, this, &MainWindow::onCreateTransactionError); + connect(m_ctx.get(), &AppContext::createTransactionSuccess, this, &MainWindow::onCreateTransactionSuccess); + connect(m_ctx.get(), &AppContext::transactionCommitted, this, &MainWindow::onTransactionCommitted); + connect(m_ctx.get(), &AppContext::deviceError, this, &MainWindow::onDeviceError); + connect(m_ctx.get(), &AppContext::initiateTransaction, this, &MainWindow::onInitiateTransaction); + connect(m_ctx.get(), &AppContext::endTransaction, this, &MainWindow::onEndTransaction); + connect(m_ctx.get(), &AppContext::customRestoreHeightSet, this, &MainWindow::onCustomRestoreHeightSet); // Nodes connect(m_ctx->nodes, &Nodes::updateStatus, [=](const QString &msg){this->setStatusText(msg);}); connect(m_ctx->nodes, &Nodes::nodeExhausted, this, &MainWindow::showNodeExhaustedMessage); connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage); -} -void MainWindow::initWizard() { - this->setEnabled(false); - auto startPage = WalletWizard::Page_Menu; - if (config()->get(Config::firstRun).toBool() && !(TailsOS::detect() || WhonixOS::detect())) { - startPage = WalletWizard::Page_Network; - } - - m_wizard = this->createWizard(startPage); - m_wizard->show(); - m_wizard->setEnabled(true); - this->touchbarShowWizard(); + // Wallet + connect(m_ctx->wallet.get(), &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged); } void MainWindow::startupWarning() { // Stagenet / Testnet auto worthlessWarning = QString("Feather wallet is currently running in %1 mode. This is meant " "for developers only. Your coins are WORTHLESS."); - if (m_ctx->networkType == NetworkType::STAGENET && config()->get(Config::warnOnStagenet).toBool()) { + if (constants::networkType == NetworkType::STAGENET && config()->get(Config::warnOnStagenet).toBool()) { QMessageBox::warning(this, "Warning", worthlessWarning.arg("stagenet")); config()->set(Config::warnOnStagenet, false); } - else if (m_ctx->networkType == NetworkType::TESTNET && config()->get(Config::warnOnTestnet).toBool()){ + else if (constants::networkType == NetworkType::TESTNET && config()->get(Config::warnOnTestnet).toBool()){ QMessageBox::warning(this, "Warning", worthlessWarning.arg("testnet")); config()->set(Config::warnOnTestnet, false); } @@ -456,18 +379,6 @@ void MainWindow::startupWarning() { } } -bool MainWindow::autoOpenWallet() { - QString autoPath = config()->get(Config::autoOpenWalletPath).toString(); - if (!autoPath.isEmpty() && autoPath.startsWith(QString::number(m_ctx->networkType))) { - autoPath.remove(0, 1); - } - if (!autoPath.isEmpty() && Utils::fileExists(autoPath)) { - m_ctx->onOpenWallet(autoPath, m_ctx->walletPassword); - return true; - } - return false; -} - void MainWindow::menuToggleTabVisible(const QString &key){ const auto toggleTab = m_tabShowHideMapper[key]; bool show = config()->get(toggleTab->configKey).toBool(); @@ -477,91 +388,16 @@ void MainWindow::menuToggleTabVisible(const QString &key){ toggleTab->menuAction->setText((show ? QString("Hide ") : QString("Show ")) + toggleTab->name); } -WalletWizard *MainWindow::createWizard(WalletWizard::Page startPage){ - auto *wizard = new WalletWizard(m_ctx, startPage, this); - connect(wizard, &WalletWizard::initialNetworkConfigured, this, &MainWindow::onInitialNetworkConfigured); - connect(wizard, &WalletWizard::skinChanged, this, &MainWindow::skinChanged); - connect(wizard, &WalletWizard::openWallet, m_ctx, &AppContext::onOpenWallet); - connect(wizard, &WalletWizard::defaultWalletDirChanged, m_windowSettings, &Settings::updatePaths); - connect(wizard, &WalletWizard::rejected, [this]{ - this->cleanupBeforeClose(); - QCoreApplication::quit(); - }); - return wizard; +QString MainWindow::walletName() { + return QFileInfo(m_ctx->wallet->cachePath()).fileName(); } -void MainWindow::showWizard(WalletWizard::Page startPage) { - this->setEnabled(false); - if (m_wizard == nullptr) - m_wizard = this->createWizard(startPage); - m_wizard->setStartId(startPage); - m_wizard->restart(); - m_wizard->setEnabled(true); - m_wizard->show(); +QString MainWindow::walletCachePath() { + return m_ctx->wallet->cachePath(); } -void MainWindow::onWalletClosed(WalletWizard::Page page) { - m_statusLabelBalance->clear(); - m_statusLabelStatus->clear(); - this->showWizard(page); -} - -void MainWindow::touchbarShowWizard() { -#ifdef Q_OS_MAC - m_touchbar->clear(); - for(auto* action: m_touchbarWizardItems) m_touchbar->addAction(action); -#endif -} - -void MainWindow::touchbarShowWallet() { -#ifdef Q_OS_MAC - m_touchbar->clear(); - for(auto* action: m_touchbarWalletItems) m_touchbar->addAction(action); -#endif -} - -void MainWindow::onWalletCreatedError(const QString &err) { - this->displayWalletErrorMsg(err); - m_splashDialog->hide(); - this->showWizard(WalletWizard::Page_Menu); -} - -void MainWindow::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) { - QFileInfo fileInfo(path); - - auto dialog = new PasswordDialog(this, fileInfo.fileName(), invalidPassword); - switch (dialog->exec()) { - case QDialog::Rejected: - { - this->showWizard(WalletWizard::Page_OpenWallet); - return; - } - } - - m_ctx->walletPassword = dialog->password; - m_ctx->onOpenWallet(m_ctx->walletPath, m_ctx->walletPassword); - - dialog->deleteLater(); -} - -void MainWindow::onDeviceButtonRequest(quint64 code) { - if (m_wizard) { - m_wizard->hide(); - } - - m_splashDialog->setMessage("Action required on device: Export the view key to open the wallet."); - m_splashDialog->setIcon(QPixmap(":/assets/images/key.png")); - m_splashDialog->show(); - m_splashDialog->setEnabled(true); -} - -void MainWindow::onWalletOpenedError(const QString &err) { - qDebug() << Q_FUNC_INFO << QString("Wallet open error: %1").arg(err); - m_splashDialog->hide(); - this->displayWalletErrorMsg(err); - this->setWindowTitle("Feather"); - this->showWizard(WalletWizard::Page_OpenWallet); - this->touchbarShowWizard(); +QString MainWindow::walletKeysPath() { + return m_ctx->wallet->keysPath(); } void MainWindow::displayWalletErrorMsg(const QString &err) { @@ -591,49 +427,38 @@ void MainWindow::onWalletOpened() { qDebug() << Q_FUNC_INFO; m_splashDialog->hide(); - if (m_wizard) { - m_wizard->hide(); - } - - if (m_ctx->currentWallet->isHwBacked()) { + if (m_ctx->wallet->isHwBacked()) { m_statusBtnHwDevice->show(); } this->bringToFront(); this->setEnabled(true); - if(!torManager()->torConnected) + if (!torManager()->torConnected) this->setStatusText("Wallet opened - Starting Tor (may take a while)"); else this->setStatusText("Wallet opened - Searching for node"); - connect(m_ctx->currentWallet, &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged); - // receive page - m_ctx->currentWallet->subaddress()->refresh( m_ctx->currentWallet->currentSubaddressAccount()); - ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet); - if (m_ctx->currentWallet->subaddress()->count() == 1) { + m_ctx->wallet->subaddress()->refresh( m_ctx->wallet->currentSubaddressAccount()); + if (m_ctx->wallet->subaddress()->count() == 1) { for (int i = 0; i < 10; i++) { - m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), ""); + m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), ""); } } // history page - m_ctx->currentWallet->history()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); - ui->historyWidget->setModel(m_ctx->currentWallet->historyModel(), m_ctx->currentWallet); - - // contacts widget - ui->contactWidget->setModel(m_ctx->currentWallet->addressBookModel(), m_ctx->currentWallet); + m_ctx->wallet->history()->refresh(m_ctx->wallet->currentSubaddressAccount()); // coins page - m_ctx->currentWallet->coins()->refresh(m_ctx->currentWallet->currentSubaddressAccount()); - m_coinsWidget->setModel(m_ctx->currentWallet->coinsModel(), m_ctx->currentWallet->coins()); + m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount()); + m_coinsWidget->setModel(m_ctx->wallet->coinsModel(), m_ctx->wallet->coins()); - this->touchbarShowWallet(); this->updatePasswordIcon(); - this->setTitle(false); - + m_ctx->nodes->connectToNode(); m_updateBytes.start(250); + + this->updateRecentlyOpened(m_ctx->wallet->cachePath()); } void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { @@ -650,7 +475,6 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { label_str += QString(" (+%1 XMR unconfirmed)").arg(Utils::balanceFormat(balance - spendable)); } - if (hide) label_str = "Balance: HIDDEN"; @@ -736,36 +560,35 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVecto auto tx_err = tx->errorString(); qCritical() << tx_err; - if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion) + if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion) err = QString("%1 Wrong daemon version: %2").arg(err).arg(tx_err); else err = QString("%1 %2").arg(err).arg(tx_err); qDebug() << Q_FUNC_INFO << err; this->displayWalletErrorMsg(err); - m_ctx->currentWallet->disposeTransaction(tx); + m_ctx->wallet->disposeTransaction(tx); } else if (tx->txCount() == 0) { err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep."); qDebug() << Q_FUNC_INFO << err; this->displayWalletErrorMsg(err); - m_ctx->currentWallet->disposeTransaction(tx); + m_ctx->wallet->disposeTransaction(tx); } else { const auto &description = m_ctx->tmpTxDescription; // Show advanced dialog on multi-destination transactions if (address.size() > 1) { - auto *dialog_adv = new TxConfAdvDialog(m_ctx, description, this); - dialog_adv->setTransaction(tx); - dialog_adv->exec(); - dialog_adv->deleteLater(); + TxConfAdvDialog dialog_adv{m_ctx, description, this}; + dialog_adv.setTransaction(tx); + dialog_adv.exec(); return; } - auto *dialog = new TxConfDialog(m_ctx, tx, address[0], description, this); - switch (dialog->exec()) { + TxConfDialog dialog{m_ctx, tx, address[0], description, this}; + switch (dialog.exec()) { case QDialog::Rejected: { - if (!dialog->showAdvanced) + if (!dialog.showAdvanced) m_ctx->onCancelTransaction(tx, address); break; } @@ -774,13 +597,11 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVecto break; } - if (dialog->showAdvanced) { - auto *dialog_adv = new TxConfAdvDialog(m_ctx, description, this); - dialog_adv->setTransaction(tx); - dialog_adv->exec(); - dialog_adv->deleteLater(); + if (dialog.showAdvanced) { + TxConfAdvDialog dialog_adv{m_ctx, description, this}; + dialog_adv.setTransaction(tx); + dialog_adv.exec(); } - dialog->deleteLater(); } } @@ -807,35 +628,33 @@ void MainWindow::onCreateTransactionError(const QString &message) { } void MainWindow::showWalletInfoDialog() { - auto *dialog = new WalletInfoDialog(m_ctx, this); - dialog->exec(); - dialog->deleteLater(); + WalletInfoDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::showSeedDialog() { - if (m_ctx->currentWallet->isHwBacked()) { + if (m_ctx->wallet->isHwBacked()) { QMessageBox::information(this, "Information", "Seed unavailable: Wallet keys are stored on hardware device."); return; } - if (m_ctx->currentWallet->viewOnly()) { + if (m_ctx->wallet->viewOnly()) { QMessageBox::information(this, "Information", "Wallet is view-only and has no seed.\n\nTo obtain wallet keys go to Wallet -> View-Only"); return; } - if (!m_ctx->currentWallet->isDeterministic()) { + if (!m_ctx->wallet->isDeterministic()) { QMessageBox::information(this, "Information", "Wallet is non-deterministic and has no seed.\n\nTo obtain wallet keys go to Wallet -> Keys"); return; } - auto *dialog = new SeedDialog(m_ctx->currentWallet, this); - dialog->exec(); - dialog->deleteLater(); + SeedDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::showConnectionStatusDialog() { - auto status = m_ctx->currentWallet->connectionStatus(); - bool synchronized = m_ctx->currentWallet->isSynchronized(); + auto status = m_ctx->wallet->connectionStatus(); + bool synchronized = m_ctx->wallet->isSynchronized(); QString statusMsg; switch(status){ @@ -866,27 +685,26 @@ void MainWindow::showConnectionStatusDialog() { statusMsg = "Unknown connection status (this should never happen)."; } - statusMsg += QString("\n\nTx: %1, Rx: %2").arg(Utils::formatBytes(m_ctx->currentWallet->getBytesSent()), - Utils::formatBytes(m_ctx->currentWallet->getBytesReceived())); + statusMsg += QString("\n\nTx: %1, Rx: %2").arg(Utils::formatBytes(m_ctx->wallet->getBytesSent()), + Utils::formatBytes(m_ctx->wallet->getBytesReceived())); QMessageBox::information(this, "Connection Status", statusMsg); } void MainWindow::showPasswordDialog() { - auto *pdialog = new PasswordChangeDialog(this, m_ctx->currentWallet); - pdialog->exec(); - pdialog->deleteLater(); + PasswordChangeDialog dialog{this, m_ctx->wallet.get()}; + dialog.exec(); this->updatePasswordIcon(); } void MainWindow::updatePasswordIcon() { - QIcon icon = m_ctx->currentWallet->getPassword().isEmpty() ? icons()->icon("unlock.svg") : icons()->icon("lock.svg"); + QIcon icon = m_ctx->wallet->getPassword().isEmpty() ? icons()->icon("unlock.svg") : icons()->icon("lock.svg"); m_statusBtnPassword->setIcon(icon); } void MainWindow::showRestoreHeightDialog() { // settings custom restore height is only available for 25 word seeds - auto seed = m_ctx->currentWallet->getCacheAttribute("feather.seed"); + auto seed = m_ctx->wallet->getCacheAttribute("feather.seed"); if(!seed.isEmpty()) { const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; QMessageBox::warning(this, "Cannot set custom restore height", msg); @@ -910,20 +728,18 @@ void MainWindow::showRestoreHeightDialog() { } void MainWindow::showKeysDialog() { - auto *dialog = new KeysDialog(m_ctx, this); - dialog->exec(); - dialog->deleteLater(); + KeysDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::showViewOnlyDialog() { - auto *dialog = new ViewOnlyDialog(m_ctx, this); - dialog->exec(); - dialog->deleteLater(); + ViewOnlyDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::menuTorClicked() { - auto *dialog = new TorInfoDialog(this, m_ctx); - connect(dialog, &TorInfoDialog::torSettingsChanged, m_ctx, &AppContext::onTorSettingsChanged); + auto *dialog = new TorInfoDialog(m_ctx, this); + connect(dialog, &TorInfoDialog::torSettingsChanged, m_windowManager, &WindowManager::onTorSettingsChanged); dialog->exec(); dialog->deleteLater(); } @@ -932,20 +748,21 @@ void MainWindow::menuHwDeviceClicked() { QMessageBox::information(this, "Hardware Device", QString("This wallet is backed by a %1 hardware device.").arg(this->getHardwareDevice())); } +void MainWindow::menuOpenClicked() { + m_windowManager->wizardOpenWallet(); +} + void MainWindow::menuNewRestoreClicked() { - // TODO: implement later + m_windowManager->showWizard(WalletWizard::Page_Menu); } void MainWindow::menuQuitClicked() { - cleanupBeforeClose(); - QCoreApplication::quit(); + this->close(); } void MainWindow::menuWalletCloseClicked() { - if (m_ctx->currentWallet == nullptr) - return; - - m_ctx->closeWallet(true, true); + m_windowManager->showWizard(WalletWizard::Page_Menu); + this->close(); } void MainWindow::menuAboutClicked() { @@ -960,24 +777,17 @@ void MainWindow::menuSettingsClicked() { } void MainWindow::menuSignVerifyClicked() { - SignVerifyDialog dialog{m_ctx->currentWallet, this}; + SignVerifyDialog dialog{m_ctx->wallet.get(), this}; dialog.exec(); } void MainWindow::menuVerifyTxProof() { - VerifyProofDialog dialog{m_ctx->currentWallet, this}; + VerifyProofDialog dialog{m_ctx->wallet.get(), this}; dialog.exec(); } void MainWindow::skinChanged(const QString &skinName) { - if (!m_skins.contains(skinName)) { - qWarning() << QString("No such skin %1").arg(skinName); - return; - } - - config()->set(Config::skin, skinName); - qApp->setStyleSheet(m_skins[skinName]); - qDebug() << QString("Skin changed to %1").arg(skinName); + m_windowManager->changeSkin(skinName); ColorScheme::updateFromWidget(this); #ifdef HAS_LOCALMONERO @@ -988,17 +798,27 @@ void MainWindow::skinChanged(const QString &skinName) { } void MainWindow::closeEvent(QCloseEvent *event) { - cleanupBeforeClose(); + qDebug() << Q_FUNC_INFO; - QWidget::closeEvent(event); + if (!this->cleanedUp) { + this->cleanedUp = true; + + m_updateBytes.stop(); + m_txTimer.stop(); + + this->saveGeo(); + m_windowManager->closeWindow(this); + } + + event->accept(); } void MainWindow::donateButtonClicked() { - double donation = appData()->prices.convert("EUR", "XMR", globals::donationAmount); + double donation = appData()->prices.convert("EUR", "XMR", constants::donationAmount); if (donation <= 0) donation = 0.1337; - m_sendWidget->fill(globals::donationAddress, "Donation to the Feather development team", donation); + m_sendWidget->fill(constants::donationAddress, "Donation to the Feather development team", donation); ui->tabWidget->setCurrentIndex(Tabs::SEND); } @@ -1031,12 +851,12 @@ void MainWindow::showSendScreen(const CCSEntry &entry) { } void MainWindow::onViewOnBlockExplorer(const QString &txid) { - QString blockExplorerLink = Utils::blockExplorerLink(config()->get(Config::blockExplorer).toString(), m_ctx->networkType, txid); + QString blockExplorerLink = Utils::blockExplorerLink(config()->get(Config::blockExplorer).toString(), constants::networkType, txid); Utils::externalLinkWarning(this, blockExplorerLink); } void MainWindow::onResendTransaction(const QString &txid) { - if (!AppContext::txCache.contains(txid)) { + if (!m_ctx->txCache.contains(txid)) { QMessageBox::warning(this, "Unable to resend transaction", "Transaction was not found in transaction cache. Unable to resend."); return; } @@ -1044,23 +864,22 @@ void MainWindow::onResendTransaction(const QString &txid) { // Connect to a different node so chances of successful relay are higher m_ctx->nodes->autoConnect(true); - auto dialog = new BroadcastTxDialog(this, m_ctx, AppContext::txCache[txid]); - dialog->exec(); - dialog->deleteLater(); + BroadcastTxDialog dialog{this, m_ctx, m_ctx->txCache[txid]}; + dialog.exec(); } void MainWindow::importContacts() { const QString targetFile = QFileDialog::getOpenFileName(this, "Import CSV file", QDir::homePath(), "CSV Files (*.csv)"); if(targetFile.isEmpty()) return; - auto *model = m_ctx->currentWallet->addressBookModel(); + auto *model = m_ctx->wallet->addressBookModel(); QMapIterator i(model->readCSV(targetFile)); int inserts = 0; while (i.hasNext()) { i.next(); - bool addressValid = WalletManager::addressValid(i.value(), m_ctx->currentWallet->nettype()); + bool addressValid = WalletManager::addressValid(i.value(), m_ctx->wallet->nettype()); if(addressValid) { - m_ctx->currentWallet->addressBook()->addRow(i.value(), "", i.key()); + m_ctx->wallet->addressBook()->addRow(i.value(), "", i.key()); inserts++; } } @@ -1068,22 +887,6 @@ void MainWindow::importContacts() { QMessageBox::information(this, "Contacts imported", QString("Total contacts imported: %1").arg(inserts)); } -QString MainWindow::loadStylesheet(const QString &resource) { - QFile f(resource); - if (!f.exists()) { - printf("Unable to set stylesheet, file not found\n"); - f.close(); - return ""; - } - - f.open(QFile::ReadOnly | QFile::Text); - QTextStream ts(&f); - QString data = ts.readAll(); - f.close(); - - return data; -} - void MainWindow::saveGeo() { config()->set(Config::geometry, QString(saveGeometry().toBase64())); config()->set(Config::windowState, QString(saveState().toBase64())); @@ -1096,15 +899,13 @@ void MainWindow::restoreGeo() { } void MainWindow::showDebugInfo() { - auto *dialog = new DebugInfoDialog(m_ctx, this); - dialog->exec(); - dialog->deleteLater(); + DebugInfoDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::showWalletCacheDebugDialog() { - auto *dialog = new WalletCacheDebugDialog(m_ctx, this); - dialog->exec(); - dialog->deleteLater(); + WalletCacheDebugDialog dialog{m_ctx, this}; + dialog.exec(); } void MainWindow::showNodeExhaustedMessage() { @@ -1127,8 +928,8 @@ void MainWindow::exportKeyImages() { QString fn = QFileDialog::getSaveFileName(this, "Save key images to file", QDir::homePath(), "Key Images (*_keyImages)"); if (fn.isEmpty()) return; if (!fn.endsWith("_keyImages")) fn += "_keyImages"; - m_ctx->currentWallet->exportKeyImages(fn, true); - auto err = m_ctx->currentWallet->errorString(); + m_ctx->wallet->exportKeyImages(fn, true); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Key image export", QString("Failed to export key images.\nReason: %1").arg(err)); } else { @@ -1139,8 +940,8 @@ void MainWindow::exportKeyImages() { void MainWindow::importKeyImages() { QString fn = QFileDialog::getOpenFileName(this, "Import key image file", QDir::homePath(), "Key Images (*_keyImages)"); if (fn.isEmpty()) return; - m_ctx->currentWallet->importKeyImages(fn); - auto err = m_ctx->currentWallet->errorString(); + m_ctx->wallet->importKeyImages(fn); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Key image import", QString("Failed to import key images.\n\n%1").arg(err)); } else { @@ -1153,8 +954,8 @@ void MainWindow::exportOutputs() { QString fn = QFileDialog::getSaveFileName(this, "Save outputs to file", QDir::homePath(), "Outputs (*_outputs)"); if (fn.isEmpty()) return; if (!fn.endsWith("_outputs")) fn += "_outputs"; - m_ctx->currentWallet->exportOutputs(fn, true); - auto err = m_ctx->currentWallet->errorString(); + m_ctx->wallet->exportOutputs(fn, true); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Outputs export", QString("Failed to export outputs.\nReason: %1").arg(err)); } else { @@ -1165,8 +966,8 @@ void MainWindow::exportOutputs() { void MainWindow::importOutputs() { QString fn = QFileDialog::getOpenFileName(this, "Import outputs file", QDir::homePath(), "Outputs (*_outputs)"); if (fn.isEmpty()) return; - m_ctx->currentWallet->importOutputs(fn); - auto err = m_ctx->currentWallet->errorString(); + m_ctx->wallet->importOutputs(fn); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Outputs import", QString("Failed to import outputs.\n\n%1").arg(err)); } else { @@ -1175,17 +976,11 @@ void MainWindow::importOutputs() { } } -void MainWindow::cleanupBeforeClose() { - m_ctx->closeWallet(false, true); - torManager()->stop(); - this->saveGeo(); -} - void MainWindow::loadUnsignedTx() { QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*unsigned_monero_tx)"); if (fn.isEmpty()) return; - UnsignedTransaction *tx = m_ctx->currentWallet->loadTxFile(fn); - auto err = m_ctx->currentWallet->errorString(); + UnsignedTransaction *tx = m_ctx->wallet->loadTxFile(fn); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Load transaction from file", QString("Failed to load transaction.\n\n%1").arg(err)); return; @@ -1200,8 +995,8 @@ void MainWindow::loadUnsignedTxFromClipboard() { QMessageBox::warning(this, "Load unsigned transaction from clipboard", "Clipboard is empty"); return; } - UnsignedTransaction *tx = m_ctx->currentWallet->loadTxFromBase64Str(unsigned_tx); - auto err = m_ctx->currentWallet->errorString(); + UnsignedTransaction *tx = m_ctx->wallet->loadTxFromBase64Str(unsigned_tx); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Load unsigned transaction from clipboard", QString("Failed to load transaction.\n\n%1").arg(err)); return; @@ -1213,34 +1008,30 @@ void MainWindow::loadUnsignedTxFromClipboard() { void MainWindow::loadSignedTx() { QString fn = QFileDialog::getOpenFileName(this, "Select transaction to load", QDir::homePath(), "Transaction (*signed_monero_tx)"); if (fn.isEmpty()) return; - PendingTransaction *tx = m_ctx->currentWallet->loadSignedTxFile(fn); - auto err = m_ctx->currentWallet->errorString(); + PendingTransaction *tx = m_ctx->wallet->loadSignedTxFile(fn); + auto err = m_ctx->wallet->errorString(); if (!err.isEmpty()) { QMessageBox::warning(this, "Load signed transaction from file", err); return; } - auto *dialog = new TxConfAdvDialog(m_ctx, "", this); - dialog->setTransaction(tx); - dialog->exec(); - dialog->deleteLater(); + TxConfAdvDialog dialog{m_ctx, "", this}; + dialog.setTransaction(tx); + dialog.exec(); } void MainWindow::loadSignedTxFromText() { - auto dialog = new BroadcastTxDialog(this, m_ctx); - dialog->exec(); - dialog->deleteLater(); + BroadcastTxDialog dialog{this, m_ctx}; + dialog.exec(); } void MainWindow::createUnsignedTxDialog(UnsignedTransaction *tx) { - auto *dialog = new TxConfAdvDialog(m_ctx, "", this); - dialog->setUnsignedTransaction(tx); - dialog->exec(); - dialog->deleteLater(); + TxConfAdvDialog dialog{m_ctx, "", this}; + dialog.setUnsignedTransaction(tx); + dialog.exec(); } void MainWindow::importTransaction() { - if (config()->get(Config::torPrivacyLevel).toInt() == Config::allTorExceptNode) { // TODO: don't show if connected to local node @@ -1253,9 +1044,8 @@ void MainWindow::importTransaction() { } } - auto *dialog = new TxImportDialog(this, m_ctx); - dialog->exec(); - dialog->deleteLater(); + TxImportDialog dialog(this, m_ctx); + dialog.exec(); } void MainWindow::onDeviceError(const QString &error) { @@ -1267,56 +1057,52 @@ void MainWindow::onDeviceError(const QString &error) { m_showDeviceError = true; auto result = QMessageBox::question(this, "Hardware device", "Lost connection to hardware device. Attempt to reconnect?"); if (result == QMessageBox::Yes) { - bool r = m_ctx->currentWallet->reconnectDevice(); + bool r = m_ctx->wallet->reconnectDevice(); if (r) { break; } } - if (result == QMessageBox::No){ - m_ctx->closeWallet(true); + if (result == QMessageBox::No) { + this->menuWalletCloseClicked(); return; } } m_statusBtnHwDevice->setIcon(icons()->icon("ledger.png")); - m_ctx->currentWallet->startRefresh(); + m_ctx->wallet->startRefresh(); m_showDeviceError = false; } void MainWindow::updateNetStats() { - if (m_ctx->currentWallet == nullptr) { + if (m_ctx->wallet == nullptr) { m_statusLabelNetStats->setText(""); return; } - if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) { + if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) { m_statusLabelNetStats->setText(""); return; } - if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized) { + if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized) { m_statusLabelNetStats->setText(""); return; } - m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_ctx->currentWallet->getBytesReceived()))); + m_statusLabelNetStats->setText(QString("(D: %1)").arg(Utils::formatBytes(m_ctx->wallet->getBytesReceived()))); } void MainWindow::rescanSpent() { - if (!m_ctx->currentWallet->rescanSpent()) { - QMessageBox::warning(this, "Rescan spent", m_ctx->currentWallet->errorString()); + if (!m_ctx->wallet->rescanSpent()) { + QMessageBox::warning(this, "Rescan spent", m_ctx->wallet->errorString()); } else { QMessageBox::information(this, "Rescan spent", "Successfully rescanned spent outputs."); } } void MainWindow::showBalanceDialog() { - if (!m_ctx->currentWallet) { - return; - } - auto *dialog = new BalanceDialog(this, m_ctx->currentWallet); - dialog->exec(); - dialog->deleteLater(); + BalanceDialog dialog{this, m_ctx->wallet.get()}; + dialog.exec(); } QString MainWindow::statusDots() { @@ -1325,6 +1111,13 @@ QString MainWindow::statusDots() { return QString(".").repeated(m_statusDots); } +void MainWindow::showOrHide() { + if (this->isHidden()) + this->bringToFront(); + else + this->hide(); +} + void MainWindow::bringToFront() { ensurePolished(); setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); @@ -1333,12 +1126,11 @@ void MainWindow::bringToFront() { activateWindow(); } -void MainWindow::onInitialNetworkConfigured() { - m_ctx->onInitialNetworkConfigured(); - - connect(torManager(), &TorManager::connectionStateChanged, [this](bool connected){ - connected ? m_statusBtnTor->setIcon(icons()->icon("tor_logo.png")) - : m_statusBtnTor->setIcon(icons()->icon("tor_logo_disabled.png"));}); +void MainWindow::onTorConnectionStateChanged(bool connected) { + if (connected) + m_statusBtnTor->setIcon(icons()->icon("tor_logo.png")); + else + m_statusBtnTor->setIcon(icons()->icon("tor_logo_disabled.png")); } void MainWindow::onCheckUpdatesComplete(const QString &version, const QString &binaryFilename, @@ -1361,7 +1153,7 @@ void MainWindow::onShowUpdateCheck(const QString &version, const QString &binary QString downloadUrl = QString("https://featherwallet.org/files/releases/%1/%2").arg(this->getPlatformTag(), binaryFilename); UpdateDialog updateDialog{this, version, downloadUrl, hash, signer}; - connect(&updateDialog, &UpdateDialog::restartWallet, this, &MainWindow::onRestartApplication); + connect(&updateDialog, &UpdateDialog::restartWallet, m_windowManager, &WindowManager::restartApplication); updateDialog.exec(); } @@ -1389,7 +1181,7 @@ void MainWindow::onUpdatesAvailable(const QJsonObject &updates) { // Hooray! New update available - QString hashesUrl = QString("%1/files/releases/hashes-%2-plain.txt").arg(globals::websiteUrl, newVersion); + QString hashesUrl = QString("%1/files/releases/hashes-%2-plain.txt").arg(constants::websiteUrl, newVersion); UtilsNetworking network{getNetworkTor()}; QNetworkReply *reply = network.get(hashesUrl); @@ -1440,7 +1232,7 @@ void MainWindow::onInitiateTransaction() { m_constructingTransaction = true; m_txTimer.start(1000); - if (m_ctx->currentWallet->isHwBacked()) { + if (m_ctx->wallet->isHwBacked()) { QString message = "Constructing transaction: action may be required on device."; m_splashDialog->setMessage(message); m_splashDialog->setIcon(QPixmap(":/assets/images/unconfirmed.png")); @@ -1455,7 +1247,7 @@ void MainWindow::onEndTransaction() { m_txTimer.stop(); this->setStatusText(m_statusText); - if (m_ctx->currentWallet->isHwBacked()) { + if (m_ctx->wallet->isHwBacked()) { m_splashDialog->hide(); } } @@ -1467,34 +1259,21 @@ void MainWindow::onCustomRestoreHeightSet(int height) { this->menuQuitClicked(); } -void MainWindow::onWalletAboutToClose() { - if (!config()->get(Config::showTabHome).toBool()) - ui->tabWidget->setCurrentIndex(Tabs::HISTORY); - else - ui->tabWidget->setCurrentIndex(Tabs::HOME); - - // Clear all tables when wallet is closed - ui->historyWidget->resetModel(); - ui->contactWidget->resetModel(); - ui->receiveWidget->resetModel(); - m_coinsWidget->resetModel(); -} - void MainWindow::onExportHistoryCSV(bool checked) { - if (m_ctx->currentWallet == nullptr) + if (m_ctx->wallet == nullptr) return; QString fn = QFileDialog::getSaveFileName(this, "Save CSV file", QDir::homePath(), "CSV (*.csv)"); if (fn.isEmpty()) return; if (!fn.endsWith(".csv")) fn += ".csv"; - m_ctx->currentWallet->history()->writeCSV(fn); + m_ctx->wallet->history()->writeCSV(fn); QMessageBox::information(this, "CSV export", QString("Transaction history exported to %1").arg(fn)); } void MainWindow::onExportContactsCSV(bool checked) { - if (m_ctx->currentWallet == nullptr) return; - auto *model = m_ctx->currentWallet->addressBookModel(); + if (m_ctx->wallet == nullptr) return; + auto *model = m_ctx->wallet->addressBookModel(); if (model->rowCount() <= 0){ QMessageBox::warning(this, "Error", "Addressbook empty"); return; @@ -1524,13 +1303,6 @@ void MainWindow::onReportBug(bool checked) { "Try to explain not only what the bug is, but how it occurs."); } -void MainWindow::onRestartApplication(const QString &binaryFilename) { - QProcess::startDetached(binaryFilename, qApp->arguments()); - - this->cleanupBeforeClose(); - QCoreApplication::quit(); -} - QString MainWindow::getPlatformTag() { #ifdef Q_OS_MACOS return "mac"; @@ -1548,19 +1320,18 @@ QString MainWindow::getPlatformTag() { } QString MainWindow::getHardwareDevice() { - if (!m_ctx->currentWallet->isHwBacked()) + if (!m_ctx->wallet->isHwBacked()) return ""; - if (m_ctx->currentWallet->isTrezor()) + if (m_ctx->wallet->isTrezor()) return "Trezor"; - if (m_ctx->currentWallet->isLedger()) + if (m_ctx->wallet->isLedger()) return "Ledger"; return "Unknown"; } void MainWindow::setTitle(bool mining) { - QFileInfo fileInfo(m_ctx->walletPath); - auto title = QString("Feather - [%1]").arg(fileInfo.fileName()); - if (m_ctx->currentWallet && m_ctx->currentWallet->viewOnly()) + auto title = QString("Feather - [%1]").arg(this->walletName()); + if (m_ctx->wallet && m_ctx->wallet->viewOnly()) title += " [view-only]"; if (mining) title += " [mining]"; @@ -1568,6 +1339,58 @@ void MainWindow::setTitle(bool mining) { this->setWindowTitle(title); } +void MainWindow::donationNag() { + if (m_ctx->networkType != NetworkType::Type::MAINNET) + return; + + if (m_ctx->wallet->viewOnly()) + return; + + auto donationCounter = config()->get(Config::donateBeg).toInt(); + if (donationCounter == -1) + return; + + donationCounter++; + if (donationCounter % constants::donationBoundary == 0) { + auto msg = "Feather is a 100% community-sponsored endeavor. Please consider supporting " + "the project financially. Get rid of this message by donating any amount."; + int ret = QMessageBox::information(this, "Donate to Feather", msg, QMessageBox::Yes, QMessageBox::No); + if (ret == QMessageBox::Yes) { + this->donateButtonClicked(); + } + } + config()->set(Config::donateBeg, donationCounter); +} + +void MainWindow::updateRecentlyOpened(const QString &keysFile) { + auto recent = config()->get(Config::recentlyOpenedWallets).toList(); + + if (recent.contains(keysFile)) { + recent.removeOne(keysFile); + } + recent.insert(0, keysFile); + + QList recent_; + int count = 0; + for (const auto &file : recent) { + if (Utils::fileExists(file.toString())) { + recent_.append(file); + count++; + } + if (count >= 5) { + break; + } + } + + config()->set(Config::recentlyOpenedWallets, recent_); + ui->menuRecently_open->clear(); + for (const auto &var : recent_) { + QString path = var.toString(); + QFileInfo fileInfo{path}; + ui->menuRecently_open->addAction(fileInfo.fileName(), m_windowManager, std::bind(&WindowManager::tryOpenWallet, m_windowManager, path, "")); + } +} + MainWindow::~MainWindow() { delete ui; } diff --git a/src/mainwindow.h b/src/mainwindow.h index a32e2ad8..e59e4aee 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -36,9 +36,14 @@ #include "widgets/tickerwidget.h" #include "wizard/WalletWizard.h" +#include "contactswidget.h" +#include "historywidget.h" #include "sendwidget.h" +#include "receivewidget.h" #include "coinswidget.h" +#include "WindowManager.h" + #ifdef HAS_LOCALMONERO #include "widgets/LocalMoneroWidget.h" #endif @@ -47,10 +52,6 @@ #include "widgets/xmrigwidget.h" #endif -#ifdef Q_OS_MAC -#include "src/kdmactouchbar.h" -#endif - namespace Ui { class MainWindow; } @@ -65,14 +66,19 @@ struct ToggleTab { Config::ConfigKey configKey; }; +class WindowManager; class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr); + explicit MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent = nullptr); ~MainWindow() override; + QString walletName(); + QString walletCachePath(); + QString walletKeysPath(); + enum Tabs { HOME = 0, HISTORY, @@ -89,44 +95,29 @@ public: REDDIT }; -public slots: - void showWizard(WalletWizard::Page startPage); + void showOrHide(); + void bringToFront(); + +signals: + void closed(); + +private slots: + // TODO: use a consistent naming convention for slots + // Menu + void menuOpenClicked(); void menuNewRestoreClicked(); void menuQuitClicked(); void menuSettingsClicked(); void menuAboutClicked(); void menuSignVerifyClicked(); void menuVerifyTxProof(); - void showWalletInfoDialog(); - void showSeedDialog(); - void showConnectionStatusDialog(); - void showPasswordDialog(); - void showKeysDialog(); - void showViewOnlyDialog(); - void donateButtonClicked(); - void showCalcWindow(); - void payToMany(); - void showWalletCacheDebugDialog(); - void showSendTab(); - void showHistoryTab(); - void showSendScreen(const CCSEntry &entry); - void skinChanged(const QString &skinName); - void menuTorClicked(); - void onBlockchainSync(int height, int target); - void onRefreshSync(int height, int target); - void onWalletOpenedError(const QString &err); - void onWalletCreatedError(const QString &err); void menuWalletCloseClicked(); - void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); - void onDeviceButtonRequest(quint64 code); - void onViewOnBlockExplorer(const QString &txid); - void onResendTransaction(const QString &txid); - void importContacts(); - void showRestoreHeightDialog(); - void importTransaction(); - void onDeviceError(const QString &error); - void menuHwDeviceClicked(); - void onUpdatesAvailable(const QJsonObject &updates); + void menuTorClicked(); + void menuToggleTabVisible(const QString &key); + void onExportHistoryCSV(bool checked); + void onExportContactsCSV(bool checked); + void onCreateDesktopEntry(bool checked); + void onReportBug(bool checked); // offline tx signing void exportKeyImages(); @@ -138,97 +129,99 @@ public slots: void loadSignedTx(); void loadSignedTxFromText(); - // libwalletqt - void onBalanceUpdated(quint64 balance, quint64 spendable); - void onSynchronized(); - void onWalletOpened(); - void onWalletClosed(WalletWizard::Page page = WalletWizard::Page_Menu); - void onConnectionStatusChanged(int status); - void onCreateTransactionError(const QString &message); - void onCreateTransactionSuccess(PendingTransaction *tx, const QVector &address); - void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); - -signals: - void closed(); - -private slots: - void onInitialNetworkConfigured(); + void onTorConnectionStateChanged(bool connected); void onCheckUpdatesComplete(const QString &version, const QString &binaryFilename, const QString &hash, const QString &signer); void onShowUpdateCheck(const QString &version, const QString &binaryFilename, const QString &hash, const QString &signer); - void onRestartApplication(const QString &binaryFilename); void onSignedHashesReceived(QNetworkReply *reply, const QString &platformTag, const QString &version); void onShowDonationNag(); void onInitiateTransaction(); void onEndTransaction(); void onCustomRestoreHeightSet(int height); - void onWalletAboutToClose(); - // Menu - void onExportHistoryCSV(bool checked); - void onExportContactsCSV(bool checked); - void onCreateDesktopEntry(bool checked); - void onReportBug(bool checked); + // libwalletqt + void onBalanceUpdated(quint64 balance, quint64 spendable); + void onSynchronized(); + void onWalletOpened(); + void onConnectionStatusChanged(int status); + void onCreateTransactionError(const QString &message); + void onCreateTransactionSuccess(PendingTransaction *tx, const QVector &address); + void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); + + // Dialogs + void showWalletInfoDialog(); + void showSeedDialog(); + void showConnectionStatusDialog(); + void showPasswordDialog(); + void showKeysDialog(); + void showViewOnlyDialog(); + void showWalletCacheDebugDialog(); + + void donateButtonClicked(); + void showCalcWindow(); + void payToMany(); + void showSendTab(); + void showHistoryTab(); + void showSendScreen(const CCSEntry &entry); + void skinChanged(const QString &skinName); + void onBlockchainSync(int height, int target); + void onRefreshSync(int height, int target); + void onViewOnBlockExplorer(const QString &txid); + void onResendTransaction(const QString &txid); + void importContacts(); + void showRestoreHeightDialog(); + void importTransaction(); + void onDeviceError(const QString &error); + void menuHwDeviceClicked(); + void onUpdatesAvailable(const QJsonObject &updates); private: - void initSkins(); void initStatusBar(); void initWidgets(); void initMenu(); - void initTray(); void initHome(); - void initTouchBar(); void initWalletContext(); - void initWizard(); void startupWarning(); - bool autoOpenWallet(); void closeEvent(QCloseEvent *event) override; - void cleanupBeforeClose(); - QString loadStylesheet(const QString &resource); + void saveGeo(); void restoreGeo(); void showDebugInfo(); void showNodeExhaustedMessage(); void showWSNodeExhaustedMessage(); void createUnsignedTxDialog(UnsignedTransaction *tx); - void touchbarShowWizard(); - void touchbarShowWallet(); void updatePasswordIcon(); void updateNetStats(); void rescanSpent(); void setStatusText(const QString &text, bool override = false, int timeout = 1000); void showBalanceDialog(); QString statusDots(); - void bringToFront(); QString getPlatformTag(); void displayWalletErrorMsg(const QString &err); QString getHardwareDevice(); void setTitle(bool mining); - - WalletWizard *createWizard(WalletWizard::Page startPage); + void donationNag(); + void updateRecentlyOpened(const QString &filename); Ui::MainWindow *ui; - AppContext *m_ctx; + WindowManager *m_windowManager; + QSharedPointer m_ctx; Settings *m_windowSettings = nullptr; CalcWindow *m_windowCalc = nullptr; RestoreDialog *m_restoreDialog = nullptr; - XMRigWidget *m_xmrig = nullptr; SplashDialog *m_splashDialog = nullptr; + XMRigWidget *m_xmrig = nullptr; + ContactsWidget *m_contactsWidget = nullptr; + HistoryWidget *m_historyWidget = nullptr; SendWidget *m_sendWidget = nullptr; + ReceiveWidget *m_receiveWidget = nullptr; CoinsWidget *m_coinsWidget = nullptr; #ifdef HAS_LOCALMONERO LocalMoneroWidget *m_localMoneroWidget = nullptr; #endif - QSystemTrayIcon *m_trayIcon; - QMenu m_trayMenu; - QAction *m_trayActionCalc; - QAction *m_trayActionExit; - QAction *m_trayActionSend; - QAction *m_trayActionHistory; - QList m_tickerWidgets; TickerWidget *m_balanceWidget; @@ -244,18 +237,8 @@ private: StatusBarButton *m_statusBtnTor; StatusBarButton *m_statusBtnHwDevice; -#ifdef Q_OS_MAC - QAction *m_touchbarActionWelcome; - KDMacTouchBar *m_touchbar; - QList m_touchbarWalletItems; - QList m_touchbarWizardItems; -#endif - QSignalMapper *m_tabShowHideSignalMapper; QMap m_tabShowHideMapper; - WalletWizard *m_wizard = nullptr; - - QMap m_skins; QTimer m_updateBytes; @@ -266,8 +249,7 @@ private: bool m_showDeviceError = false; QTimer m_txTimer; -private slots: - void menuToggleTabVisible(const QString &key); + bool cleanedUp = false; }; #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0b385454..5d503c85 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -161,8 +161,8 @@ 9 - - + + @@ -208,14 +208,7 @@ - - - - 0 - 0 - - - + @@ -229,7 +222,7 @@ - + @@ -349,6 +342,14 @@ File + + + Recently open + + + + + @@ -548,7 +549,7 @@ - Close current wallet + Close wallet @@ -721,26 +722,29 @@ Pay to many + + + Open wallet + + + + + New/Restore + + + + + Recently open + + + + + t + + - - ContactsWidget - QWidget -
contactswidget.h
- 1 -
- - ReceiveWidget - QWidget -
receivewidget.h
- 1 -
- - HistoryWidget - QWidget -
historywidget.h
-
CalcWidget QWidget diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp index 83c4471e..1e7d5255 100644 --- a/src/model/CoinsModel.cpp +++ b/src/model/CoinsModel.cpp @@ -5,7 +5,7 @@ #include "CoinsInfo.h" #include "Coins.h" #include "ModelUtils.h" -#include "globals.h" +#include "constants.h" #include "utils/ColorScheme.h" #include "utils/Icons.h" @@ -182,9 +182,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in case Amount: { if (role == Qt::UserRole) { - return cInfo.amount() / globals::cdiv; + return cInfo.amount() / constants::cdiv; } - return QString::number(cInfo.amount() / globals::cdiv, 'f', 12); + return QString::number(cInfo.amount() / constants::cdiv, 'f', 12); } case Frozen: return cInfo.frozen(); diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp index db0d7993..2991d095 100644 --- a/src/model/TransactionHistoryModel.cpp +++ b/src/model/TransactionHistoryModel.cpp @@ -4,7 +4,7 @@ #include "TransactionHistoryModel.h" #include "TransactionHistory.h" #include "TransactionInfo.h" -#include "globals.h" +#include "constants.h" #include "utils/config.h" #include "utils/ColorScheme.h" #include "utils/Icons.h" @@ -147,7 +147,7 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI if (role == Qt::UserRole) { return tInfo.balanceDelta(); } - QString amount = QString::number(tInfo.balanceDelta() / globals::cdiv, 'f', this->amountPrecision); + QString amount = QString::number(tInfo.balanceDelta() / constants::cdiv, 'f', this->amountPrecision); amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount; return amount; } @@ -160,7 +160,7 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI if (usd_price == 0.0) return QVariant("?"); - double usd_amount = usd_price * (tInfo.balanceDelta() / globals::cdiv); + double usd_amount = usd_price * (tInfo.balanceDelta() / constants::cdiv); if(this->preferredFiatSymbol != "USD") usd_amount = appData()->prices.convert("USD", this->preferredFiatSymbol, usd_amount); if (role == Qt::UserRole) { diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index f40b8816..0f5373e6 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -10,12 +10,31 @@ #include #include -ReceiveWidget::ReceiveWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::ReceiveWidget) +ReceiveWidget::ReceiveWidget(QSharedPointer ctx, QWidget *parent) + : QWidget(parent) + , ui(new Ui::ReceiveWidget) + , m_ctx(std::move(ctx)) { ui->setupUi(this); + m_model = m_ctx->wallet->subaddressModel(); + m_proxyModel = new SubaddressProxyModel(this, m_ctx->wallet->subaddress()); + m_proxyModel->setSourceModel(m_model); + m_proxyModel->setHiddenAddresses(this->getHiddenAddresses()); + + ui->addresses->setModel(m_proxyModel); + ui->addresses->setColumnHidden(SubaddressModel::isUsed, true); + ui->addresses->header()->setSectionResizeMode(SubaddressModel::Address, QHeaderView::Stretch); + ui->addresses->header()->setSectionResizeMode(SubaddressModel::Label, QHeaderView::ResizeToContents); + ui->addresses->header()->setMinimumSectionSize(200); + + connect(ui->addresses->selectionModel(), &QItemSelectionModel::currentChanged, [=](QModelIndex current, QModelIndex prev){ + this->updateQrCode(); + }); + connect(m_model, &SubaddressModel::modelReset, [this](){ + this->updateQrCode(); + }); + // header context menu ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu); m_headerMenu = new QMenu(this); @@ -40,29 +59,6 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) : connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); } -void ReceiveWidget::setModel(SubaddressModel * model, Wallet * wallet) { - m_wallet = wallet; - m_subaddress = wallet->subaddress(); - m_model = model; - m_proxyModel = new SubaddressProxyModel(this, m_subaddress); - m_proxyModel->setSourceModel(m_model); - m_proxyModel->setHiddenAddresses(this->getHiddenAddresses()); - - ui->addresses->setModel(m_proxyModel); - - ui->addresses->setColumnHidden(SubaddressModel::isUsed, true); - ui->addresses->header()->setSectionResizeMode(SubaddressModel::Address, QHeaderView::Stretch); - ui->addresses->header()->setSectionResizeMode(SubaddressModel::Label, QHeaderView::ResizeToContents); - ui->addresses->header()->setMinimumSectionSize(200); - - connect(ui->addresses->selectionModel(), &QItemSelectionModel::currentChanged, [=](QModelIndex current, QModelIndex prev){ - this->updateQrCode(); - }); - connect(m_model, &SubaddressModel::modelReset, [this](){ - this->updateQrCode(); - }); -} - void ReceiveWidget::copyAddress() { QModelIndex index = ui->addresses->currentIndex(); ModelUtils::copyColumn(&index, SubaddressModel::Address); @@ -103,7 +99,7 @@ void ReceiveWidget::showContextMenu(const QPoint &point) { menu->addAction("Hide address", this, &ReceiveWidget::hideAddress); } - if (m_wallet->isHwBacked()) { + if (m_ctx->wallet->isHwBacked()) { menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice); } @@ -172,15 +168,13 @@ void ReceiveWidget::showAddress() void ReceiveWidget::showOnDevice() { Monero::SubaddressRow* row = this->currentEntry(); if (!row) return; - m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRowId(), ""); + m_ctx->wallet->deviceShowAddressAsync(m_ctx->wallet->currentSubaddressAccount(), row->getRowId(), ""); } void ReceiveWidget::generateSubaddress() { - if (!m_wallet) return; - - bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), ""); + bool r = m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), ""); if (!r) { - QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_wallet->subaddress()->errorString())); + QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_ctx->wallet->subaddress()->errorString())); } } @@ -213,7 +207,7 @@ void ReceiveWidget::showQrCodeDialog() { } QStringList ReceiveWidget::getHiddenAddresses() { - QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses"); + QString data = m_ctx->wallet->getCacheAttribute("feather.hiddenaddresses"); return data.split(","); } @@ -223,14 +217,14 @@ void ReceiveWidget::addHiddenAddress(const QString& address) { hiddenAddresses.append(address); } QString data = hiddenAddresses.join(","); - m_wallet->setCacheAttribute("feather.hiddenaddresses", data); + m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data); } void ReceiveWidget::removeHiddenAddress(const QString &address) { QStringList hiddenAddresses = this->getHiddenAddresses(); hiddenAddresses.removeAll(address); QString data = hiddenAddresses.join(","); - m_wallet->setCacheAttribute("feather.hiddenaddresses", data); + m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data); } Monero::SubaddressRow* ReceiveWidget::currentEntry() { diff --git a/src/receivewidget.h b/src/receivewidget.h index da6285a1..308e8d52 100644 --- a/src/receivewidget.h +++ b/src/receivewidget.h @@ -22,11 +22,9 @@ class ReceiveWidget : public QWidget Q_OBJECT public: - explicit ReceiveWidget(QWidget *parent = nullptr); - void setModel(SubaddressModel * model, Wallet * wallet); + explicit ReceiveWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~ReceiveWidget() override; - public slots: void copyAddress(); void copyLabel(); @@ -51,14 +49,13 @@ private slots: private: Ui::ReceiveWidget *ui; + QSharedPointer m_ctx; QMenu *m_headerMenu; QAction *m_showFullAddressesAction; QAction *m_showUsedAddressesAction; QAction *m_showTransactionsAction; - Subaddress * m_subaddress; SubaddressModel * m_model; SubaddressProxyModel * m_proxyModel; - Wallet * m_wallet; void updateQrCode(); void showQrCodeDialog(); diff --git a/src/sendwidget.cpp b/src/sendwidget.cpp index 7c6eb3ba..d0c30b46 100644 --- a/src/sendwidget.cpp +++ b/src/sendwidget.cpp @@ -5,13 +5,13 @@ #include "sendwidget.h" #include "mainwindow.h" #include "ui_sendwidget.h" -#include "globals.h" +#include "constants.h" #include "utils/AppData.h" -SendWidget::SendWidget(AppContext *ctx, QWidget *parent) +SendWidget::SendWidget(QSharedPointer ctx, QWidget *parent) : QWidget(parent) , ui(new Ui::SendWidget) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); @@ -21,11 +21,10 @@ SendWidget::SendWidget(AppContext *ctx, QWidget *parent) QValidator *validator = new QRegExpValidator(rx, this); ui->lineAmount->setValidator(validator); - connect(m_ctx, &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction); - connect(m_ctx, &AppContext::endTransaction, this, &SendWidget::onEndTransaction); - connect(m_ctx, &AppContext::openAliasResolved, this, &SendWidget::onOpenAliasResolved); - connect(m_ctx, &AppContext::openAliasResolveError, this, &SendWidget::onOpenAliasResolveError); - connect(m_ctx, &AppContext::walletClosed, this, &SendWidget::onWalletClosed); + connect(m_ctx.get(), &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction); + connect(m_ctx.get(), &AppContext::endTransaction, this, &SendWidget::onEndTransaction); + connect(m_ctx.get(), &AppContext::openAliasResolved, this, &SendWidget::onOpenAliasResolved); + connect(m_ctx.get(), &AppContext::openAliasResolveError, this, &SendWidget::onOpenAliasResolveError); connect(ui->btnSend, &QPushButton::clicked, this, &SendWidget::sendClicked); connect(ui->btnClear, &QPushButton::clicked, this, &SendWidget::clearClicked); @@ -48,7 +47,7 @@ SendWidget::SendWidget(AppContext *ctx, QWidget *parent) "You will be able to review the transaction fee before the transaction is broadcast.\n\n" "To send all your balance, click the Max button to the right."); - ui->lineAddress->setNetType(m_ctx->networkType); + ui->lineAddress->setNetType(constants::networkType); this->setupComboBox(); } @@ -107,7 +106,7 @@ void SendWidget::fillAddress(const QString &address) { } void SendWidget::sendClicked() { - if (!m_ctx->currentWallet->isConnected()) { + if (!m_ctx->wallet->isConnected()) { QMessageBox::warning(this, "Error", "Unable to create transaction:\n\n" "Wallet is not connected to a node.\n" "Go to File -> Settings -> Node to manually connect to a node."); @@ -229,7 +228,7 @@ quint64 SendWidget::amount() { double SendWidget::amountDouble() { quint64 amount = this->amount(); - return amount / globals::cdiv; + return amount / constants::cdiv; } void SendWidget::onOpenAliasResolved(const QString &address, const QString &openAlias) { @@ -252,11 +251,6 @@ void SendWidget::payToMany() { ui->lineAddress->payToMany(); } -void SendWidget::onWalletClosed() { - this->clearFields(); - ui->btnSend->setEnabled(true); -} - void SendWidget::onInitiateTransaction() { ui->btnSend->setEnabled(false); } diff --git a/src/sendwidget.h b/src/sendwidget.h index 94b4163e..f4666db7 100644 --- a/src/sendwidget.h +++ b/src/sendwidget.h @@ -17,7 +17,7 @@ class SendWidget : public QWidget Q_OBJECT public: - explicit SendWidget(AppContext *ctx, QWidget *parent = nullptr); + explicit SendWidget(QSharedPointer ctx, QWidget *parent = nullptr); void fill(const CCSEntry &entry); void fill(const QString &address, const QString& description, double amount = 0); void fill(double amount); @@ -37,7 +37,6 @@ public slots: void updateConversionLabel(); void onOpenAliasResolveError(const QString &err); void onOpenAliasResolved(const QString &address, const QString &openAlias); - void onWalletClosed(); void onPreferredFiatCurrencyChanged(); void onInitiateTransaction(); @@ -48,7 +47,7 @@ private: double amountDouble(); Ui::SendWidget *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; quint64 amount(); double conversionAmount(); }; diff --git a/src/settings.cpp b/src/settings.cpp index 4be0ae2b..28433187 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -7,10 +7,10 @@ #include -Settings::Settings(AppContext *ctx, QWidget *parent) +Settings::Settings(QSharedPointer ctx, QWidget *parent) : QDialog(parent) , ui(new Ui::Settings) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); @@ -89,11 +89,12 @@ Settings::Settings(AppContext *ctx, QWidget *parent) // setup paths tab this->updatePaths(); connect(ui->btn_browseDefaultWalletDir, &QPushButton::clicked, [this]{ - QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", m_ctx->defaultWalletDir, QFileDialog::ShowDirsOnly); - if (walletDir.isEmpty()) return; - m_ctx->defaultWalletDir = walletDir; + QString walletDirOld = config()->get(Config::walletDirectory).toString(); + QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", walletDirOld, QFileDialog::ShowDirsOnly); + if (walletDir.isEmpty()) + return; config()->set(Config::walletDirectory, walletDir); - ui->lineEdit_defaultWalletDir->setText(m_ctx->defaultWalletDir); + ui->lineEdit_defaultWalletDir->setText(walletDir); }); // Links tab @@ -110,7 +111,7 @@ Settings::Settings(AppContext *ctx, QWidget *parent) } void Settings::updatePaths() { - ui->lineEdit_defaultWalletDir->setText(m_ctx->defaultWalletDir); + ui->lineEdit_defaultWalletDir->setText(config()->get(Config::walletDirectory).toString()); ui->lineEdit_configDir->setText(Config::defaultConfigDir().path()); ui->lineEdit_applicationDir->setText(QCoreApplication::applicationDirPath()); } diff --git a/src/settings.h b/src/settings.h index e02c3b03..10c0ba67 100644 --- a/src/settings.h +++ b/src/settings.h @@ -20,7 +20,7 @@ class Settings : public QDialog Q_OBJECT public: - explicit Settings(AppContext *ctx, QWidget *parent = nullptr); + explicit Settings(QSharedPointer ctx, QWidget *parent = nullptr); ~Settings() override; signals: @@ -50,7 +50,7 @@ private: void setupLocalMoneroFrontendCombobox(); Ui::Settings *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"}; diff --git a/src/utils/RestoreHeightLookup.h b/src/utils/RestoreHeightLookup.h index 8ae4292b..4b23d76a 100644 --- a/src/utils/RestoreHeightLookup.h +++ b/src/utils/RestoreHeightLookup.h @@ -31,9 +31,9 @@ struct RestoreHeightLookup { int blocksPerDay = 86400 / blockTime; int blockCalcClearance = blocksPerDay * 5; QList values = this->data.keys(); - if(date <= values.at(0)) + if (date <= values.at(0)) return this->data[values.at(0)]; - for(int i = 0; i != values.count(); i++) { + for (int i = 0; i != values.count(); i++) { if(values[i] > date) { return i - 1 < 0 ? this->data[values[i]] : this->data[values[i-1]] - blockCalcClearance; } diff --git a/src/utils/TorManager.cpp b/src/utils/TorManager.cpp index 252417b0..398fd826 100644 --- a/src/utils/TorManager.cpp +++ b/src/utils/TorManager.cpp @@ -9,6 +9,7 @@ #include #include "utils/utils.h" +#include "utils/tails.h" #include "appcontext.h" #include "config-feather.h" diff --git a/src/utils/WebsocketClient.h b/src/utils/WebsocketClient.h index 805e6524..c9e098db 100644 --- a/src/utils/WebsocketClient.h +++ b/src/utils/WebsocketClient.h @@ -8,7 +8,7 @@ #include #include #include -#include "globals.h" +#include "constants.h" class WebsocketClient : public QObject { Q_OBJECT @@ -36,7 +36,7 @@ private slots: private: bool m_connect = false; - QUrl m_url = globals::websocketUrl; + QUrl m_url = constants::websocketUrl; QTimer m_connectionTimer; QTimer m_pingTimer; }; diff --git a/src/utils/WebsocketNotifier.cpp b/src/utils/WebsocketNotifier.cpp index 1d509a64..dff4d5d1 100644 --- a/src/utils/WebsocketNotifier.cpp +++ b/src/utils/WebsocketNotifier.cpp @@ -20,6 +20,8 @@ QPointer WebsocketNotifier::m_instance(nullptr); void WebsocketNotifier::onWSMessage(const QJsonObject &msg) { QString cmd = msg.value("cmd").toString(); + m_cache[cmd] = msg; + if (cmd == "blockheights") { QJsonObject data = msg.value("data").toObject(); int mainnet = data.value("mainnet").toInt(); @@ -84,6 +86,12 @@ void WebsocketNotifier::onWSMessage(const QJsonObject &msg) { #endif } +void WebsocketNotifier::emitCache() { + for (const auto &msg : m_cache) { + this->onWSMessage(msg); + } +} + void WebsocketNotifier::onWSNodes(const QJsonArray &nodes) { // TODO: Refactor, should be filtered client side @@ -93,7 +101,7 @@ void WebsocketNotifier::onWSNodes(const QJsonArray &nodes) { auto nettype = obj.value("nettype"); auto type = obj.value("type"); - auto networkType = config()->get(Config::networkType).toInt(); + auto networkType = constants::networkType; // filter remote node network types if(nettype == "mainnet" && networkType != NetworkType::MAINNET) diff --git a/src/utils/WebsocketNotifier.h b/src/utils/WebsocketNotifier.h index 3fa17c5c..96096034 100644 --- a/src/utils/WebsocketNotifier.h +++ b/src/utils/WebsocketNotifier.h @@ -22,10 +22,10 @@ public: explicit WebsocketNotifier(QObject *parent); QMap heights; - WebsocketClient websocketClient; static WebsocketNotifier* instance(); + void emitCache(); signals: void BlockHeightsReceived(int mainnet, int stagenet); @@ -52,6 +52,8 @@ private slots: private: static QPointer m_instance; + + QHash m_cache; }; inline WebsocketNotifier* websocketNotifier() diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 883a871d..ee0e7325 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -17,49 +17,62 @@ struct ConfigDirective static const QHash configStrings = { // General - {Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, - {Config::checkForUpdates,{QS("checkForUpdates"), true}}, + {Config::firstRun, {QS("firstRun"), true}}, {Config::warnOnStagenet,{QS("warnOnStagenet"), true}}, {Config::warnOnTestnet,{QS("warnOnTestnet"), true}}, {Config::warnOnAlpha,{QS("warnOnAlpha"), true}}, + {Config::homeWidget,{QS("homeWidget"), "ccs"}}, {Config::donateBeg,{QS("donateBeg"), 1}}, - {Config::skin,{QS("skin"), "light"}}, - {Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}}, - {Config::blockExplorer,{QS("blockExplorer"), "exploremonero.com"}}, + {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}, + + {Config::geometry, {QS("geometry"), {}}}, + {Config::windowState, {QS("windowState"), {}}}, + {Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}}, + + // Wallets {Config::walletDirectory,{QS("walletDirectory"), ""}}, {Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}}, - {Config::walletPath,{QS("walletPath"), ""}}, - {Config::xmrigPath,{QS("xmrigPath"), ""}}, - {Config::xmrigPool,{QS("xmrigPool"), "pool.xmr.pt:9000"}}, + {Config::recentlyOpenedWallets, {QS("recentlyOpenedWallets"), {}}}, + + // Nodes {Config::nodes,{QS("nodes"), "{}"}}, - {Config::websocketEnabled,{QS("websocketEnabled"), true}}, {Config::nodeSource,{QS("nodeSource"), 0}}, {Config::useOnionNodes,{QS("useOnionNodes"), false}}, + + // Tabs {Config::showTabHome,{QS("showTabHome"), true}}, {Config::showTabCoins,{QS("showTabCoins"), false}}, {Config::showTabExchange, {QS("showTabExchange"), false}}, {Config::showTabXMRig,{QS("showTabXMRig"), false}}, {Config::showTabCalc,{QS("showTabCalc"), true}}, - {Config::geometry, {QS("geometry"), {}}}, - {Config::windowState, {QS("windowState"), {}}}, - {Config::firstRun, {QS("firstRun"), true}}, - {Config::hideBalance, {QS("hideBalance"), false}}, - {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, - {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}, - {Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}}, + + // Mining + {Config::xmrigPath,{QS("xmrigPath"), ""}}, + {Config::xmrigPool,{QS("xmrigPool"), "pool.xmr.pt:9000"}}, + + // Settings + {Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}}, + {Config::skin,{QS("skin"), "light"}}, {Config::amountPrecision, {QS("amountPrecision"), 12}}, {Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}}, {Config::timeFormat, {QS("timeFormat"), "HH:mm"}}, + {Config::multiBroadcast, {QS("multiBroadcast"), true}}, + {Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, + {Config::hideBalance, {QS("hideBalance"), false}}, + + {Config::blockExplorer,{QS("blockExplorer"), "exploremonero.com"}}, + {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, + {Config::localMoneroFrontend, {QS("localMoneroFrontend"), "https://localmonero.co"}}, + + // Tor {Config::torPrivacyLevel, {QS("torPrivacyLevel"), 1}}, {Config::socks5Host, {QS("socks5Host"), "127.0.0.1"}}, {Config::socks5Port, {QS("socks5Port"), "9050"}}, - {Config::socks5User, {QS("socks5User"), ""}}, - {Config::socks5Pass, {QS("socks5Pass"), ""}}, - {Config::useLocalTor, {QS("useLocalTor"), false}}, - {Config::networkType, {QS("networkType"), NetworkType::Type::MAINNET}}, - {Config::localMoneroFrontend, {QS("localMoneroFrontend"), "https://localmonero.co"}} + {Config::socks5User, {QS("socks5User"), ""}}, // Unused + {Config::socks5Pass, {QS("socks5Pass"), ""}}, // Unused + {Config::useLocalTor, {QS("useLocalTor"), false}} }; diff --git a/src/utils/config.h b/src/utils/config.h index 91268975..d8103282 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -20,50 +20,56 @@ public: enum ConfigKey { - warnOnExternalLink, - checkForUpdates, + firstRun, warnOnStagenet, warnOnTestnet, warnOnAlpha, + homeWidget, donateBeg, + showHistorySyncNotice, + + geometry, + windowState, + GUI_HistoryViewState, + + walletDirectory, // Directory where wallet files are stored autoOpenWalletPath, - skin, - preferredFiatCurrency, - blockExplorer, - walletDirectory, - walletPath, - xmrigPath, - xmrigPool, + recentlyOpenedWallets, + nodes, - websocketEnabled, nodeSource, useOnionNodes, + showTabHome, showTabCoins, showTabExchange, showTabCalc, showTabXMRig, - geometry, - windowState, - firstRun, - hideBalance, - redditFrontend, - showHistorySyncNotice, - GUI_HistoryViewState, + + xmrigPath, + xmrigPool, + + preferredFiatCurrency, + skin, amountPrecision, - portableMode, dateFormat, timeFormat, + multiBroadcast, + warnOnExternalLink, + hideBalance, + + blockExplorer, + redditFrontend, + localMoneroFrontend, + torPrivacyLevel, socks5Host, socks5Port, socks5User, socks5Pass, useLocalTor, // Prevents Feather from starting bundled Tor daemon - networkType, - localMoneroFrontend }; enum PrivacyLevel { diff --git a/src/utils/keysfiles.cpp b/src/utils/keysfiles.cpp index 4c78d103..495ecc79 100644 --- a/src/utils/keysfiles.cpp +++ b/src/utils/keysfiles.cpp @@ -1,18 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2014-2021, The Monero Project. -#include -#include -#include -#include -#include -#include - -#include "appcontext.h" +#include "keysfiles.h" using namespace std::chrono; - WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) : m_fileName(info.fileName()), m_modified(info.lastModified().toSecsSinceEpoch()), @@ -47,9 +39,8 @@ int WalletKeysFiles::networkType() const { return m_networkType; } -WalletKeysFilesModel::WalletKeysFilesModel(AppContext *ctx, QObject *parent) +WalletKeysFilesModel::WalletKeysFilesModel(QObject *parent) : QAbstractTableModel(parent) - , m_ctx(ctx) { this->updateDirectories(); this->m_walletKeysFilesItemModel = qobject_cast(this); @@ -67,20 +58,15 @@ void WalletKeysFilesModel::refresh() { endResetModel(); } -void WalletKeysFilesModel::updateDirectories() { +void WalletKeysFilesModel::updateDirectories() { // TODO this->walletDirectories.clear(); QDir defaultWalletDir = QDir(Utils::defaultWalletDir()); QString walletDir = defaultWalletDir.path(); defaultWalletDir.cdUp(); QString walletDirRoot = defaultWalletDir.path(); + this->walletDirectories << walletDir; this->walletDirectories << walletDirRoot; - auto walletPath = config()->get(Config::walletPath).toString(); - if(!walletPath.isEmpty() && Utils::fileExists(walletPath)) { - QDir d = QFileInfo(walletPath).absoluteDir(); - this->walletDirectories << d.absolutePath(); - } - this->walletDirectories << QDir::homePath(); this->walletDirectories.removeDuplicates(); } diff --git a/src/utils/keysfiles.h b/src/utils/keysfiles.h index 4c01edd2..efd773f2 100644 --- a/src/utils/keysfiles.h +++ b/src/utils/keysfiles.h @@ -38,7 +38,7 @@ public: Modified }; - explicit WalletKeysFilesModel(AppContext *ctx, QObject *parent = nullptr); + explicit WalletKeysFilesModel(QObject *parent = nullptr); Q_INVOKABLE void refresh(); Q_INVOKABLE void clear(); @@ -55,7 +55,6 @@ public: private: void updateDirectories(); - AppContext *m_ctx; QList m_walletKeyFiles; QAbstractItemModel *m_walletKeysFilesItemModel; QSortFilterProxyModel m_walletKeysFilesModelProxy; diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index 76b6e45a..86462625 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -5,7 +5,83 @@ #include "nodes.h" #include "utils/utils.h" +#include "utils/tails.h" #include "appcontext.h" +#include "constants.h" +#include "utils/WebsocketNotifier.h" +#include "utils/TorManager.h" + +bool NodeList::addNode(const QString &node, NetworkType::Type networkType, NodeList::Type source) { + // We can't obtain references to QJsonObjects... + + QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + this->ensureStructure(obj, networkType); + + QString networkTypeStr = QString::number(networkType); + QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); + + QString sourceStr = Utils::QtEnumToString(source); + QJsonArray sourceArray = netTypeObj.value(sourceStr).toArray(); + + if (sourceArray.contains(node)) { + return false; + } + + sourceArray.append(node); + + netTypeObj[sourceStr] = sourceArray; + obj[networkTypeStr] = netTypeObj; + + config()->set(Config::nodes, obj); + return true; +} + +void NodeList::setNodes(const QStringList &nodes, NetworkType::Type networkType, NodeList::Type source) { + QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + this->ensureStructure(obj, networkType); + + QString networkTypeStr = QString::number(networkType); + QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); + + QString sourceStr = Utils::QtEnumToString(source); + QJsonArray sourceArray = QJsonArray::fromStringList(nodes); + + netTypeObj[sourceStr] = sourceArray; + obj[networkTypeStr] = netTypeObj; + + config()->set(Config::nodes, obj); +} + +QStringList NodeList::getNodes(NetworkType::Type networkType, NodeList::Type source) { + QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + + QString networkTypeStr = QString::number(networkType); + QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); + + QString sourceStr = Utils::QtEnumToString(source); + QJsonArray sourceArray = netTypeObj.value(sourceStr).toArray(); + + QStringList nodes; + for (const auto &node : sourceArray) { + nodes << node.toString(); + } + return nodes; +} + +void NodeList::ensureStructure(QJsonObject &obj, NetworkType::Type networkType) { + QString networkTypeStr = QString::number(networkType); + + if (!obj.contains(networkTypeStr)) + obj[networkTypeStr] = QJsonObject(); + + QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); + if (!netTypeObj.contains("ws")) + netTypeObj["ws"] = QJsonArray(); + if (!netTypeObj.contains("custom")) + netTypeObj["custom"] = QJsonArray(); + + obj[networkTypeStr] = netTypeObj; +} Nodes::Nodes(AppContext *ctx, QObject *parent) : QObject(parent) @@ -16,50 +92,30 @@ Nodes::Nodes(AppContext *ctx, QObject *parent) { this->loadConfig(); connect(m_ctx, &AppContext::walletRefreshed, this, &Nodes::onWalletRefreshed); + connect(websocketNotifier(), &WebsocketNotifier::NodesReceived, this, &Nodes::onWSNodesReceived); } void Nodes::loadConfig() { - auto configNodes = config()->get(Config::nodes).toByteArray(); - auto key = QString::number(m_ctx->networkType); - if (!Utils::validateJSON(configNodes)) { - m_configJson[key] = QJsonObject(); - qCritical() << "Fixed malformed config key \"nodes\""; - } - - QJsonDocument doc = QJsonDocument::fromJson(configNodes); - m_configJson = doc.object(); - - if (!m_configJson.contains(key)) - m_configJson[key] = QJsonObject(); - - auto obj = m_configJson.value(key).toObject(); - if (!obj.contains("custom")) - obj["custom"] = QJsonArray(); - if (!obj.contains("ws")) - obj["ws"] = QJsonArray(); - - // load custom nodes - auto nodes = obj.value("custom").toArray(); - for (auto value: nodes) { - auto customNode = FeatherNode(value.toString()); + QStringList customNodes = m_nodes.getNodes(constants::networkType, NodeList::custom); + for (const auto &node : customNodes) { + FeatherNode customNode{node}; customNode.custom = true; - if(m_connection == customNode) { - if(m_connection.isActive) + if (m_connection == customNode) { + if (m_connection.isActive) customNode.isActive = true; - else if(m_connection.isConnecting) + else if (m_connection.isConnecting) customNode.isConnecting = true; } m_customNodes.append(customNode); } - // load cached websocket nodes - auto ws = obj.value("ws").toArray(); - for (auto value: ws) { - auto wsNode = FeatherNode(value.toString()); + QStringList websocketNodes = m_nodes.getNodes(constants::networkType, NodeList::ws); + for (const auto &node : websocketNodes) { + FeatherNode wsNode{node}; wsNode.custom = false; - wsNode.online = true; // assume online + wsNode.online = true; // assume online if (m_connection == wsNode) { if (m_connection.isActive) @@ -86,9 +142,9 @@ void Nodes::loadConfig() { QJsonObject nodes_obj = nodes_json.object(); QString netKey; - if (m_ctx->networkType == NetworkType::MAINNET) { + if (constants::networkType == NetworkType::MAINNET) { netKey = "mainnet"; - } else if (m_ctx->networkType == NetworkType::STAGENET) { + } else if (constants::networkType == NetworkType::STAGENET) { netKey = "stagenet"; } @@ -96,30 +152,22 @@ void Nodes::loadConfig() { QJsonArray nodes_list; nodes_list = nodes_json[netKey].toObject()["tor"].toArray(); nodes_list.append(nodes_list = nodes_json[netKey].toObject()["clearnet"].toArray()); + for (auto node: nodes_list) { - auto wsNode = FeatherNode(node.toString()); + FeatherNode wsNode(node.toString()); wsNode.custom = false; wsNode.online = true; m_websocketNodes.append(wsNode); + m_nodes.addNode(node.toString(), constants::networkType, NodeList::Type::ws); } } qDebug() << QString("Loaded %1 nodes from hardcoded list").arg(m_websocketNodes.count()); } - m_configJson[key] = obj; - this->writeConfig(); this->updateModels(); } -void Nodes::writeConfig() { - QJsonDocument doc(m_configJson); - QString output(doc.toJson(QJsonDocument::Compact)); - config()->set(Config::nodes, output); - - qDebug() << "Saved node config."; -} - void Nodes::connectToNode() { // auto connect m_wsExhaustedWarningEmitted = false; @@ -135,10 +183,10 @@ void Nodes::connectToNode(const FeatherNode &node) { qInfo() << QString("Attempting to connect to %1 (%2)").arg(node.toAddress()).arg(node.custom ? "custom" : "ws"); if (!node.url.userName().isEmpty() && !node.url.password().isEmpty()) - m_ctx->currentWallet->setDaemonLogin(node.url.userName(), node.url.password()); + m_ctx->wallet->setDaemonLogin(node.url.userName(), node.url.password()); // Don't use SSL over Tor - m_ctx->currentWallet->setUseSSL(!node.isOnion()); + m_ctx->wallet->setUseSSL(!node.isOnion()); QString proxyAddress; if (useTorProxy(node)) { @@ -150,7 +198,7 @@ void Nodes::connectToNode(const FeatherNode &node) { } } - m_ctx->currentWallet->initAsync(node.toAddress(), true, 0, false, false, 0, proxyAddress); + m_ctx->wallet->initAsync(node.toAddress(), true, 0, false, false, 0, proxyAddress); m_connection = node; m_connection.isActive = false; @@ -162,11 +210,11 @@ void Nodes::connectToNode(const FeatherNode &node) { void Nodes::autoConnect(bool forceReconnect) { // this function is responsible for automatically connecting to a daemon. - if (m_ctx->currentWallet == nullptr || !m_enableAutoconnect) { + if (m_ctx->wallet == nullptr || !m_enableAutoconnect) { return; } - Wallet::ConnectionStatus status = m_ctx->currentWallet->connectionStatus(); + Wallet::ConnectionStatus status = m_ctx->wallet->connectionStatus(); bool wsMode = (this->source() == NodeSource::websocket); if (wsMode && !m_wsNodesReceived && websocketNodes().count() == 0) { @@ -276,15 +324,12 @@ void Nodes::onWSNodesReceived(QList &nodes) { } // cache into config - auto key = QString::number(m_ctx->networkType); - auto obj = m_configJson.value(key).toObject(); - auto ws = QJsonArray(); - for (auto const &node: m_websocketNodes) - ws.push_back(node.toAddress()); + QStringList wsNodeList; + for (const auto &node : m_websocketNodes) { + wsNodeList << node.toAddress(); + } + m_nodes.setNodes(wsNodeList, constants::networkType, NodeList::ws); - obj["ws"] = ws; - m_configJson[key] = obj; - this->writeConfig(); this->resetLocalState(); this->updateModels(); } @@ -297,20 +342,17 @@ void Nodes::onNodeSourceChanged(NodeSource nodeSource) { void Nodes::setCustomNodes(const QList &nodes) { m_customNodes.clear(); - auto key = QString::number(m_ctx->networkType); - auto obj = m_configJson.value(key).toObject(); QStringList nodesList; for (auto const &node: nodes) { - if (nodesList.contains(node.toAddress())) continue; + if (nodesList.contains(node.toAddress())) // skip duplicates + continue; nodesList.append(node.toAddress()); m_customNodes.append(node); } - auto arr = QJsonArray::fromStringList(nodesList); - obj["custom"] = arr; - m_configJson[key] = obj; - this->writeConfig(); + m_nodes.setNodes(nodesList, constants::networkType, NodeList::Type::custom); + this->resetLocalState(); this->updateModels(); } diff --git a/src/utils/nodes.h b/src/utils/nodes.h index a70881df..8d38cfd1 100644 --- a/src/utils/nodes.h +++ b/src/utils/nodes.h @@ -20,6 +20,24 @@ enum NodeSource { custom }; +class NodeList : public QObject { +Q_OBJECT + +public: + enum Type { + ws = 0, + custom + }; + Q_ENUM(Type) + + bool addNode(const QString &node, NetworkType::Type networkType, NodeList::Type source); + void setNodes(const QStringList &nodes, NetworkType::Type networkType, NodeList::Type source); + QStringList getNodes(NetworkType::Type networkType, NodeList::Type source); + +private: + void ensureStructure(QJsonObject &obj, NetworkType::Type networkType); +}; + struct FeatherNode { explicit FeatherNode(QString address = "", int height = 0, int target_height = 0, bool online = false) : height(height) @@ -92,7 +110,6 @@ class Nodes : public QObject { public: explicit Nodes(AppContext *ctx, QObject *parent = nullptr); void loadConfig(); - void writeConfig(); NodeSource source(); FeatherNode connection(); @@ -122,9 +139,11 @@ private slots: void onWalletRefreshed(); private: - AppContext *m_ctx = nullptr; + AppContext *m_ctx; QJsonObject m_configJson; + NodeList m_nodes; + QStringList m_recentFailures; QList m_customNodes; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 5ca76771..60706a92 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -15,7 +15,7 @@ #include "utils/tails.h" #include "utils/whonix.h" #include "utils/ColorScheme.h" -#include "globals.h" +#include "constants.h" QByteArray Utils::fileGetContents(const QString &path) { @@ -454,7 +454,7 @@ int Utils::maxLength(const QVector &array) { } QString Utils::balanceFormat(quint64 balance) { - QString str = QString::number(balance / globals::cdiv, 'f', 4); + QString str = QString::number(balance / constants::cdiv, 'f', 4); str.remove(QRegExp("0+$")); str.remove(QRegExp("\\.$")); diff --git a/src/utils/xmrig.cpp b/src/utils/xmrig.cpp index 6d0d9c45..f9f937f4 100644 --- a/src/utils/xmrig.cpp +++ b/src/utils/xmrig.cpp @@ -7,6 +7,7 @@ #include "utils/utils.h" #include "utils/xmrig.h" +#include "utils/TorManager.h" #include "appcontext.h" XmRig::XmRig(const QString &configDir, QObject *parent) diff --git a/src/widgets/LocalMoneroWidget.cpp b/src/widgets/LocalMoneroWidget.cpp index e8565c07..6670f7ea 100644 --- a/src/widgets/LocalMoneroWidget.cpp +++ b/src/widgets/LocalMoneroWidget.cpp @@ -12,10 +12,10 @@ #include #include -LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, AppContext *ctx) +LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, QSharedPointer ctx) : QWidget(parent) , ui(new Ui::LocalMoneroWidget) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) { ui->setupUi(this); diff --git a/src/widgets/LocalMoneroWidget.h b/src/widgets/LocalMoneroWidget.h index 1bace38f..1fce1df7 100644 --- a/src/widgets/LocalMoneroWidget.h +++ b/src/widgets/LocalMoneroWidget.h @@ -19,7 +19,7 @@ class LocalMoneroWidget : public QWidget Q_OBJECT public: - explicit LocalMoneroWidget(QWidget *parent, AppContext *ctx); + explicit LocalMoneroWidget(QWidget *parent, QSharedPointer ctx); ~LocalMoneroWidget() override; public slots: @@ -45,7 +45,7 @@ private: Ui::LocalMoneroWidget *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; LocalMoneroApi *m_api; LocalMoneroModel *m_model; UtilsNetworking *m_network; diff --git a/src/widgets/nodewidget.cpp b/src/widgets/nodewidget.cpp index d082f93a..94b857c4 100644 --- a/src/widgets/nodewidget.cpp +++ b/src/widgets/nodewidget.cpp @@ -156,7 +156,7 @@ void NodeWidget::onCustomAddClicked(){ m_ctx->nodes->setCustomNodes(nodesList); } -void NodeWidget::setupUI(AppContext *ctx) { +void NodeWidget::setupUI(QSharedPointer ctx) { m_ctx = ctx; auto nodeSource = m_ctx->nodes->source(); diff --git a/src/widgets/nodewidget.h b/src/widgets/nodewidget.h index be987f43..e7fa10d6 100644 --- a/src/widgets/nodewidget.h +++ b/src/widgets/nodewidget.h @@ -25,7 +25,7 @@ public: ~NodeWidget(); void setWSModel(NodeModel *model); void setCustomModel(NodeModel *model); - void setupUI(AppContext *ctx); + void setupUI(QSharedPointer ctx); NodeModel* model(); public slots: @@ -44,7 +44,7 @@ signals: void nodeSourceChanged(NodeSource nodeSource); private: - AppContext *m_ctx; + QSharedPointer m_ctx; Ui::NodeWidget *ui; NodeModel* m_customModel; NodeModel* m_wsModel; diff --git a/src/widgets/restoreheightwidget.cpp b/src/widgets/restoreheightwidget.cpp index b0ecb2cb..6ec42e80 100644 --- a/src/widgets/restoreheightwidget.cpp +++ b/src/widgets/restoreheightwidget.cpp @@ -8,9 +8,9 @@ #include "restoreheightwidget.h" #include "ui_restoreheightwidget.h" -RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::RestoreHeightWidget) +RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::RestoreHeightWidget) { ui->setupUi(this); ui->lineEdit_restoreHeight->setValidator(new QIntValidator(0, 2147483647, this)); diff --git a/src/widgets/tickerwidget.cpp b/src/widgets/tickerwidget.cpp index 9fa98ca5..621835d9 100644 --- a/src/widgets/tickerwidget.cpp +++ b/src/widgets/tickerwidget.cpp @@ -4,16 +4,16 @@ #include "tickerwidget.h" #include "ui_tickerwidget.h" -#include "globals.h" +#include "constants.h" #include "utils/AppData.h" -TickerWidget::TickerWidget(QWidget *parent, AppContext *ctx, QString symbol, QString title, bool convertBalance, bool hidePercent) : - QWidget(parent), - ui(new Ui::TickerWidget), - m_ctx(ctx), - m_symbol(std::move(symbol)), - m_convertBalance(convertBalance), - m_hidePercent(hidePercent) +TickerWidget::TickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol, QString title, bool convertBalance, bool hidePercent) + : QWidget(parent) + , ui(new Ui::TickerWidget) + , m_ctx(std::move(ctx)) + , m_symbol(std::move(symbol)) + , m_convertBalance(convertBalance) + , m_hidePercent(hidePercent) { ui->setupUi(this); @@ -31,8 +31,9 @@ TickerWidget::TickerWidget(QWidget *parent, AppContext *ctx, QString symbol, QSt connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &TickerWidget::init); connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init); + if (convertBalance) - connect(m_ctx, &AppContext::balanceUpdated, this, &TickerWidget::init); + connect(m_ctx.get(), &AppContext::balanceUpdated, this, &TickerWidget::init); } void TickerWidget::init() { @@ -46,7 +47,7 @@ void TickerWidget::init() { return; } - double walletBalance = m_ctx->currentWallet ? (m_ctx->currentWallet->balance() / globals::cdiv) : 0; + double walletBalance = m_ctx->wallet ? (m_ctx->wallet->balance() / constants::cdiv) : 0; double amount = m_convertBalance ? walletBalance : 1.0; double conversion = appData()->prices.convert(m_symbol, fiatCurrency, amount); diff --git a/src/widgets/tickerwidget.h b/src/widgets/tickerwidget.h index 74386a1a..6c50ec99 100644 --- a/src/widgets/tickerwidget.h +++ b/src/widgets/tickerwidget.h @@ -17,7 +17,7 @@ class TickerWidget : public QWidget Q_OBJECT public: - explicit TickerWidget(QWidget *parent, AppContext *ctx, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false); + explicit TickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false); void setFiatText(QString &fiatCurrency, double amount); void setPctText(QString &text, bool positive); void setFontSizes(); @@ -29,7 +29,7 @@ public slots: private: Ui::TickerWidget *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; QString m_symbol; bool m_convertBalance; bool m_hidePercent; diff --git a/src/widgets/xmrigwidget.cpp b/src/widgets/xmrigwidget.cpp index 77f53a96..5a4a98dc 100644 --- a/src/widgets/xmrigwidget.cpp +++ b/src/widgets/xmrigwidget.cpp @@ -12,10 +12,10 @@ #include "ui_xmrigwidget.h" #include "utils/Icons.h" -XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) +XMRigWidget::XMRigWidget(QSharedPointer ctx, QWidget *parent) : QWidget(parent) , ui(new Ui::XMRigWidget) - , m_ctx(ctx) + , m_ctx(std::move(ctx)) , m_XMRig(new XmRig(Config::defaultConfigDir().path())) , m_model(new QStandardItemModel(this)) , m_contextMenu(new QMenu(this)) @@ -29,9 +29,6 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) connect(m_XMRig, &XmRig::error, this, &XMRigWidget::onProcessError); connect(m_XMRig, &XmRig::hashrate, this, &XMRigWidget::onHashrate); - connect(m_ctx, &AppContext::walletClosed, this, &XMRigWidget::onWalletClosed); - connect(m_ctx, &AppContext::walletOpened, this, &XMRigWidget::onWalletOpened); - // table ui->tableView->setModel(this->m_model); m_contextMenu->addAction(icons()->icon("network.png"), "Download file", this, &XMRigWidget::linkClicked); @@ -92,16 +89,30 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) // username/password connect(ui->lineEdit_password, &QLineEdit::editingFinished, [=]() { - m_ctx->currentWallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text()); + m_ctx->wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text()); m_ctx->storeWallet(); }); connect(ui->lineEdit_address, &QLineEdit::editingFinished, [=]() { - m_ctx->currentWallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text()); + m_ctx->wallet->setCacheAttribute("feather.xmrig_username", ui->lineEdit_address->text()); m_ctx->storeWallet(); }); // checkbox connects connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked); + + // Xmrig username + auto username = m_ctx->wallet->getCacheAttribute("feather.xmrig_username"); + if(!username.isEmpty()) + ui->lineEdit_address->setText(username); + + // Xmrig passwd + auto password = m_ctx->wallet->getCacheAttribute("feather.xmrig_password"); + if(!password.isEmpty()) { + ui->lineEdit_password->setText(password); + } else { + ui->lineEdit_password->setText("featherwallet"); + m_ctx->wallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text()); + } } void XMRigWidget::onWalletClosed() { @@ -111,22 +122,6 @@ void XMRigWidget::onWalletClosed() { ui->lineEdit_address->setText(""); } -void XMRigWidget::onWalletOpened(){ - // Xmrig username - auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username"); - if(!username.isEmpty()) - ui->lineEdit_address->setText(username); - - // Xmrig passwd - auto password = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_password"); - if(!password.isEmpty()) { - ui->lineEdit_password->setText(password); - } else { - ui->lineEdit_password->setText("featherwallet"); - m_ctx->currentWallet->setCacheAttribute("feather.xmrig_password", ui->lineEdit_password->text()); - } -} - void XMRigWidget::onThreadsValueChanged(int threads) { m_threads = threads; ui->label_threads->setText(QString("CPU threads: %1").arg(m_threads)); @@ -154,8 +149,8 @@ void XMRigWidget::onStartClicked() { xmrigPath = config()->get(Config::xmrigPath).toString(); // username is receiving address usually - auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username"); - auto password = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_password"); + auto username = m_ctx->wallet->getCacheAttribute("feather.xmrig_username"); + auto password = m_ctx->wallet->getCacheAttribute("feather.xmrig_password"); if(username.isEmpty()) { QString err = "Please specify a receiving address on the Settings screen"; @@ -172,7 +167,7 @@ void XMRigWidget::onStartClicked() { if(address.contains("cryptonote.social") && !username.contains(".")) { // cryptonote social requires ., we'll just grab a few chars from primary addy - username = QString("%1.%2").arg(username, m_ctx->currentWallet->address(0, 0).mid(0, 6)); + username = QString("%1.%2").arg(username, m_ctx->wallet->address(0, 0).mid(0, 6)); } m_XMRig->start(xmrigPath, m_threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked()); diff --git a/src/widgets/xmrigwidget.h b/src/widgets/xmrigwidget.h index b38efb83..cadd801a 100644 --- a/src/widgets/xmrigwidget.h +++ b/src/widgets/xmrigwidget.h @@ -21,13 +21,12 @@ class XMRigWidget : public QWidget Q_OBJECT public: - explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr); + explicit XMRigWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~XMRigWidget() override; QStandardItemModel *model(); public slots: void onWalletClosed(); - void onWalletOpened(); void onStartClicked(); void onStopClicked(); void onClearClicked(); @@ -51,7 +50,7 @@ private: void showContextMenu(const QPoint &pos); Ui::XMRigWidget *ui; - AppContext *m_ctx; + QSharedPointer m_ctx; XmRig * m_XMRig; QStandardItemModel *m_model; QMenu *m_contextMenu; diff --git a/src/wizard/PageHardwareDevice.cpp b/src/wizard/PageHardwareDevice.cpp index 03e0a413..6bdb48fd 100644 --- a/src/wizard/PageHardwareDevice.cpp +++ b/src/wizard/PageHardwareDevice.cpp @@ -7,10 +7,9 @@ #include -PageHardwareDevice::PageHardwareDevice(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageHardwareDevice::PageHardwareDevice(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageHardwareDevice) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); diff --git a/src/wizard/PageHardwareDevice.h b/src/wizard/PageHardwareDevice.h index d20a6b95..689bd29c 100644 --- a/src/wizard/PageHardwareDevice.h +++ b/src/wizard/PageHardwareDevice.h @@ -21,7 +21,7 @@ class PageHardwareDevice : public QWizardPage Q_OBJECT public: - explicit PageHardwareDevice(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageHardwareDevice(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -29,7 +29,6 @@ public: private: Ui::PageHardwareDevice *ui; - AppContext *m_ctx; WizardFields *m_fields; }; diff --git a/src/wizard/PageMenu.cpp b/src/wizard/PageMenu.cpp index 2ca886b3..da8c2896 100644 --- a/src/wizard/PageMenu.cpp +++ b/src/wizard/PageMenu.cpp @@ -7,10 +7,9 @@ #include -PageMenu::PageMenu(AppContext *ctx, WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent) +PageMenu::PageMenu(WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageMenu) - , m_ctx(ctx) , m_walletKeysFilesModel(wallets) , m_fields(fields) { diff --git a/src/wizard/PageMenu.h b/src/wizard/PageMenu.h index 49e19577..ba20662a 100644 --- a/src/wizard/PageMenu.h +++ b/src/wizard/PageMenu.h @@ -19,7 +19,7 @@ class PageMenu : public QWizardPage Q_OBJECT public: - explicit PageMenu(AppContext *ctx, WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent = nullptr); + explicit PageMenu(WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -29,7 +29,6 @@ signals: private: Ui::PageMenu *ui; - AppContext *m_ctx; WalletKeysFilesModel *m_walletKeysFilesModel; WizardFields *m_fields; }; diff --git a/src/wizard/PageNetwork.cpp b/src/wizard/PageNetwork.cpp index f6d39ec3..b359c887 100644 --- a/src/wizard/PageNetwork.cpp +++ b/src/wizard/PageNetwork.cpp @@ -4,11 +4,11 @@ #include "PageNetwork.h" #include "ui_PageNetwork.h" #include "WalletWizard.h" +#include "constants.h" -PageNetwork::PageNetwork(AppContext *ctx, QWidget *parent) +PageNetwork::PageNetwork(QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageNetwork) - , m_ctx(ctx) { ui->setupUi(this); this->setTitle("Welcome to Feather"); @@ -35,10 +35,8 @@ bool PageNetwork::validatePage() { config()->set(Config::nodeSource, id); if (id == 1) { - QList nodes; - FeatherNode node{ui->line_customNode->text()}; - nodes.append(node); - m_ctx->nodes->setCustomNodes(nodes); + NodeList nodeList; + nodeList.addNode(ui->line_customNode->text(), constants::networkType, NodeList::Type::custom); } return true; diff --git a/src/wizard/PageNetwork.h b/src/wizard/PageNetwork.h index 7c2aafe3..4e68bb9a 100644 --- a/src/wizard/PageNetwork.h +++ b/src/wizard/PageNetwork.h @@ -20,14 +20,13 @@ class PageNetwork : public QWizardPage Q_OBJECT public: - explicit PageNetwork(AppContext *ctx, QWidget *parent = nullptr); + explicit PageNetwork(QWidget *parent = nullptr); bool validatePage() override; int nextId() const override; bool isComplete() const override; private: Ui::PageNetwork *ui; - AppContext *m_ctx; }; #endif //FEATHER_WIZARDNETWORK_H diff --git a/src/wizard/PageNetworkTor.cpp b/src/wizard/PageNetworkTor.cpp index cade2ee7..e3649e4c 100644 --- a/src/wizard/PageNetworkTor.cpp +++ b/src/wizard/PageNetworkTor.cpp @@ -5,10 +5,9 @@ #include "ui_PageNetworkTor.h" #include "WalletWizard.h" -PageNetworkTor::PageNetworkTor(AppContext *ctx, QWidget *parent) +PageNetworkTor::PageNetworkTor(QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageNetworkTor) - , m_ctx(ctx) { ui->setupUi(this); diff --git a/src/wizard/PageNetworkTor.h b/src/wizard/PageNetworkTor.h index 48056abe..5447f079 100644 --- a/src/wizard/PageNetworkTor.h +++ b/src/wizard/PageNetworkTor.h @@ -17,7 +17,7 @@ class PageNetworkTor : public QWizardPage Q_OBJECT public: - explicit PageNetworkTor(AppContext *ctx, QWidget *parent = nullptr); + explicit PageNetworkTor(QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -27,7 +27,6 @@ signals: private: Ui::PageNetworkTor *ui; - AppContext *m_ctx; }; #endif //FEATHER_PAGENETWORKTOR_H diff --git a/src/wizard/PageOpenWallet.cpp b/src/wizard/PageOpenWallet.cpp index cb76f278..34f1a6f1 100644 --- a/src/wizard/PageOpenWallet.cpp +++ b/src/wizard/PageOpenWallet.cpp @@ -7,21 +7,21 @@ #include #include -PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, QWidget *parent) +#include "constants.h" +#include "WalletWizard.h" + +PageOpenWallet::PageOpenWallet(WalletKeysFilesModel *wallets, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageOpenWallet) - , m_ctx(ctx) , m_walletKeysFilesModel(wallets) { ui->setupUi(this); - connect(ui->btnBrowse, &QPushButton::clicked, [=]{ - // manually browsing for wallet - auto walletPath = config()->get(Config::walletPath).toString(); - if (walletPath.isEmpty()) - walletPath = m_ctx->defaultWalletDir; - QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletPath, "Wallet file (*.keys)"); - if(path.isEmpty()) return; + connect(ui->btnBrowse, &QPushButton::clicked, [this]{ + QString walletDir = config()->get(Config::walletDirectory).toString(); + QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletDir, "Wallet file (*.keys)"); + if (path.isEmpty()) + return; QFileInfo infoPath(path); if(!infoPath.isReadable()) { @@ -30,7 +30,7 @@ PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, Q } if (ui->openOnStartup->isChecked()) - config()->set(Config::autoOpenWalletPath, QString("%1%2").arg(m_ctx->networkType).arg(path)); + config()->set(Config::autoOpenWalletPath, QString("%1%2").arg(constants::networkType).arg(path)); emit openWallet(path); }); @@ -41,7 +41,7 @@ PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, Q ui->walletTable->setSelectionBehavior(QAbstractItemView::SelectRows); ui->walletTable->setContextMenuPolicy(Qt::CustomContextMenu); - m_keysProxy = new WalletKeysFilesProxyModel(this, m_ctx->networkType); + m_keysProxy = new WalletKeysFilesProxyModel(this, constants::networkType); m_keysProxy->setSourceModel(m_walletKeysFilesModel); m_keysProxy->setSortRole(Qt::UserRole); @@ -57,7 +57,13 @@ PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, Q connect(ui->walletTable->selectionModel(), &QItemSelectionModel::currentRowChanged, [this](QModelIndex current, QModelIndex prev){ this->updatePath(); }); - connect(ui->walletTable, &QTreeView::doubleClicked, this, &PageOpenWallet::validatePage); + connect(ui->walletTable, &QTreeView::doubleClicked, [this]{ + // Simulate next button click + QWizard *wizard = this->wizard(); + if (wizard) { + wizard->button(QWizard::FinishButton)->click(); + } + }); } void PageOpenWallet::initializePage() { @@ -87,7 +93,7 @@ bool PageOpenWallet::validatePage() { } QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString(); - auto autoWallet = ui->openOnStartup->isChecked() ? QString("%1%2").arg(m_ctx->networkType).arg(walletPath) : ""; + auto autoWallet = ui->openOnStartup->isChecked() ? QString("%1%2").arg(constants::networkType).arg(walletPath) : ""; config()->set(Config::autoOpenWalletPath, autoWallet); emit openWallet(walletPath); diff --git a/src/wizard/PageOpenWallet.h b/src/wizard/PageOpenWallet.h index 5342b473..3ed45a1c 100644 --- a/src/wizard/PageOpenWallet.h +++ b/src/wizard/PageOpenWallet.h @@ -20,7 +20,7 @@ class PageOpenWallet : public QWizardPage Q_OBJECT public: - explicit PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, QWidget *parent = nullptr); + explicit PageOpenWallet(WalletKeysFilesModel *wallets, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -32,7 +32,6 @@ private: void updatePath(); Ui::PageOpenWallet *ui; - AppContext *m_ctx; WalletKeysFilesModel *m_walletKeysFilesModel; WalletKeysFilesProxyModel *m_keysProxy; QStandardItemModel *m_model; diff --git a/src/wizard/PageSetPassword.cpp b/src/wizard/PageSetPassword.cpp index f4b6c93f..11366c4b 100644 --- a/src/wizard/PageSetPassword.cpp +++ b/src/wizard/PageSetPassword.cpp @@ -5,10 +5,9 @@ #include "ui_PageSetPassword.h" #include "WalletWizard.h" -PageSetPassword::PageSetPassword(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageSetPassword::PageSetPassword(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageSetPassword) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); diff --git a/src/wizard/PageSetPassword.h b/src/wizard/PageSetPassword.h index 263ae1ff..2ba604de 100644 --- a/src/wizard/PageSetPassword.h +++ b/src/wizard/PageSetPassword.h @@ -19,7 +19,7 @@ class PageSetPassword : public QWizardPage Q_OBJECT public: - explicit PageSetPassword(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageSetPassword(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -31,7 +31,6 @@ signals: private: Ui::PageSetPassword *ui; - AppContext *m_ctx; WizardFields *m_fields; }; diff --git a/src/wizard/PageSetRestoreHeight.cpp b/src/wizard/PageSetRestoreHeight.cpp index 12e00a01..bf28d060 100644 --- a/src/wizard/PageSetRestoreHeight.cpp +++ b/src/wizard/PageSetRestoreHeight.cpp @@ -5,11 +5,11 @@ #include "PageSetRestoreHeight.h" #include "ui_PageSetRestoreHeight.h" #include "WalletWizard.h" +#include "constants.h" -PageSetRestoreHeight::PageSetRestoreHeight(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageSetRestoreHeight::PageSetRestoreHeight(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageSetRestoreHeight) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); @@ -61,7 +61,7 @@ void PageSetRestoreHeight::onCreationDateEdited() { QDateTime restoreDate = date > curDate ? curDate : date; int timestamp = restoreDate.toSecsSinceEpoch(); - QString restoreHeight = QString::number(appData()->restoreHeights[m_ctx->networkType]->dateToRestoreHeight(timestamp)); + QString restoreHeight = QString::number(appData()->restoreHeights[constants::networkType]->dateToRestoreHeight(timestamp)); ui->line_restoreHeight->setText(restoreHeight); this->showScanWarning(restoreDate); @@ -77,7 +77,7 @@ void PageSetRestoreHeight::onRestoreHeightEdited() { return; } - int timestamp = appData()->restoreHeights[m_ctx->networkType]->restoreHeightToDate(restoreHeight); + int timestamp = appData()->restoreHeights[constants::networkType]->restoreHeightToDate(restoreHeight); auto date = QDateTime::fromSecsSinceEpoch(timestamp); ui->line_creationDate->setText(date.toString("yyyy-MM-dd")); diff --git a/src/wizard/PageSetRestoreHeight.h b/src/wizard/PageSetRestoreHeight.h index 4ab90b3d..6230a1e2 100644 --- a/src/wizard/PageSetRestoreHeight.h +++ b/src/wizard/PageSetRestoreHeight.h @@ -19,7 +19,7 @@ class PageSetRestoreHeight : public QWizardPage Q_OBJECT public: - explicit PageSetRestoreHeight(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageSetRestoreHeight(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -34,7 +34,6 @@ private: void showWalletAgeWarning(const QDateTime &date); Ui::PageSetRestoreHeight *ui; - AppContext *m_ctx; WizardFields *m_fields; }; diff --git a/src/wizard/PageWalletFile.cpp b/src/wizard/PageWalletFile.cpp index cfde928b..4171ae45 100644 --- a/src/wizard/PageWalletFile.cpp +++ b/src/wizard/PageWalletFile.cpp @@ -10,10 +10,9 @@ #include #include -PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageWalletFile::PageWalletFile(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageWalletFile) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); @@ -23,9 +22,9 @@ PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *p ui->lockIcon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation)); connect(ui->btnChange, &QPushButton::clicked, [=] { - QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", m_ctx->defaultWalletDir, QFileDialog::ShowDirsOnly); + QString currentWalletDir = config()->get(Config::walletDirectory).toString(); + QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", currentWalletDir, QFileDialog::ShowDirsOnly); if(walletDir.isEmpty()) return; - m_ctx->defaultWalletDir = walletDir; ui->line_walletDir->setText(walletDir); config()->set(Config::walletDirectory, walletDir); emit defaultWalletDirChanged(walletDir); @@ -37,7 +36,7 @@ PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *p void PageWalletFile::initializePage() { this->setTitle(m_fields->modeText); - ui->line_walletDir->setText(m_ctx->defaultWalletDir); + ui->line_walletDir->setText(config()->get(Config::walletDirectory).toString()); ui->line_walletName->setText(this->defaultWalletName()); } diff --git a/src/wizard/PageWalletFile.h b/src/wizard/PageWalletFile.h index 3f9c2ba4..36e4f66e 100644 --- a/src/wizard/PageWalletFile.h +++ b/src/wizard/PageWalletFile.h @@ -20,7 +20,7 @@ class PageWalletFile : public QWizardPage Q_OBJECT public: - explicit PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageWalletFile(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -35,7 +35,6 @@ private: bool validateWidgets(); Ui::PageWalletFile *ui; - AppContext *m_ctx; WizardFields *m_fields; bool m_validated; }; diff --git a/src/wizard/PageWalletRestoreKeys.cpp b/src/wizard/PageWalletRestoreKeys.cpp index 364213fa..390a3179 100644 --- a/src/wizard/PageWalletRestoreKeys.cpp +++ b/src/wizard/PageWalletRestoreKeys.cpp @@ -1,16 +1,17 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. -#include "WalletWizard.h" #include "PageWalletRestoreKeys.h" #include "ui_PageWalletRestoreKeys.h" #include -PageWalletRestoreKeys::PageWalletRestoreKeys(AppContext *ctx, WizardFields *fields, QWidget *parent) +#include "WalletWizard.h" +#include "constants.h" + +PageWalletRestoreKeys::PageWalletRestoreKeys(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageWalletRestoreKeys) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); @@ -25,9 +26,9 @@ PageWalletRestoreKeys::PageWalletRestoreKeys(AppContext *ctx, WizardFields *fiel QGuiApplication::restoreOverrideCursor(); #endif - if (m_ctx->networkType == NetworkType::Type::MAINNET) { + if (constants::networkType == NetworkType::Type::MAINNET) { ui->line_address->setPlaceholderText("4..."); - } else if (m_ctx->networkType == NetworkType::Type::STAGENET) { + } else if (constants::networkType == NetworkType::Type::STAGENET) { ui->line_address->setPlaceholderText("5..."); } } @@ -53,21 +54,21 @@ bool PageWalletRestoreKeys::validatePage() { QString viewkey = ui->line_viewkey->text().trimmed(); QString spendkey = ui->line_spendkey->text().trimmed(); - if(!m_ctx->walletManager->addressValid(address, m_ctx->networkType)){ + if(!WalletManager::addressValid(address, constants::networkType)){ ui->label_errorString->show(); ui->label_errorString->setText("Invalid address."); ui->line_address->setStyleSheet(errStyle); return false; } - if(!m_ctx->walletManager->keyValid(viewkey, address, true, m_ctx->networkType)) { + if(!WalletManager::keyValid(viewkey, address, true, constants::networkType)) { ui->label_errorString->show(); ui->label_errorString->setText("Invalid key."); ui->line_viewkey->setStyleSheet(errStyle); return false; } - if(!spendkey.isEmpty() && !m_ctx->walletManager->keyValid(spendkey, address, false, m_ctx->networkType)) { + if(!spendkey.isEmpty() && !WalletManager::keyValid(spendkey, address, false, constants::networkType)) { ui->label_errorString->show(); ui->label_errorString->setText("Invalid key."); ui->line_viewkey->setStyleSheet(errStyle); diff --git a/src/wizard/PageWalletRestoreKeys.h b/src/wizard/PageWalletRestoreKeys.h index 3be83b92..9aeb0fa0 100644 --- a/src/wizard/PageWalletRestoreKeys.h +++ b/src/wizard/PageWalletRestoreKeys.h @@ -11,6 +11,7 @@ #include #include "appcontext.h" +#include "WalletWizard.h" namespace Ui { class PageWalletRestoreKeys; @@ -21,14 +22,13 @@ class PageWalletRestoreKeys : public QWizardPage Q_OBJECT public: - explicit PageWalletRestoreKeys(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageWalletRestoreKeys(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; private: Ui::PageWalletRestoreKeys *ui; - AppContext *m_ctx; WizardFields *m_fields; }; diff --git a/src/wizard/PageWalletRestoreSeed.cpp b/src/wizard/PageWalletRestoreSeed.cpp index a7d44212..f9128560 100644 --- a/src/wizard/PageWalletRestoreSeed.cpp +++ b/src/wizard/PageWalletRestoreSeed.cpp @@ -10,12 +10,11 @@ #include // tevador 14 word #include "utils/FeatherSeed.h" -#include "globals.h" +#include "constants.h" -PageWalletRestoreSeed::PageWalletRestoreSeed(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageWalletRestoreSeed::PageWalletRestoreSeed(WizardFields *fields, QWidget *parent) : QWizardPage(parent) , ui(new Ui::PageWalletRestoreSeed) - , m_ctx(ctx) , m_fields(fields) { ui->setupUi(this); @@ -110,7 +109,7 @@ bool PageWalletRestoreSeed::validatePage() { } } - auto _seed = FeatherSeed(m_ctx->networkType, QString::fromStdString(globals::coinName), m_ctx->seedLanguage, seedSplit); + auto _seed = FeatherSeed(constants::networkType, QString::fromStdString(constants::coinName), constants::seedLanguage, seedSplit); if (!_seed.errorString.isEmpty()) { QMessageBox::warning(this, "Invalid seed", QString("Invalid seed:\n\n%1").arg(_seed.errorString)); ui->seedEdit->setStyleSheet(errStyle); diff --git a/src/wizard/PageWalletRestoreSeed.h b/src/wizard/PageWalletRestoreSeed.h index 9b792835..f2d89717 100644 --- a/src/wizard/PageWalletRestoreSeed.h +++ b/src/wizard/PageWalletRestoreSeed.h @@ -22,7 +22,7 @@ class PageWalletRestoreSeed : public QWizardPage Q_OBJECT public: - explicit PageWalletRestoreSeed(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageWalletRestoreSeed(WizardFields *fields, QWidget *parent = nullptr); bool validatePage() override; void initializePage() override; int nextId() const override; @@ -51,7 +51,6 @@ private: void onSeedTypeToggled(); Ui::PageWalletRestoreSeed *ui; - AppContext *m_ctx; WizardFields *m_fields; seedType m_tevador; diff --git a/src/wizard/PageWalletSeed.cpp b/src/wizard/PageWalletSeed.cpp index 241c8c96..5030208a 100644 --- a/src/wizard/PageWalletSeed.cpp +++ b/src/wizard/PageWalletSeed.cpp @@ -4,13 +4,12 @@ #include "WalletWizard.h" #include "PageWalletSeed.h" #include "ui_PageWalletSeed.h" -#include "globals.h" +#include "constants.h" #include -PageWalletSeed::PageWalletSeed(AppContext *ctx, WizardFields *fields, QWidget *parent) +PageWalletSeed::PageWalletSeed(WizardFields *fields, QWidget *parent) : QWizardPage(parent) - , m_ctx(ctx) , ui(new Ui::PageWalletSeed) , m_fields(fields) { @@ -50,7 +49,7 @@ void PageWalletSeed::seedRoulette(int count) { void PageWalletSeed::generateSeed() { do { - FeatherSeed seed = FeatherSeed(m_ctx->networkType, QString::fromStdString(globals::coinName), m_ctx->seedLanguage); + FeatherSeed seed = FeatherSeed(constants::networkType, QString::fromStdString(constants::coinName), constants::seedLanguage); m_mnemonic = seed.mnemonic.join(" "); m_restoreHeight = seed.restoreHeight; } while (m_mnemonic.split(" ").length() != 14); // https://github.com/tevador/monero-seed/issues/2 diff --git a/src/wizard/PageWalletSeed.h b/src/wizard/PageWalletSeed.h index dcb4f8da..5ed406d3 100644 --- a/src/wizard/PageWalletSeed.h +++ b/src/wizard/PageWalletSeed.h @@ -9,7 +9,6 @@ #include #include "utils/utils.h" -#include "appcontext.h" namespace Ui { class PageWalletSeed; @@ -20,7 +19,7 @@ class PageWalletSeed : public QWizardPage Q_OBJECT public: - explicit PageWalletSeed(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); + explicit PageWalletSeed(WizardFields *fields, QWidget *parent = nullptr); void initializePage() override; bool validatePage() override; int nextId() const override; @@ -36,7 +35,6 @@ signals: void createWallet(); private: - AppContext *m_ctx; Ui::PageWalletSeed *ui; WizardFields *m_fields; diff --git a/src/wizard/WalletWizard.cpp b/src/wizard/WalletWizard.cpp index 78198c5f..6b551577 100644 --- a/src/wizard/WalletWizard.cpp +++ b/src/wizard/WalletWizard.cpp @@ -15,29 +15,28 @@ #include "PageSetRestoreHeight.h" #include "PageHardwareDevice.h" #include "PageNetworkTor.h" -#include "globals.h" +#include "constants.h" #include #include #include -WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidget *parent) - : QWizard(parent) - , m_ctx(ctx) +WalletWizard::WalletWizard(QWidget *parent) + : QWizard(parent) { this->setWindowTitle("Welcome to Feather Wallet"); this->setWindowIcon(QIcon(":/assets/images/appicons/64x64.png")); - m_walletKeysFilesModel = new WalletKeysFilesModel(m_ctx, this); + m_walletKeysFilesModel = new WalletKeysFilesModel(this); m_walletKeysFilesModel->refresh(); - auto networkPage = new PageNetwork(m_ctx, this); - auto networkTorPage = new PageNetworkTor(m_ctx, this); - auto menuPage = new PageMenu(m_ctx, &m_wizardFields, m_walletKeysFilesModel, this); - auto openWalletPage = new PageOpenWallet(m_ctx, m_walletKeysFilesModel, this); - auto createWallet = new PageWalletFile(m_ctx, &m_wizardFields , this); - auto createWalletSeed = new PageWalletSeed(m_ctx, &m_wizardFields, this); - auto walletSetPasswordPage = new PageSetPassword(m_ctx, &m_wizardFields, this); + auto networkPage = new PageNetwork(this); + auto networkTorPage = new PageNetworkTor(this); + auto menuPage = new PageMenu(&m_wizardFields, m_walletKeysFilesModel, this); + auto openWalletPage = new PageOpenWallet(m_walletKeysFilesModel, this); + auto createWallet = new PageWalletFile(&m_wizardFields , this); + auto createWalletSeed = new PageWalletSeed(&m_wizardFields, this); + auto walletSetPasswordPage = new PageSetPassword(&m_wizardFields, this); setPage(Page_Menu, menuPage); setPage(Page_WalletFile, createWallet); setPage(Page_OpenWallet, openWalletPage); @@ -45,22 +44,18 @@ WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidge setPage(Page_SetPasswordPage, walletSetPasswordPage); setPage(Page_Network, networkPage); setPage(Page_NetworkTor, networkTorPage); - setPage(Page_WalletRestoreSeed, new PageWalletRestoreSeed(m_ctx, &m_wizardFields, this)); - setPage(Page_WalletRestoreKeys, new PageWalletRestoreKeys(m_ctx, &m_wizardFields, this)); - setPage(Page_SetRestoreHeight, new PageSetRestoreHeight(m_ctx, &m_wizardFields, this)); - setPage(Page_HardwareDevice, new PageHardwareDevice(m_ctx, &m_wizardFields, this)); + setPage(Page_WalletRestoreSeed, new PageWalletRestoreSeed(&m_wizardFields, this)); + setPage(Page_WalletRestoreKeys, new PageWalletRestoreKeys(&m_wizardFields, this)); + setPage(Page_SetRestoreHeight, new PageSetRestoreHeight(&m_wizardFields, this)); + setPage(Page_HardwareDevice, new PageHardwareDevice(&m_wizardFields, this)); - setStartId(startPage); + setStartId(Page_Menu); setButtonText(QWizard::CancelButton, "Close"); setPixmap(QWizard::WatermarkPixmap, QPixmap(":/assets/images/banners/3.png")); setWizardStyle(WizardStyle::ModernStyle); setOption(QWizard::NoBackButtonOnStartPage); - connect(this, &QWizard::rejected, [=]{ - return QApplication::exit(1); - }); - connect(networkTorPage, &PageNetworkTor::initialNetworkConfigured, [this](){ emit initialNetworkConfigured(); }); @@ -72,7 +67,9 @@ WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidge emit skinChanged("Native"); }); - connect(walletSetPasswordPage, &PageSetPassword::createWallet, this, &WalletWizard::createWallet); + connect(walletSetPasswordPage, &PageSetPassword::createWallet, this, &WalletWizard::onCreateWallet); + + connect(createWallet, &PageWalletFile::defaultWalletDirChanged, [this](const QString &walletDir){ emit defaultWalletDirChanged(walletDir); }); @@ -82,12 +79,16 @@ WalletWizard::WalletWizard(AppContext *ctx, WalletWizard::Page startPage, QWidge }); } -void WalletWizard::createWallet() { +WalletWizard::~WalletWizard() { + qDebug() << "We're killing the walletwizard"; +} + +void WalletWizard::onCreateWallet() { auto walletPath = QString("%1/%2").arg(m_wizardFields.walletDir, m_wizardFields.walletName); int currentBlockHeight = 0; - if (appData()->heights.contains(m_ctx->networkType)) { - currentBlockHeight = appData()->heights[m_ctx->networkType]; + if (appData()->heights.contains(constants::networkType)) { + currentBlockHeight = appData()->heights[constants::networkType]; } if (m_wizardFields.mode == WizardMode::CreateWalletFromDevice) { @@ -96,23 +97,23 @@ void WalletWizard::createWallet() { restoreHeight = m_wizardFields.restoreHeight; } - m_ctx->createWalletFromDevice(walletPath, m_wizardFields.password, restoreHeight); + emit createWalletFromDevice(walletPath, m_wizardFields.password, restoreHeight); return; } if (m_wizardFields.mode == WizardMode::RestoreFromKeys) { - m_ctx->createWalletFromKeys(walletPath, - m_wizardFields.password, - m_wizardFields.address, - m_wizardFields.secretViewKey, - m_wizardFields.secretSpendKey, - m_wizardFields.restoreHeight); + emit createWalletFromKeys(walletPath, + m_wizardFields.password, + m_wizardFields.address, + m_wizardFields.secretViewKey, + m_wizardFields.secretSpendKey, + m_wizardFields.restoreHeight); return; } - auto seed = FeatherSeed(m_ctx->networkType, QString::fromStdString(globals::coinName), m_ctx->seedLanguage, m_wizardFields.seed.split(" ")); + auto seed = FeatherSeed(constants::networkType, QString::fromStdString(constants::coinName), constants::seedLanguage, m_wizardFields.seed.split(" ")); - if (m_wizardFields.mode == WizardMode::CreateWallet) { + if (m_wizardFields.mode == WizardMode::CreateWallet && currentBlockHeight > 0) { qInfo() << "New wallet, setting restore height to latest blockheight: " << currentBlockHeight; seed.setRestoreHeight(currentBlockHeight); } @@ -120,5 +121,5 @@ void WalletWizard::createWallet() { if (m_wizardFields.mode == WizardMode::RestoreFromSeed && m_wizardFields.seedType == SeedType::MONERO) seed.setRestoreHeight(m_wizardFields.restoreHeight); - m_ctx->createWallet(seed, walletPath, m_wizardFields.password, m_wizardFields.seedOffsetPassphrase); + emit createWallet(seed, walletPath, m_wizardFields.password, m_wizardFields.seedOffsetPassphrase); } diff --git a/src/wizard/WalletWizard.h b/src/wizard/WalletWizard.h index 19d0178a..6161f710 100644 --- a/src/wizard/WalletWizard.h +++ b/src/wizard/WalletWizard.h @@ -9,6 +9,7 @@ #include #include "appcontext.h" +#include "utils/keysfiles.h" #include "utils/RestoreHeightLookup.h" #include "utils/config.h" @@ -54,7 +55,8 @@ public: Page_NetworkTor }; - explicit WalletWizard(AppContext *ctx, WalletWizard::Page startPage = WalletWizard::Page::Page_Menu, QWidget *parent = nullptr); + explicit WalletWizard(QWidget *parent = nullptr); + ~WalletWizard() override; signals: void initialNetworkConfigured(); @@ -62,12 +64,16 @@ signals: void openWallet(QString path, QString password); void defaultWalletDirChanged(QString walletDir); + void createWalletFromDevice(const QString &path, const QString &password, int restoreHeight); + void createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic = false); + void createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset = ""); + +private slots: + void onCreateWallet(); + private: - AppContext *m_ctx; WalletKeysFilesModel *m_walletKeysFilesModel; WizardFields m_wizardFields; - - void createWallet(); }; #endif // WALLETWIZARD_H From 1e23b0679ed2ed693dfbf68f128e21a86ed1773c Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 20 May 2021 15:13:50 +0200 Subject: [PATCH 04/62] Amount display improvements --- src/appcontext.cpp | 92 ++++++++++++++++--------------- src/appcontext.h | 2 +- src/libwalletqt/WalletManager.cpp | 11 +++- src/libwalletqt/WalletManager.h | 2 +- src/mainwindow.cpp | 10 +--- src/model/CoinsModel.cpp | 5 +- src/utils/utils.cpp | 9 --- src/utils/utils.h | 1 - 8 files changed, 64 insertions(+), 68 deletions(-) diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 75588a46..6ae6b9fa 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -56,26 +56,9 @@ AppContext::AppContext(Wallet *wallet) this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString()); } -void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector &address) { - // tx cancelled by user - double amount = tx->amount() / constants::cdiv; - emit createTransactionCancelled(address, amount); - this->wallet->disposeTransaction(tx); -} - -void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) { - if (churn) { - address = this->wallet->address(0, 0); // primary address - } - - qCritical() << "Creating transaction"; - this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); - - emit initiateTransaction(); -} +// ################## Transaction creation ################## void AppContext::onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all) { - // tx creation this->tmpTxDescription = description; if (!all && amount == 0) { @@ -83,16 +66,16 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con return; } - auto unlocked_balance = this->wallet->unlockedBalance(); - if(!all && amount > unlocked_balance) { + quint64 unlocked_balance = this->wallet->unlockedBalance(); + if (!all && amount > unlocked_balance) { emit createTransactionError("Not enough money to spend"); return; - } else if(unlocked_balance == 0) { + } else if (unlocked_balance == 0) { emit createTransactionError("No money to spend"); return; } - qDebug() << "Creating tx"; + qInfo() << "Creating transaction"; if (all) this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority); else @@ -114,28 +97,32 @@ void AppContext::onCreateTransactionMultiDest(const QVector &addresses, emit createTransactionError("Not enough money to spend"); } - qDebug() << "Creating tx"; + qInfo() << "Creating transaction"; this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority); emit initiateTransaction(); } +void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) { + if (churn) { + address = this->wallet->address(0, 0); // primary address + } + + qInfo() << "Creating transaction"; + this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); + + emit initiateTransaction(); +} + void AppContext::onCreateTransactionError(const QString &msg) { this->tmpTxDescription = ""; emit endTransaction(); } -void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) { - auto *model = this->wallet->transactionHistoryModel(); - if (model != nullptr) { - model->preferredFiatSymbol = symbol; - } -} - -void AppContext::onAmountPrecisionChanged(int precision) { - auto *model = this->wallet->transactionHistoryModel(); - if (!model) return; - model->amountPrecision = precision; +void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector &address) { + // tx cancelled by user + emit createTransactionCancelled(address, tx->amount()); + this->wallet->disposeTransaction(tx); } void AppContext::commitTransaction(PendingTransaction *tx) { @@ -164,6 +151,23 @@ void AppContext::onMultiBroadcast(PendingTransaction *tx) { } } +// ################## Models ################## + +void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) { + auto *model = this->wallet->transactionHistoryModel(); + if (model != nullptr) { + model->preferredFiatSymbol = symbol; + } +} + +void AppContext::onAmountPrecisionChanged(int precision) { + auto *model = this->wallet->transactionHistoryModel(); + if (!model) return; + model->amountPrecision = precision; +} + +// ################## Device ################## + void AppContext::onDeviceButtonRequest(quint64 code) { emit deviceButtonRequest(code); } @@ -173,6 +177,8 @@ void AppContext::onDeviceError(const QString &message) { emit deviceError(message); } +// ################## Misc ################## + void AppContext::onTorSettingsChanged() { if (Utils::isTorsocks()) { return; @@ -247,23 +253,21 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) { // ########################################## LIBWALLET QT SIGNALS #################################################### void AppContext::onMoneySpent(const QString &txId, quint64 amount) { - auto amount_num = amount / constants::cdiv; - qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); + // Outgoing tx included in a block + qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount); } void AppContext::onMoneyReceived(const QString &txId, quint64 amount) { // Incoming tx included in a block. - auto amount_num = amount / constants::cdiv; - qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); + qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount); } void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) { - // Incoming transaction in pool - auto amount_num = amount / constants::cdiv; - qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num); + // Incoming tx in pool + qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount); - if(this->wallet->synchronized()) { - auto notify = QString("%1 XMR (pending)").arg(amount_num); + if (this->wallet->synchronized()) { + auto notify = QString("%1 XMR (pending)").arg(WalletManager::displayAmount(amount, false)); Utils::desktopNotify("Payment received", notify, 5000); } } @@ -353,7 +357,7 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con this->updateBalance(); // this tx was a donation to Feather, stop our nagging - if(this->donationSending) { + if (this->donationSending) { this->donationSending = false; config()->set(Config::donateBeg, -1); } diff --git a/src/appcontext.h b/src/appcontext.h index 646457de..af45fa64 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -82,7 +82,7 @@ signals: void walletRefreshed(); void transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid); void createTransactionError(QString message); - void createTransactionCancelled(const QVector &address, double amount); + void createTransactionCancelled(const QVector &address, quint64 amount); void createTransactionSuccess(PendingTransaction *tx, const QVector &address); void openAliasResolveError(const QString &msg); void openAliasResolved(const QString &address, const QString &openAlias); diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp index aa34a533..b91b7cf0 100644 --- a/src/libwalletqt/WalletManager.cpp +++ b/src/libwalletqt/WalletManager.cpp @@ -208,9 +208,16 @@ QString WalletManager::maximumAllowedAmountAsString() const return WalletManager::displayAmount(WalletManager::maximumAllowedAmount()); } -QString WalletManager::displayAmount(quint64 amount) +QString WalletManager::displayAmount(quint64 amount, bool trailing_zeroes) { - return QString::fromStdString(Monero::Wallet::displayAmount(amount)); + auto amountStr = QString::fromStdString(Monero::Wallet::displayAmount(amount)); + + if (!trailing_zeroes) { + amountStr.remove(QRegExp("0+$")); + amountStr.remove(QRegExp("\\.$")); + } + + return amountStr; } quint64 WalletManager::amountFromString(const QString &amount) diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h index 1a02d456..156b497d 100644 --- a/src/libwalletqt/WalletManager.h +++ b/src/libwalletqt/WalletManager.h @@ -108,7 +108,7 @@ public: Q_INVOKABLE QString errorString() const; //! since we can't call static method from QML, move it to this class - Q_INVOKABLE static QString displayAmount(quint64 amount); + Q_INVOKABLE static QString displayAmount(quint64 amount, bool trailing_zeroes = true); Q_INVOKABLE static quint64 amountFromString(const QString &amount); Q_INVOKABLE static quint64 amountFromDouble(double amount); Q_INVOKABLE quint64 maximumAllowedAmount() const; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0850dedc..a5358810 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -465,14 +465,9 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { qDebug() << Q_FUNC_INFO; bool hide = config()->get(Config::hideBalance).toBool(); - QString balance_str = WalletManager::displayAmount(spendable); - balance_str.remove(QRegExp("0+$")); - - QString label_str = QString("Balance: %1 XMR").arg(balance_str); + QString label_str = QString("Balance: %1 XMR").arg(WalletManager::displayAmount(spendable, false)); if (balance > spendable) { - QString unconfirmed_str = WalletManager::displayAmount(spendable); - unconfirmed_str.remove(QRegExp("0+$")); - label_str += QString(" (+%1 XMR unconfirmed)").arg(Utils::balanceFormat(balance - spendable)); + label_str += QString(" (+%1 XMR unconfirmed)").arg(WalletManager::displayAmount(balance - spendable, false)); } if (hide) @@ -1077,7 +1072,6 @@ void MainWindow::updateNetStats() { m_statusLabelNetStats->setText(""); return; } - if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) { m_statusLabelNetStats->setText(""); return; diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp index 1e7d5255..ca297fbb 100644 --- a/src/model/CoinsModel.cpp +++ b/src/model/CoinsModel.cpp @@ -8,6 +8,7 @@ #include "constants.h" #include "utils/ColorScheme.h" #include "utils/Icons.h" +#include "libwalletqt/WalletManager.h" #include @@ -182,9 +183,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in case Amount: { if (role == Qt::UserRole) { - return cInfo.amount() / constants::cdiv; + return cInfo.amount(); } - return QString::number(cInfo.amount() / constants::cdiv, 'f', 12); + return cInfo.displayAmount(); } case Frozen: return cInfo.frozen(); diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 60706a92..eb352741 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -453,15 +453,6 @@ int Utils::maxLength(const QVector &array) { return maxLength; } -QString Utils::balanceFormat(quint64 balance) { - QString str = QString::number(balance / constants::cdiv, 'f', 4); - - str.remove(QRegExp("0+$")); - str.remove(QRegExp("\\.$")); - - return str; -} - QTextCharFormat Utils::addressTextFormat(const SubaddressIndex &index) { if (index.isPrimary()) { QTextCharFormat rec; diff --git a/src/utils/utils.h b/src/utils/utils.h index e72a8e73..7b88b8d8 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -75,7 +75,6 @@ public: static QString amountToCurrencyString(double amount, const QString ¤cyCode); static int maxLength(const QVector &array); static QMap localeCache; - static QString balanceFormat(quint64 balance); static QTextCharFormat addressTextFormat(const SubaddressIndex &index); static bool isTorsocks(); static QString defaultWalletDir(); From 65e95f0e65b0673a229faeffea5d336626e3af83 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 20 May 2021 16:04:59 +0200 Subject: [PATCH 05/62] Clean up calcwidget --- src/calcwidget.cpp | 100 +++++++++++++-------------------------------- src/calcwidget.h | 26 +++++------- src/calcwidget.ui | 67 +----------------------------- src/calcwindow.cpp | 11 ----- src/calcwindow.h | 4 -- 5 files changed, 39 insertions(+), 169 deletions(-) diff --git a/src/calcwidget.cpp b/src/calcwidget.cpp index b4ce187d..2190c408 100644 --- a/src/calcwidget.cpp +++ b/src/calcwidget.cpp @@ -29,92 +29,48 @@ CalcWidget::CalcWidget(QWidget *parent) ui->lineFrom->setValidator(dv); ui->lineTo->setValidator(dv); - connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::initFiat); - connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::initCrypto);; + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::initComboBox); + connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::initComboBox); + + connect(ui->lineFrom, &QLineEdit::textEdited, this, [this]{this->convert(false);}); + connect(ui->lineTo, &QLineEdit::textEdited, this, [this]{this->convert(true);}); + + connect(ui->comboCalcFrom, QOverload::of(&QComboBox::currentIndexChanged), [this]{this->convert(false);}); + connect(ui->comboCalcTo, QOverload::of(&QComboBox::currentIndexChanged), [this]{this->convert(true);}); } -void CalcWidget::fromChanged(const QString &data) { - if(!this->m_comboBoxInit) return; - if(this->m_changing){ - this->m_changing = false; +void CalcWidget::convert(bool reverse) { + if (!m_comboBoxInit) return; + + auto lineFrom = reverse ? ui->lineTo : ui->lineFrom; + auto lineTo = reverse ? ui->lineFrom : ui->lineTo; + + auto comboFrom = reverse ? ui->comboCalcTo : ui->comboCalcFrom; + auto comboTo = reverse ? ui->comboCalcFrom : ui->comboCalcTo; + + QString symbolFrom = comboFrom->itemText(comboFrom->currentIndex()); + QString symbolTo = comboTo->itemText(comboTo->currentIndex()); + + if (symbolFrom == symbolTo) { + lineTo->setText(lineFrom->text()); } - QString symbolFrom = ui->comboCalcFrom->itemText(ui->comboCalcFrom->currentIndex()); - QString symbolTo = ui->comboCalcTo->itemText(ui->comboCalcTo->currentIndex()); - - if(symbolFrom == symbolTo){ - ui->lineTo->setText(data); - return; - } - - QString amount_str = ui->lineFrom->text(); - if(amount_str.startsWith('.')){ - ui->lineFrom->setText(ui->lineTo->text()); - return; - } - - double amount = amount_str.toDouble(); + QString amountStr = lineFrom->text(); + double amount = amountStr.toDouble(); double result = appData()->prices.convert(symbolFrom, symbolTo, amount); - this->m_changing = true; - int precision = 10; if (appData()->prices.rates.contains(symbolTo)) precision = 2; - ui->lineTo->setText(QString::number(result, 'f', precision)); -} - -void CalcWidget::toChanged(const QString &data) { - if(!this->m_comboBoxInit) return; - if(this->m_changing){ - this->m_changing = false; - return; - } - - QString symbolFrom = ui->comboCalcFrom->itemText( - ui->comboCalcFrom->currentIndex()); - QString symbolTo = ui->comboCalcTo->itemText( - ui->comboCalcTo->currentIndex()); - - if(symbolFrom == symbolTo){ - ui->lineTo->setText(ui->lineFrom->text()); - return; - } - - QString amount_str = ui->lineTo->text(); - if(amount_str.startsWith('.')){ - ui->lineTo->setText(""); - return; - } - - double amount = amount_str.toDouble(); - double result = appData()->prices.convert(symbolTo, symbolFrom, amount); - - this->m_changing = true; - - int precision = 10; - if(appData()->prices.rates.contains(symbolFrom)) - precision = 2; - - ui->lineFrom->setText(QString::number(result, 'f', precision)); -} - -void CalcWidget::toComboChanged(const QString &data) { - this->fromChanged(data); -} - -void CalcWidget::initCrypto() { - this->initComboBox(); -} - -void CalcWidget::initFiat() { - this->initComboBox(); + lineTo->setText(QString::number(result, 'f', precision)); } void CalcWidget::initComboBox() { - if(m_comboBoxInit) return; + if (m_comboBoxInit) + return; + QList marketsKeys = appData()->prices.markets.keys(); QList ratesKeys = appData()->prices.rates.keys(); if(marketsKeys.count() <= 0 || ratesKeys.count() <= 0) return; diff --git a/src/calcwidget.h b/src/calcwidget.h index 9ad2134c..de95604a 100644 --- a/src/calcwidget.h +++ b/src/calcwidget.h @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. -#ifndef CALC_H -#define CALC_H +#ifndef FEATHER_CALCWIDGET_H +#define FEATHER_CALCWIDGET_H #include @@ -18,23 +18,17 @@ public: explicit CalcWidget(QWidget *parent = nullptr); ~CalcWidget() override; -signals: - void closed(); - public slots: - void fromChanged(const QString& data); - void toChanged(const QString& data); - void toComboChanged(const QString& data); - void initFiat(); - void initCrypto(); void skinChanged(); -private: - Ui::CalcWidget *ui; - - bool m_comboBoxInit = false; +private slots: void initComboBox(); - bool m_changing = false; + +private: + void convert(bool reverse); + + Ui::CalcWidget *ui; + bool m_comboBoxInit = false; }; -#endif // CALC_H +#endif // FEATHER_CALCWIDGET_H diff --git a/src/calcwidget.ui b/src/calcwidget.ui index dbd49bbd..66360aed 100644 --- a/src/calcwidget.ui +++ b/src/calcwidget.ui @@ -167,72 +167,7 @@
- - - lineFrom - textChanged(QString) - CalcWidget - fromChanged(QString) - - - 119 - 77 - - - 427 - -1 - - - - - lineTo - textChanged(QString) - CalcWidget - toChanged(QString) - - - 463 - 86 - - - 640 - -4 - - - - - comboCalcFrom - currentIndexChanged(QString) - CalcWidget - fromChanged(QString) - - - 196 - 77 - - - 330 - -9 - - - - - comboCalcTo - currentIndexChanged(QString) - CalcWidget - toComboChanged(QString) - - - 574 - 82 - - - 265 - -5 - - - - + fromChanged(QString) toChanged(QString) diff --git a/src/calcwindow.cpp b/src/calcwindow.cpp index 3a363e73..1b72fc33 100644 --- a/src/calcwindow.cpp +++ b/src/calcwindow.cpp @@ -17,17 +17,6 @@ CalcWindow::CalcWindow(QWidget *parent) ui->setupUi(this); this->setWindowIcon(icons()->icon("gnome-calc.png")); - - connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWindow::initFiat); - connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWindow::initCrypto); -} - -void CalcWindow::initFiat() { - this->ui->calcWidget->initFiat(); -} - -void CalcWindow::initCrypto() { - this->ui->calcWidget->initCrypto(); } void CalcWindow::closeEvent(QCloseEvent *foo) { diff --git a/src/calcwindow.h b/src/calcwindow.h index 8d6b6ed0..886a9fb8 100644 --- a/src/calcwindow.h +++ b/src/calcwindow.h @@ -21,10 +21,6 @@ public: signals: void closed(); -public slots: - void initFiat(); - void initCrypto(); - private: void closeEvent(QCloseEvent *bar) override; From b0834f87292d43155c46c41664c594b10e27855e Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 20 May 2021 17:04:47 +0200 Subject: [PATCH 06/62] Fix keysfiles debug message --- src/utils/keysfiles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/keysfiles.cpp b/src/utils/keysfiles.cpp index 495ecc79..8a0a2c36 100644 --- a/src/utils/keysfiles.cpp +++ b/src/utils/keysfiles.cpp @@ -116,7 +116,7 @@ void WalletKeysFilesModel::findWallets() { this->addWalletKeysFile(WalletKeysFiles(fileInfo, networkType, std::move(addr))); } - auto duration = duration_cast(high_resolution_clock::now() - now).count(); + auto duration = duration_cast(high_resolution_clock::now() - now).count(); qDebug() << QString("wallet .keys search completed in %1 ms").arg(duration); } From 3d646fb345783a443c2822292ccef19194f2f9ce Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 20 May 2021 21:39:53 +0200 Subject: [PATCH 07/62] Clean up WalletKeysFilesModel --- .../WalletKeysFilesModel.cpp} | 101 +++++++++--------- .../WalletKeysFilesModel.h} | 47 ++++---- src/wizard/PageOpenWallet.cpp | 2 +- src/wizard/PageOpenWallet.h | 2 +- src/wizard/WalletWizard.cpp | 4 - src/wizard/WalletWizard.h | 3 +- 6 files changed, 81 insertions(+), 78 deletions(-) rename src/{utils/keysfiles.cpp => model/WalletKeysFilesModel.cpp} (74%) rename src/{utils/keysfiles.h => model/WalletKeysFilesModel.h} (59%) diff --git a/src/utils/keysfiles.cpp b/src/model/WalletKeysFilesModel.cpp similarity index 74% rename from src/utils/keysfiles.cpp rename to src/model/WalletKeysFilesModel.cpp index 8a0a2c36..37fd03d5 100644 --- a/src/utils/keysfiles.cpp +++ b/src/model/WalletKeysFilesModel.cpp @@ -1,49 +1,41 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2014-2021, The Monero Project. -#include "keysfiles.h" +#include "WalletKeysFilesModel.h" + +#include "utils/utils.h" +#include +#include +#include "config.h" using namespace std::chrono; -WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) : - m_fileName(info.fileName()), - m_modified(info.lastModified().toSecsSinceEpoch()), - m_path(QDir::toNativeSeparators(info.absoluteFilePath())), - m_networkType(networkType), - m_address(std::move(address)) +WalletKeysFile::WalletKeysFile(const QFileInfo &info, int networkType, QString address) + : m_fileName(info.fileName()) + , m_modified(getModified(info)) + , m_path(QDir::toNativeSeparators(info.absoluteFilePath())) + , m_networkType(networkType) + , m_address(std::move(address)) { +} + +qint64 WalletKeysFile::getModified(const QFileInfo &info) { + qint64 m = info.lastModified().toSecsSinceEpoch(); + QFileInfo cacheFile = QFileInfo(info.absoluteFilePath().replace(QRegExp(".keys$"), "")); qint64 cacheLastModified = cacheFile.lastModified().toSecsSinceEpoch(); - if (cacheFile.exists()) { - m_modified = (cacheLastModified > m_modified) ? cacheLastModified : m_modified; + if (cacheFile.exists() && cacheLastModified > m) { + m = cacheLastModified; } + return m; } -QString WalletKeysFiles::fileName() const { - return m_fileName; -} - -qint64 WalletKeysFiles::modified() const { - return m_modified; -} - -QString WalletKeysFiles::address() const { - return m_address; -} - -QString WalletKeysFiles::path() const { - return m_path; -} - -int WalletKeysFiles::networkType() const { - return m_networkType; -} +// Model WalletKeysFilesModel::WalletKeysFilesModel(QObject *parent) - : QAbstractTableModel(parent) + : QAbstractTableModel(parent) { this->updateDirectories(); - this->m_walletKeysFilesItemModel = qobject_cast(this); } void WalletKeysFilesModel::clear() { @@ -58,17 +50,23 @@ void WalletKeysFilesModel::refresh() { endResetModel(); } -void WalletKeysFilesModel::updateDirectories() { // TODO - this->walletDirectories.clear(); +void WalletKeysFilesModel::updateDirectories() { + m_walletDirectories.clear(); + QDir defaultWalletDir = QDir(Utils::defaultWalletDir()); QString walletDir = defaultWalletDir.path(); defaultWalletDir.cdUp(); QString walletDirRoot = defaultWalletDir.path(); - this->walletDirectories << walletDir; - this->walletDirectories << walletDirRoot; - this->walletDirectories << QDir::homePath(); - this->walletDirectories.removeDuplicates(); + m_walletDirectories << walletDir; + m_walletDirectories << walletDirRoot; + m_walletDirectories << QDir::homePath(); + + QString walletDirectory = config()->get(Config::walletDirectory).toString(); + if (!walletDirectory.isEmpty()) + m_walletDirectories << walletDirectory; + + m_walletDirectories.removeDuplicates(); } void WalletKeysFilesModel::findWallets() { @@ -79,9 +77,9 @@ void WalletKeysFilesModel::findWallets() { rx.setPatternSyntax(QRegExp::Wildcard); QStringList walletPaths; - for(auto i = 0; i != this->walletDirectories.length(); i++) { + for(auto i = 0; i != m_walletDirectories.length(); i++) { // Scan default wallet dir (~/Monero/) - walletPaths << Utils::fileFind(rx, this->walletDirectories[i], 0, i == 0 ? 2 : 0, 200); + walletPaths << Utils::fileFind(rx, m_walletDirectories[i], 0, i == 0 ? 2 : 0, 200); } walletPaths.removeDuplicates(); @@ -113,16 +111,16 @@ void WalletKeysFilesModel::findWallets() { file.close(); } - this->addWalletKeysFile(WalletKeysFiles(fileInfo, networkType, std::move(addr))); + this->addWalletKeysFile(WalletKeysFile(fileInfo, networkType, std::move(addr))); } auto duration = duration_cast(high_resolution_clock::now() - now).count(); qDebug() << QString("wallet .keys search completed in %1 ms").arg(duration); } -void WalletKeysFilesModel::addWalletKeysFile(const WalletKeysFiles &walletKeysFile) { +void WalletKeysFilesModel::addWalletKeysFile(const WalletKeysFile &walletKeysFile) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_walletKeyFiles << walletKeysFile; + m_walletKeyFiles.append(walletKeysFile); endInsertRows(); } @@ -131,7 +129,7 @@ int WalletKeysFilesModel::rowCount(const QModelIndex & parent) const { } int WalletKeysFilesModel::columnCount(const QModelIndex &) const { - return 4; + return Column::COUNT; } QVariant WalletKeysFilesModel::data(const QModelIndex &index, int role) const { @@ -142,7 +140,7 @@ QVariant WalletKeysFilesModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { switch(index.column()) { - case ModelColumns::NetworkType: { + case Column::NetworkType: { auto c = static_cast(walletKeyFile.networkType()); if (c == NetworkType::Type::STAGENET) return QString("stage"); @@ -150,9 +148,10 @@ QVariant WalletKeysFilesModel::data(const QModelIndex &index, int role) const { return QString("test"); return QString("main"); } - case ModelColumns::FileName: + case Column::FileName: { return walletKeyFile.fileName().replace(".keys", ""); - case ModelColumns::Path: { + } + case Column::Path: { auto fp = walletKeyFile.path(); #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) if (fp.startsWith(QDir::homePath())) { @@ -161,20 +160,20 @@ QVariant WalletKeysFilesModel::data(const QModelIndex &index, int role) const { #endif return fp; } - case ModelColumns::Modified: + case Column::Modified: return walletKeyFile.modified(); default: break; } } else if(role == Qt::UserRole) { switch(index.column()) { - case ModelColumns::NetworkType: + case Column::NetworkType: return static_cast(walletKeyFile.networkType()); - case ModelColumns::FileName: + case Column::FileName: return walletKeyFile.fileName(); - case ModelColumns::Modified: + case Column::Modified: return (int)walletKeyFile.modified(); - case ModelColumns::Path: + case Column::Path: return walletKeyFile.path(); default: break; @@ -202,6 +201,8 @@ QVariant WalletKeysFilesModel::headerData(int section, Qt::Orientation orientati return QVariant(); } +// ProxyModel + WalletKeysFilesProxyModel::WalletKeysFilesProxyModel(QObject *parent, NetworkType::Type nettype) : QSortFilterProxyModel(parent) , m_nettype(nettype) diff --git a/src/utils/keysfiles.h b/src/model/WalletKeysFilesModel.h similarity index 59% rename from src/utils/keysfiles.h rename to src/model/WalletKeysFilesModel.h index efd773f2..cdabe08b 100644 --- a/src/utils/keysfiles.h +++ b/src/model/WalletKeysFilesModel.h @@ -1,25 +1,30 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2014-2021, The Monero Project. -#ifndef KEYSFILES_H -#define KEYSFILES_H +#ifndef FEATHER_WALLETKEYSFILESMODEL_H +#define FEATHER_WALLETKEYSFILESMODEL_H + +#include +#include +#include +#include -#include "libwalletqt/WalletManager.h" #include "utils/networktype.h" -#include "utils/utils.h" -class WalletKeysFiles +class WalletKeysFile { public: - WalletKeysFiles(const QFileInfo &info, int networkType, QString address); + WalletKeysFile(const QFileInfo &info, int networkType, QString address); - QString fileName() const; - qint64 modified() const; - QString path() const; - int networkType() const; - QString address() const; + QString fileName() const {return m_fileName;}; + qint64 modified() const {return m_modified;}; + QString path() const {return m_path;}; + int networkType() const {return m_networkType;}; + QString address() const {return m_address;}; private: + static qint64 getModified(const QFileInfo &info); + QString m_fileName; qint64 m_modified; QString m_path; @@ -29,13 +34,15 @@ private: class WalletKeysFilesModel : public QAbstractTableModel { - Q_OBJECT +Q_OBJECT + public: - enum ModelColumns { + enum Column { NetworkType = 0, FileName, Path, - Modified + Modified, + COUNT }; explicit WalletKeysFilesModel(QObject *parent = nullptr); @@ -44,25 +51,25 @@ public: Q_INVOKABLE void clear(); void findWallets(); - void addWalletKeysFile(const WalletKeysFiles &walletKeysFile); + void addWalletKeysFile(const WalletKeysFile &walletKeysFile); int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QStringList walletDirectories; private: void updateDirectories(); - QList m_walletKeyFiles; - QAbstractItemModel *m_walletKeysFilesItemModel; - QSortFilterProxyModel m_walletKeysFilesModelProxy; + QStringList m_walletDirectories; + + QList m_walletKeyFiles; }; class WalletKeysFilesProxyModel : public QSortFilterProxyModel { Q_OBJECT + public: explicit WalletKeysFilesProxyModel(QObject *parent, NetworkType::Type nettype); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; @@ -71,4 +78,4 @@ private: NetworkType::Type m_nettype; }; -#endif // KEYSFILES_H +#endif //FEATHER_WALLETKEYSFILESMODEL_H diff --git a/src/wizard/PageOpenWallet.cpp b/src/wizard/PageOpenWallet.cpp index 34f1a6f1..4c0e1883 100644 --- a/src/wizard/PageOpenWallet.cpp +++ b/src/wizard/PageOpenWallet.cpp @@ -91,7 +91,7 @@ bool PageOpenWallet::validatePage() { QMessageBox::warning(this, "Wallet not selected", "Please select a wallet from the list."); return false; } - QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString(); + QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::Column::Path), Qt::UserRole).toString(); auto autoWallet = ui->openOnStartup->isChecked() ? QString("%1%2").arg(constants::networkType).arg(walletPath) : ""; config()->set(Config::autoOpenWalletPath, autoWallet); diff --git a/src/wizard/PageOpenWallet.h b/src/wizard/PageOpenWallet.h index 3ed45a1c..1385203d 100644 --- a/src/wizard/PageOpenWallet.h +++ b/src/wizard/PageOpenWallet.h @@ -9,7 +9,7 @@ #include #include "appcontext.h" -#include "utils/keysfiles.h" +#include "model/WalletKeysFilesModel.h" namespace Ui { class PageOpenWallet; diff --git a/src/wizard/WalletWizard.cpp b/src/wizard/WalletWizard.cpp index 6b551577..5501b6d9 100644 --- a/src/wizard/WalletWizard.cpp +++ b/src/wizard/WalletWizard.cpp @@ -79,10 +79,6 @@ WalletWizard::WalletWizard(QWidget *parent) }); } -WalletWizard::~WalletWizard() { - qDebug() << "We're killing the walletwizard"; -} - void WalletWizard::onCreateWallet() { auto walletPath = QString("%1/%2").arg(m_wizardFields.walletDir, m_wizardFields.walletName); diff --git a/src/wizard/WalletWizard.h b/src/wizard/WalletWizard.h index 6161f710..2c2db39c 100644 --- a/src/wizard/WalletWizard.h +++ b/src/wizard/WalletWizard.h @@ -9,7 +9,7 @@ #include #include "appcontext.h" -#include "utils/keysfiles.h" +#include "model/WalletKeysFilesModel.h" #include "utils/RestoreHeightLookup.h" #include "utils/config.h" @@ -56,7 +56,6 @@ public: }; explicit WalletWizard(QWidget *parent = nullptr); - ~WalletWizard() override; signals: void initialNetworkConfigured(); From 9a97c44d4ccf1f4a1093d3f54b84892f2ba952fa Mon Sep 17 00:00:00 2001 From: tobtoht Date: Thu, 20 May 2021 23:41:12 +0200 Subject: [PATCH 08/62] Wizard: Change date format for clarity --- src/wizard/PageSetRestoreHeight.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wizard/PageSetRestoreHeight.cpp b/src/wizard/PageSetRestoreHeight.cpp index bf28d060..8fdc07d4 100644 --- a/src/wizard/PageSetRestoreHeight.cpp +++ b/src/wizard/PageSetRestoreHeight.cpp @@ -86,7 +86,7 @@ void PageSetRestoreHeight::onRestoreHeightEdited() { } void PageSetRestoreHeight::showScanWarning(const QDateTime &date) { - QString dateString = date.toString("yyyy-MM-dd"); + QString dateString = date.toString("MMMM dd, yyyy"); ui->label_scanWarning->setText(QString("Wallet will not scan for transactions before %1").arg(dateString)); ui->frame_scanWarning->show(); } From 57593589dfd04f8d51806e44d50d9fb654d20297 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 21 May 2021 00:11:59 +0200 Subject: [PATCH 09/62] SeedDialog: Fix missing 25 word seed if lang not set --- src/dialog/seeddialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dialog/seeddialog.cpp b/src/dialog/seeddialog.cpp index 123dcaee..ca8405d2 100644 --- a/src/dialog/seeddialog.cpp +++ b/src/dialog/seeddialog.cpp @@ -3,6 +3,7 @@ #include "ui_seeddialog.h" #include "seeddialog.h" +#include "constants.h" SeedDialog::SeedDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) @@ -14,6 +15,11 @@ SeedDialog::SeedDialog(QSharedPointer ctx, QWidget *parent) ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight())); + if (m_ctx->wallet->getSeedLanguage().isEmpty()) { + qDebug() << "No seed language set, using default"; + m_ctx->wallet->setSeedLanguage(constants::seedLanguage); + } + QString seedOffset = m_ctx->wallet->getCacheAttribute("feather.seedoffset"); QString seed_14_words = m_ctx->wallet->getCacheAttribute("feather.seed"); QString seed_25_words = m_ctx->wallet->getSeed(seedOffset); From 132a738ebacdd91ba1a7475477db554166aecb6b Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 21 May 2021 22:09:23 +0200 Subject: [PATCH 10/62] Dockerfile: fix reproducibility issue with libudev --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 52f8bacb..99449088 100644 --- a/Dockerfile +++ b/Dockerfile @@ -88,8 +88,6 @@ RUN apt-get update && \ # build tools software-properties-common automake pkg-config python \ libtool-bin wget zip \ -# dependencies - libusb-1.0-0-dev \ # Qt libgl1-mesa-dev libglib2.0-dev mesa-common-dev \ # libusb @@ -112,6 +110,11 @@ RUN add-apt-repository ppa:git-core/ppa && \ apt-get install -y git && \ rm -rf /var/lib/apt/lists/* +RUN wget http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/libudev-dev_229-4ubuntu21.31_amd64.deb && \ + echo "f1f72bd814d1e8ca2828ac004924fba0b54a3299e60f089c6d818262b11750f7 libudev-dev_229-4ubuntu21.31_amd64.deb" | sha256sum -c && \ + apt install ./libudev-dev_229-4ubuntu21.31_amd64.deb && \ + rm libudev-dev_229-4ubuntu21.31_amd64.deb + RUN mkdir appimagetool && \ cd appimagetool && \ wget https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage && \ From 80f7ea11b8fe5558b62133bff50367f378222f31 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 21 May 2021 22:12:12 +0200 Subject: [PATCH 11/62] Dockerfile: fix Qt tag --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 99449088..d7b0eee8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -69,7 +69,7 @@ RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \ FROM ubuntu:16.04 ARG THREADS=1 -ARG QT_VERSION=5.15.2 +ARG QT_VERSION=v5.15.2 ENV CFLAGS="-fPIC" ENV CPPFLAGS="-fPIC" From 21d29fa7eee512e6c603a4fdb28031de56991f21 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 21 May 2021 22:44:46 +0200 Subject: [PATCH 12/62] Fix build issue --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc3e7ad4..399b0b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ endif() set(MONERO_HEAD "36fb05da3394505f8033ceb8806b28909617696f") set(BUILD_GUI_DEPS ON) -set(ARCH "x86-64" CACHE STRING "Target architecture") +set(ARCH "x86-64") set(BUILD_64 ON) set(INSTALL_VENDORED_LIBUNBOUND ${STATIC}) set(USE_SINGLE_BUILDDIR ON) From 50a77307f477fd63a722a1a3fff9bafc38c7f37a Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 15:42:26 +0200 Subject: [PATCH 13/62] Account switcher --- src/appcontext.cpp | 7 ++ src/assets.qrc | 1 + src/assets/images/change_account.png | Bin 0 -> 1939 bytes src/dialog/AccountSwitcherDialog.cpp | 107 +++++++++++++++++++++ src/dialog/AccountSwitcherDialog.h | 41 +++++++++ src/dialog/AccountSwitcherDialog.ui | 88 ++++++++++++++++++ src/libwalletqt/Coins.cpp | 4 + src/libwalletqt/SubaddressAccount.cpp | 5 + src/libwalletqt/SubaddressAccount.h | 1 + src/libwalletqt/TransactionHistory.cpp | 1 - src/libwalletqt/TransactionHistory.h | 1 + src/libwalletqt/Wallet.cpp | 2 + src/mainwindow.cpp | 14 ++- src/mainwindow.h | 2 + src/mainwindow.ui | 25 +++++ src/model/SubaddressAccountModel.cpp | 123 +++++++++++++++++++------ src/model/SubaddressAccountModel.h | 29 ++++-- src/model/SubaddressModel.cpp | 12 ++- src/model/SubaddressModel.h | 2 + 19 files changed, 421 insertions(+), 44 deletions(-) create mode 100644 src/assets/images/change_account.png create mode 100644 src/dialog/AccountSwitcherDialog.cpp create mode 100644 src/dialog/AccountSwitcherDialog.h create mode 100644 src/dialog/AccountSwitcherDialog.ui diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 6ae6b9fa..96b45635 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -41,6 +41,9 @@ AppContext::AppContext(Wallet *wallet) connect(this->wallet.get(), &Wallet::connectionStatusChanged, [this]{ this->nodes->autoConnect(); }); + connect(this->wallet.get(), &Wallet::currentSubaddressAccountChanged, [this]{ + this->updateBalance(); + }); connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError); @@ -54,6 +57,10 @@ AppContext::AppContext(Wallet *wallet) // force trigger preferredFiat signal for history model this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString()); + + connect(this->wallet->history(), &TransactionHistory::txNoteChanged, [this]{ + this->wallet->history()->refresh(this->wallet->currentSubaddressAccount()); + }); } // ################## Transaction creation ################## diff --git a/src/assets.qrc b/src/assets.qrc index 8f7488aa..9956d8be 100644 --- a/src/assets.qrc +++ b/src/assets.qrc @@ -19,6 +19,7 @@ assets/images/bitcoin.png assets/images/camera_dark.png assets/images/camera_white.png + assets/images/change_account.png assets/images/clock1.png assets/images/clock2.png assets/images/clock3.png diff --git a/src/assets/images/change_account.png b/src/assets/images/change_account.png new file mode 100644 index 0000000000000000000000000000000000000000..f24a4ba220b3284a6ec57e84f44b60ce333810a1 GIT binary patch literal 1939 zcmV;E2WP)y`sI?7HeyaDWqW1L^R6> zLkW!_1%qg?#6$yrFa*WKOAw5oFinVPst75G6crRpt)XcQi2-V%rnK9Zw%fApc6Ynm z-I+Ph&+#>76!$(}QNX6E-l=YMYV!qvDM|KA~#{eo?GHs9v3$AD!( z9z+blzzonV51+by+u48B`uy%EmahR>Y9(Ee2VOOWOKbFK8m@klQZxr*FUG1)^Hs=PoDw^BWqbOC0Vo z0b;Pj0OZk3{(ab((DYzxz z2#ANQT-W>Hi(mfhhkqLH`!8t>?E2dDovOMnwMc4}k~N0?4I(gYP9x|061*CXt$AiG zs;BkZJkBW{Z}qTm$2l;;iERcZPrw^rZ<`S%`e-hYjY({+;sD8jGs~2Pkp53&$Z5!` zJLchnRF#=x>M>1N@X2PnIwDRUh{5bLweZw526o*$b9x->9x)z_V{0u)d+sb>an%)xuPhS~F=cwfNlC^|UQ+Bt8$_$0GVVBL;h8 zOrhAEW7_;FG|kT8oN|0`9|!*4j{%3@>|(~pr-GK|4?|3G7SKAoU?=tuo|r@d%mrwk zlV|3VCdB0^HigV?ZbX)6gCT>u(BpGfG|_z|qU-&bo)7vF7nC1pqKG&|94#~R!HNAt zH7#hhtpkcjp>1&k;y&u-YI$)vuDzi#wU-(~3XC`eNk=_G!;FH6$~%)LK#fjuVokH^ zM))_)XRtx8qQ|efu8v%tqtH;Sy!r?KQq1D3?b({;h zW_F%pLzvpj6il)5s5gprj^!JQTRNVbw{%hjDDqxYTfvn)i#SArVOYshNt6UxoisH} z&oia9kc|yLEW*+;<8nrB3JY<;t>a~?X%LIrzYC3Fx@?JL{>=b!;9OQuK@7`0ZY7UT z&l8_7U>akpm?oK!1hh04gCYASMS!WkQ)~*x-a%zsh>Ne)w*(~hdDJIhez+%mf@*>$ zaReMpBH4Y}1ss0<`el7*&TlC;24&A$Hiw&O+9MfsHIL`(9H)Cv&^R=UAP6w?n2)m_ zNdW!J(oM(O$IDcc07E|?6j>PLN`M!@t4}Ls3d(Ch1&>>hFgV!HlwtwYqncz^iWAg7 zUJHCp0#JE3rAvX$C77n(&MIK#IYCGDxWh0Xl@~hG1XX*arTx%9Crv<{$Q!_W>f=R- z%Q^2Z05;45Bs+SUSv8LnhK@iIG_lk|<_&nHrTx&8wZg*$4m3S4FZ!c|`7gL^g_R&g zB+RDOvYyOl!yZ>3r>$Pv2?9}Ubocsa7vFPq(?sB5B1cN+A2*G?`WW>QmPDu@%2J%A zv~0-`>Z251W4u?q8UusIiLQi$$0PoH_+v9#Hf~utQ2`S=Ql8yD|6y^#Po%t+2%x;D zp?oa6(Bqw_BhK{tk34JZ(OcMh^cKM07VMc~pKUq5{egk;vP|eu-`w8uQ#1cv)yUKj zp-I*Q$whge_Q1(AmEi#*4N14uwi2_S57yiMmW@x}HC~oWI@BNf{i0`^iu#oxxcG6Y z#}f}H&nmrramD*%4fy8U-{6D(X$*hq0>Ln|=ZXWtSI6p&34c~u^-A{*yY$AHr_RFJ za}dR#W~doaoL>8|2VUx1&q24iBK(j4v!Nn9W(am?R7_sE{?=aHd#f>xy9d_%t>^9_DC}2nPpPs()riTDd0%9CRE@514!F3)6<6=*`IR^QwW-Z91y#e$cr(0_SaMbGjU~r!)?#Yuhb%KJ zS0J}!IpMOE!@Jii@TIajzBM5MH@|MhK0W)Is@_wAD8ZW=M`R&S7Jo=m!HKct_>p{{ zBRa1PuWDs6GIb{I6RQy?qrzvOuGdURK%ejZr5bB1!I#Q=f^}@3@;m+!tfyZZ=%<05 zvYrQIE4%fkitwiCV5hMK7AzeL98 zd-ouHXR5&?W<#f5{C2Un9uWVXD*JQnmOB!DCk2uQKBjU}{g8T687gO{;tSYFv%0aW($8 Z + +AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer ctx, QWidget *parent) + : QDialog(parent) + , ui(new Ui::AccountSwitcherDialog) + , m_ctx(std::move(ctx)) + , m_model(m_ctx->wallet->subaddressAccountModel()) +{ + ui->setupUi(this); + + ui->accounts->setContextMenuPolicy(Qt::CustomContextMenu); + + m_ctx->wallet->subaddressAccount()->refresh(); + ui->accounts->setModel(m_ctx->wallet->subaddressAccountModel()); + ui->accounts->setSelectionMode(QAbstractItemView::SingleSelection); + ui->accounts->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->accounts->hideColumn(SubaddressAccountModel::Column::Address); + ui->accounts->hideColumn(SubaddressAccountModel::Column::UnlockedBalance); + ui->accounts->setColumnWidth(SubaddressAccountModel::Column::Label, 200); + ui->accounts->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui->accounts->header()->setSectionResizeMode(SubaddressAccountModel::Label, QHeaderView::Stretch); + + connect(ui->accounts->selectionModel(), &QItemSelectionModel::currentChanged, this, &AccountSwitcherDialog::switchAccount); + connect(ui->accounts, &QTreeView::customContextMenuRequested, this, &AccountSwitcherDialog::showContextMenu); + connect(ui->accounts, &QTreeView::doubleClicked, [this](QModelIndex index){ + if (!m_model) return; + if (!(m_model->flags(index) & Qt::ItemIsEditable)) { + this->switchAccount(); + } + }); + + connect(ui->btn_newAccount, &QPushButton::clicked, [this]{ + m_ctx->wallet->addSubaddressAccount("New account"); + m_ctx->wallet->subaddressAccount()->refresh(); + }); + + connect(m_ctx->wallet.get(), &Wallet::currentSubaddressAccountChanged, this, &AccountSwitcherDialog::updateSelection); + connect(m_ctx->wallet->subaddressAccount(), &SubaddressAccount::refreshFinished, this, &AccountSwitcherDialog::updateSelection); + + this->updateSelection(); +} + +void AccountSwitcherDialog::switchAccount() { + QModelIndex index = ui->accounts->currentIndex(); + m_ctx->wallet->switchSubaddressAccount(index.row()); +} + +void AccountSwitcherDialog::copyLabel() { + auto row = this->currentEntry(); + if (!row) + return; + + Utils::copyToClipboard(QString::fromStdString(row->getLabel())); +} + +void AccountSwitcherDialog::copyBalance() { + auto row = this->currentEntry(); + if (!row) + return; + + Utils::copyToClipboard(QString::fromStdString(row->getBalance())); +} + +void AccountSwitcherDialog::editLabel() { + QModelIndex index = ui->accounts->currentIndex().siblingAtColumn(m_ctx->wallet->subaddressAccountModel()->Column::Label); + ui->accounts->setCurrentIndex(index); + ui->accounts->edit(index); +} + +void AccountSwitcherDialog::updateSelection() { + qDebug() << "test"; + QModelIndex index = m_model->index(m_ctx->wallet->currentSubaddressAccount(), 0); + ui->accounts->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); +} + +void AccountSwitcherDialog::showContextMenu(const QPoint &point) { + QModelIndex index = ui->accounts->currentIndex(); + if (!index.isValid()) { + return; + } + + auto *menu = new QMenu(ui->accounts); + + menu->addAction("Switch to account", this, &AccountSwitcherDialog::switchAccount); + menu->addAction("Copy label", this, &AccountSwitcherDialog::copyLabel); + menu->addAction("Copy balance", this, &AccountSwitcherDialog::copyBalance); + menu->addAction("Edit label", this, &AccountSwitcherDialog::editLabel); + + menu->popup(ui->accounts->viewport()->mapToGlobal(point)); +} + +Monero::SubaddressAccountRow* AccountSwitcherDialog::currentEntry() { + QModelIndex index = ui->accounts->currentIndex(); + return m_ctx->wallet->subaddressAccountModel()->entryFromIndex(index); +} + +AccountSwitcherDialog::~AccountSwitcherDialog() { + delete ui; +} diff --git a/src/dialog/AccountSwitcherDialog.h b/src/dialog/AccountSwitcherDialog.h new file mode 100644 index 00000000..59cc79bb --- /dev/null +++ b/src/dialog/AccountSwitcherDialog.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_ACCOUNTSWITCHERDIALOG_H +#define FEATHER_ACCOUNTSWITCHERDIALOG_H + +#include +#include "appcontext.h" + +#include "model/SubaddressAccountModel.h" + +namespace Ui { + class AccountSwitcherDialog; +} + +class AccountSwitcherDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AccountSwitcherDialog(QSharedPointer ctx, QWidget *parent = nullptr); + ~AccountSwitcherDialog() override; + +private slots: + void showContextMenu(const QPoint& point); + void updateSelection(); + +private: + void switchAccount(); + void copyLabel(); + void copyBalance(); + void editLabel(); + + Monero::SubaddressAccountRow* currentEntry(); + + Ui::AccountSwitcherDialog *ui; + QSharedPointer m_ctx; + SubaddressAccountModel *m_model; +}; + +#endif //FEATHER_ACCOUNTSWITCHERDIALOG_H diff --git a/src/dialog/AccountSwitcherDialog.ui b/src/dialog/AccountSwitcherDialog.ui new file mode 100644 index 00000000..d332d8e1 --- /dev/null +++ b/src/dialog/AccountSwitcherDialog.ui @@ -0,0 +1,88 @@ + + + AccountSwitcherDialog + + + + 0 + 0 + 521 + 275 + + + + Accounts + + + + + + Qt::NoFocus + + + false + + + false + + + + + + + + + New account + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + AccountSwitcherDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AccountSwitcherDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/libwalletqt/Coins.cpp b/src/libwalletqt/Coins.cpp index c275cab4..d0440db4 100644 --- a/src/libwalletqt/Coins.cpp +++ b/src/libwalletqt/Coins.cpp @@ -41,6 +41,10 @@ void Coins::refresh(quint32 accountIndex) m_pimpl->refresh(); for (const auto i : m_pimpl->getAll()) { + if (i->subaddrAccount() != accountIndex) { + continue; + } + m_tinfo.append(new CoinsInfo(i, this)); } } diff --git a/src/libwalletqt/SubaddressAccount.cpp b/src/libwalletqt/SubaddressAccount.cpp index db885e8b..5aa304a2 100644 --- a/src/libwalletqt/SubaddressAccount.cpp +++ b/src/libwalletqt/SubaddressAccount.cpp @@ -62,3 +62,8 @@ quint64 SubaddressAccount::count() const return m_rows.size(); } + +Monero::SubaddressAccountRow* SubaddressAccount::row(int index) const +{ + return m_rows.value(index); +} \ No newline at end of file diff --git a/src/libwalletqt/SubaddressAccount.h b/src/libwalletqt/SubaddressAccount.h index e2db11e3..7cc380e0 100644 --- a/src/libwalletqt/SubaddressAccount.h +++ b/src/libwalletqt/SubaddressAccount.h @@ -22,6 +22,7 @@ public: Q_INVOKABLE void setLabel(quint32 accountIndex, const QString &label) const; Q_INVOKABLE void refresh() const; quint64 count() const; + Monero::SubaddressAccountRow* row(int index) const; signals: void refreshStarted() const; diff --git a/src/libwalletqt/TransactionHistory.cpp b/src/libwalletqt/TransactionHistory.cpp index 42d2349c..e355275c 100644 --- a/src/libwalletqt/TransactionHistory.cpp +++ b/src/libwalletqt/TransactionHistory.cpp @@ -104,7 +104,6 @@ void TransactionHistory::refresh(quint32 accountIndex) void TransactionHistory::setTxNote(const QString &txid, const QString ¬e) { m_pimpl->setTxNote(txid.toStdString(), note.toStdString()); - this->refresh(0); // todo: get actual account index emit txNoteChanged(); } diff --git a/src/libwalletqt/TransactionHistory.h b/src/libwalletqt/TransactionHistory.h index c00a3872..15b0ba20 100644 --- a/src/libwalletqt/TransactionHistory.h +++ b/src/libwalletqt/TransactionHistory.h @@ -60,6 +60,7 @@ private: // history contains locked transfers mutable bool m_locked; + quint32 lastAccountIndex = 0; }; #endif // TRANSACTIONHISTORY_H diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 6edffa22..29bd6c9e 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -375,6 +375,8 @@ void Wallet::switchSubaddressAccount(quint32 accountIndex) } m_subaddress->refresh(m_currentSubaddressAccount); m_history->refresh(m_currentSubaddressAccount); + m_coins->refresh(m_currentSubaddressAccount); + this->subaddressModel()->setCurrentSubaddressAcount(m_currentSubaddressAccount); emit currentSubaddressAccountChanged(); } } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a5358810..7be69434 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -20,6 +20,7 @@ #include "dialog/balancedialog.h" #include "dialog/WalletCacheDebugDialog.h" #include "dialog/UpdateDialog.h" +#include "dialog/AccountSwitcherDialog.h" #include "constants.h" #include "libwalletqt/AddressBook.h" #include "utils/AsyncTask.h" @@ -128,6 +129,10 @@ void MainWindow::initStatusBar() { connect(m_statusBtnConnectionStatusIndicator, &StatusBarButton::clicked, this, &MainWindow::showConnectionStatusDialog); this->statusBar()->addPermanentWidget(m_statusBtnConnectionStatusIndicator); + m_statusAccountSwitcher = new StatusBarButton(icons()->icon("change_account.png"), "Account switcher", this); + connect(m_statusAccountSwitcher, &StatusBarButton::clicked, this, &MainWindow::showAccountSwitcherDialog); + this->statusBar()->addPermanentWidget(m_statusAccountSwitcher); + m_statusBtnPassword = new StatusBarButton(icons()->icon("lock.svg"), "Password", this); connect(m_statusBtnPassword, &StatusBarButton::clicked, this, &MainWindow::showPasswordDialog); this->statusBar()->addPermanentWidget(m_statusBtnPassword); @@ -212,6 +217,7 @@ void MainWindow::initMenu() { // [Wallet] connect(ui->actionInformation, &QAction::triggered, this, &MainWindow::showWalletInfoDialog); + connect(ui->actionAccount, &QAction::triggered, this, &MainWindow::showAccountSwitcherDialog); connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog); connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog); connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog); @@ -439,12 +445,13 @@ void MainWindow::onWalletOpened() { this->setStatusText("Wallet opened - Searching for node"); // receive page - m_ctx->wallet->subaddress()->refresh( m_ctx->wallet->currentSubaddressAccount()); + m_ctx->wallet->subaddress()->refresh(m_ctx->wallet->currentSubaddressAccount()); if (m_ctx->wallet->subaddress()->count() == 1) { for (int i = 0; i < 10; i++) { m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), ""); } } + m_ctx->wallet->subaddressModel()->setCurrentSubaddressAcount(m_ctx->wallet->currentSubaddressAccount()); // history page m_ctx->wallet->history()->refresh(m_ctx->wallet->currentSubaddressAccount()); @@ -903,6 +910,11 @@ void MainWindow::showWalletCacheDebugDialog() { dialog.exec(); } +void MainWindow::showAccountSwitcherDialog() { + AccountSwitcherDialog dialog{m_ctx, this}; + dialog.exec(); +} + void MainWindow::showNodeExhaustedMessage() { // Spawning dialogs inside a lambda can cause system freezes on linux so we have to do it this way ¯\_(ツ)_/¯ diff --git a/src/mainwindow.h b/src/mainwindow.h index e59e4aee..4d142514 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -155,6 +155,7 @@ private slots: void showKeysDialog(); void showViewOnlyDialog(); void showWalletCacheDebugDialog(); + void showAccountSwitcherDialog(); void donateButtonClicked(); void showCalcWindow(); @@ -230,6 +231,7 @@ private: ClickableLabel *m_statusLabelBalance; QLabel *m_statusLabelStatus; QLabel *m_statusLabelNetStats; + StatusBarButton *m_statusAccountSwitcher; StatusBarButton *m_statusBtnConnectionStatusIndicator; StatusBarButton *m_statusBtnPassword; StatusBarButton *m_statusBtnPreferences; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 5d503c85..4ecec6bf 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -403,6 +403,7 @@ + @@ -742,6 +743,30 @@ t + + + d + + + + + true + + + true + + + false + + + Primary account + + + + + Account + + diff --git a/src/model/SubaddressAccountModel.cpp b/src/model/SubaddressAccountModel.cpp index 8a1f75fa..53e91094 100644 --- a/src/model/SubaddressAccountModel.cpp +++ b/src/model/SubaddressAccountModel.cpp @@ -7,7 +7,8 @@ #include SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount) - : QAbstractListModel(parent), m_subaddressAccount(subaddressAccount) + : QAbstractTableModel(parent) + , m_subaddressAccount(subaddressAccount) { connect(m_subaddressAccount, &SubaddressAccount::refreshStarted, this, &SubaddressAccountModel::startReset); connect(m_subaddressAccount, &SubaddressAccount::refreshFinished, this, &SubaddressAccountModel::endReset); @@ -16,13 +17,26 @@ SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccoun void SubaddressAccountModel::startReset(){ beginResetModel(); } + void SubaddressAccountModel::endReset(){ endResetModel(); } -int SubaddressAccountModel::rowCount(const QModelIndex &) const +int SubaddressAccountModel::rowCount(const QModelIndex &parent) const { - return m_subaddressAccount->count(); + if (parent.isValid()) { + return 0; + } else { + return m_subaddressAccount->count(); + } +} + +int SubaddressAccountModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return Column::COUNT; } QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const @@ -32,24 +46,12 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const QVariant result; - bool found = m_subaddressAccount->getRow(index.row(), [&result, &role](const Monero::SubaddressAccountRow &row) { - switch (role) { - case SubaddressAccountAddressRole: - result = QString::fromStdString(row.getAddress()); - break; - case SubaddressAccountLabelRole: - result = QString::fromStdString(row.getLabel()); - break; - case SubaddressAccountBalanceRole: - result = QString::fromStdString(row.getBalance()); - break; - case SubaddressAccountUnlockedBalanceRole: - result = QString::fromStdString(row.getUnlockedBalance()); - break; - default: - qCritical() << "Unimplemented role" << role; + bool found = m_subaddressAccount->getRow(index.row(), [this, &index, &result, &role](const Monero::SubaddressAccountRow &row) { + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) { + result = parseSubaddressAccountRow(row, index, role); } }); + if (!found) { qCritical("%s: internal error: invalid index %d", __FUNCTION__, index.row()); } @@ -57,15 +59,80 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const return result; } -QHash SubaddressAccountModel::roleNames() const +QVariant SubaddressAccountModel::parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row, + const QModelIndex &index, int role) const { - static QHash roleNames; - if (roleNames.empty()) - { - roleNames.insert(SubaddressAccountAddressRole, "address"); - roleNames.insert(SubaddressAccountLabelRole, "label"); - roleNames.insert(SubaddressAccountBalanceRole, "balance"); - roleNames.insert(SubaddressAccountUnlockedBalanceRole, "unlockedBalance"); + switch (index.column()) { + case Number: + return QString("#%1").arg(QString::number(index.row())); + case Address: + return QString::fromStdString(row.getAddress()); + case Label: + return QString::fromStdString(row.getLabel()); + case Balance: + return QString::fromStdString(row.getBalance()); + case UnlockedBalance: + return QString::fromStdString(row.getUnlockedBalance()); + default: + return QVariant(); } - return roleNames; } + +QVariant SubaddressAccountModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) + { + switch (section) { + case Address: + return QString("Address"); + case Label: + return QString("Label"); + case Balance: + return QString("Balance"); + case UnlockedBalance: + return QString("Spendable balance"); + default: + return QVariant(); + } + } + return QVariant(); +} + +bool SubaddressAccountModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + const int row = index.row(); + + switch (index.column()) { + case Label: + m_subaddressAccount->setLabel(row, value.toString()); + break; + default: + return false; + } + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + + return true; + } + return false; +} + + +Qt::ItemFlags SubaddressAccountModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + if (index.column() == Label) + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + + return QAbstractTableModel::flags(index); +} + +Monero::SubaddressAccountRow* SubaddressAccountModel::entryFromIndex(const QModelIndex &index) const { + Q_ASSERT(index.isValid() && index.row() < m_subaddressAccount->count()); + return m_subaddressAccount->row(index.row()); +} \ No newline at end of file diff --git a/src/model/SubaddressAccountModel.h b/src/model/SubaddressAccountModel.h index cbc7019b..b49f5bab 100644 --- a/src/model/SubaddressAccountModel.h +++ b/src/model/SubaddressAccountModel.h @@ -4,35 +4,44 @@ #ifndef SUBADDRESSACCOUNTMODEL_H #define SUBADDRESSACCOUNTMODEL_H -#include +#include "Subaddress.h" +#include class SubaddressAccount; -class SubaddressAccountModel : public QAbstractListModel +class SubaddressAccountModel : public QAbstractTableModel { Q_OBJECT public: - enum SubaddressAccountRowRole { - SubaddressAccountRole = Qt::UserRole + 1, // for the SubaddressAccountRow object; - SubaddressAccountAddressRole, - SubaddressAccountLabelRole, - SubaddressAccountBalanceRole, - SubaddressAccountUnlockedBalanceRole, + enum Column { + Number, + Address, + Label, + Balance, + UnlockedBalance, + COUNT }; - Q_ENUM(SubaddressAccountRowRole) SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount); int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QHash roleNames() const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + + Monero::SubaddressAccountRow* entryFromIndex(const QModelIndex &index) const; public slots: void startReset(); void endReset(); private: + QVariant parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row, const QModelIndex &index, int role) const; + SubaddressAccount *m_subaddressAccount; }; diff --git a/src/model/SubaddressModel.cpp b/src/model/SubaddressModel.cpp index 7b170b33..bad56e35 100644 --- a/src/model/SubaddressModel.cpp +++ b/src/model/SubaddressModel.cpp @@ -11,9 +11,9 @@ #include SubaddressModel::SubaddressModel(QObject *parent, Subaddress *subaddress) - : QAbstractTableModel(parent), - m_subaddress(subaddress), - m_showFullAddresses(false) + : QAbstractTableModel(parent) + , m_subaddress(subaddress) + , m_showFullAddresses(false) { connect(m_subaddress, &Subaddress::refreshStarted, this, &SubaddressModel::startReset); connect(m_subaddress, &Subaddress::refreshFinished, this, &SubaddressModel::endReset); @@ -143,7 +143,7 @@ bool SubaddressModel::setData(const QModelIndex &index, const QVariant &value, i switch (index.column()) { case Label: - m_subaddress->setLabel(0, row, value.toString()); // Todo: get actual account index + m_subaddress->setLabel(m_currentSubaddressAcount, row, value.toString()); break; default: return false; @@ -180,6 +180,10 @@ int SubaddressModel::unusedLookahead() const { return m_subaddress->unusedLookahead(); } +void SubaddressModel::setCurrentSubaddressAcount(quint32 accountIndex) { + m_currentSubaddressAcount = accountIndex; +} + Monero::SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const { Q_ASSERT(index.isValid() && index.row() < m_subaddress->count()); return m_subaddress->row(index.row()); diff --git a/src/model/SubaddressModel.h b/src/model/SubaddressModel.h index 0b8eb0cf..3056c028 100644 --- a/src/model/SubaddressModel.h +++ b/src/model/SubaddressModel.h @@ -40,6 +40,7 @@ public: Monero::SubaddressRow* entryFromIndex(const QModelIndex &index) const; + void setCurrentSubaddressAcount(quint32 accountIndex); int unusedLookahead() const; public slots: @@ -51,6 +52,7 @@ private: QVariant parseSubaddressRow(const Monero::SubaddressRow &subaddress, const QModelIndex &index, int role) const; bool m_showFullAddresses; + quint32 m_currentSubaddressAcount; }; #endif // SUBADDRESSMODEL_H From 43d9624f5cc8bfed19aa0c51cfb39b4eb5fdf50f Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 16:12:39 +0200 Subject: [PATCH 14/62] Settings: balance display --- src/mainwindow.cpp | 25 +++++++++++++++++-------- src/settings.cpp | 11 ++++++++++- src/settings.h | 1 + src/settings.ui | 26 ++++++++++++++++++++++++++ src/utils/config.cpp | 1 + src/utils/config.h | 7 +++++++ 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7be69434..1a81f294 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -470,18 +470,27 @@ void MainWindow::onWalletOpened() { void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { qDebug() << Q_FUNC_INFO; - bool hide = config()->get(Config::hideBalance).toBool(); - QString label_str = QString("Balance: %1 XMR").arg(WalletManager::displayAmount(spendable, false)); - if (balance > spendable) { - label_str += QString(" (+%1 XMR unconfirmed)").arg(WalletManager::displayAmount(balance - spendable, false)); + bool hide = config()->get(Config::hideBalance).toBool(); + int displaySetting = config()->get(Config::balanceDisplay).toInt(); + + QString balance_str = "Balance: "; + if (hide) { + balance_str += "HIDDEN"; + } + else if (displaySetting == Config::totalBalance) { + balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(balance, false)); + } + else if (displaySetting == Config::spendable || displaySetting == Config::spendablePlusUnconfirmed) { + balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(spendable, false)); + + if (displaySetting == Config::spendablePlusUnconfirmed && balance > spendable) { + balance_str += QString(" (+%1 XMR unconfirmed)").arg(WalletManager::displayAmount(balance - spendable, false)); + } } - if (hide) - label_str = "Balance: HIDDEN"; - m_statusLabelBalance->setToolTip("Click for details"); - m_statusLabelBalance->setText(label_str); + m_statusLabelBalance->setText(balance_str); m_balanceWidget->setHidden(hide); } diff --git a/src/settings.cpp b/src/settings.cpp index 28433187..845f7a3c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -74,7 +74,11 @@ Settings::Settings(QSharedPointer ctx, QWidget *parent) connect(ui->comboBox_dateFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_dateFormatChanged); connect(ui->comboBox_timeFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_timeFormatChanged); - // setup preferred fiat currency combobox + // Balance display combobox + ui->comboBox_balanceDisplay->setCurrentIndex(config()->get(Config::balanceDisplay).toInt()); + connect(ui->comboBox_balanceDisplay, QOverload::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_balanceDisplayChanged); + + // Preferred fiat currency combobox QStringList fiatCurrencies; for (int index = 0; index < ui->comboBox_fiatCurrency->count(); index++) fiatCurrencies << ui->comboBox_fiatCurrency->itemText(index); @@ -155,6 +159,11 @@ void Settings::comboBox_timeFormatChanged(int pos) { config()->set(Config::timeFormat, m_timeFormats.at(pos)); } +void Settings::comboBox_balanceDisplayChanged(int pos) { + config()->set(Config::balanceDisplay, pos); + m_ctx->updateBalance(); +} + void Settings::copyToClipboard() { ui->textLogs->copy(); } diff --git a/src/settings.h b/src/settings.h index 10c0ba67..24d01db3 100644 --- a/src/settings.h +++ b/src/settings.h @@ -40,6 +40,7 @@ public slots: void comboBox_amountPrecisionChanged(int pos); void comboBox_dateFormatChanged(int pos); void comboBox_timeFormatChanged(int pos); + void comboBox_balanceDisplayChanged(int pos); void comboBox_blockExplorerChanged(int pos); void comboBox_redditFrontendChanged(int pos); diff --git a/src/settings.ui b/src/settings.ui index 71787f33..533afdf8 100644 --- a/src/settings.ui +++ b/src/settings.ui @@ -162,6 +162,32 @@ + + + + Balance display: + + + + + + + + Total balance + + + + + Spendable balance (+ unconfirmed balance) + + + + + Spendable balance + + + + diff --git a/src/utils/config.cpp b/src/utils/config.cpp index ee0e7325..7d84f006 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -57,6 +57,7 @@ static const QHash configStrings = { {Config::amountPrecision, {QS("amountPrecision"), 12}}, {Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}}, {Config::timeFormat, {QS("timeFormat"), "HH:mm"}}, + {Config::balanceDisplay, {QS("balanceDisplay"), Config::BalanceDisplay::spendablePlusUnconfirmed}}, {Config::multiBroadcast, {QS("multiBroadcast"), true}}, {Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, diff --git a/src/utils/config.h b/src/utils/config.h index d8103282..1a5f9226 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -55,6 +55,7 @@ public: amountPrecision, dateFormat, timeFormat, + balanceDisplay, multiBroadcast, warnOnExternalLink, @@ -78,6 +79,12 @@ public: allTor }; + enum BalanceDisplay { + totalBalance = 0, + spendablePlusUnconfirmed, + spendable + }; + ~Config() override; QVariant get(ConfigKey key); QString getFileName(); From a60326a593a39d1904cdef47442f61e9e2a67e96 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 20:13:48 +0200 Subject: [PATCH 15/62] Improve warning message on remote node attack --- src/mainwindow.cpp | 20 +++++++++++++++----- src/model/NodeModel.cpp | 10 +++++++++- src/utils/nodes.cpp | 2 +- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1a81f294..5429cb7a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -565,10 +565,10 @@ void MainWindow::onConnectionStatusChanged(int status) void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVector &address) { auto tx_status = tx->status(); - auto err = QString("Can't create transaction: "); + QString err{"Can't create transaction: "}; - if(tx_status != PendingTransaction::Status_Ok){ - auto tx_err = tx->errorString(); + if (tx_status != PendingTransaction::Status_Ok){ + QString tx_err = tx->errorString(); qCritical() << tx_err; if (m_ctx->wallet->connectionStatus() == Wallet::ConnectionStatus_WrongVersion) @@ -576,15 +576,25 @@ void MainWindow::onCreateTransactionSuccess(PendingTransaction *tx, const QVecto else err = QString("%1 %2").arg(err).arg(tx_err); + if (tx_err.contains("Daemon response did not include the requested real output")) { + QString currentNode = m_ctx->nodes->connection().toAddress(); + + err += QString("\nYou are currently connected to: %1\n\n" + "This node may be acting maliciously. You are strongly recommended to disconnect from this node." + "Please report this incident to dev@featherwallet.org, #feather on OFTC or /r/FeatherWallet.").arg(currentNode); + } + qDebug() << Q_FUNC_INFO << err; this->displayWalletErrorMsg(err); m_ctx->wallet->disposeTransaction(tx); - } else if (tx->txCount() == 0) { + } + else if (tx->txCount() == 0) { err = QString("%1 %2").arg(err).arg("No unmixable outputs to sweep."); qDebug() << Q_FUNC_INFO << err; this->displayWalletErrorMsg(err); m_ctx->wallet->disposeTransaction(tx); - } else { + } + else { const auto &description = m_ctx->tmpTxDescription; // Show advanced dialog on multi-destination transactions diff --git a/src/model/NodeModel.cpp b/src/model/NodeModel.cpp index 6224d0b6..040d4ce9 100644 --- a/src/model/NodeModel.cpp +++ b/src/model/NodeModel.cpp @@ -69,7 +69,15 @@ QVariant NodeModel::data(const QModelIndex &index, int role) const { } } } - else if(role == Qt::BackgroundRole) { + else if (role == Qt::ToolTipRole) { + switch (index.column()) { + case NodeModel::URL: { + if (node.isActive) + return QString("Feather is connected to this node."); + } + } + } + else if (role == Qt::BackgroundRole) { if (node.isConnecting) return QBrush(ColorScheme::YELLOW.asColor(true)); else if (node.isActive) diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index 86462625..e477fd20 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -229,7 +229,7 @@ void Nodes::autoConnect(bool forceReconnect) { } // try a connect - auto node = this->pickEligibleNode(); + FeatherNode node = this->pickEligibleNode(); this->connectToNode(node); return; } From e6f1feaa29a5779a0c85d639169f497cafbae239 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 21:01:46 +0200 Subject: [PATCH 16/62] Fix history date sort --- src/model/TransactionHistoryModel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp index 2991d095..0374cf17 100644 --- a/src/model/TransactionHistoryModel.cpp +++ b/src/model/TransactionHistoryModel.cpp @@ -137,6 +137,9 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI { case Column::Date: { + if (role == Qt::UserRole) { + return tInfo.timestamp(); + } return tInfo.timestamp().toString(QString("%1 %2 ").arg(config()->get(Config::dateFormat).toString(), config()->get(Config::timeFormat).toString())); } From 6a5e662f85f5f17f53471751446e3718d672ec3b Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 21:09:22 +0200 Subject: [PATCH 17/62] AccountSwitcherDialog: remove useless code --- src/dialog/AccountSwitcherDialog.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/dialog/AccountSwitcherDialog.cpp b/src/dialog/AccountSwitcherDialog.cpp index dfa66dba..33f1ae44 100644 --- a/src/dialog/AccountSwitcherDialog.cpp +++ b/src/dialog/AccountSwitcherDialog.cpp @@ -30,12 +30,6 @@ AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer ctx, QWi connect(ui->accounts->selectionModel(), &QItemSelectionModel::currentChanged, this, &AccountSwitcherDialog::switchAccount); connect(ui->accounts, &QTreeView::customContextMenuRequested, this, &AccountSwitcherDialog::showContextMenu); - connect(ui->accounts, &QTreeView::doubleClicked, [this](QModelIndex index){ - if (!m_model) return; - if (!(m_model->flags(index) & Qt::ItemIsEditable)) { - this->switchAccount(); - } - }); connect(ui->btn_newAccount, &QPushButton::clicked, [this]{ m_ctx->wallet->addSubaddressAccount("New account"); @@ -89,7 +83,6 @@ void AccountSwitcherDialog::showContextMenu(const QPoint &point) { auto *menu = new QMenu(ui->accounts); - menu->addAction("Switch to account", this, &AccountSwitcherDialog::switchAccount); menu->addAction("Copy label", this, &AccountSwitcherDialog::copyLabel); menu->addAction("Copy balance", this, &AccountSwitcherDialog::copyBalance); menu->addAction("Edit label", this, &AccountSwitcherDialog::editLabel); From 31893f1d45c17eb98871132d11fa3781d87029e9 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 21:32:48 +0200 Subject: [PATCH 18/62] Add wallet creation date to debug info --- src/dialog/debuginfodialog.cpp | 3 ++- src/utils/FeatherSeed.h | 4 ++-- src/utils/RestoreHeightLookup.h | 8 ++++++-- src/widgets/restoreheightwidget.cpp | 4 ++-- src/wizard/PageSetRestoreHeight.cpp | 5 ++--- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/dialog/debuginfodialog.cpp b/src/dialog/debuginfodialog.cpp index 7fcab2ef..768fa07e 100644 --- a/src/dialog/debuginfodialog.cpp +++ b/src/dialog/debuginfodialog.cpp @@ -50,7 +50,8 @@ void DebugInfoDialog::updateInfo() { ui->label_walletHeight->setText(QString::number(m_ctx->wallet->blockChainHeight())); ui->label_daemonHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainHeight())); ui->label_targetHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainTargetHeight())); - ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight())); + QDateTime restoreDate = appData()->restoreHeights[constants::networkType]->heightToDate(m_ctx->wallet->getWalletCreationHeight()); + ui->label_restoreHeight->setText(QString("%1 (%2)").arg(QString::number(m_ctx->wallet->getWalletCreationHeight()), restoreDate.toString("yyyy-MM-dd"))); ui->label_synchronized->setText(m_ctx->wallet->isSynchronized() ? "True" : "False"); auto node = m_ctx->nodes->connection(); diff --git a/src/utils/FeatherSeed.h b/src/utils/FeatherSeed.h index 47d6780d..3232e67f 100644 --- a/src/utils/FeatherSeed.h +++ b/src/utils/FeatherSeed.h @@ -93,13 +93,13 @@ struct FeatherSeed { if (this->time == 0) this->restoreHeight = 1; - this->restoreHeight = appData()->restoreHeights[netType]->dateToRestoreHeight(this->time); + this->restoreHeight = appData()->restoreHeights[netType]->dateToHeight(this->time); } int setRestoreHeight(int height) { auto now = std::time(nullptr); auto nowClearance = 3600 * 24; - auto currentBlockHeight = appData()->restoreHeights[netType]->dateToRestoreHeight(now - nowClearance); + auto currentBlockHeight = appData()->restoreHeights[netType]->dateToHeight(now - nowClearance); if (height >= currentBlockHeight + nowClearance) { qCritical() << "unrealistic restore height detected, setting to current blockheight instead: " << currentBlockHeight; this->restoreHeight = currentBlockHeight; diff --git a/src/utils/RestoreHeightLookup.h b/src/utils/RestoreHeightLookup.h index 4b23d76a..b0499f03 100644 --- a/src/utils/RestoreHeightLookup.h +++ b/src/utils/RestoreHeightLookup.h @@ -17,7 +17,7 @@ struct RestoreHeightLookup { QMap data; explicit RestoreHeightLookup(NetworkType::Type type) : type(type) {} - int dateToRestoreHeight(int date) { + int dateToHeight(int date) { // restore height based on a given timestamp using a lookup // table. If it cannot find the date in the lookup table, it // will calculate the blockheight based off the last known @@ -49,7 +49,7 @@ struct RestoreHeightLookup { return blockHeight; } - int restoreHeightToDate(int height) { + int heightToTimestamp(int height) { // @TODO: most likely inefficient, refactor QMap::iterator i; int timestamp = 0; @@ -70,6 +70,10 @@ struct RestoreHeightLookup { return timestamp; } + QDateTime heightToDate(int height) { + return QDateTime::fromSecsSinceEpoch(this->heightToTimestamp(height)); + } + static RestoreHeightLookup *fromFile(const QString &fn, NetworkType::Type type) { // initialize this class using a lookup table, e.g `:/assets/restore_heights_monero_mainnet.txt`/ auto rtn = new RestoreHeightLookup(type); diff --git a/src/widgets/restoreheightwidget.cpp b/src/widgets/restoreheightwidget.cpp index 6ec42e80..f8b6a1d0 100644 --- a/src/widgets/restoreheightwidget.cpp +++ b/src/widgets/restoreheightwidget.cpp @@ -33,7 +33,7 @@ void RestoreHeightWidget::setHeight(int height) { ui->lineEdit_restoreHeight->setText(QString::number(height)); // Update slider - int date = m_restoreHeightLookup->restoreHeightToDate(height); + int date = m_restoreHeightLookup->heightToTimestamp(height); ui->restoreSlider->setValue(date); this->updateTimestamp(date); @@ -49,7 +49,7 @@ void RestoreHeightWidget::initRestoreHeights(RestoreHeightLookup *lookup) { connect(ui->restoreSlider, &QSlider::sliderMoved, [this](int date){ // Update lineEdit - int blockHeight = m_restoreHeightLookup->dateToRestoreHeight(date); + int blockHeight = m_restoreHeightLookup->dateToHeight(date); ui->lineEdit_restoreHeight->setText(QString::number(blockHeight)); this->updateTimestamp(date); diff --git a/src/wizard/PageSetRestoreHeight.cpp b/src/wizard/PageSetRestoreHeight.cpp index 8fdc07d4..7bd13fac 100644 --- a/src/wizard/PageSetRestoreHeight.cpp +++ b/src/wizard/PageSetRestoreHeight.cpp @@ -61,7 +61,7 @@ void PageSetRestoreHeight::onCreationDateEdited() { QDateTime restoreDate = date > curDate ? curDate : date; int timestamp = restoreDate.toSecsSinceEpoch(); - QString restoreHeight = QString::number(appData()->restoreHeights[constants::networkType]->dateToRestoreHeight(timestamp)); + QString restoreHeight = QString::number(appData()->restoreHeights[constants::networkType]->dateToHeight(timestamp)); ui->line_restoreHeight->setText(restoreHeight); this->showScanWarning(restoreDate); @@ -77,8 +77,7 @@ void PageSetRestoreHeight::onRestoreHeightEdited() { return; } - int timestamp = appData()->restoreHeights[constants::networkType]->restoreHeightToDate(restoreHeight); - auto date = QDateTime::fromSecsSinceEpoch(timestamp); + QDateTime date = appData()->restoreHeights[constants::networkType]->heightToDate(restoreHeight); ui->line_creationDate->setText(date.toString("yyyy-MM-dd")); this->showScanWarning(date); From bee7853fb9f8533e07fe2e7718c973988288f059 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sat, 22 May 2021 21:53:42 +0200 Subject: [PATCH 19/62] AppImage: build in ./build --- BUILDING.md | 4 +++- contrib/build-appimage.sh | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 68e130d7..16ea8eab 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -49,9 +49,11 @@ The resulting binary can be found in `build/bin/feather`. First create the standalone binary using the Docker command in the previous step. ```bash -docker run --rm -it -v $PWD:/feather -w /feather feather:linux contrib/build-appimage.sh +docker run --rm -it -v $PWD:/feather -w /feather/build feather:linux ../contrib/build-appimage.sh ``` +The resulting AppImage will be located in `./build`. + ### Windows (reproducible) #### 1. Clone diff --git a/contrib/build-appimage.sh b/contrib/build-appimage.sh index c68b5039..3ba81573 100755 --- a/contrib/build-appimage.sh +++ b/contrib/build-appimage.sh @@ -4,13 +4,14 @@ set -e unset SOURCE_DATE_EPOCH APPDIR="$PWD/feather.AppDir" +rm -rf $APPDIR mkdir -p "$APPDIR" mkdir -p "$APPDIR/usr/share/applications/" mkdir -p "$APPDIR/usr/bin" -cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop" -cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather.png" -cp "$PWD/build/bin/feather" "$APPDIR/usr/bin/feather" +cp "$PWD/../src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop" +cp "$PWD/../src/assets/images/appicons/64x64.png" "$APPDIR/feather.png" +cp "$PWD/bin/feather" "$APPDIR/usr/bin/feather" LD_LIBRARY_PATH=/usr/local/lib /linuxdeployqt/squashfs-root/AppRun feather.AppDir/usr/share/applications/feather.desktop -bundle-non-qt-libs From 1e0450ab7afe88a151fb394355d626c745dc09f1 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 14:34:31 +0200 Subject: [PATCH 20/62] PasswordDialog: add window icon --- src/dialog/passworddialog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dialog/passworddialog.cpp b/src/dialog/passworddialog.cpp index a576929e..284c47f2 100644 --- a/src/dialog/passworddialog.cpp +++ b/src/dialog/passworddialog.cpp @@ -3,6 +3,7 @@ #include "passworddialog.h" #include "ui_passworddialog.h" +#include "utils/Icons.h" PasswordDialog::PasswordDialog(const QString &walletName, bool incorrectPassword, QWidget *parent) : QDialog(parent) @@ -10,6 +11,7 @@ PasswordDialog::PasswordDialog(const QString &walletName, bool incorrectPassword { ui->setupUi(this); + this->setWindowIcon(icons()->icon("appicons/64x64.png")); ui->label_wallet->setText(QString("Please enter password for wallet: %1").arg(walletName)); ui->label_incorrectPassword->setVisible(incorrectPassword); From 53f0356dc075183fc78e362a097eddc812c4638c Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 15:29:53 +0200 Subject: [PATCH 21/62] TxProofDialog: add copy address button --- src/dialog/TxProofDialog.cpp | 5 +++++ src/dialog/TxProofDialog.ui | 28 ++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/dialog/TxProofDialog.cpp b/src/dialog/TxProofDialog.cpp index ef7b3e0d..428a6970 100644 --- a/src/dialog/TxProofDialog.cpp +++ b/src/dialog/TxProofDialog.cpp @@ -8,6 +8,7 @@ #include "libwalletqt/Transfer.h" #include "utils/utils.h" +#include "utils/Icons.h" TxProofDialog::TxProofDialog(QWidget *parent, QSharedPointer ctx, TransactionInfo *txInfo) : QDialog(parent) @@ -44,6 +45,10 @@ TxProofDialog::TxProofDialog(QWidget *parent, QSharedPointer ctx, Tr ui->radio_SpendProof->setChecked(true); ui->label_txid->setText(m_txid); + ui->btn_copyAddress->setIcon(icons()->icon("copy.png")); + connect(ui->btn_copyAddress, &QPushButton::clicked, [this]{ + Utils::copyToClipboard(ui->combo_address->currentText()); + }); ui->group_summary->hide(); // todo this->adjustSize(); diff --git a/src/dialog/TxProofDialog.ui b/src/dialog/TxProofDialog.ui index bd599b68..f71486aa 100644 --- a/src/dialog/TxProofDialog.ui +++ b/src/dialog/TxProofDialog.ui @@ -30,7 +30,7 @@ - Prove a payment to an address (OutProof) + Prove payment to an address (OutProof) @@ -226,7 +226,31 @@ - + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Copy + + + + From d3227ce054726d970d642a9791b13835393093f9 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 15:30:38 +0200 Subject: [PATCH 22/62] QDarkStyle: fix button squish issue --- src/ui/qdarkstyle/style.qss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ui/qdarkstyle/style.qss b/src/ui/qdarkstyle/style.qss index 9b1368d4..a85365fd 100644 --- a/src/ui/qdarkstyle/style.qss +++ b/src/ui/qdarkstyle/style.qss @@ -986,8 +986,6 @@ QPushButton { border-radius: 4px; padding: 3px; outline: none; - /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */ - min-width: 80px; } QPushButton:disabled { @@ -2152,10 +2150,6 @@ QComboBox::item:checked { max-height: 30px; } -QPushButton { - min-width: default; -} - QPushButton:flat { background-color: transparent; border: none; From 184d8666140d34f45741888f949e8476ee6c044c Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 15:58:28 +0200 Subject: [PATCH 23/62] MainWindow: add account id to title --- src/mainwindow.cpp | 18 +++++++++++------- src/mainwindow.h | 2 +- src/widgets/xmrigwidget.cpp | 7 +++++++ src/widgets/xmrigwidget.h | 3 +++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5429cb7a..1fe25b60 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -199,8 +199,8 @@ void MainWindow::initWidgets() { m_xmrig = new XMRigWidget(m_ctx, this); ui->xmrRigLayout->addWidget(m_xmrig); - connect(m_xmrig, &XMRigWidget::miningStarted, [this]{ this->setTitle(true); }); - connect(m_xmrig, &XMRigWidget::miningEnded, [this]{ this->setTitle(false); }); + connect(m_xmrig, &XMRigWidget::miningStarted, [this]{ this->updateTitle(); }); + connect(m_xmrig, &XMRigWidget::miningEnded, [this]{ this->updateTitle(); }); #else ui->tabWidget->setTabVisible(Tabs::XMRIG, false); #endif @@ -361,6 +361,7 @@ void MainWindow::initWalletContext() { // Wallet connect(m_ctx->wallet.get(), &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged); + connect(m_ctx->wallet.get(), &Wallet::currentSubaddressAccountChanged, [this]{this->updateTitle();}); } void MainWindow::startupWarning() { @@ -461,7 +462,7 @@ void MainWindow::onWalletOpened() { m_coinsWidget->setModel(m_ctx->wallet->coinsModel(), m_ctx->wallet->coins()); this->updatePasswordIcon(); - this->setTitle(false); + this->updateTitle(); m_ctx->nodes->connectToNode(); m_updateBytes.start(250); @@ -1354,13 +1355,16 @@ QString MainWindow::getHardwareDevice() { return "Unknown"; } -void MainWindow::setTitle(bool mining) { - auto title = QString("Feather - [%1]").arg(this->walletName()); - if (m_ctx->wallet && m_ctx->wallet->viewOnly()) +void MainWindow::updateTitle() { + QString title = QString("%1 (#%2)").arg(this->walletName(), QString::number(m_ctx->wallet->currentSubaddressAccount())); + + if (m_ctx->wallet->viewOnly()) title += " [view-only]"; - if (mining) + if (m_xmrig->isMining()) title += " [mining]"; + title += " - Feather"; + this->setWindowTitle(title); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 4d142514..22acbb28 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -200,7 +200,7 @@ private: QString getPlatformTag(); void displayWalletErrorMsg(const QString &err); QString getHardwareDevice(); - void setTitle(bool mining); + void updateTitle(); void donationNag(); void updateRecentlyOpened(const QString &filename); diff --git a/src/widgets/xmrigwidget.cpp b/src/widgets/xmrigwidget.cpp index 5a4a98dc..aef8e7cc 100644 --- a/src/widgets/xmrigwidget.cpp +++ b/src/widgets/xmrigwidget.cpp @@ -115,6 +115,10 @@ XMRigWidget::XMRigWidget(QSharedPointer ctx, QWidget *parent) } } +bool XMRigWidget::isMining() { + return m_isMining; +} + void XMRigWidget::onWalletClosed() { this->onStopClicked(); this->onClearClicked(); @@ -173,6 +177,7 @@ void XMRigWidget::onStartClicked() { m_XMRig->start(xmrigPath, m_threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked()); ui->btn_start->setEnabled(false); ui->btn_stop->setEnabled(true); + m_isMining = true; emit miningStarted(); } @@ -181,6 +186,7 @@ void XMRigWidget::onStopClicked() { ui->btn_start->setEnabled(true); ui->btn_stop->setEnabled(false); ui->label_status->hide(); + m_isMining = false; emit miningEnded(); } @@ -200,6 +206,7 @@ void XMRigWidget::onProcessError(const QString &msg) { ui->btn_start->setEnabled(true); ui->btn_stop->setEnabled(false); ui->label_status->hide(); + m_isMining = false; emit miningEnded(); } diff --git a/src/widgets/xmrigwidget.h b/src/widgets/xmrigwidget.h index cadd801a..fd800a47 100644 --- a/src/widgets/xmrigwidget.h +++ b/src/widgets/xmrigwidget.h @@ -25,6 +25,8 @@ public: ~XMRigWidget() override; QStandardItemModel *model(); + bool isMining(); + public slots: void onWalletClosed(); void onStartClicked(); @@ -55,6 +57,7 @@ private: QStandardItemModel *m_model; QMenu *m_contextMenu; + bool m_isMining = false; int m_threads; QStringList m_urls; QStringList m_pools{"pool.xmr.pt:9000", "pool.supportxmr.com:9000", "mine.xmrpool.net:443", "xmrpool.eu:9999", "xmr-eu1.nanopool.org:14433", "pool.minexmr.com:6666", "us-west.minexmr.com:6666", "monerohash.com:9999", "cryptonote.social:5555", "cryptonote.social:5556"}; From 91beff44110cf8536c6f2a18fa1f6cdb28652d32 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 16:17:04 +0200 Subject: [PATCH 24/62] VerifyProofDialog: use monospace font for formatted proof input --- src/dialog/verifyproofdialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dialog/verifyproofdialog.cpp b/src/dialog/verifyproofdialog.cpp index 98b4fa8b..ecabd65e 100644 --- a/src/dialog/verifyproofdialog.cpp +++ b/src/dialog/verifyproofdialog.cpp @@ -6,6 +6,7 @@ #include "libwalletqt/WalletManager.h" #include "utils/utils.h" +#include "model/ModelUtils.h" #include @@ -48,6 +49,8 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent) break; } }); + + ui->input_formattedProof->setFont(ModelUtils::getMonospaceFont()); } VerifyProofDialog::~VerifyProofDialog() From 0ba485c9de9420198f7f5b859b9f2f955135d8ae Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 16:58:18 +0200 Subject: [PATCH 25/62] View: show/hide searchbar --- src/contactswidget.cpp | 9 +++++++++ src/contactswidget.h | 3 +++ src/historywidget.cpp | 9 +++++++++ src/historywidget.h | 3 +++ src/mainwindow.cpp | 19 +++++++++++++++++++ src/mainwindow.h | 1 + src/mainwindow.ui | 13 +++++++++++++ src/receivewidget.cpp | 11 ++++++++++- src/receivewidget.h | 3 +++ src/receivewidget.ui | 2 +- src/utils/config.cpp | 1 + src/utils/config.h | 1 + 12 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/contactswidget.cpp b/src/contactswidget.cpp index f031c579..147e579d 100644 --- a/src/contactswidget.cpp +++ b/src/contactswidget.cpp @@ -63,6 +63,15 @@ ContactsWidget::ContactsWidget(QSharedPointer ctx, QWidget *parent) connect(ui->search, &QLineEdit::textChanged, this, &ContactsWidget::setSearchFilter); } +void ContactsWidget::setSearchbarVisible(bool visible) { + ui->search->setVisible(visible); +} + +void ContactsWidget::focusSearchbar() { + ui->search->setFocusPolicy(Qt::StrongFocus); + ui->search->setFocus(); +} + void ContactsWidget::copyAddress() { QModelIndex index = ui->contacts->currentIndex(); ModelUtils::copyColumn(&index, AddressBookModel::Address); diff --git a/src/contactswidget.h b/src/contactswidget.h index 17395ff7..280e9828 100644 --- a/src/contactswidget.h +++ b/src/contactswidget.h @@ -23,6 +23,9 @@ public: explicit ContactsWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~ContactsWidget() override; + void setSearchbarVisible(bool visible); + void focusSearchbar(); + public slots: void copyAddress(); void copyName(); diff --git a/src/historywidget.cpp b/src/historywidget.cpp index 22416824..a0e86028 100644 --- a/src/historywidget.cpp +++ b/src/historywidget.cpp @@ -61,6 +61,15 @@ HistoryWidget::HistoryWidget(QSharedPointer ctx, QWidget *parent) } } +void HistoryWidget::setSearchbarVisible(bool visible) { + ui->search->setVisible(visible); +} + +void HistoryWidget::focusSearchbar() { + ui->search->setFocusPolicy(Qt::StrongFocus); + ui->search->setFocus(); +} + void HistoryWidget::showContextMenu(const QPoint &point) { QModelIndex index = ui->history->indexAt(point); if (!index.isValid()) { diff --git a/src/historywidget.h b/src/historywidget.h index 82d2cf86..a41a262b 100644 --- a/src/historywidget.h +++ b/src/historywidget.h @@ -25,6 +25,9 @@ public: explicit HistoryWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~HistoryWidget() override; + void setSearchbarVisible(bool visible); + void focusSearchbar(); + public slots: void setSearchText(const QString &text); void resetModel(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1fe25b60..0a75493c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -248,6 +248,8 @@ void MainWindow::initMenu() { // [View] m_tabShowHideSignalMapper = new QSignalMapper(this); + connect(ui->actionShow_Searchbar, &QAction::toggled, this, &MainWindow::toggleSearchbar); + ui->actionShow_Searchbar->setChecked(config()->get(Config::showSearchbar).toBool()); // Show/Hide Home connect(ui->actionShow_Home, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); @@ -325,6 +327,7 @@ void MainWindow::initMenu() { ui->actionShow_debug_info->setShortcut(QKeySequence("Ctrl+D")); ui->actionSettings->setShortcut(QKeySequence("Ctrl+Alt+S")); ui->actionUpdate_balance->setShortcut(QKeySequence("Ctrl+U")); + ui->actionShow_Searchbar->setShortcut(QKeySequence("Ctrl+F")); } void MainWindow::initHome() { @@ -1420,6 +1423,22 @@ void MainWindow::updateRecentlyOpened(const QString &keysFile) { } } +void MainWindow::toggleSearchbar(bool visible) { + config()->set(Config::showSearchbar, visible); + + m_historyWidget->setSearchbarVisible(visible); + m_receiveWidget->setSearchbarVisible(visible); + m_contactsWidget->setSearchbarVisible(visible); + + int currentTab = ui->tabWidget->currentIndex(); + if (currentTab == Tabs::HISTORY) + m_historyWidget->focusSearchbar(); + else if (currentTab == Tabs::SEND) + m_contactsWidget->focusSearchbar(); + else if (currentTab == Tabs::RECEIVE) + m_receiveWidget->focusSearchbar(); +} + MainWindow::~MainWindow() { delete ui; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 22acbb28..52e2f743 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -174,6 +174,7 @@ private slots: void onDeviceError(const QString &error); void menuHwDeviceClicked(); void onUpdatesAvailable(const QJsonObject &updates); + void toggleSearchbar(bool enabled); private: void initStatusBar(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 4ecec6bf..3358f0f3 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -461,6 +461,8 @@ + + @@ -767,6 +769,17 @@ Account + + + true + + + true + + + Show Searchbar + + diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index 0f5373e6..f6697b66 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -53,12 +53,21 @@ ReceiveWidget::ReceiveWidget(QSharedPointer ctx, QWidget *parent) connect(ui->btn_generateSubaddress, &QPushButton::clicked, this, &ReceiveWidget::generateSubaddress); connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog); - connect(ui->label_addressSearch, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter); + connect(ui->search, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter); connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses); connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); } +void ReceiveWidget::setSearchbarVisible(bool visible) { + ui->search->setVisible(visible); +} + +void ReceiveWidget::focusSearchbar() { + ui->search->setFocusPolicy(Qt::StrongFocus); + ui->search->setFocus(); +} + void ReceiveWidget::copyAddress() { QModelIndex index = ui->addresses->currentIndex(); ModelUtils::copyColumn(&index, SubaddressModel::Address); diff --git a/src/receivewidget.h b/src/receivewidget.h index 308e8d52..7adc7989 100644 --- a/src/receivewidget.h +++ b/src/receivewidget.h @@ -25,6 +25,9 @@ public: explicit ReceiveWidget(QSharedPointer ctx, QWidget *parent = nullptr); ~ReceiveWidget() override; + void setSearchbarVisible(bool visible); + void focusSearchbar(); + public slots: void copyAddress(); void copyLabel(); diff --git a/src/receivewidget.ui b/src/receivewidget.ui index 52c8e74c..494b2a57 100644 --- a/src/receivewidget.ui +++ b/src/receivewidget.ui @@ -27,7 +27,7 @@ 0 - + true diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 7d84f006..c8d2208f 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -46,6 +46,7 @@ static const QHash configStrings = { {Config::showTabExchange, {QS("showTabExchange"), false}}, {Config::showTabXMRig,{QS("showTabXMRig"), false}}, {Config::showTabCalc,{QS("showTabCalc"), true}}, + {Config::showSearchbar,{QS("showSearchbar"), true}}, // Mining {Config::xmrigPath,{QS("xmrigPath"), ""}}, diff --git a/src/utils/config.h b/src/utils/config.h index 1a5f9226..062b531b 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -46,6 +46,7 @@ public: showTabExchange, showTabCalc, showTabXMRig, + showSearchbar, xmrigPath, xmrigPool, From 029200840afdffdc91f3cabd1d2ed8f882a154e5 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 19:40:34 +0200 Subject: [PATCH 26/62] AddressBook: remove lookupPaymentID --- src/libwalletqt/AddressBook.cpp | 7 ------- src/libwalletqt/AddressBook.h | 1 - src/model/AddressBookModel.cpp | 11 +++-------- src/model/AddressBookModel.h | 1 - 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/libwalletqt/AddressBook.cpp b/src/libwalletqt/AddressBook.cpp index 381d763c..3f4fd85f 100644 --- a/src/libwalletqt/AddressBook.cpp +++ b/src/libwalletqt/AddressBook.cpp @@ -116,13 +116,6 @@ quint64 AddressBook::count() const return m_rows.size(); } -int AddressBook::lookupPaymentID(const QString &payment_id) const -{ - QReadLocker locker(&m_lock); - - return m_addressBookImpl->lookupPaymentID(payment_id.toStdString()); -} - QString AddressBook::getDescription(const QString &address) const { QReadLocker locker(&m_lock); diff --git a/src/libwalletqt/AddressBook.h b/src/libwalletqt/AddressBook.h index 56d78279..6b88704f 100644 --- a/src/libwalletqt/AddressBook.h +++ b/src/libwalletqt/AddressBook.h @@ -28,7 +28,6 @@ public: quint64 count() const; Q_INVOKABLE QString errorString() const; Q_INVOKABLE int errorCode() const; - Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const; Q_INVOKABLE QString getDescription(const QString &address) const; enum ErrorCode { diff --git a/src/model/AddressBookModel.cpp b/src/model/AddressBookModel.cpp index 92004b15..9f96a8f3 100644 --- a/src/model/AddressBookModel.cpp +++ b/src/model/AddressBookModel.cpp @@ -8,9 +8,9 @@ #include "utils/Icons.h" AddressBookModel::AddressBookModel(QObject *parent, AddressBook *addressBook) - : QAbstractTableModel(parent), - m_addressBook(addressBook), - m_showFullAddresses(false) + : QAbstractTableModel(parent) + , m_addressBook(addressBook) + , m_showFullAddresses(false) { connect(m_addressBook, &AddressBook::refreshStarted, this, &AddressBookModel::startReset); connect(m_addressBook, &AddressBook::refreshFinished, this, &AddressBookModel::endReset); @@ -150,11 +150,6 @@ bool AddressBookModel::deleteRow(int row) return m_addressBook->deleteRow(row); } -int AddressBookModel::lookupPaymentID(const QString &payment_id) const -{ - return m_addressBook->lookupPaymentID(payment_id); -} - bool AddressBookModel::writeCSV(const QString &path) { QString csv = ""; for(int i = 0; i < this->rowCount(); i++) { diff --git a/src/model/AddressBookModel.h b/src/model/AddressBookModel.h index 93854280..7157c6d1 100644 --- a/src/model/AddressBookModel.h +++ b/src/model/AddressBookModel.h @@ -31,7 +31,6 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role) override; Q_INVOKABLE bool deleteRow(int row); - Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const; bool isShowFullAddresses() const; void setShowFullAddresses(bool show); From e054db66ca672f8399064ced9cd8cca193cefd81 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 21:16:16 +0200 Subject: [PATCH 27/62] Wallet: omit redundant 'delete' on destruction From upstream: monero-project/monero-gui/pull/3431 Co-authored-by: xiphon --- src/libwalletqt/Wallet.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 29bd6c9e..003fd364 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -1267,18 +1267,18 @@ void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device Wallet::Wallet(Monero::Wallet *w, QObject *parent) : QObject(parent) , m_walletImpl(w) - , m_history(nullptr) + , m_history(new TransactionHistory(m_walletImpl->history(), this)) , m_historyModel(nullptr) - , m_addressBook(nullptr) + , m_addressBook(new AddressBook(m_walletImpl->addressBook(), this)) , m_addressBookModel(nullptr) , m_daemonBlockChainHeight(0) , m_daemonBlockChainTargetHeight(0) , m_connectionStatus(Wallet::ConnectionStatus_Disconnected) , m_disconnected(true) , m_currentSubaddressAccount(0) - , m_subaddress(nullptr) + , m_subaddress(new Subaddress(m_walletImpl->subaddress(), this)) , m_subaddressModel(nullptr) - , m_subaddressAccount(nullptr) + , m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this)) , m_subaddressAccountModel(nullptr) , m_coinsModel(nullptr) , m_refreshNow(false) @@ -1286,12 +1286,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent) , m_refreshing(false) , m_scheduler(this) , m_useSSL(true) + , m_coins(new Coins(m_walletImpl->coins(), this)) { - m_history = new TransactionHistory(m_walletImpl->history(), this); - m_addressBook = new AddressBook(m_walletImpl->addressBook(), this); - m_subaddress = new Subaddress(m_walletImpl->subaddress(), this); - m_subaddressAccount = new SubaddressAccount(m_walletImpl->subaddressAccount(), this); - m_coins = new Coins(m_walletImpl->coins(), this); m_walletListener = new WalletListenerImpl(this); m_walletImpl->setListener(m_walletListener); m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt(); @@ -1314,19 +1310,6 @@ Wallet::~Wallet() m_scheduler.shutdownWaitForFinished(); - delete m_addressBook; - m_addressBook = NULL; - - delete m_history; - m_history = NULL; - delete m_addressBook; - m_addressBook = NULL; - delete m_subaddress; - m_subaddress = NULL; - delete m_subaddressAccount; - m_subaddressAccount = NULL; - delete m_coins; - m_coins = NULL; //Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl); if(status() == Status_Critical || status() == Status_BadPassword) qDebug("Not storing wallet cache"); From cebe92b61fe48e30d5e25e88032c79bccb7dd76a Mon Sep 17 00:00:00 2001 From: tobtoht Date: Sun, 23 May 2021 22:24:03 +0200 Subject: [PATCH 28/62] LocalMoneroWidget: disable search button during search --- src/widgets/LocalMoneroWidget.cpp | 5 ++--- src/widgets/LocalMoneroWidget.h | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/widgets/LocalMoneroWidget.cpp b/src/widgets/LocalMoneroWidget.cpp index 6670f7ea..54fe3678 100644 --- a/src/widgets/LocalMoneroWidget.cpp +++ b/src/widgets/LocalMoneroWidget.cpp @@ -19,8 +19,6 @@ LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, QSharedPointer { ui->setupUi(this); -// this->adjustSize(); - QPixmap logo(":/assets/images/localMonero_logo.png"); ui->logo->setPixmap(logo.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)); @@ -68,6 +66,7 @@ void LocalMoneroWidget::skinChanged() { void LocalMoneroWidget::onSearchClicked() { m_model->clearData(); m_currentPage = 0; + ui->btn_search->setEnabled(false); this->searchOffers(); } @@ -78,7 +77,7 @@ void LocalMoneroWidget::onSignUpClicked() { } void LocalMoneroWidget::onApiResponse(const LocalMoneroApi::LocalMoneroResponse &resp) { - qDebug() << "We got a response"; + ui->btn_search->setEnabled(true); if (!resp.ok) { QMessageBox::warning(this, "LocalMonero error", QString("Request failed:\n\n%1").arg(resp.message)); diff --git a/src/widgets/LocalMoneroWidget.h b/src/widgets/LocalMoneroWidget.h index 1fce1df7..4c08878d 100644 --- a/src/widgets/LocalMoneroWidget.h +++ b/src/widgets/LocalMoneroWidget.h @@ -41,11 +41,11 @@ private: void viewOfferDetails(); void updatePaymentMethods(); + Ui::LocalMoneroWidget *ui; + QSharedPointer m_ctx; + int m_currentPage = 0; - Ui::LocalMoneroWidget *ui; - - QSharedPointer m_ctx; LocalMoneroApi *m_api; LocalMoneroModel *m_model; UtilsNetworking *m_network; From fadb2d7a50180975a5f7219ccd2078b470059ad8 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 00:02:36 +0200 Subject: [PATCH 29/62] Receive: add pointer cursor to Qr code --- src/receivewidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index f6697b66..73be25df 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -35,6 +35,8 @@ ReceiveWidget::ReceiveWidget(QSharedPointer ctx, QWidget *parent) this->updateQrCode(); }); + ui->qrCode->setCursor(Qt::PointingHandCursor); + // header context menu ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu); m_headerMenu = new QMenu(this); From 0f64f78bb812833efcd0c581068189a878e72b6b Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 00:11:13 +0200 Subject: [PATCH 30/62] TxImportDialog: fix segfault --- src/dialog/tximportdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialog/tximportdialog.cpp b/src/dialog/tximportdialog.cpp index f3843b86..771dd928 100644 --- a/src/dialog/tximportdialog.cpp +++ b/src/dialog/tximportdialog.cpp @@ -17,7 +17,7 @@ TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer ctx) ui->resp->hide(); ui->label_loading->hide(); - auto node = ctx->nodes->connection(); + auto node = m_ctx->nodes->connection(); m_rpc = new DaemonRpc(this, getNetworkTor(), node.toAddress()); connect(ui->btn_load, &QPushButton::clicked, this, &TxImportDialog::loadTx); From b2217c974b22061a76e01d8371783d2e3418696a Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 00:15:31 +0200 Subject: [PATCH 31/62] BroadcastTxDialog: fix segv --- src/dialog/broadcasttxdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialog/broadcasttxdialog.cpp b/src/dialog/broadcasttxdialog.cpp index 7ab90d1f..6a0a213d 100644 --- a/src/dialog/broadcasttxdialog.cpp +++ b/src/dialog/broadcasttxdialog.cpp @@ -14,7 +14,7 @@ BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, QSharedPointer { ui->setupUi(this); - auto node = ctx->nodes->connection(); + auto node = m_ctx->nodes->connection(); m_rpc = new DaemonRpc(this, getNetworkTor(), node.toAddress()); connect(ui->btn_Broadcast, &QPushButton::clicked, this, &BroadcastTxDialog::broadcastTx); From 5edea3c436fee1273054f658e31f15ea438dd2d4 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 00:30:47 +0200 Subject: [PATCH 32/62] TxImportDialog: change daemon rpc network if connected to local node --- src/dialog/tximportdialog.cpp | 12 ++++++++---- src/utils/daemonrpc.cpp | 4 ++++ src/utils/daemonrpc.h | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dialog/tximportdialog.cpp b/src/dialog/tximportdialog.cpp index 771dd928..a2562484 100644 --- a/src/dialog/tximportdialog.cpp +++ b/src/dialog/tximportdialog.cpp @@ -34,12 +34,16 @@ TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer ctx) void TxImportDialog::loadTx() { QString txid = ui->line_txid->text(); - QString node = m_ctx->nodes->connection().toAddress(); + FeatherNode node = m_ctx->nodes->connection(); - if (!node.startsWith("http://")) - node = QString("http://%1").arg(node); + if (node.isLocal()) { + m_rpc->setNetwork(getNetworkClearnet()); + } else { + m_rpc->setNetwork(getNetworkTor()); + } - m_rpc->setDaemonAddress(node); + qDebug() << node.toURL(); + m_rpc->setDaemonAddress(node.toURL()); m_rpc->getTransactions(QStringList() << txid, false, true); ui->label_loading->setText("Loading transaction"); diff --git a/src/utils/daemonrpc.cpp b/src/utils/daemonrpc.cpp index 58c57d9f..48faafd5 100644 --- a/src/utils/daemonrpc.cpp +++ b/src/utils/daemonrpc.cpp @@ -93,3 +93,7 @@ QString DaemonRpc::onSendRawTransactionFailed(const QJsonObject &obj) { void DaemonRpc::setDaemonAddress(const QString &daemonAddress) { m_daemonAddress = daemonAddress; } + +void DaemonRpc::setNetwork(QNetworkAccessManager *network) { + m_network = new UtilsNetworking(network, this); +} \ No newline at end of file diff --git a/src/utils/daemonrpc.h b/src/utils/daemonrpc.h index 403e8939..0bd1af8e 100644 --- a/src/utils/daemonrpc.h +++ b/src/utils/daemonrpc.h @@ -33,6 +33,7 @@ public: void getTransactions(const QStringList &txs_hashes, bool decode_as_json = false, bool prune = false); void setDaemonAddress(const QString &daemonAddress); + void setNetwork(QNetworkAccessManager *network); signals: void ApiResponse(DaemonResponse resp); From 09639181ba24c734826e4b43b574d3002455a856 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 00:53:13 +0200 Subject: [PATCH 33/62] FeatherNode: add regex for local node detection --- src/utils/nodes.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/nodes.h b/src/utils/nodes.h index 8d38cfd1..66b79f88 100644 --- a/src/utils/nodes.h +++ b/src/utils/nodes.h @@ -74,7 +74,8 @@ struct FeatherNode { } bool isLocal() const { - return (url.host() == "127.0.0.1" || url.host() == "localhost"); + QRegularExpression localNetwork(R"((^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.))"); + return (localNetwork.match(url.host()).hasMatch() || url.host() == "localhost"); } bool isOnion() const { From 2d267994efa3d8cdd74fdfd861a765b40c1b0a4e Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 14:22:25 +0200 Subject: [PATCH 34/62] Send: don't wipe amount field --- src/sendwidget.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sendwidget.cpp b/src/sendwidget.cpp index d0c30b46..c2a6f52f 100644 --- a/src/sendwidget.cpp +++ b/src/sendwidget.cpp @@ -70,8 +70,6 @@ void SendWidget::addressEdited() { if (outputs.size() > 0) { ui->lineAmount->setText(WalletManager::displayAmount(ui->lineAddress->getTotal())); ui->comboCurrencySelection->setCurrentIndex(0); - } else { - ui->lineAmount->setText(""); } ui->btn_openAlias->setVisible(ui->lineAddress->isOpenAlias()); From 89fd3cf27c764100d6abece02e50f5d82da82ede Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 14:26:04 +0200 Subject: [PATCH 35/62] TxInfoDialog: fix amount string --- src/dialog/transactioninfodialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialog/transactioninfodialog.cpp b/src/dialog/transactioninfodialog.cpp index 433acd16..b4d0adcb 100644 --- a/src/dialog/transactioninfodialog.cpp +++ b/src/dialog/transactioninfodialog.cpp @@ -104,7 +104,7 @@ void TransactionInfoDialog::setData(TransactionInfo* tx) { } QString direction = tx->direction() == TransactionInfo::Direction_In ? "received" : "sent"; - ui->label_amount->setText(QString("Amount %1: %2").arg(direction, tx->displayAmount())); + ui->label_amount->setText(QString("Amount %1: %2 XMR").arg(direction, tx->displayAmount())); QString fee; if (tx->isCoinbase()) From f9ef0a141d5f42590775593e922ef7c3e0904a2d Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 14:35:45 +0200 Subject: [PATCH 36/62] build: prepare beta-7 --- BUILDING.md | 4 ++-- CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 16ea8eab..8959837e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -22,7 +22,7 @@ git clone --branch master --recursive https://git.featherwallet.org/feather/feat cd feather ``` -Replace `master` with the desired version tag (e.g. `beta-6`) to build the release binary. +Replace `master` with the desired version tag (e.g. `beta-7`) to build the release binary. #### 2. Base image @@ -63,7 +63,7 @@ git clone --branch master --recursive https://git.featherwallet.org/feather/feat cd feather ``` -Replace `master` with the desired version tag (e.g. `beta-4`) to build the release binary. +Replace `master` with the desired version tag (e.g. `beta-7`) to build the release binary. #### 2. Base image diff --git a/CMakeLists.txt b/CMakeLists.txt index 399b0b0a..d2da3361 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) set(VERSION_MAJOR "0") set(VERSION_MINOR "1") set(VERSION_REVISION "0") -set(VERSION "beta-6") +set(VERSION "beta-7") option(STATIC "Link libraries statically, requires static Qt") From 808fd94f2a043336572b3198254953a3146fd0dc Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 14:40:05 +0200 Subject: [PATCH 37/62] About: add icons8 link --- src/assets/about.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/assets/about.txt b/src/assets/about.txt index 06b7ab9e..84af5c19 100644 --- a/src/assets/about.txt +++ b/src/assets/about.txt @@ -5,6 +5,8 @@ E-mail: dev@featherwallet.org Created by dsc, tobtoht, and contributors. +Uses icons from the Icons8 icon pack (icons8.com). + Copyright (c) 2020-, The Monero Project All rights reserved. From 58b927f9a3aa416977c552328647f4f2181848f8 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 16:50:09 +0200 Subject: [PATCH 38/62] MainWindow: fix potential segfault --- src/mainwindow.cpp | 8 ++++++-- src/mainwindow.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0a75493c..56ab81e0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -358,13 +358,13 @@ void MainWindow::initWalletContext() { connect(m_ctx.get(), &AppContext::customRestoreHeightSet, this, &MainWindow::onCustomRestoreHeightSet); // Nodes - connect(m_ctx->nodes, &Nodes::updateStatus, [=](const QString &msg){this->setStatusText(msg);}); + connect(m_ctx->nodes, &Nodes::updateStatus, this, &MainWindow::onSetStatusText); connect(m_ctx->nodes, &Nodes::nodeExhausted, this, &MainWindow::showNodeExhaustedMessage); connect(m_ctx->nodes, &Nodes::WSNodeExhausted, this, &MainWindow::showWSNodeExhaustedMessage); // Wallet connect(m_ctx->wallet.get(), &Wallet::connectionStatusChanged, this, &MainWindow::onConnectionStatusChanged); - connect(m_ctx->wallet.get(), &Wallet::currentSubaddressAccountChanged, [this]{this->updateTitle();}); + connect(m_ctx->wallet.get(), &Wallet::currentSubaddressAccountChanged, this, &MainWindow::updateTitle); } void MainWindow::startupWarning() { @@ -498,6 +498,10 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { m_balanceWidget->setHidden(hide); } +void MainWindow::onSetStatusText(const QString &text) { + this->setStatusText(text); +} + void MainWindow::setStatusText(const QString &text, bool override, int timeout) { if (override) { m_statusOverrideActive = true; diff --git a/src/mainwindow.h b/src/mainwindow.h index 52e2f743..5379c48e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -175,6 +175,7 @@ private slots: void menuHwDeviceClicked(); void onUpdatesAvailable(const QJsonObject &updates); void toggleSearchbar(bool enabled); + void onSetStatusText(const QString &text); private: void initStatusBar(); From fba93e98fc2f11389d5b0ba704ad7c1e97577367 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 17:20:19 +0200 Subject: [PATCH 39/62] Nodes: initSyncThreshold --- src/utils/config.cpp | 3 ++- src/utils/config.h | 1 + src/utils/nodes.cpp | 25 ++++++++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/utils/config.cpp b/src/utils/config.cpp index c8d2208f..fd393647 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -74,7 +74,8 @@ static const QHash configStrings = { {Config::socks5Port, {QS("socks5Port"), "9050"}}, {Config::socks5User, {QS("socks5User"), ""}}, // Unused {Config::socks5Pass, {QS("socks5Pass"), ""}}, // Unused - {Config::useLocalTor, {QS("useLocalTor"), false}} + {Config::useLocalTor, {QS("useLocalTor"), false}}, + {Config::initSyncThreshold, {QS("initSyncThreshold"), 360}} }; diff --git a/src/utils/config.h b/src/utils/config.h index 062b531b..5a0fb4b0 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -72,6 +72,7 @@ public: socks5User, socks5Pass, useLocalTor, // Prevents Feather from starting bundled Tor daemon + initSyncThreshold }; enum PrivacyLevel { diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index e477fd20..ef292ff9 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -359,10 +359,18 @@ void Nodes::setCustomNodes(const QList &nodes) { void Nodes::onWalletRefreshed() { if (config()->get(Config::torPrivacyLevel).toInt() == Config::allTorExceptInitSync) { + // Don't reconnect if we're connected to a local node (traffic will not be routed through Tor) if (m_connection.isLocal()) return; + + // Don't reconnect if we're already connected to an .onion node + if (m_connection.isOnion()) + return; + + // Don't reconnect on Tails or Whonix (all traffic is already routed through Tor) if (TailsOS::detect() || WhonixOS::detect()) return; + this->autoConnect(true); } } @@ -372,9 +380,24 @@ bool Nodes::useOnionNodes() { return true; } auto privacyLevel = config()->get(Config::torPrivacyLevel).toInt(); - if (privacyLevel == Config::allTor || (privacyLevel == Config::allTorExceptInitSync && m_ctx->refreshed)) { + if (privacyLevel == Config::allTor) { return true; } + + if (privacyLevel == Config::allTorExceptInitSync) { + if (m_ctx->refreshed) + return true; + + if (appData()->heights.contains(constants::networkType)) { + int initSyncThreshold = config()->get(Config::initSyncThreshold).toInt(); + int networkHeight = appData()->heights[constants::networkType]; + + if (m_ctx->wallet->blockChainHeight() > (networkHeight - initSyncThreshold)) { + return true; + } + } + } + return false; } From 064dd585adbba4c2c928279a8cb84e1bfaa149c8 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 20:56:42 +0200 Subject: [PATCH 40/62] Nodes: load old config format --- src/utils/nodes.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index ef292ff9..a683c4ba 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -13,8 +13,7 @@ bool NodeList::addNode(const QString &node, NetworkType::Type networkType, NodeList::Type source) { // We can't obtain references to QJsonObjects... - - QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + QJsonObject obj = this->getConfigData(); this->ensureStructure(obj, networkType); QString networkTypeStr = QString::number(networkType); @@ -37,7 +36,7 @@ bool NodeList::addNode(const QString &node, NetworkType::Type networkType, NodeL } void NodeList::setNodes(const QStringList &nodes, NetworkType::Type networkType, NodeList::Type source) { - QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + QJsonObject obj = this->getConfigData(); this->ensureStructure(obj, networkType); QString networkTypeStr = QString::number(networkType); @@ -53,7 +52,8 @@ void NodeList::setNodes(const QStringList &nodes, NetworkType::Type networkType, } QStringList NodeList::getNodes(NetworkType::Type networkType, NodeList::Type source) { - QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + QJsonObject obj = this->getConfigData(); + this->ensureStructure(obj, networkType); QString networkTypeStr = QString::number(networkType); QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); @@ -68,12 +68,23 @@ QStringList NodeList::getNodes(NetworkType::Type networkType, NodeList::Type sou return nodes; } +QJsonObject NodeList::getConfigData() { + QJsonObject obj = config()->get(Config::nodes).toJsonObject(); + + // Load old config format + if (obj.isEmpty()) { + auto jsonData = config()->get(Config::nodes).toByteArray(); + if (Utils::validateJSON(jsonData)) { + QJsonDocument doc = QJsonDocument::fromJson(jsonData); + obj = doc.object(); + } + } + + return obj; +} + void NodeList::ensureStructure(QJsonObject &obj, NetworkType::Type networkType) { QString networkTypeStr = QString::number(networkType); - - if (!obj.contains(networkTypeStr)) - obj[networkTypeStr] = QJsonObject(); - QJsonObject netTypeObj = obj.value(networkTypeStr).toObject(); if (!netTypeObj.contains("ws")) netTypeObj["ws"] = QJsonArray(); From ede6f7e9426c7a267aa3b5b0ba4bb340bccf2b47 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Mon, 24 May 2021 21:56:23 +0200 Subject: [PATCH 41/62] WindowManager: make sure Tor is stopped before close --- src/WindowManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index fca665bc..f920d664 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -48,7 +48,7 @@ void WindowManager::quitAfterLastWindow() { } qDebug() << "No wizards in progress and no wallets open, quitting application."; - QApplication::quit(); + this->close(); } void WindowManager::close() { From 3410132033fbd8028c9733d2bff5f64cad479af8 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 00:08:19 +0200 Subject: [PATCH 42/62] BroadcastTxDialog: change daemon rpc network if connected to local node --- src/dialog/broadcasttxdialog.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/dialog/broadcasttxdialog.cpp b/src/dialog/broadcasttxdialog.cpp index 6a0a213d..42b5d59a 100644 --- a/src/dialog/broadcasttxdialog.cpp +++ b/src/dialog/broadcasttxdialog.cpp @@ -32,19 +32,15 @@ BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, QSharedPointer void BroadcastTxDialog::broadcastTx() { QString tx = ui->transaction->toPlainText(); - QString node = [this]{ - QString node; - if (ui->radio_useCustom->isChecked()) - node = ui->customNode->text(); - else if (ui->radio_useDefault->isChecked()) - node = m_ctx->nodes->connection().toAddress(); + FeatherNode node = ui->radio_useCustom->isChecked() ? FeatherNode(ui->customNode->text()) : m_ctx->nodes->connection(); - if (!node.startsWith("http://")) - node = QString("http://%1").arg(node); - return node; - }(); + if (node.isLocal()) { + m_rpc->setNetwork(getNetworkClearnet()); + } else { + m_rpc->setNetwork(getNetworkTor()); + } - m_rpc->setDaemonAddress(node); + m_rpc->setDaemonAddress(node.toURL()); m_rpc->sendRawTransaction(tx); } From ba2b0ac5504e5b7bec2243fb18c48b01e74e3290 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 01:10:45 +0200 Subject: [PATCH 43/62] TickerWidget: rework --- src/mainwindow.cpp | 21 ++-- src/mainwindow.h | 6 +- src/widgets/TickerWidget.cpp | 105 ++++++++++++++++++ src/widgets/TickerWidget.h | 67 +++++++++++ .../{tickerwidget.ui => TickerWidget.ui} | 0 src/widgets/tickerwidget.cpp | 95 ---------------- src/widgets/tickerwidget.h | 38 ------- 7 files changed, 186 insertions(+), 146 deletions(-) create mode 100644 src/widgets/TickerWidget.cpp create mode 100644 src/widgets/TickerWidget.h rename src/widgets/{tickerwidget.ui => TickerWidget.ui} (100%) delete mode 100644 src/widgets/tickerwidget.cpp delete mode 100644 src/widgets/tickerwidget.h diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 56ab81e0..4de7ad6a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -68,9 +68,9 @@ MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *pa websocketNotifier()->emitCache(); // Get cached data // Settings - for (auto tickerWidget: m_tickerWidgets) - connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, tickerWidget, &TickerWidget::init); - connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceWidget, &TickerWidget::init); + for (const auto &widget: m_priceTickerWidgets) + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, widget, &PriceTickerWidget::updateDisplay); + connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_balanceTickerWidget, &BalanceTickerWidget::updateDisplay); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_ctx.get(), &AppContext::onPreferredFiatCurrencyChanged); connect(m_windowSettings, &Settings::preferredFiatCurrencyChanged, m_sendWidget, QOverload<>::of(&SendWidget::onPreferredFiatCurrencyChanged)); connect(m_windowSettings, &Settings::amountPrecisionChanged, m_ctx.get(), &AppContext::onAmountPrecisionChanged); @@ -332,13 +332,14 @@ void MainWindow::initMenu() { void MainWindow::initHome() { // Ticker widgets - m_tickerWidgets.append(new TickerWidget(this, m_ctx, "XMR")); - m_tickerWidgets.append(new TickerWidget(this, m_ctx, "BTC")); - for (auto tickerWidget: m_tickerWidgets) { - ui->tickerLayout->addWidget(tickerWidget); + m_priceTickerWidgets.append(new PriceTickerWidget(this, m_ctx, "XMR")); + m_priceTickerWidgets.append(new PriceTickerWidget(this, m_ctx, "BTC")); + for (const auto &widget : m_priceTickerWidgets) { + ui->tickerLayout->addWidget(widget); } - m_balanceWidget = new TickerWidget(this, m_ctx, "XMR", "Balance", true, true); - ui->fiatTickerLayout->addWidget(m_balanceWidget); + + m_balanceTickerWidget = new BalanceTickerWidget(this, m_ctx, false); + ui->fiatTickerLayout->addWidget(m_balanceTickerWidget); connect(ui->ccsWidget, &CCSWidget::selected, this, &MainWindow::showSendScreen); connect(ui->redditWidget, &RedditWidget::setStatusText, this, &MainWindow::setStatusText); @@ -495,7 +496,7 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { m_statusLabelBalance->setToolTip("Click for details"); m_statusLabelBalance->setText(balance_str); - m_balanceWidget->setHidden(hide); + m_balanceTickerWidget->setHidden(hide); } void MainWindow::onSetStatusText(const QString &text) { diff --git a/src/mainwindow.h b/src/mainwindow.h index 5379c48e..3dfb3f62 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -33,7 +33,7 @@ #include "utils/config.h" #include "widgets/ccswidget.h" #include "widgets/redditwidget.h" -#include "widgets/tickerwidget.h" +#include "widgets/TickerWidget.h" #include "wizard/WalletWizard.h" #include "contactswidget.h" @@ -225,8 +225,8 @@ private: LocalMoneroWidget *m_localMoneroWidget = nullptr; #endif - QList m_tickerWidgets; - TickerWidget *m_balanceWidget; + QList m_priceTickerWidgets; + BalanceTickerWidget *m_balanceTickerWidget; // lower status bar QPushButton *m_statusUpdateAvailable; diff --git a/src/widgets/TickerWidget.cpp b/src/widgets/TickerWidget.cpp new file mode 100644 index 00000000..2e11d367 --- /dev/null +++ b/src/widgets/TickerWidget.cpp @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "TickerWidget.h" +#include "ui_TickerWidget.h" + +#include "constants.h" +#include "utils/AppData.h" + +TickerWidgetBase::TickerWidgetBase(QWidget *parent, QSharedPointer ctx) + : QWidget(parent) + , ui(new Ui::TickerWidget) + , m_ctx(std::move(ctx)) +{ + ui->setupUi(this); + + ui->tickerPct->setFont(Utils::relativeFont(-2)); + ui->tickerFiat->setFont(Utils::relativeFont(0)); + + this->setPercentageText("0.0", true); + ui->tickerFiat->setText("..."); +} + +TickerWidgetBase::~TickerWidgetBase() { + delete ui; +} + +void TickerWidgetBase::setTitle(const QString &title) { + ui->tickerBox->setTitle(title); +} + +void TickerWidgetBase::setPercentageVisible(bool visible) { + ui->tickerPct->setVisible(visible); +} + +void TickerWidgetBase::setPercentageText(const QString &text, bool positive) { + QString pctText = "

"; + if(positive) { + pctText = pctText.replace("red", "green"); + pctText += QString("+%1%").arg(text); + } else + pctText += QString("%1%").arg(text); + pctText += "

"; + + ui->tickerPct->setText(pctText); +} + +void TickerWidgetBase::setFiatText(double amount, const QString &fiatCurrency) { + QString conversionText = Utils::amountToCurrencyString(amount, fiatCurrency); + ui->tickerFiat->setText(conversionText); +} + +// BalanceTickerWidget +BalanceTickerWidget::BalanceTickerWidget(QWidget *parent, QSharedPointer ctx, bool totalBalance) + : TickerWidgetBase(parent, std::move(ctx)) + , m_totalBalance(totalBalance) +{ + if (totalBalance) + this->setTitle("Total balance"); + else + this->setTitle("Balance"); + + this->setPercentageVisible(false); + + connect(m_ctx.get(), &AppContext::balanceUpdated, this, &BalanceTickerWidget::updateDisplay); + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &BalanceTickerWidget::updateDisplay); + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &BalanceTickerWidget::updateDisplay); +} + +void BalanceTickerWidget::updateDisplay() { + double balance = (m_totalBalance ? m_ctx->wallet->balanceAll() : m_ctx->wallet->balanceAll()) / constants::cdiv; + QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); + double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance); + if (balanceFiatAmount < 0) + return; + this->setFiatText(balanceFiatAmount, fiatCurrency); +} + +// PriceTickerWidget +PriceTickerWidget::PriceTickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol) + : TickerWidgetBase(parent, std::move(ctx)) + , m_symbol(std::move(symbol)) +{ + this->setTitle(m_symbol); + + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &PriceTickerWidget::updateDisplay); + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &PriceTickerWidget::updateDisplay); +} + +void PriceTickerWidget::updateDisplay() { + QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); + double price = appData()->prices.convert(m_symbol, fiatCurrency, 1.0); + if (price < 0) + return; + + auto markets = appData()->prices.markets; + if (!markets.contains(m_symbol)) + return; + + double percentChange24h = markets[m_symbol].price_usd_change_pct_24h; + QString percentChange24hStr = QString::number(percentChange24h, 'f', 2); + this->setPercentageText(percentChange24hStr, percentChange24h >= 0.0); + + this->setFiatText(price, fiatCurrency); +} diff --git a/src/widgets/TickerWidget.h b/src/widgets/TickerWidget.h new file mode 100644 index 00000000..cd586bf0 --- /dev/null +++ b/src/widgets/TickerWidget.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_TICKERWIDGET_H +#define FEATHER_TICKERWIDGET_H + +#include + +#include "appcontext.h" + +namespace Ui { + class TickerWidget; +} + +class TickerWidgetBase : public QWidget +{ + Q_OBJECT + +public: + explicit TickerWidgetBase(QWidget *parent, QSharedPointer ctx); + ~TickerWidgetBase() override; + + void setTitle(const QString &title); + void setPercentageVisible(bool visible); + + void setPercentageText(const QString &text, bool positive); + void setFiatText(double amount, const QString &fiatCurrency); + +public slots: + virtual void updateDisplay() = 0; + +private: + Ui::TickerWidget *ui; + +protected: + QSharedPointer m_ctx; +}; + +class BalanceTickerWidget : public TickerWidgetBase +{ + Q_OBJECT + +public: + explicit BalanceTickerWidget(QWidget *parent, QSharedPointer ctx, bool totalBalance); + +public slots: + void updateDisplay() override; + +private: + bool m_totalBalance; +}; + +class PriceTickerWidget : public TickerWidgetBase +{ + Q_OBJECT + +public: + explicit PriceTickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol); + +public slots: + void updateDisplay() override; + +private: + QString m_symbol; +}; + +#endif // FEATHER_TICKERWIDGET_H diff --git a/src/widgets/tickerwidget.ui b/src/widgets/TickerWidget.ui similarity index 100% rename from src/widgets/tickerwidget.ui rename to src/widgets/TickerWidget.ui diff --git a/src/widgets/tickerwidget.cpp b/src/widgets/tickerwidget.cpp deleted file mode 100644 index 621835d9..00000000 --- a/src/widgets/tickerwidget.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2020-2021, The Monero Project. - -#include "tickerwidget.h" -#include "ui_tickerwidget.h" - -#include "constants.h" -#include "utils/AppData.h" - -TickerWidget::TickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol, QString title, bool convertBalance, bool hidePercent) - : QWidget(parent) - , ui(new Ui::TickerWidget) - , m_ctx(std::move(ctx)) - , m_symbol(std::move(symbol)) - , m_convertBalance(convertBalance) - , m_hidePercent(hidePercent) -{ - ui->setupUi(this); - - // default values before API data - if (title == "") title = m_symbol; - this->ui->tickerBox->setTitle(title); - QString defaultPct = "0.0"; - QString defaultFiat = "..."; - - this->setFontSizes(); - this->setPctText(defaultPct, true); - this->setFiatText(defaultFiat, 0.0); - - ui->tickerPct->setHidden(hidePercent); - - connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &TickerWidget::init); - connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init); - - if (convertBalance) - connect(m_ctx.get(), &AppContext::balanceUpdated, this, &TickerWidget::init); -} - -void TickerWidget::init() { - if(!appData()->prices.markets.count() || !appData()->prices.rates.count()) - return; - - QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); - - if(!appData()->prices.rates.contains(fiatCurrency)){ - config()->set(Config::preferredFiatCurrency, "USD"); - return; - } - - double walletBalance = m_ctx->wallet ? (m_ctx->wallet->balance() / constants::cdiv) : 0; - - double amount = m_convertBalance ? walletBalance : 1.0; - double conversion = appData()->prices.convert(m_symbol, fiatCurrency, amount); - if (conversion < 0) return; - - auto markets = appData()->prices.markets; - if(!markets.contains(m_symbol)) return; - - bool hidePercent = (conversion == 0 || m_hidePercent); - if (hidePercent) { - ui->tickerPct->hide(); - } else { - auto pct24h = markets[m_symbol].price_usd_change_pct_24h; - auto pct24hText = QString::number(pct24h, 'f', 2); - this->setPctText(pct24hText, pct24h >= 0.0); - } - - this->setFiatText(fiatCurrency, conversion); -} - -void TickerWidget::setFiatText(QString &fiatCurrency, double amount) { - QString conversionText = Utils::amountToCurrencyString(amount, fiatCurrency); - ui->tickerFiat->setText(conversionText); -} - -void TickerWidget::setPctText(QString &text, bool positive) { - QString pctText = "

"; - if(positive) { - pctText = pctText.replace("red", "green"); - pctText += QString("+%1%").arg(text); - } else - pctText += QString("%1%").arg(text); - - pctText += "

"; - ui->tickerPct->setText(pctText); -} - -void TickerWidget::setFontSizes() { - ui->tickerPct->setFont(Utils::relativeFont(-2)); - ui->tickerFiat->setFont(Utils::relativeFont(0)); -} - -TickerWidget::~TickerWidget() { - delete ui; -} diff --git a/src/widgets/tickerwidget.h b/src/widgets/tickerwidget.h deleted file mode 100644 index 6c50ec99..00000000 --- a/src/widgets/tickerwidget.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2020-2021, The Monero Project. - -#ifndef TICKERWIDGET_H -#define TICKERWIDGET_H - -#include - -#include "appcontext.h" - -namespace Ui { - class TickerWidget; -} - -class TickerWidget : public QWidget -{ - Q_OBJECT - -public: - explicit TickerWidget(QWidget *parent, QSharedPointer ctx, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false); - void setFiatText(QString &fiatCurrency, double amount); - void setPctText(QString &text, bool positive); - void setFontSizes(); - ~TickerWidget() override; - - -public slots: - void init(); - -private: - Ui::TickerWidget *ui; - QSharedPointer m_ctx; - QString m_symbol; - bool m_convertBalance; - bool m_hidePercent; -}; - -#endif // TICKERWIDGET_H From 08d5fd26fff8f8d16d92ef4114a6b0dfd3ab33f2 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 02:26:28 +0200 Subject: [PATCH 44/62] RestoreHeightDialog: rework --- src/dialog/RestoreHeightDialog.cpp | 40 +++++++ src/dialog/RestoreHeightDialog.h | 23 ++++ src/dialog/restoredialog.cpp | 38 ------ src/dialog/restoredialog.h | 39 ------ src/dialog/restoredialog.ui | 56 --------- src/mainwindow.cpp | 21 +--- src/mainwindow.h | 3 +- src/widgets/RestoreHeightWidget.cpp | 61 ++++++++++ ...reheightwidget.h => RestoreHeightWidget.h} | 24 ++-- src/widgets/RestoreHeightWidget.ui | 61 ++++++++++ src/widgets/restoreheightwidget.cpp | 71 ----------- src/widgets/restoreheightwidget.ui | 112 ------------------ 12 files changed, 203 insertions(+), 346 deletions(-) create mode 100644 src/dialog/RestoreHeightDialog.cpp create mode 100644 src/dialog/RestoreHeightDialog.h delete mode 100644 src/dialog/restoredialog.cpp delete mode 100644 src/dialog/restoredialog.h delete mode 100644 src/dialog/restoredialog.ui create mode 100644 src/widgets/RestoreHeightWidget.cpp rename src/widgets/{restoreheightwidget.h => RestoreHeightWidget.h} (53%) create mode 100644 src/widgets/RestoreHeightWidget.ui delete mode 100644 src/widgets/restoreheightwidget.cpp delete mode 100644 src/widgets/restoreheightwidget.ui diff --git a/src/dialog/RestoreHeightDialog.cpp b/src/dialog/RestoreHeightDialog.cpp new file mode 100644 index 00000000..ca7cfda8 --- /dev/null +++ b/src/dialog/RestoreHeightDialog.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "RestoreHeightDialog.h" + +#include +#include +#include + +RestoreHeightDialog::RestoreHeightDialog(QWidget *parent, quint64 currentRestoreHeight) + : QDialog(parent) + , m_restoreHeightWidget(new RestoreHeightWidget(this)) +{ + auto *layout = new QVBoxLayout(this); + + auto *label = new QLabel(this); + label->setText("Enter a wallet creation date or restore height."); + + auto *buttonBox = new QDialogButtonBox(this); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + + layout->addWidget(label); + layout->addWidget(m_restoreHeightWidget); + layout->addWidget(buttonBox); + + this->setLayout(layout); + + if (currentRestoreHeight) { + m_restoreHeightWidget->setHeight(currentRestoreHeight); + } + + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + this->adjustSize(); +} + +int RestoreHeightDialog::getHeight() { + return m_restoreHeightWidget->getHeight(); +} \ No newline at end of file diff --git a/src/dialog/RestoreHeightDialog.h b/src/dialog/RestoreHeightDialog.h new file mode 100644 index 00000000..16159c9d --- /dev/null +++ b/src/dialog/RestoreHeightDialog.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_RESTOREHEIGHTDIALOG_H +#define FEATHER_RESTOREHEIGHTDIALOG_H + +#include +#include "widgets/RestoreHeightWidget.h" + +class RestoreHeightDialog : public QDialog +{ +Q_OBJECT + +public: + explicit RestoreHeightDialog(QWidget *parent = nullptr, quint64 currentRestoreHeight = 0); + int getHeight(); + +private: + RestoreHeightWidget *m_restoreHeightWidget; +}; + + +#endif //FEATHER_RESTOREHEIGHTDIALOG_H diff --git a/src/dialog/restoredialog.cpp b/src/dialog/restoredialog.cpp deleted file mode 100644 index fa9679a4..00000000 --- a/src/dialog/restoredialog.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2020-2021, The Monero Project. - -#include "restoredialog.h" -#include "ui_restoredialog.h" - -#include "constants.h" - -RestoreDialog::RestoreDialog(QSharedPointer ctx, QWidget *parent) - : QDialog(parent) - , ui(new Ui::RestoreDialog) - , m_ctx(std::move(ctx)) -{ - ui->setupUi(this); - this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RestoreDialog::accepted); - connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RestoreDialog::rejected); - - if(constants::networkType == NetworkType::Type::TESTNET) { - ui->restoreHeightWidget->hideSlider(); - } else { - // load restoreHeight lookup db - ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[constants::networkType]); - } -} - -int RestoreDialog::getHeight() { - return ui->restoreHeightWidget->getHeight(); -} - -void RestoreDialog::initRestoreHeights(RestoreHeightLookup *lookup) { - ui->restoreHeightWidget->initRestoreHeights(lookup); -} - -RestoreDialog::~RestoreDialog() { - delete ui; -} - diff --git a/src/dialog/restoredialog.h b/src/dialog/restoredialog.h deleted file mode 100644 index e6118c81..00000000 --- a/src/dialog/restoredialog.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2020-2021, The Monero Project. - -#ifndef RESTOREDIALOG_H -#define RESTOREDIALOG_H - -#include -#include -#include -#include -#include - -#include "utils/RestoreHeightLookup.h" -#include "appcontext.h" - -namespace Ui { - class RestoreDialog; -} - -class RestoreDialog : public QDialog -{ -Q_OBJECT - -public: - explicit RestoreDialog(QSharedPointer ctx, QWidget *parent = nullptr); - void initRestoreHeights(RestoreHeightLookup *lookup); - int getHeight(); - ~RestoreDialog() override; - -signals: - void accepted(); - void rejected(); - -private: - Ui::RestoreDialog *ui; - QSharedPointer m_ctx; -}; - -#endif // RESTOREDIALOG_H diff --git a/src/dialog/restoredialog.ui b/src/dialog/restoredialog.ui deleted file mode 100644 index 5c914bb6..00000000 --- a/src/dialog/restoredialog.ui +++ /dev/null @@ -1,56 +0,0 @@ - - - RestoreDialog - - - - 0 - 0 - 584 - 99 - - - - specify restore height - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - RestoreHeightWidget - QWidget -
widgets/restoreheightwidget.h
- 1 -
-
- - -
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4de7ad6a..baedfd42 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -735,26 +735,17 @@ void MainWindow::updatePasswordIcon() { void MainWindow::showRestoreHeightDialog() { // settings custom restore height is only available for 25 word seeds auto seed = m_ctx->wallet->getCacheAttribute("feather.seed"); - if(!seed.isEmpty()) { + if(!seed.isEmpty()) { // TODO: update this warning (import tx, delete cache, restore from seed) const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; QMessageBox::warning(this, "Cannot set custom restore height", msg); return; } - m_restoreDialog = new RestoreDialog(m_ctx, this); - m_restoreDialog->show(); - - connect(m_restoreDialog, &RestoreDialog::accepted, [=]{ - auto height = m_restoreDialog->getHeight(); - m_restoreDialog->disconnect(); - m_restoreDialog->deleteLater(); - m_ctx->onSetRestoreHeight(height); - }); - - connect(m_restoreDialog, &RestoreDialog::rejected, [=]{ - m_restoreDialog->disconnect(); - m_restoreDialog->deleteLater(); - }); + RestoreHeightDialog dialog{this, m_ctx->wallet->getWalletCreationHeight()}; + if (dialog.exec() == QDialog::Accepted) { + int restoreHeight = dialog.getHeight(); + m_ctx->onSetRestoreHeight(restoreHeight); + } } void MainWindow::showKeysDialog() { diff --git a/src/mainwindow.h b/src/mainwindow.h index 3dfb3f62..56f2dc09 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -21,7 +21,7 @@ #include "dialog/passwordchangedialog.h" #include "dialog/keysdialog.h" #include "dialog/aboutdialog.h" -#include "dialog/restoredialog.h" +#include "dialog/RestoreHeightDialog.h" #include "dialog/splashdialog.h" #include "libwalletqt/Wallet.h" #include "model/SubaddressModel.h" @@ -212,7 +212,6 @@ private: Settings *m_windowSettings = nullptr; CalcWindow *m_windowCalc = nullptr; - RestoreDialog *m_restoreDialog = nullptr; SplashDialog *m_splashDialog = nullptr; XMRigWidget *m_xmrig = nullptr; diff --git a/src/widgets/RestoreHeightWidget.cpp b/src/widgets/RestoreHeightWidget.cpp new file mode 100644 index 00000000..b3250f17 --- /dev/null +++ b/src/widgets/RestoreHeightWidget.cpp @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "RestoreHeightWidget.h" +#include "ui_RestoreHeightWidget.h" + +#include + +#include "AppData.h" +#include "constants.h" + +RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::RestoreHeightWidget) +{ + ui->setupUi(this); + + QRegExp yearRe(R"(\d{2,4}-\d{1,2}-\d{1,2})"); + QValidator *yearValidator = new QRegExpValidator(yearRe, this); + ui->line_creationDate->setValidator(yearValidator); + + QRegExp heightRe(R"(\d{7})"); + QValidator *heightValidator = new QRegExpValidator(heightRe, this); + ui->line_restoreHeight->setValidator(heightValidator); + + connect(ui->line_creationDate, &QLineEdit::textEdited, this, &RestoreHeightWidget::onCreationDateChanged); + connect(ui->line_restoreHeight, &QLineEdit::textEdited, this, &RestoreHeightWidget::onRestoreHeightChanged); +} + +void RestoreHeightWidget::setHeight(quint64 restoreHeight) { + ui->line_restoreHeight->setText(QString::number(restoreHeight)); + this->onRestoreHeightChanged(); +} + +int RestoreHeightWidget::getHeight() { + return ui->line_restoreHeight->text().toInt(); +} + +void RestoreHeightWidget::onCreationDateChanged() { + auto curDate = QDateTime::currentDateTime().addDays(-7); + auto date = QDateTime::fromString(ui->line_creationDate->text(), "yyyy-MM-dd"); + if (!date.isValid()) { + return; + } + + QDateTime restoreDate = date > curDate ? curDate : date; + qint64 timestamp = restoreDate.toSecsSinceEpoch(); + + QString restoreHeight = QString::number(appData()->restoreHeights[constants::networkType]->dateToHeight(timestamp)); + ui->line_restoreHeight->setText(restoreHeight); +} + +void RestoreHeightWidget::onRestoreHeightChanged() { + int restoreHeight = ui->line_restoreHeight->text().toInt(); + QDateTime date = appData()->restoreHeights[constants::networkType]->heightToDate(restoreHeight); + ui->line_creationDate->setText(date.toString("yyyy-MM-dd")); +} + +RestoreHeightWidget::~RestoreHeightWidget() { + delete ui; +} \ No newline at end of file diff --git a/src/widgets/restoreheightwidget.h b/src/widgets/RestoreHeightWidget.h similarity index 53% rename from src/widgets/restoreheightwidget.h rename to src/widgets/RestoreHeightWidget.h index a1418c35..a7f466bd 100644 --- a/src/widgets/restoreheightwidget.h +++ b/src/widgets/RestoreHeightWidget.h @@ -1,13 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. -#ifndef RESTOREHEIGHTWIDGET_H -#define RESTOREHEIGHTWIDGET_H +#ifndef FEATHER_RESTOREHEIGHTWIDGET_H +#define FEATHER_RESTOREHEIGHTWIDGET_H #include -#include - -#include "appcontext.h" namespace Ui { class RestoreHeightWidget; @@ -19,17 +16,18 @@ class RestoreHeightWidget : public QWidget public: explicit RestoreHeightWidget(QWidget *parent = nullptr); - void initRestoreHeights(RestoreHeightLookup *lookup); - void setHeight(int height); - int getHeight(); - void hideSlider(); ~RestoreHeightWidget() override; -private: - void updateTimestamp(int date); + void setHeight(quint64 restoreHeight); + int getHeight(); - RestoreHeightLookup *m_restoreHeightLookup = nullptr; +private slots: + void onCreationDateChanged(); + void onRestoreHeightChanged(); + +private: Ui::RestoreHeightWidget *ui; }; -#endif // RESTOREHEIGHTWIDGET_H + +#endif //FEATHER_RESTOREHEIGHTWIDGET_H diff --git a/src/widgets/RestoreHeightWidget.ui b/src/widgets/RestoreHeightWidget.ui new file mode 100644 index 00000000..491c9fdf --- /dev/null +++ b/src/widgets/RestoreHeightWidget.ui @@ -0,0 +1,61 @@ + + + RestoreHeightWidget + + + + 0 + 0 + 622 + 88 + + + + Form + + + + + + Wallet creation date: + + + + + + + + + + (YYYY-MM-DD) + + + + + + + Restore height: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + diff --git a/src/widgets/restoreheightwidget.cpp b/src/widgets/restoreheightwidget.cpp deleted file mode 100644 index f8b6a1d0..00000000 --- a/src/widgets/restoreheightwidget.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright (c) 2020-2021, The Monero Project. - -#include -#include -#include - -#include "restoreheightwidget.h" -#include "ui_restoreheightwidget.h" - -RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) - : QWidget(parent) - , ui(new Ui::RestoreHeightWidget) -{ - ui->setupUi(this); - ui->lineEdit_restoreHeight->setValidator(new QIntValidator(0, 2147483647, this)); - - connect(ui->lineEdit_restoreHeight, &QLineEdit::textEdited, [this](const QString &val){ - if (val.isEmpty()) return; - this->setHeight(val.toInt()); - }); -} - -void RestoreHeightWidget::hideSlider(){ - ui->restoreGrid->hide(); -} - -void RestoreHeightWidget::setHeight(int height) { - if (height < 0) - height = 0; - - // Update lineEdit - ui->lineEdit_restoreHeight->setText(QString::number(height)); - - // Update slider - int date = m_restoreHeightLookup->heightToTimestamp(height); - ui->restoreSlider->setValue(date); - - this->updateTimestamp(date); -} - -void RestoreHeightWidget::initRestoreHeights(RestoreHeightLookup *lookup) { - // init slider - m_restoreHeightLookup = lookup; - int now = std::time(nullptr); - QList blockDates = m_restoreHeightLookup->data.keys(); - ui->restoreSlider->setMinimum(blockDates[0]); - ui->restoreSlider->setMaximum(now); - - connect(ui->restoreSlider, &QSlider::sliderMoved, [this](int date){ - // Update lineEdit - int blockHeight = m_restoreHeightLookup->dateToHeight(date); - ui->lineEdit_restoreHeight->setText(QString::number(blockHeight)); - - this->updateTimestamp(date); - }); -} - -void RestoreHeightWidget::updateTimestamp(int date) { - QDateTime timestamp; - timestamp.setTime_t(date); - ui->label_restoreHeightDate->setText(timestamp.toString("yyyy-MM-dd")); -} - -int RestoreHeightWidget::getHeight() { - return ui->lineEdit_restoreHeight->text().toInt(); -} - -RestoreHeightWidget::~RestoreHeightWidget() { - delete ui; -} diff --git a/src/widgets/restoreheightwidget.ui b/src/widgets/restoreheightwidget.ui deleted file mode 100644 index 00cb7d37..00000000 --- a/src/widgets/restoreheightwidget.ui +++ /dev/null @@ -1,112 +0,0 @@ - - - RestoreHeightWidget - - - - 0 - 0 - 360 - 89 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 2014-04-18 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Restore height - - - - - - - Qt::Horizontal - - - - - - - - - - - - - - 1 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - From 8de152376ece1acb42c0e1f22a73eabb2a9668f7 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 03:07:42 +0200 Subject: [PATCH 45/62] Prices: cleanup --- src/utils/prices.cpp | 103 ++++++++++++++++++------------------------- src/utils/prices.h | 5 +-- 2 files changed, 43 insertions(+), 65 deletions(-) diff --git a/src/utils/prices.cpp b/src/utils/prices.cpp index 1ff50853..ca9bd817 100644 --- a/src/utils/prices.cpp +++ b/src/utils/prices.cpp @@ -1,93 +1,74 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. -#include -#include -#include - #include "utils/prices.h" Prices::Prices(QObject *parent) : QObject(parent) { this->rates = QMap(); this->markets = QMap(); - this->fiat = QMap(); - fiat["USD"] = "$"; - fiat["EUR"] = "€"; - fiat["JPY"] = "¥"; - fiat["KRW"] = "₩"; - fiat["MXN"] = "$"; - fiat["RUB"] = "\u20BD"; - fiat["CAD"] = "$"; - fiat["GBP"] = "£"; - fiat["SEK"] = "kr"; - fiat["ZAR"] = "R"; - fiat["THB"] = "฿"; - fiat["TRY"] = "₺"; - fiat["CHF"] = "Fr"; - fiat["CNY"] = "¥"; - fiat["CZK"] = "Kč"; - fiat["AUD"] = "$"; - fiat["NZD"] = "$"; } void Prices::cryptoPricesReceived(const QJsonArray &data) { - QStringList filter = QStringList() << "XMR" << "ZEC" << "BTC" << "ETH" << "BCH" << "LTC"; - filter << "EOS" << "ADA" << "XLM" << "TRX" << "DASH" << "DCR" << "VET" << "DOGE" << "XRP" << "WOW"; + this->markets.clear(); - QMap msMap; - for(auto &&entry: data) { - marketStruct ms; + for (const auto &entry : data) { QJsonObject obj = entry.toObject(); + marketStruct ms; ms.symbol = obj.value("symbol").toString(); ms.image = obj.value("image").toString(); ms.name = obj.value("name").toString(); ms.price_usd = obj.value("current_price").toDouble(); ms.price_usd_change_pct_24h = obj.value("price_change_percentage_24h").toDouble(); + if (ms.price_usd <= 0) + continue; - if(ms.price_usd <= 0) continue; - if(filter.contains(ms.symbol.toUpper())) - msMap.insert(ms.symbol.toUpper(), ms); + this->markets.insert(ms.symbol.toUpper(), ms); } - if(msMap.count() > 0) - this->markets = msMap; - emit cryptoPricesUpdated(); } -double Prices::convert(const QString &symbolFrom, const QString &symbolTo, double amount) { - if(symbolFrom == symbolTo) return amount; - if(amount <= 0.0) return 0.0; +void Prices::fiatPricesReceived(const QJsonObject &data) { + QJsonObject ratesData = data.value("rates").toObject(); + for (const auto ¤cy : ratesData) { + QString currencyStr = currency.toString(); + this->rates.insert(currencyStr, ratesData.value(currencyStr).toDouble()); + } + emit fiatPricesUpdated(); +} - double usd_from; - QString from = symbolFrom.toUpper(); - QString to = symbolTo.toUpper(); - - if(this->markets.contains(from)) - usd_from = this->markets[from].price_usd * amount; - else if(this->rates.contains(from)) { - if(from == "USD") - usd_from = amount; - else - usd_from = amount / this->rates[from]; - } else +double Prices::convert(QString symbolFrom, QString symbolTo, double amount) { + if (symbolFrom == symbolTo) + return amount; + if (amount <= 0.0) return 0.0; - if(to == "USD") - return usd_from; + symbolFrom = symbolFrom.toUpper(); + symbolTo = symbolTo.toUpper(); - if(this->markets.contains(to)) - return usd_from / this->markets[to].price_usd; - else if(this->rates.contains(to)) - return usd_from * this->rates[to]; + double usdPrice; + if (this->markets.contains(symbolFrom)) { + usdPrice = this->markets[symbolFrom].price_usd * amount; + } + else if (this->rates.contains(symbolFrom)) { + if (symbolFrom == "USD") { + usdPrice = amount; + } else { + usdPrice = amount / this->rates[symbolFrom]; + } + } + else { + return 0.0; + } + + if (symbolTo == "USD") + return usdPrice; + + if (this->markets.contains(symbolTo)) + return usdPrice / this->markets[symbolTo].price_usd; + else if (this->rates.contains(symbolTo)) + return usdPrice * this->rates[symbolTo]; return 0.0; } -void Prices::fiatPricesReceived(const QJsonObject &data) { - QJsonObject rates = data.value("rates").toObject(); - for(const auto ¤cy: fiat.keys()) - if(rates.contains(currency)) - this->rates.insert(currency, rates.value(currency).toDouble()); - emit fiatPricesUpdated(); -} diff --git a/src/utils/prices.h b/src/utils/prices.h index 3f0df189..03fa06be 100644 --- a/src/utils/prices.h +++ b/src/utils/prices.h @@ -5,8 +5,6 @@ #define FEATHER_PRICES_H #include -#include -#include #include "utils/utils.h" @@ -26,13 +24,12 @@ public: explicit Prices(QObject *parent = nullptr); QMap rates; QMap markets; - QMap fiat; // symbol:sign public slots: void cryptoPricesReceived(const QJsonArray &data); void fiatPricesReceived(const QJsonObject &data); - double convert(const QString &symbolFrom, const QString &symbolTo, double amount); + double convert(QString symbolFrom, QString symbolTo, double amount); signals: void fiatPricesUpdated(); From 2d4ccd70198a812974eff2f011511b2768e9ab26 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 15:06:38 +0200 Subject: [PATCH 46/62] Move Tails/Whonix to utils/os --- src/CMakeLists.txt | 2 ++ src/WindowManager.cpp | 2 +- src/appcontext.h | 2 +- src/dialog/debuginfodialog.cpp | 2 +- src/dialog/torinfodialog.cpp | 2 +- src/mainwindow.cpp | 2 +- src/utils/TorManager.cpp | 2 +- src/utils/WebsocketNotifier.cpp | 4 ++-- src/utils/config.cpp | 2 +- src/utils/nodes.cpp | 2 +- src/utils/{ => os}/tails.cpp | 0 src/utils/{ => os}/tails.h | 0 src/utils/{ => os}/whonix.cpp | 0 src/utils/{ => os}/whonix.h | 0 src/utils/utils.cpp | 4 ++-- 15 files changed, 14 insertions(+), 12 deletions(-) rename src/utils/{ => os}/tails.cpp (100%) rename src/utils/{ => os}/tails.h (100%) rename src/utils/{ => os}/whonix.cpp (100%) rename src/utils/{ => os}/whonix.h (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94b89688..bdac1b53 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,8 @@ file(GLOB SOURCE_FILES "api/*.cpp" "utils/*.h" "utils/*.cpp" + "utils/os/*.h" + "utils/os/*.cpp" "libwalletqt/*.h" "libwalletqt/*.cpp" "daemon/*.h" diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index f920d664..f01219c8 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -6,7 +6,7 @@ #include "dialog/passworddialog.h" #include "dialog/splashdialog.h" #include "utils/WebsocketNotifier.h" -#include "utils/tails.h" +#include "utils/os/tails.h" #include "utils/Icons.h" #include "utils/NetworkManager.h" #include "utils/TorManager.h" diff --git a/src/appcontext.h b/src/appcontext.h index af45fa64..ebf482b8 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -7,7 +7,7 @@ #include #include -#include "utils/whonix.h" +#include "utils/os/whonix.h" #include "utils/networking.h" #include "utils/wsclient.h" #include "utils/FeatherSeed.h" diff --git a/src/dialog/debuginfodialog.cpp b/src/dialog/debuginfodialog.cpp index 768fa07e..f6371ad4 100644 --- a/src/dialog/debuginfodialog.cpp +++ b/src/dialog/debuginfodialog.cpp @@ -7,7 +7,7 @@ #include "utils/WebsocketClient.h" #include "utils/TorManager.h" #include "utils/WebsocketNotifier.h" -#include "utils/tails.h" +#include "utils/os/tails.h" DebugInfoDialog::DebugInfoDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) diff --git a/src/dialog/torinfodialog.cpp b/src/dialog/torinfodialog.cpp index 0c9ab787..1c395a9c 100644 --- a/src/dialog/torinfodialog.cpp +++ b/src/dialog/torinfodialog.cpp @@ -9,7 +9,7 @@ #include #include "utils/TorManager.h" -#include "utils/tails.h" +#include "utils/os/tails.h" TorInfoDialog::TorInfoDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index baedfd42..04705ae2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -31,7 +31,7 @@ #include "utils/Icons.h" #include "utils/WebsocketNotifier.h" #include "utils/Updater.h" -#include "utils/tails.h" +#include "utils/os/tails.h" #include "utils/TorManager.h" MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent) diff --git a/src/utils/TorManager.cpp b/src/utils/TorManager.cpp index 398fd826..3a9c7bb7 100644 --- a/src/utils/TorManager.cpp +++ b/src/utils/TorManager.cpp @@ -9,7 +9,7 @@ #include #include "utils/utils.h" -#include "utils/tails.h" +#include "utils/os/tails.h" #include "appcontext.h" #include "config-feather.h" diff --git a/src/utils/WebsocketNotifier.cpp b/src/utils/WebsocketNotifier.cpp index dff4d5d1..39a7c450 100644 --- a/src/utils/WebsocketNotifier.cpp +++ b/src/utils/WebsocketNotifier.cpp @@ -3,8 +3,8 @@ #include "WebsocketNotifier.h" #include "utils.h" -#include "tails.h" -#include "whonix.h" +#include "utils/os/tails.h" +#include "utils/os/whonix.h" #include diff --git a/src/utils/config.cpp b/src/utils/config.cpp index fd393647..9af405c7 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -5,7 +5,7 @@ #include "config.h" #include "utils/utils.h" -#include "utils/tails.h" +#include "utils/os/tails.h" #define QS QStringLiteral diff --git a/src/utils/nodes.cpp b/src/utils/nodes.cpp index a683c4ba..a16f5c06 100644 --- a/src/utils/nodes.cpp +++ b/src/utils/nodes.cpp @@ -5,7 +5,7 @@ #include "nodes.h" #include "utils/utils.h" -#include "utils/tails.h" +#include "utils/os/tails.h" #include "appcontext.h" #include "constants.h" #include "utils/WebsocketNotifier.h" diff --git a/src/utils/tails.cpp b/src/utils/os/tails.cpp similarity index 100% rename from src/utils/tails.cpp rename to src/utils/os/tails.cpp diff --git a/src/utils/tails.h b/src/utils/os/tails.h similarity index 100% rename from src/utils/tails.h rename to src/utils/os/tails.h diff --git a/src/utils/whonix.cpp b/src/utils/os/whonix.cpp similarity index 100% rename from src/utils/whonix.cpp rename to src/utils/os/whonix.cpp diff --git a/src/utils/whonix.h b/src/utils/os/whonix.h similarity index 100% rename from src/utils/whonix.h rename to src/utils/os/whonix.h diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index eb352741..78fc8306 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -12,8 +12,8 @@ #include "utils.h" #include "utils/config.h" -#include "utils/tails.h" -#include "utils/whonix.h" +#include "utils/os/tails.h" +#include "utils/os/whonix.h" #include "utils/ColorScheme.h" #include "constants.h" From e49b5667bb9a7b383deed6b249950f155edb1745 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 15:15:19 +0200 Subject: [PATCH 47/62] WindowManager: Hide tray icon on close --- src/WindowManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index f01219c8..1091bb01 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -56,7 +56,10 @@ void WindowManager::close() { for (const auto &window: m_windows) { window->close(); } + torManager()->stop(); + m_tray->hide(); + QApplication::quit(); } From 1ba4600442eb6ec600def72f9472735693ab20d6 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 15:20:10 +0200 Subject: [PATCH 48/62] SendWidget: remove trailing zeroes pay-to-many amount --- src/sendwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sendwidget.cpp b/src/sendwidget.cpp index c2a6f52f..2e1cd29b 100644 --- a/src/sendwidget.cpp +++ b/src/sendwidget.cpp @@ -60,15 +60,15 @@ void SendWidget::currencyComboChanged(int index) { void SendWidget::addressEdited() { QVector outputs = ui->lineAddress->getOutputs(); - bool freezeAmounts = outputs.size() > 0; + bool freezeAmounts = !outputs.empty(); ui->lineAmount->setReadOnly(freezeAmounts); ui->lineAmount->setFrame(!freezeAmounts); ui->btnMax->setDisabled(freezeAmounts); ui->comboCurrencySelection->setDisabled(freezeAmounts); - if (outputs.size() > 0) { - ui->lineAmount->setText(WalletManager::displayAmount(ui->lineAddress->getTotal())); + if (!outputs.empty()) { + ui->lineAmount->setText(WalletManager::displayAmount(ui->lineAddress->getTotal(), false)); ui->comboCurrencySelection->setCurrentIndex(0); } From 4f40e3005664624f551f612b0f42f75dcb0b0e85 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 15:30:19 +0200 Subject: [PATCH 49/62] Save historyWidget viewstate on close --- src/mainwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 04705ae2..5c923ce3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -824,6 +824,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (!this->cleanedUp) { this->cleanedUp = true; + m_historyWidget->resetModel(); + m_updateBytes.stop(); m_txTimer.stop(); From 811421dca93819626b3a6957bb8a23319fd7d477 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 15:33:41 +0200 Subject: [PATCH 50/62] Remove unused resetModel functions --- src/coinswidget.cpp | 4 ---- src/coinswidget.h | 3 --- src/contactswidget.cpp | 5 ----- src/contactswidget.h | 1 - src/receivewidget.cpp | 4 ---- src/receivewidget.h | 1 - 6 files changed, 18 deletions(-) diff --git a/src/coinswidget.cpp b/src/coinswidget.cpp index 74a534b2..60228c13 100644 --- a/src/coinswidget.cpp +++ b/src/coinswidget.cpp @@ -186,10 +186,6 @@ void CoinsWidget::onSweepOutput() { dialog->deleteLater(); } -void CoinsWidget::resetModel() { - ui->coins->setModel(nullptr); -} - void CoinsWidget::copy(copyField field) { CoinsInfo* c = this->currentEntry(); if (!c) return; diff --git a/src/coinswidget.h b/src/coinswidget.h index 9939d4ce..91ffba96 100644 --- a/src/coinswidget.h +++ b/src/coinswidget.h @@ -26,9 +26,6 @@ public: void setModel(CoinsModel * model, Coins * coins); ~CoinsWidget() override; -public slots: - void resetModel(); - private slots: void showHeaderMenu(const QPoint& position); void setShowSpent(bool show); diff --git a/src/contactswidget.cpp b/src/contactswidget.cpp index 147e579d..62b0908f 100644 --- a/src/contactswidget.cpp +++ b/src/contactswidget.cpp @@ -97,11 +97,6 @@ void ContactsWidget::setSearchFilter(const QString &filter) { m_proxyModel->setSearchFilter(filter); } -void ContactsWidget::resetModel() -{ - ui->contacts->setModel(nullptr); -} - void ContactsWidget::showHeaderMenu(const QPoint& position) { m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses()); diff --git a/src/contactswidget.h b/src/contactswidget.h index 280e9828..5c2a819c 100644 --- a/src/contactswidget.h +++ b/src/contactswidget.h @@ -34,7 +34,6 @@ public slots: void deleteContact(); void setShowFullAddresses(bool show); void setSearchFilter(const QString &filter); - void resetModel(); signals: void fillAddress(QString &address); diff --git a/src/receivewidget.cpp b/src/receivewidget.cpp index 73be25df..e5a74e6b 100644 --- a/src/receivewidget.cpp +++ b/src/receivewidget.cpp @@ -127,10 +127,6 @@ void ReceiveWidget::onShowTransactions() { emit showTransactions(address); } -void ReceiveWidget::resetModel() { - ui->addresses->setModel(nullptr); -} - void ReceiveWidget::setShowFullAddresses(bool show) { if (!m_model) return; m_model->setShowFullAddresses(show); diff --git a/src/receivewidget.h b/src/receivewidget.h index 7adc7989..8fa16e88 100644 --- a/src/receivewidget.h +++ b/src/receivewidget.h @@ -38,7 +38,6 @@ public slots: void setShowHiddenAddresses(bool show); void setSearchFilter(const QString &filter); void onShowTransactions(); - void resetModel(); signals: void showTransactions(const QString& address); From c22ce173d6aeda9c1d134d03c0579be8ed25438d Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 19:11:45 +0200 Subject: [PATCH 51/62] Settings: amount precision affects balance --- src/libwalletqt/WalletManager.cpp | 7 ++++++- src/libwalletqt/WalletManager.h | 2 +- src/mainwindow.cpp | 7 ++++--- src/settings.cpp | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp index b91b7cf0..aab885f6 100644 --- a/src/libwalletqt/WalletManager.cpp +++ b/src/libwalletqt/WalletManager.cpp @@ -208,10 +208,15 @@ QString WalletManager::maximumAllowedAmountAsString() const return WalletManager::displayAmount(WalletManager::maximumAllowedAmount()); } -QString WalletManager::displayAmount(quint64 amount, bool trailing_zeroes) +QString WalletManager::displayAmount(quint64 amount, bool trailing_zeroes, int decimals) { auto amountStr = QString::fromStdString(Monero::Wallet::displayAmount(amount)); + if (decimals < 12) { + int i = amountStr.indexOf("."); + amountStr.remove(i+decimals+1, 12); + } + if (!trailing_zeroes) { amountStr.remove(QRegExp("0+$")); amountStr.remove(QRegExp("\\.$")); diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h index 156b497d..b43f83de 100644 --- a/src/libwalletqt/WalletManager.h +++ b/src/libwalletqt/WalletManager.h @@ -108,7 +108,7 @@ public: Q_INVOKABLE QString errorString() const; //! since we can't call static method from QML, move it to this class - Q_INVOKABLE static QString displayAmount(quint64 amount, bool trailing_zeroes = true); + Q_INVOKABLE static QString displayAmount(quint64 amount, bool trailing_zeroes = true, int decimals = 12); Q_INVOKABLE static quint64 amountFromString(const QString &amount); Q_INVOKABLE static quint64 amountFromDouble(double amount); Q_INVOKABLE quint64 maximumAllowedAmount() const; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5c923ce3..af32a627 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -478,19 +478,20 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { bool hide = config()->get(Config::hideBalance).toBool(); int displaySetting = config()->get(Config::balanceDisplay).toInt(); + int decimals = config()->get(Config::amountPrecision).toInt(); QString balance_str = "Balance: "; if (hide) { balance_str += "HIDDEN"; } else if (displaySetting == Config::totalBalance) { - balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(balance, false)); + balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(balance, false, decimals)); } else if (displaySetting == Config::spendable || displaySetting == Config::spendablePlusUnconfirmed) { - balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(spendable, false)); + balance_str += QString("%1 XMR").arg(WalletManager::displayAmount(spendable, false, decimals)); if (displaySetting == Config::spendablePlusUnconfirmed && balance > spendable) { - balance_str += QString(" (+%1 XMR unconfirmed)").arg(WalletManager::displayAmount(balance - spendable, false)); + balance_str += QString(" (+%1 XMR unconfirmed)").arg(WalletManager::displayAmount(balance - spendable, false, decimals)); } } diff --git a/src/settings.cpp b/src/settings.cpp index 845f7a3c..fe3eb2c2 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -148,6 +148,7 @@ void Settings::comboBox_localMoneroFrontendChanged(int pos) { void Settings::comboBox_amountPrecisionChanged(int pos) { config()->set(Config::amountPrecision, pos); + m_ctx->updateBalance(); emit amountPrecisionChanged(pos); } From 4fff4b8556b9557014c98820e95c813d0cddf99a Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 19:23:15 +0200 Subject: [PATCH 52/62] BalanceDialog: change title --- src/dialog/balancedialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialog/balancedialog.ui b/src/dialog/balancedialog.ui index c267fea0..b09ed90f 100644 --- a/src/dialog/balancedialog.ui +++ b/src/dialog/balancedialog.ui @@ -11,7 +11,7 @@ - Balance + Account Balance From 23d1ff2c783c18cbbb02d01ebe5a151805bd64c8 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 19:34:23 +0200 Subject: [PATCH 53/62] TickerWidget: fix balance --- src/widgets/TickerWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/TickerWidget.cpp b/src/widgets/TickerWidget.cpp index 2e11d367..d8458ff4 100644 --- a/src/widgets/TickerWidget.cpp +++ b/src/widgets/TickerWidget.cpp @@ -68,7 +68,7 @@ BalanceTickerWidget::BalanceTickerWidget(QWidget *parent, QSharedPointerwallet->balanceAll() : m_ctx->wallet->balanceAll()) / constants::cdiv; + double balance = (m_totalBalance ? m_ctx->wallet->balanceAll() : m_ctx->wallet->balance()) / constants::cdiv; QString fiatCurrency = config()->get(Config::preferredFiatCurrency).toString(); double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance); if (balanceFiatAmount < 0) From afd29c81fc4d45d5ac3c86f87166183bab8be9fd Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 25 May 2021 20:00:02 +0200 Subject: [PATCH 54/62] Ledger: add link to udev rules --- src/WindowManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index 1091bb01..107f188c 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -263,6 +263,10 @@ void WindowManager::displayWalletErrorMessage(const QString &message) { } if (message.contains("Unable to open device")) { errMsg += "\n\nThe device might be in use by a different application."; +#if defined(Q_OS_LINUX) + errMsg += "\n\nNote: On Linux you may need to follow the instructions in the link below before the device can be opened:\n" + "https://support.ledger.com/hc/en-us/articles/115005165269-Fix-connection-issues"; +#endif } if (message.contains("SW_CLIENT_NOT_SUPPORTED")) { From 4dcd34e4bf17e8649e3464d04466c4f298563ca2 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 00:08:32 +0200 Subject: [PATCH 55/62] AccountSwitcher: make table sortable --- src/dialog/AccountSwitcherDialog.cpp | 14 +++++++++++--- src/dialog/AccountSwitcherDialog.h | 1 + src/dialog/AccountSwitcherDialog.ui | 29 +++++++++++++++++++++++++++- src/model/SubaddressAccountModel.cpp | 12 ++++++++++++ src/model/SubaddressAccountModel.h | 9 +++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/dialog/AccountSwitcherDialog.cpp b/src/dialog/AccountSwitcherDialog.cpp index 33f1ae44..50416572 100644 --- a/src/dialog/AccountSwitcherDialog.cpp +++ b/src/dialog/AccountSwitcherDialog.cpp @@ -6,6 +6,7 @@ #include "libwalletqt/SubaddressAccount.h" #include "utils/Icons.h" +#include "model/ModelUtils.h" #include AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer ctx, QWidget *parent) @@ -13,15 +14,22 @@ AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer ctx, QWi , ui(new Ui::AccountSwitcherDialog) , m_ctx(std::move(ctx)) , m_model(m_ctx->wallet->subaddressAccountModel()) + , m_proxyModel(new SubaddressAccountProxyModel(this)) { ui->setupUi(this); - ui->accounts->setContextMenuPolicy(Qt::CustomContextMenu); - m_ctx->wallet->subaddressAccount()->refresh(); - ui->accounts->setModel(m_ctx->wallet->subaddressAccountModel()); + m_proxyModel->setSourceModel(m_model); + + ui->label_totalBalance->setFont(ModelUtils::getMonospaceFont()); + ui->label_totalBalance->setText(WalletManager::displayAmount(m_ctx->wallet->balanceAll())); + + ui->accounts->setModel(m_proxyModel); + ui->accounts->setContextMenuPolicy(Qt::CustomContextMenu); ui->accounts->setSelectionMode(QAbstractItemView::SingleSelection); ui->accounts->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->accounts->setSortingEnabled(true); + ui->accounts->sortByColumn(SubaddressAccountModel::Column::Number, Qt::AscendingOrder); ui->accounts->hideColumn(SubaddressAccountModel::Column::Address); ui->accounts->hideColumn(SubaddressAccountModel::Column::UnlockedBalance); ui->accounts->setColumnWidth(SubaddressAccountModel::Column::Label, 200); diff --git a/src/dialog/AccountSwitcherDialog.h b/src/dialog/AccountSwitcherDialog.h index 59cc79bb..077b3c1f 100644 --- a/src/dialog/AccountSwitcherDialog.h +++ b/src/dialog/AccountSwitcherDialog.h @@ -36,6 +36,7 @@ private: Ui::AccountSwitcherDialog *ui; QSharedPointer m_ctx; SubaddressAccountModel *m_model; + SubaddressAccountProxyModel *m_proxyModel; }; #endif //FEATHER_ACCOUNTSWITCHERDIALOG_H diff --git a/src/dialog/AccountSwitcherDialog.ui b/src/dialog/AccountSwitcherDialog.ui index d332d8e1..1b203cfd 100644 --- a/src/dialog/AccountSwitcherDialog.ui +++ b/src/dialog/AccountSwitcherDialog.ui @@ -7,7 +7,7 @@ 0 0 521 - 275 + 347 @@ -27,6 +27,33 @@
+ + + + + + Total balance: + + + + + + + + 0 + 0 + + + + TextLabel + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + diff --git a/src/model/SubaddressAccountModel.cpp b/src/model/SubaddressAccountModel.cpp index 53e91094..a15ba838 100644 --- a/src/model/SubaddressAccountModel.cpp +++ b/src/model/SubaddressAccountModel.cpp @@ -5,6 +5,8 @@ #include "SubaddressAccount.h" #include +#include +#include "ModelUtils.h" SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount) : QAbstractTableModel(parent) @@ -50,6 +52,11 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) { result = parseSubaddressAccountRow(row, index, role); } + else if (role == Qt::FontRole) { + if (index.column() == Column::Balance || index.column() == Column::UnlockedBalance) { + result = ModelUtils::getMonospaceFont(); + } + } }); if (!found) { @@ -135,4 +142,9 @@ Qt::ItemFlags SubaddressAccountModel::flags(const QModelIndex &index) const Monero::SubaddressAccountRow* SubaddressAccountModel::entryFromIndex(const QModelIndex &index) const { Q_ASSERT(index.isValid() && index.row() < m_subaddressAccount->count()); return m_subaddressAccount->row(index.row()); +} + +SubaddressAccountProxyModel::SubaddressAccountProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ } \ No newline at end of file diff --git a/src/model/SubaddressAccountModel.h b/src/model/SubaddressAccountModel.h index b49f5bab..1c145580 100644 --- a/src/model/SubaddressAccountModel.h +++ b/src/model/SubaddressAccountModel.h @@ -6,6 +6,7 @@ #include "Subaddress.h" #include +#include class SubaddressAccount; @@ -45,4 +46,12 @@ private: SubaddressAccount *m_subaddressAccount; }; +class SubaddressAccountProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit SubaddressAccountProxyModel(QObject *parent = nullptr); +}; + #endif // SUBADDRESSACCOUNTMODEL_H From 8e663d4a1856b1c0208858d879d96d1275804717 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 00:13:58 +0200 Subject: [PATCH 56/62] TorInfoDialog: clarify text --- src/dialog/torinfodialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialog/torinfodialog.cpp b/src/dialog/torinfodialog.cpp index 1c395a9c..46a0dec2 100644 --- a/src/dialog/torinfodialog.cpp +++ b/src/dialog/torinfodialog.cpp @@ -119,7 +119,7 @@ void TorInfoDialog::initPrivacyLevel() { } if (m_ctx->nodes->connection().isLocal()) { - ui->label_notice->setText("You are connected to a local node. Traffic is not routed over Tor."); + ui->label_notice->setText("You are connected to a local node. Traffic to node is not routed over Tor."); } else if (Utils::isTorsocks()) { ui->label_notice->setText("Feather was started with torsocks, all traffic is routed over Tor"); From bf533ddfaa37207d5b08100391adfbec17960546 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 15:14:53 +0200 Subject: [PATCH 57/62] Calc: configure crypto/fiat symbols --- src/calcwidget.cpp | 82 +++++++++--- src/calcwidget.h | 4 + src/calcwidget.ui | 227 ++++++++++++++------------------ src/dialog/CalcConfigDialog.cpp | 102 ++++++++++++++ src/dialog/CalcConfigDialog.h | 39 ++++++ src/dialog/CalcConfigDialog.ui | 153 +++++++++++++++++++++ src/mainwindow.ui | 35 ++++- src/utils/config.cpp | 3 + src/utils/config.h | 10 ++ src/utils/prices.cpp | 11 +- 10 files changed, 515 insertions(+), 151 deletions(-) create mode 100644 src/dialog/CalcConfigDialog.cpp create mode 100644 src/dialog/CalcConfigDialog.h create mode 100644 src/dialog/CalcConfigDialog.ui diff --git a/src/calcwidget.cpp b/src/calcwidget.cpp index 2190c408..11616a29 100644 --- a/src/calcwidget.cpp +++ b/src/calcwidget.cpp @@ -8,6 +8,7 @@ #include "utils/ColorScheme.h" #include "utils/AppData.h" #include "utils/config.h" +#include "dialog/CalcConfigDialog.h" CalcWidget::CalcWidget(QWidget *parent) : QWidget(parent) @@ -29,14 +30,20 @@ CalcWidget::CalcWidget(QWidget *parent) ui->lineFrom->setValidator(dv); ui->lineTo->setValidator(dv); - connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::initComboBox); - connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::initComboBox); + connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::onPricesReceived); + connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::onPricesReceived); connect(ui->lineFrom, &QLineEdit::textEdited, this, [this]{this->convert(false);}); connect(ui->lineTo, &QLineEdit::textEdited, this, [this]{this->convert(true);}); connect(ui->comboCalcFrom, QOverload::of(&QComboBox::currentIndexChanged), [this]{this->convert(false);}); - connect(ui->comboCalcTo, QOverload::of(&QComboBox::currentIndexChanged), [this]{this->convert(true);}); + connect(ui->comboCalcTo, QOverload::of(&QComboBox::currentIndexChanged), [this]{this->convert(false);}); + + connect(ui->btn_configure, &QPushButton::clicked, this, &CalcWidget::showCalcConfigureDialog); + + QTimer::singleShot(1, [this]{ + this->skinChanged(); + }); } void CalcWidget::convert(bool reverse) { @@ -67,33 +74,76 @@ void CalcWidget::convert(bool reverse) { lineTo->setText(QString::number(result, 'f', precision)); } -void CalcWidget::initComboBox() { +void CalcWidget::onPricesReceived() { if (m_comboBoxInit) return; - QList marketsKeys = appData()->prices.markets.keys(); - QList ratesKeys = appData()->prices.rates.keys(); - if(marketsKeys.count() <= 0 || ratesKeys.count() <= 0) return; + QList cryptoKeys = appData()->prices.markets.keys(); + QList fiatKeys = appData()->prices.rates.keys(); + if (cryptoKeys.empty() || fiatKeys.empty()) + return; - ui->comboCalcFrom->addItems(marketsKeys); - ui->comboCalcFrom->insertSeparator(marketsKeys.count()); - ui->comboCalcFrom->addItems(ratesKeys); - ui->comboCalcFrom->setCurrentIndex(marketsKeys.indexOf("XMR")); + ui->btn_configure->setEnabled(true); + this->initComboBox(); + m_comboBoxInit = true; +} - ui->comboCalcTo->addItems(marketsKeys); - ui->comboCalcTo->insertSeparator(marketsKeys.count()); - ui->comboCalcTo->addItems(ratesKeys); +void CalcWidget::initComboBox() { + QList cryptoKeys = appData()->prices.markets.keys(); + QList fiatKeys = appData()->prices.rates.keys(); + QStringList enabledCrypto = config()->get(Config::cryptoSymbols).toStringList(); + QStringList filteredCryptoKeys; + for (const auto& symbol : cryptoKeys) { + if (enabledCrypto.contains(symbol)) { + filteredCryptoKeys.append(symbol); + } + } + + QStringList enabledFiat = config()->get(Config::fiatSymbols).toStringList(); auto preferredFiat = config()->get(Config::preferredFiatCurrency).toString(); - ui->comboCalcTo->setCurrentText(preferredFiat); + if (!enabledFiat.contains(preferredFiat) && fiatKeys.contains(preferredFiat)) { + enabledFiat.append(preferredFiat); + config()->set(Config::fiatSymbols, enabledFiat); + } + QStringList filteredFiatKeys; + for (const auto &symbol : fiatKeys) { + if (enabledFiat.contains(symbol)) { + filteredFiatKeys.append(symbol); + } + } - this->m_comboBoxInit = true; + this->setupComboBox(ui->comboCalcFrom, filteredCryptoKeys, filteredFiatKeys); + this->setupComboBox(ui->comboCalcTo, filteredCryptoKeys, filteredFiatKeys); + + ui->comboCalcFrom->setCurrentIndex(ui->comboCalcFrom->findText("XMR")); + + if (!preferredFiat.isEmpty()) { + ui->comboCalcTo->setCurrentIndex(ui->comboCalcTo->findText(preferredFiat)); + } else { + ui->comboCalcTo->setCurrentIndex(ui->comboCalcTo->findText("USD")); + } } void CalcWidget::skinChanged() { ui->imageExchange->setMode(ColorScheme::hasDarkBackground(this)); } +void CalcWidget::showCalcConfigureDialog() { + CalcConfigDialog dialog{this}; + + if (dialog.exec() == QDialog::Accepted) { + this->initComboBox(); + } +} + +void CalcWidget::setupComboBox(QComboBox *comboBox, const QStringList &crypto, const QStringList &fiat) { + comboBox->clear(); + comboBox->addItems(crypto); + comboBox->insertSeparator(comboBox->count()); + comboBox->addItems(fiat); +} + CalcWidget::~CalcWidget() { delete ui; } diff --git a/src/calcwidget.h b/src/calcwidget.h index de95604a..f5c4af12 100644 --- a/src/calcwidget.h +++ b/src/calcwidget.h @@ -5,6 +5,7 @@ #define FEATHER_CALCWIDGET_H #include +#include namespace Ui { class CalcWidget; @@ -23,9 +24,12 @@ public slots: private slots: void initComboBox(); + void showCalcConfigureDialog(); + void onPricesReceived(); private: void convert(bool reverse); + void setupComboBox(QComboBox *comboBox, const QStringList &crypto, const QStringList &fiat); Ui::CalcWidget *ui; bool m_comboBoxInit = false; diff --git a/src/calcwidget.ui b/src/calcwidget.ui index 66360aed..3fa1db2b 100644 --- a/src/calcwidget.ui +++ b/src/calcwidget.ui @@ -6,141 +6,22 @@ 0 0 - 737 - 153 + 800 + 132 MainWindow - - - 0 - - - 0 - - - 0 - - - 0 - - - + + + - - - 9 + + + Crypto/fiat and fiat/fiat calculator. - - - - Crypto/fiat and fiat/fiat calculator. - - - - - - - Qt::Horizontal - - - - - - - - - 18 - - - - - 0 - - - 0 - - - - - - 0 - 0 - - - - true - - - From... - - - - - - - - - - - - exchange image - - - - - - - 0 - - - - - - 0 - 0 - - - - false - - - To... - - - - - - - - - - - - - - - - Exchange rates are updated every 2 minutes. - - - - - - - Qt::Vertical - - - - 20 - 170 - - - - - + @@ -155,8 +36,98 @@ + + + + Configure + + + + + + + Qt::Horizontal + + + + + + + 18 + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + From... + + + + + + + + + + + + exchange image + + + + + + + 0 + + + + + + 0 + 0 + + + + false + + + To... + + + + + + + + + + + + + + Exchange rates are updated every 2 minutes. + + + diff --git a/src/dialog/CalcConfigDialog.cpp b/src/dialog/CalcConfigDialog.cpp new file mode 100644 index 00000000..319d376b --- /dev/null +++ b/src/dialog/CalcConfigDialog.cpp @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include "CalcConfigDialog.h" +#include "ui_CalcConfigDialog.h" +#include "AppData.h" +#include "utils/config.h" + +CalcConfigDialog::CalcConfigDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::CalcConfigDialog) +{ + ui->setupUi(this); + + this->fillListWidgets(); + + connect(ui->btn_selectAll, &QPushButton::clicked, this, &CalcConfigDialog::selectAll); + connect(ui->btn_deselectAll, &QPushButton::clicked, this, &CalcConfigDialog::deselectAll); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]{ + config()->set(Config::fiatSymbols, this->checkedFiat()); + config()->set(Config::cryptoSymbols, this->checkedCrypto()); + this->accept(); + }); + + this->adjustSize(); +} + +QStringList CalcConfigDialog::checkedFiat() { + return this->getChecked(ui->list_fiat); +} + +QStringList CalcConfigDialog::checkedCrypto() { + return this->getChecked(ui->list_crypto); +} + +void CalcConfigDialog::selectAll() { + this->setCheckState(this->getVisibleListWidget(), Qt::Checked); +} + +void CalcConfigDialog::deselectAll() { + this->setCheckState(this->getVisibleListWidget(), Qt::Unchecked); +} + +void CalcConfigDialog::setCheckState(QListWidget *widget, Qt::CheckState checkState) { + QListWidgetItem *item; + for (int i=0; i < widget->count(); i++) { + item = widget->item(i); + item->setCheckState(checkState); + } +} + +QStringList CalcConfigDialog::getChecked(QListWidget *widget) { + QStringList checked; + QListWidgetItem *item; + for (int i=0; i < widget->count(); i++) { + item = widget->item(i); + if (item->checkState() == Qt::Checked) { + checked.append(item->text()); + } + } + return checked; +} + +QListWidget* CalcConfigDialog::getVisibleListWidget() { + if (ui->tabWidget->currentIndex() == 0) { + return ui->list_fiat; + } else { + return ui->list_crypto; + } +} + +void CalcConfigDialog::fillListWidgets() { + QStringList cryptoCurrencies = appData()->prices.markets.keys(); + QStringList fiatCurrencies = appData()->prices.rates.keys(); + + QStringList checkedCryptoCurrencies = config()->get(Config::cryptoSymbols).toStringList(); + QStringList checkedFiatCurrencies = config()->get(Config::fiatSymbols).toStringList(); + + ui->list_crypto->addItems(cryptoCurrencies); + ui->list_fiat->addItems(fiatCurrencies); + + auto setChecked = [](QListWidget *widget, const QStringList &checked){ + QListWidgetItem *item; + for (int i=0; i < widget->count(); i++) { + item = widget->item(i); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + if (checked.contains(item->text())) { + item->setCheckState(Qt::Checked); + } else { + item->setCheckState(Qt::Unchecked); + } + } + }; + + setChecked(ui->list_crypto, checkedCryptoCurrencies); + setChecked(ui->list_fiat, checkedFiatCurrencies); +} + +CalcConfigDialog::~CalcConfigDialog() { + delete ui; +} diff --git a/src/dialog/CalcConfigDialog.h b/src/dialog/CalcConfigDialog.h new file mode 100644 index 00000000..aceed432 --- /dev/null +++ b/src/dialog/CalcConfigDialog.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef FEATHER_CALCCONFIGDIALOG_H +#define FEATHER_CALCCONFIGDIALOG_H + +#include +#include + +namespace Ui { + class CalcConfigDialog; +} + +class CalcConfigDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CalcConfigDialog(QWidget *parent = nullptr); + ~CalcConfigDialog() override; + + QStringList checkedFiat(); + QStringList checkedCrypto(); + +private slots: + void selectAll(); + void deselectAll(); + +private: + void setCheckState(QListWidget *widget, Qt::CheckState checkState); + QStringList getChecked(QListWidget *widget); + void fillListWidgets(); + QListWidget* getVisibleListWidget(); + + Ui::CalcConfigDialog *ui; +}; + + +#endif //FEATHER_CALCCONFIGDIALOG_H diff --git a/src/dialog/CalcConfigDialog.ui b/src/dialog/CalcConfigDialog.ui new file mode 100644 index 00000000..d88daeeb --- /dev/null +++ b/src/dialog/CalcConfigDialog.ui @@ -0,0 +1,153 @@ + + + CalcConfigDialog + + + + 0 + 0 + 509 + 574 + + + + Calc config + + + + + + 0 + + + + Fiat + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Crypto + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + Qt::Vertical + + + + + + + + + Select all + + + + + + + Deselect all + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + CalcConfigDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CalcConfigDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 3358f0f3..577576a8 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -249,8 +249,41 @@ Calc + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 0 + 20 + + + + - + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 9af405c7..2e4baf96 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -68,6 +68,9 @@ static const QHash configStrings = { {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, {Config::localMoneroFrontend, {QS("localMoneroFrontend"), "https://localmonero.co"}}, + {Config::fiatSymbols, {QS("fiatSymbols"), QStringList{"USD", "EUR", "GBP", "CAD", "AUD", "RUB"}}}, + {Config::cryptoSymbols, {QS("cryptoSymbols"), QStringList{"BTC", "ETH", "LTC", "XMR", "ZEC"}}}, + // Tor {Config::torPrivacyLevel, {QS("torPrivacyLevel"), 1}}, {Config::socks5Host, {QS("socks5Host"), "127.0.0.1"}}, diff --git a/src/utils/config.h b/src/utils/config.h index 5a0fb4b0..96fdb345 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -20,6 +20,7 @@ public: enum ConfigKey { + // General firstRun, warnOnStagenet, warnOnTestnet, @@ -33,14 +34,17 @@ public: windowState, GUI_HistoryViewState, + // Wallets walletDirectory, // Directory where wallet files are stored autoOpenWalletPath, recentlyOpenedWallets, + // Nodes nodes, nodeSource, useOnionNodes, + // Tabs showTabHome, showTabCoins, showTabExchange, @@ -48,9 +52,11 @@ public: showTabXMRig, showSearchbar, + // Mining xmrigPath, xmrigPool, + // Settings preferredFiatCurrency, skin, amountPrecision, @@ -66,6 +72,10 @@ public: redditFrontend, localMoneroFrontend, + fiatSymbols, + cryptoSymbols, + + // Tor torPrivacyLevel, socks5Host, socks5Port, diff --git a/src/utils/prices.cpp b/src/utils/prices.cpp index ca9bd817..ea1d03c5 100644 --- a/src/utils/prices.cpp +++ b/src/utils/prices.cpp @@ -3,9 +3,9 @@ #include "utils/prices.h" -Prices::Prices(QObject *parent) : QObject(parent) { - this->rates = QMap(); - this->markets = QMap(); +Prices::Prices(QObject *parent) + : QObject(parent) +{ } void Prices::cryptoPricesReceived(const QJsonArray &data) { @@ -30,9 +30,8 @@ void Prices::cryptoPricesReceived(const QJsonArray &data) { void Prices::fiatPricesReceived(const QJsonObject &data) { QJsonObject ratesData = data.value("rates").toObject(); - for (const auto ¤cy : ratesData) { - QString currencyStr = currency.toString(); - this->rates.insert(currencyStr, ratesData.value(currencyStr).toDouble()); + for (const auto ¤cy : ratesData.keys()) { + this->rates.insert(currency, ratesData.value(currency).toDouble()); } emit fiatPricesUpdated(); } From 6ad1e76b31eaf733c0bfa88a529530a3e7a31219 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 15:16:20 +0200 Subject: [PATCH 58/62] LocalMonero: fix icon color dark theme --- src/widgets/LocalMoneroWidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/LocalMoneroWidget.cpp b/src/widgets/LocalMoneroWidget.cpp index 54fe3678..db3c31b5 100644 --- a/src/widgets/LocalMoneroWidget.cpp +++ b/src/widgets/LocalMoneroWidget.cpp @@ -50,7 +50,9 @@ LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, QSharedPointer ui->frame_loadMore->hide(); - this->skinChanged(); + QTimer::singleShot(1, [this]{ + this->skinChanged(); + }); } void LocalMoneroWidget::skinChanged() { From e1f305e44cd1677e38644c8ece793bade7330478 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 15:47:48 +0200 Subject: [PATCH 59/62] MainWindow: minor layout fix --- src/mainwindow.ui | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 577576a8..fc0c81d6 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -248,31 +248,15 @@ Calc - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 0 - 20 - - - - - + + - + Qt::Vertical From 01df614daac9421f09458c2e82794aa5f48dd364 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 15:48:53 +0200 Subject: [PATCH 60/62] Change Tor string --- src/dialog/torinfodialog.ui | 2 +- src/mainwindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dialog/torinfodialog.ui b/src/dialog/torinfodialog.ui index a71c1093..46b41ec4 100644 --- a/src/dialog/torinfodialog.ui +++ b/src/dialog/torinfodialog.ui @@ -11,7 +11,7 @@ - Tor information + Tor settings diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index af32a627..f81df981 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -145,7 +145,7 @@ void MainWindow::initStatusBar() { connect(m_statusBtnSeed, &StatusBarButton::clicked, this, &MainWindow::showSeedDialog); this->statusBar()->addPermanentWidget(m_statusBtnSeed); - m_statusBtnTor = new StatusBarButton(icons()->icon("tor_logo_disabled.png"), "Tor", this); + m_statusBtnTor = new StatusBarButton(icons()->icon("tor_logo_disabled.png"), "Tor settings", this); connect(m_statusBtnTor, &StatusBarButton::clicked, this, &MainWindow::menuTorClicked); this->statusBar()->addPermanentWidget(m_statusBtnTor); From 8ec65d8f076d761c57fce2236ef3730ebc796034 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 21:41:14 +0200 Subject: [PATCH 61/62] TorInfoDialog: allow setting initSyncThreshold --- src/dialog/torinfodialog.cpp | 19 +++++++++++++++++++ src/dialog/torinfodialog.h | 1 + src/dialog/torinfodialog.ui | 13 +++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/dialog/torinfodialog.cpp b/src/dialog/torinfodialog.cpp index 46a0dec2..59ebbf56 100644 --- a/src/dialog/torinfodialog.cpp +++ b/src/dialog/torinfodialog.cpp @@ -7,9 +7,11 @@ #include #include #include +#include #include "utils/TorManager.h" #include "utils/os/tails.h" +#include "utils/Icons.h" TorInfoDialog::TorInfoDialog(QSharedPointer ctx, QWidget *parent) : QDialog(parent) @@ -46,6 +48,9 @@ TorInfoDialog::TorInfoDialog(QSharedPointer ctx, QWidget *parent) ui->label_changes->hide(); + ui->btn_configureInitSync->setIcon(icons()->icon("preferences.svg")); + connect(ui->btn_configureInitSync, &QPushButton::clicked, this, &TorInfoDialog::onShowInitSyncConfigDialog); + #ifndef HAS_TOR_BIN ui->check_useLocalTor->setChecked(true); ui->check_useLocalTor->setEnabled(false); @@ -146,6 +151,20 @@ void TorInfoDialog::onStopTor() { torManager()->stop(); } +void TorInfoDialog::onShowInitSyncConfigDialog() { + + int threshold = config()->get(Config::initSyncThreshold).toInt(); + + bool ok; + int newThreshold = QInputDialog::getInt(this, "Sync threshold", + "Synchronize over clearnet if wallet is behind more than x blocks: ", + threshold, 0, 10000, 10, &ok); + + if (ok) { + config()->set(Config::initSyncThreshold, newThreshold); + } +} + TorInfoDialog::~TorInfoDialog() { delete ui; } diff --git a/src/dialog/torinfodialog.h b/src/dialog/torinfodialog.h index 1ca07448..3b3847ed 100644 --- a/src/dialog/torinfodialog.h +++ b/src/dialog/torinfodialog.h @@ -29,6 +29,7 @@ private slots: void onApplySettings(); void onSettingsChanged(); void onStopTor(); + void onShowInitSyncConfigDialog(); signals: void torSettingsChanged(); diff --git a/src/dialog/torinfodialog.ui b/src/dialog/torinfodialog.ui index 46b41ec4..ffce23df 100644 --- a/src/dialog/torinfodialog.ui +++ b/src/dialog/torinfodialog.ui @@ -157,6 +157,19 @@ + + + + + 0 + 0 + + + + + + + From 357a46e7f7d636fdbc676f6253d59b96fb29c664 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Wed, 26 May 2021 21:45:48 +0200 Subject: [PATCH 62/62] Nodes: fix missing function in header --- src/utils/nodes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/nodes.h b/src/utils/nodes.h index 66b79f88..ce60584c 100644 --- a/src/utils/nodes.h +++ b/src/utils/nodes.h @@ -36,6 +36,7 @@ public: private: void ensureStructure(QJsonObject &obj, NetworkType::Type networkType); + QJsonObject getConfigData(); }; struct FeatherNode {