From f43949a346f6b676ce3124a153697b2ba1eb6929 Mon Sep 17 00:00:00 2001 From: tobtoht Date: Tue, 18 May 2021 17:59:18 +0200 Subject: [PATCH] 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 2a77d0d..bc3e7ad 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 0000000..fca665b --- /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 0000000..3d99c6d --- /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 a047a87..1e494d8 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 422df1c..75588a4 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 35435b7..646457d 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 48e8574..b4ce187 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 f4ccbfc..3a363e7 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 6f236dc..a0e7a63 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 38271cd..dc04a9a 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 78d80a4..74a534b 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 38c1777..9939d4c 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 fd9b67e..76c79e1 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 e7d9c01..f031c57 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 cf9a3a5..17395ff 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 811ddbc..ef7b3e0 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 1ad53ce..d010248 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 d02fbb6..3f1d2d7 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 54a5f67..e2ba3c7 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 3bb1173..7ab90d1 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 a9a5e34..0f32c7d 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 28544df..7fcab2e 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 44c1c5e..80a5391 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 7353349..5618481 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 e0fe0c0..84df75d 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 7f7d0f7..a576929 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 060de72..a204cea 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 49edce0..fa9679a 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 d7f119d..e6118c8 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 63f46a2..123dcae 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 52793e4..b1e211b 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 ded389f..06b2481 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 4852876..0c9ab78 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 60b5b86..1ca0744 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 048b3fb..433acd1 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 575a181..6cb2960 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 98fbc8d..2f27c55 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 bd68797..e59a766 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 47d959a..dbf9f23 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 0fdd95a..1057df8 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 6cffd96..f3843b8 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 4fdcb70..6b6992c 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 3a551ff..8aead69 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 ccc9c2e..50caa38 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 991cce7..57ae5c4 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 9697475..3764732 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 c74f8bb..2241682 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 197d053..82d2cf8 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 2079519..6edffa2 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 84311d9..94dcc25 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 7622014..aa34a53 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 0f4e58e..1a02d45 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 b73f8ed..a62ae80 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 7c1e0e4..0850ded 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 a32e2ad..e59e4ae 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 0b38545..5d503c8 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 83c4471..1e7d525 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 db0d799..2991d09 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 f40b881..0f5373e 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 da6285a..308e8d5 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 7c6eb3b..d0c30b4 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 94b4163..f4666db 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 4be0ae2..2843318 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 e02c3b0..10c0ba6 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 8ae4292..4b23d76 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 252417b..398fd82 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 805e652..c9e098d 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 1d509a6..dff4d5d 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 3fa17c5..9609603 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 883a871..ee0e732 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 9126897..d810328 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 4c78d10..495ecc7 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 4c01edd..efd773f 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 76b6e45..8646262 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 a70881d..8d38cfd 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 5ca7677..60706a9 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 6d0d9c4..f9f937f 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 e8565c0..6670f7e 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 1bace38..1fce1df 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 d082f93..94b857c 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 be987f4..e7fa10d 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 b0ecb2c..6ec42e8 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 9fa98ca..621835d 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 74386a1..6c50ec9 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 77f53a9..5a4a98d 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 b38efb8..cadd801 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 03e0a41..6bdb48f 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 d20a6b9..689bd29 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 2ca886b..da8c289 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 49e1957..ba20662 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 f6d39ec..b359c88 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 7c2aafe..4e68bb9 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 cade2ee..e3649e4 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 48056ab..5447f07 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 cb76f27..34f1a6f 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 5342b47..3ed45a1 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 f4b6c93..11366c4 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 263ae1f..2ba604d 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 12e00a0..bf28d06 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 4ab90b3..6230a1e 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 cfde928..4171ae4 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 3f9c2ba..36e4f66 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 364213f..390a317 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 3be83b9..9aeb0fa 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 a7d4421..f912856 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 9b79283..f2d8971 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 241c8c9..5030208 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 dcb4f8d..5ed406d 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 78198c5..6b55157 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 19d0178..6161f71 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