Allow opening multiple windows

This commit is contained in:
tobtoht 2021-05-18 17:59:18 +02:00
parent cc01924858
commit f43949a346
No known key found for this signature in database
GPG key ID: 1CADD27F41F45C3C
110 changed files with 1839 additions and 1903 deletions

View file

@ -9,15 +9,17 @@ set(VERSION_MINOR "1")
set(VERSION_REVISION "0") set(VERSION_REVISION "0")
set(VERSION "beta-6") set(VERSION "beta-6")
option(STATIC "Link libraries statically, requires static Qt")
option(FETCH_DEPS "Download dependencies if they are not found" ON) option(FETCH_DEPS "Download dependencies if they are not found" ON)
option(LOCALMONERO "Include LocalMonero module" ON) option(LOCALMONERO "Include LocalMonero module" ON)
option(XMRIG "Include XMRig module" ON) option(XMRIG "Include XMRig module" ON)
option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF) option(TOR_BIN "Path to Tor binary to embed inside Feather" OFF)
option(CHECK_UPDATES "Enable checking for application updates" 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(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
option(DONATE_BEG "Prompt donation window every once in a while" ON) option(DONATE_BEG "Prompt donation window every once in a while" ON)
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
include(CheckCCompilerFlag) include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@ -33,7 +35,7 @@ endif()
set(MONERO_HEAD "36fb05da3394505f8033ceb8806b28909617696f") set(MONERO_HEAD "36fb05da3394505f8033ceb8806b28909617696f")
set(BUILD_GUI_DEPS ON) set(BUILD_GUI_DEPS ON)
set(ARCH "x86-64") set(ARCH "x86-64" CACHE STRING "Target architecture")
set(BUILD_64 ON) set(BUILD_64 ON)
set(INSTALL_VENDORED_LIBUNBOUND ${STATIC}) set(INSTALL_VENDORED_LIBUNBOUND ${STATIC})
set(USE_SINGLE_BUILDDIR ON) set(USE_SINGLE_BUILDDIR ON)

444
src/WindowManager.cpp Normal file
View file

@ -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 <QMessageBox>
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);
}

79
src/WindowManager.h Normal file
View file

@ -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 <QObject>
#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<MainWindow*> m_windows;
WalletManager *m_walletManager;
WalletWizard *m_wizard = nullptr;
SplashDialog *m_splashDialog = nullptr;
QSystemTrayIcon *m_tray;
QMap<QString, QString> m_skins;
bool m_openWalletTriedOnce = false;
bool m_openingWallet = false;
};
#endif //FEATHER_WINDOWMANAGER_H

View file

@ -60,21 +60,6 @@ void LocalMoneroApi::onResponse(QNetworkReply *reply, LocalMoneroApi::Endpoint e
const QString err = reply->errorString(); const QString err = reply->errorString();
QByteArray data = reply->readAll(); 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(); reply->deleteLater();
QJsonObject obj; QJsonObject obj;

View file

@ -5,7 +5,7 @@
#include <QMessageBox> #include <QMessageBox>
#include "appcontext.h" #include "appcontext.h"
#include "globals.h" #include "constants.h"
// libwalletqt // libwalletqt
#include "libwalletqt/TransactionHistory.h" #include "libwalletqt/TransactionHistory.h"
@ -17,44 +17,32 @@
#include "utils/WebsocketClient.h" #include "utils/WebsocketClient.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
WalletKeysFilesModel *AppContext::wallets = nullptr; // This class serves as a business logic layer between MainWindow and libwalletqt.
QMap<QString, QString> AppContext::txCache; // 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) { AppContext::AppContext(Wallet *wallet)
this->cmdargs = cmdargs; : 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(); connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError);
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);
// Store the wallet every 2 minutes // Store the wallet every 2 minutes
m_storeTimer.start(2 * 60 * 1000); m_storeTimer.start(2 * 60 * 1000);
@ -62,71 +50,26 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
this->storeWallet(); this->storeWallet();
}); });
this->walletManager = WalletManager::instance(); this->updateBalance();
QString logPath = QString("%1/daemon.log").arg(configDir);
Monero::Utils::onStartup();
Monero::Wallet::init("", "feather", logPath.toStdString(), true);
bool logLevelFromEnv; // force trigger preferredFiat signal for history model
int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv); this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
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();
} }
void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) { void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
// tx cancelled by user // tx cancelled by user
double amount = tx->amount() / globals::cdiv; double amount = tx->amount() / constants::cdiv;
emit createTransactionCancelled(address, amount); emit createTransactionCancelled(address, amount);
this->currentWallet->disposeTransaction(tx); this->wallet->disposeTransaction(tx);
} }
void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) { 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) { if (churn) {
address = this->currentWallet->address(0, 0); // primary address address = this->wallet->address(0, 0); // primary address
} }
qCritical() << "Creating transaction"; qCritical() << "Creating transaction";
this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority); this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
emit initiateTransaction(); emit initiateTransaction();
} }
@ -135,17 +78,12 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
// tx creation // tx creation
this->tmpTxDescription = description; this->tmpTxDescription = description;
if(this->currentWallet == nullptr) {
emit createTransactionError("Cannot create transaction; no wallet loaded");
return;
}
if (!all && amount == 0) { if (!all && amount == 0) {
emit createTransactionError("Cannot send nothing"); emit createTransactionError("Cannot send nothing");
return; return;
} }
auto unlocked_balance = this->currentWallet->unlockedBalance(); auto unlocked_balance = this->wallet->unlockedBalance();
if(!all && amount > unlocked_balance) { if(!all && amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend"); emit createTransactionError("Not enough money to spend");
return; return;
@ -154,11 +92,11 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
return; return;
} }
qDebug() << "creating tx"; qDebug() << "Creating tx";
if (all) if (all)
this->currentWallet->createTransactionAllAsync(address, "", globals::mixin, this->tx_priority); this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority);
else else
this->currentWallet->createTransactionAsync(address, "", amount, globals::mixin, this->tx_priority); this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority);
emit initiateTransaction(); emit initiateTransaction();
} }
@ -166,23 +104,18 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) { void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) {
this->tmpTxDescription = description; this->tmpTxDescription = description;
if (this->currentWallet == nullptr) {
emit createTransactionError("Cannot create transaction; no wallet loaded");
return;
}
quint64 total_amount = 0; quint64 total_amount = 0;
for (auto &amount : amounts) { for (auto &amount : amounts) {
total_amount += amount; total_amount += amount;
} }
auto unlocked_balance = this->currentWallet->unlockedBalance(); auto unlocked_balance = this->wallet->unlockedBalance();
if (total_amount > unlocked_balance) { if (total_amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend"); emit createTransactionError("Not enough money to spend");
} }
qDebug() << "Creating tx"; qDebug() << "Creating tx";
this->currentWallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority); this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
emit initiateTransaction(); emit initiateTransaction();
} }
@ -192,68 +125,15 @@ void AppContext::onCreateTransactionError(const QString &msg) {
emit endTransaction(); 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) { void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
if(this->currentWallet) { auto *model = this->wallet->transactionHistoryModel();
auto *model = this->currentWallet->transactionHistoryModel();
if (model != nullptr) { if (model != nullptr) {
model->preferredFiatSymbol = symbol; model->preferredFiatSymbol = symbol;
} }
} }
}
void AppContext::onAmountPrecisionChanged(int precision) { void AppContext::onAmountPrecisionChanged(int precision) {
if (!this->currentWallet) return; auto *model = this->wallet->transactionHistoryModel();
auto *model = this->currentWallet->transactionHistoryModel();
if (!model) return; if (!model) return;
model->amountPrecision = precision; model->amountPrecision = precision;
} }
@ -265,12 +145,12 @@ void AppContext::commitTransaction(PendingTransaction *tx) {
this->onMultiBroadcast(tx); this->onMultiBroadcast(tx);
} }
this->currentWallet->commitTransactionAsync(tx); this->wallet->commitTransactionAsync(tx);
} }
void AppContext::onMultiBroadcast(PendingTransaction *tx) { void AppContext::onMultiBroadcast(PendingTransaction *tx) {
int count = tx->txCount(); quint64 count = tx->txCount();
for (int i = 0; i < count; i++) { for (quint64 i = 0; i < count; i++) {
QString txData = tx->signedTxToHex(i); QString txData = tx->signedTxToHex(i);
for (const auto& node: this->nodes->websocketNodes()) { for (const auto& node: this->nodes->websocketNodes()) {
@ -294,205 +174,37 @@ void AppContext::onDeviceError(const QString &message) {
} }
void AppContext::onTorSettingsChanged() { void AppContext::onTorSettingsChanged() {
if (WhonixOS::detect() || Utils::isTorsocks()) { if (Utils::isTorsocks()) {
return; 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(); this->nodes->connectToNode();
auto privacyLevel = config()->get(Config::torPrivacyLevel).toInt(); auto privacyLevel = config()->get(Config::torPrivacyLevel).toInt();
qDebug() << "Changed privacyLevel to " << privacyLevel; 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){ void AppContext::onSetRestoreHeight(quint64 height){
auto seed = this->currentWallet->getCacheAttribute("feather.seed"); auto seed = this->wallet->getCacheAttribute("feather.seed");
if(!seed.isEmpty()) { if(!seed.isEmpty()) {
const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded."; const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded.";
emit setRestoreHeightError(msg); emit setRestoreHeightError(msg);
return; return;
} }
this->currentWallet->setWalletCreationHeight(height); this->wallet->setWalletCreationHeight(height);
this->currentWallet->setPassword(this->currentWallet->getPassword()); // trigger .keys write this->wallet->setPassword(this->wallet->getPassword()); // trigger .keys write
// nuke wallet cache // nuke wallet cache
const auto fn = this->currentWallet->path(); const auto fn = this->wallet->cachePath();
this->walletManager->clearWalletCache(fn); WalletManager::clearWalletCache(fn);
emit customRestoreHeightSet(height); emit customRestoreHeightSet(height);
} }
void AppContext::onOpenAliasResolve(const QString &openAlias) { void AppContext::onOpenAliasResolve(const QString &openAlias) {
// @TODO: calling this freezes for about 1-2 seconds :/ // @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("|"); const auto spl = result.split("|");
auto msg = QString(""); auto msg = QString("");
if(spl.count() != 2) { if(spl.count() != 2) {
@ -503,7 +215,7 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
const auto &status = spl.at(0); const auto &status = spl.at(0);
const auto &address = spl.at(1); 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(status == "false"){
if(valid){ if(valid){
msg = "Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"; 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); emit openAliasResolveError(msg);
} }
void AppContext::donateBeg() { // ########################################## LIBWALLET QT SIGNALS ####################################################
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 #########################################################
void AppContext::onMoneySpent(const QString &txId, quint64 amount) { 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); qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
} }
void AppContext::onMoneyReceived(const QString &txId, quint64 amount) { void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
// Incoming tx included in a block. // 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); qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
} }
void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) { void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
// Incoming transaction in pool // 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); 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); auto notify = QString("%1 XMR (pending)").arg(amount_num);
Utils::desktopNotify("Payment received", notify, 5000); Utils::desktopNotify("Payment received", notify, 5000);
} }
} }
void AppContext::onWalletUpdate() { void AppContext::onWalletUpdate() {
if (this->currentWallet->synchronized()) { if (this->wallet->synchronized()) {
this->refreshModels(); this->refreshModels();
this->storeWallet(); this->storeWallet();
} }
@ -595,7 +289,7 @@ void AppContext::onWalletRefreshed(bool success, const QString &message) {
this->refreshed = true; this->refreshed = true;
emit walletRefreshed(); emit walletRefreshed();
// store wallet immediately upon finishing synchronization // store wallet immediately upon finishing synchronization
this->currentWallet->store(); this->wallet->store();
} }
qDebug() << "Wallet refresh status: " << success; 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 // Called whenever a new block gets scanned by the wallet
this->syncStatusUpdated(blockheight, targetHeight); this->syncStatusUpdated(blockheight, targetHeight);
if (!this->currentWallet) return; if (this->wallet->isSynchronized()) {
if (this->currentWallet->isSynchronized()) { this->wallet->coins()->refreshUnlocked();
this->currentWallet->coins()->refreshUnlocked(); this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
// Todo: only refresh tx confirmations // 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) { void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) {
qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight; qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight;
if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) if (this->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
return; return;
if (daemonHeight < targetHeight) { if (daemonHeight < targetHeight) {
@ -631,7 +324,7 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QStr
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
for (auto &addr : address) { for (auto &addr : address) {
if (addr == globals::donationAddress) { if (addr == constants::donationAddress) {
this->donationSending = true; this->donationSending = true;
} }
} }
@ -646,16 +339,16 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QStr
void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid){
if (status) { if (status) {
for (const auto &entry: txid) { for (const auto &entry: txid) {
this->currentWallet->setUserNote(entry, this->tmpTxDescription); this->wallet->setUserNote(entry, this->tmpTxDescription);
} }
this->tmpTxDescription = ""; this->tmpTxDescription = "";
} }
// Store wallet immediately so we don't risk losing tx key if wallet crashes // 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->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
this->updateBalance(); this->updateBalance();
@ -670,19 +363,16 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con
void AppContext::storeWallet() { void AppContext::storeWallet() {
// Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet // 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; return;
qDebug() << "Storing wallet"; qDebug() << "Storing wallet";
this->currentWallet->store(); this->wallet->store();
} }
void AppContext::updateBalance() { void AppContext::updateBalance() {
if (!this->currentWallet) quint64 balance = this->wallet->balance();
return; quint64 spendable = this->wallet->unlockedBalance();
quint64 balance = this->currentWallet->balance();
quint64 spendable = this->currentWallet->unlockedBalance();
emit balanceUpdated(balance, spendable); emit balanceUpdated(balance, spendable);
} }
@ -698,11 +388,8 @@ void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
} }
void AppContext::refreshModels() { void AppContext::refreshModels() {
if (!this->currentWallet) this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
return; this->wallet->subaddress()->refresh(this->wallet->currentSubaddressAccount());
this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->subaddress()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
// Todo: set timer for refreshes // Todo: set timer for refreshes
} }

View file

@ -7,22 +7,15 @@
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
#include "utils/tails.h"
#include "utils/whonix.h" #include "utils/whonix.h"
#include "utils/prices.h"
#include "utils/networking.h" #include "utils/networking.h"
#include "utils/TorManager.h"
#include "utils/wsclient.h" #include "utils/wsclient.h"
#include "utils/txfiathistory.h"
#include "utils/FeatherSeed.h" #include "utils/FeatherSeed.h"
#include "utils/daemonrpc.h" #include "utils/daemonrpc.h"
#include "widgets/RedditPost.h"
#include "widgets/CCSEntry.h"
#include "utils/RestoreHeightLookup.h" #include "utils/RestoreHeightLookup.h"
#include "utils/nodes.h" #include "utils/nodes.h"
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#include "utils/keysfiles.h"
#include "PendingTransaction.h" #include "PendingTransaction.h"
class AppContext : public QObject class AppContext : public QObject
@ -30,55 +23,30 @@ class AppContext : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit AppContext(QCommandLineParser *cmdargs); explicit AppContext(Wallet *wallet);
~AppContext() override;
QCommandLineParser *cmdargs; QScopedPointer<Wallet> wallet;
Nodes *nodes;
bool isTails = false;
bool isWhonix = false;
bool donationSending = false; bool donationSending = false;
QString defaultWalletDir; QString tmpTxDescription; // TODO: remove the need for this var
QString tmpTxDescription;
QString walletPath;
QString walletPassword = "";
NetworkType::Type networkType; NetworkType::Type networkType;
PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low; PendingTransaction::Priority tx_priority = PendingTransaction::Priority::Priority_Low;
QString seedLanguage = "English"; // 14 word `monero-seed` only has English QMap<QString, QString> txCache;
Nodes *nodes; // TODO: move this to mainwindow (?)
static WalletKeysFilesModel *wallets;
static QMap<QString, QString> txCache;
static void createConfigDirectory(const QString &dir);
// libwalletqt // libwalletqt
bool refreshed = false; 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 commitTransaction(PendingTransaction *tx);
void syncStatusUpdated(quint64 height, quint64 target); void syncStatusUpdated(quint64 height, quint64 target);
void updateBalance(); void updateBalance();
void initTor();
void initWS();
void donateBeg();
void refreshModels(); void refreshModels();
// Closes the currently opened wallet
void closeWallet(bool emitClosedSignal = true, bool storeWallet = false);
void storeWallet(); void storeWallet();
public slots: 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 onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all);
void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description); void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address); void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
@ -90,39 +58,28 @@ public slots:
void onAmountPrecisionChanged(int precision); void onAmountPrecisionChanged(int precision);
void onMultiBroadcast(PendingTransaction *tx); void onMultiBroadcast(PendingTransaction *tx);
void onDeviceButtonRequest(quint64 code); void onDeviceButtonRequest(quint64 code);
void onTorSettingsChanged();
void onInitialNetworkConfigured();
void onDeviceError(const QString &message); void onDeviceError(const QString &message);
void onTorSettingsChanged(); // should not be here
private slots: private slots:
void onMoneySpent(const QString &txId, quint64 amount); void onMoneySpent(const QString &txId, quint64 amount);
void onMoneyReceived(const QString &txId, quint64 amount); void onMoneyReceived(const QString &txId, quint64 amount);
void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount); void onUnconfirmedMoneyReceived(const QString &txId, quint64 amount);
void onWalletUpdate(); void onWalletUpdate();
void onWalletRefreshed(bool success, const QString &message); void onWalletRefreshed(bool success, const QString &message);
void onWalletOpened(Wallet *wallet);
void onWalletNewBlock(quint64 blockheight, quint64 targetHeight); void onWalletNewBlock(quint64 blockheight, quint64 targetHeight);
void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight); void onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight);
void onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address); void onTransactionCreated(PendingTransaction *tx, const QVector<QString> &address);
void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); void onTransactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
signals: 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 balanceUpdated(quint64 balance, quint64 spendable);
void blockchainSync(int height, int target); void blockchainSync(int height, int target);
void refreshSync(int height, int target); void refreshSync(int height, int target);
void synchronized(); void synchronized();
void walletRefreshed(); 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 transactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
void createTransactionError(QString message); void createTransactionError(QString message);
void createTransactionCancelled(const QVector<QString> &address, double amount); void createTransactionCancelled(const QVector<QString> &address, double amount);
@ -131,18 +88,14 @@ signals:
void openAliasResolved(const QString &address, const QString &openAlias); void openAliasResolved(const QString &address, const QString &openAlias);
void setRestoreHeightError(const QString &msg); void setRestoreHeightError(const QString &msg);
void customRestoreHeightSet(int height); void customRestoreHeightSet(int height);
void closeApplication();
void donationNag();
void initiateTransaction(); void initiateTransaction();
void endTransaction(); void endTransaction();
void deviceButtonRequest(quint64 code); void deviceButtonRequest(quint64 code);
void updatesAvailable(const QJsonObject &updates);
void deviceError(const QString &message); void deviceError(const QString &message);
private: private:
DaemonRpc *m_rpc; DaemonRpc *m_rpc;
QTimer m_storeTimer; QTimer m_storeTimer;
bool m_openWalletTriedOnce = false;
}; };
#endif //FEATHER_APPCONTEXT_H #endif //FEATHER_APPCONTEXT_H

View file

@ -9,9 +9,9 @@
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/config.h" #include "utils/config.h"
CalcWidget::CalcWidget(QWidget *parent) : CalcWidget::CalcWidget(QWidget *parent)
QWidget(parent), : QWidget(parent)
ui(new Ui::CalcWidget) , ui(new Ui::CalcWidget)
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -8,9 +8,9 @@
#include "ui_calcwindow.h" #include "ui_calcwindow.h"
CalcWindow::CalcWindow(QWidget *parent) : CalcWindow::CalcWindow(QWidget *parent)
QMainWindow(parent), : QMainWindow(parent)
ui(new Ui::CalcWindow) , ui(new Ui::CalcWindow)
{ {
Qt::WindowFlags flags = this->windowFlags(); Qt::WindowFlags flags = this->windowFlags();
this->setWindowFlags(flags|Qt::WindowStaysOnTopHint); // on top this->setWindowFlags(flags|Qt::WindowStaysOnTopHint); // on top

View file

@ -9,48 +9,59 @@
#include "model/AddressBookModel.h" #include "model/AddressBookModel.h"
#include "model/TransactionHistoryModel.h" #include "model/TransactionHistoryModel.h"
#include "utils/brute.h" #include "utils/brute.h"
#include "constants.h"
CLI::CLI(AppContext *ctx, QObject *parent) : CLI::CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent)
QObject(parent), : QObject(parent)
ctx(ctx) { , m_mode(mode)
connect(this->ctx, &AppContext::walletOpened, this, &CLI::onWalletOpened); , m_cmdargs(cmdargs)
connect(this->ctx, &AppContext::walletOpenedError, this, &CLI::onWalletOpenedError); {
connect(this->ctx, &AppContext::walletOpenPasswordNeeded, this, &CLI::onWalletOpenPasswordRequired); m_walletManager = WalletManager::instance();
connect(m_walletManager, &WalletManager::walletOpened, this, &CLI::onWalletOpened);
if (m_mode == Mode::ExportContacts || m_mode == Mode::ExportTxHistory)
{
if (!cmdargs->isSet("wallet-file")) {
this->finished("--wallet-file argument missing");
return;
}
if (!cmdargs->isSet("password")) {
this->finished("--password argument missing");
return;
} }
void CLI::run() { QString walletFile = cmdargs->value("wallet-file");
if (mode == CLIMode::ExportContacts || mode == CLIMode::ExportTxHistory) QString password = cmdargs->value("password");
{
if(!ctx->cmdargs->isSet("wallet-file"))
return this->finishedError("--wallet-file argument missing"); m_walletManager->openWalletAsync(walletFile, password, constants::networkType);
if(!ctx->cmdargs->isSet("password"))
return this->finishedError("--password argument missing");
ctx->onOpenWallet(ctx->cmdargs->value("wallet-file"), ctx->cmdargs->value("password"));
} }
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")) { 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; QStringList words;
if (ctx->cmdargs->isSet("bruteforce-dict")) { if (m_cmdargs->isSet("bruteforce-dict")) {
QString data = Utils::barrayToString(Utils::fileOpen(ctx->cmdargs->value("bruteforce-dict"))); QString data = Utils::barrayToString(Utils::fileOpen(m_cmdargs->value("bruteforce-dict")));
words = data.split("\n"); words = data.split("\n");
} }
if (!ctx->cmdargs->isSet("bruteforce-chars")) { if (!m_cmdargs->isSet("bruteforce-chars")) {
return this->finishedError("--bruteforce-chars argument missing"); 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()); brute b(chars.toStdString());
if (words.isEmpty()) { if (words.isEmpty()) {
qDebug() << "No dictionairy specified, bruteforcing all chars"; qDebug() << "No dictionairy specified, bruteforcing all chars";
while (true) { while (true) {
QString pass = QString::fromStdString(b.next()); 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)); this->finished(QString("Found password: %1").arg(pass));
break; break;
} }
@ -60,7 +71,7 @@ void CLI::run() {
else { else {
bruteword bb(chars.toStdString()); bruteword bb(chars.toStdString());
bool foundPass = false; bool foundPass = false;
for (auto word: words) { for (const auto& word: words) {
if (word.isEmpty()) { if (word.isEmpty()) {
continue; continue;
} }
@ -71,7 +82,7 @@ void CLI::run() {
if (pass == "") { if (pass == "") {
break; 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)); this->finished(QString("Found password: %1").arg(pass));
foundPass = true; foundPass = true;
break; break;
@ -88,50 +99,39 @@ void CLI::run() {
} }
} }
} }
else {
this->finished("Invalid mode");
}
} }
void CLI::onWalletOpened() { void CLI::onWalletOpened(Wallet *w) {
if(mode == CLIMode::ExportContacts){ QScopedPointer<Wallet> wallet{w};
auto *model = ctx->currentWallet->addressBookModel();
auto fn = ctx->cmdargs->value("export-contacts"); if (wallet->status() != Wallet::Status_Ok) {
if(model->writeCSV(fn)) this->finished(wallet->errorString());
this->finished(QString("Address book exported to %1").arg(fn)); 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 else
this->finishedError("Address book export failure"); this->finished("Failed to export contacts");
} else if(mode == ExportTxHistory) { }
ctx->currentWallet->history()->refresh(ctx->currentWallet->currentSubaddressAccount()); else if (m_mode == Mode::ExportTxHistory) {
auto *model = ctx->currentWallet->history(); wallet->history()->refresh(wallet->currentSubaddressAccount());
auto fn = ctx->cmdargs->value("export-txhistory"); auto *model = wallet->history();
if(model->writeCSV(fn)) QString fileName = m_cmdargs->value("export-txhistory");
this->finished(QString("Transaction history exported to %1").arg(fn)); if (model->writeCSV(fileName))
this->finished(QString("Transaction history exported to %1").arg(fileName));
else else
this->finishedError("Transaction history export failure"); this->finished("Failed to export transaction history");
} }
} }
void CLI::onWalletOpenedError(const QString &err) { void CLI::finished(const QString &message) {
if(mode == CLIMode::ExportContacts || qInfo() << message;
mode == CLIMode::ExportTxHistory) QApplication::quit();
return this->finishedError(err);
}
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;
} }

View file

@ -7,37 +7,28 @@
#include <QtCore> #include <QtCore>
#include "appcontext.h" #include "appcontext.h"
enum CLIMode { class CLI : public QObject
{
Q_OBJECT
public:
enum Mode {
ExportContacts, ExportContacts,
ExportTxHistory, ExportTxHistory,
BruteforcePassword BruteforcePassword
}; };
class CLI : public QObject explicit CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent = nullptr);
{
Q_OBJECT
public:
CLIMode mode;
explicit CLI(AppContext *ctx, QObject *parent = nullptr);
~CLI() override;
public slots:
void run();
//libwalletqt
void onWalletOpened();
void onWalletOpenedError(const QString& err);
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
private:
AppContext *ctx;
private slots: private slots:
void finished(const QString &msg); void onWalletOpened(Wallet *wallet);
void finishedError(const QString &err);
signals: private:
void closeApplication(); void finished(const QString &message);
Mode m_mode;
QCommandLineParser *m_cmdargs;
WalletManager *m_walletManager;
}; };
#endif //FEATHER_CLI_H #endif //FEATHER_CLI_H

View file

@ -11,10 +11,10 @@
#include <QClipboard> #include <QClipboard>
#include <QMessageBox> #include <QMessageBox>
CoinsWidget::CoinsWidget(AppContext *ctx, QWidget *parent) CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::CoinsWidget) , ui(new Ui::CoinsWidget)
, m_ctx(ctx) , m_ctx(std::move(ctx))
, m_headerMenu(new QMenu(this)) , m_headerMenu(new QMenu(this))
, m_copyMenu(new QMenu("Copy",this)) , m_copyMenu(new QMenu("Copy",this))
{ {
@ -69,7 +69,7 @@ void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
ui->coins->setColumnHidden(CoinsModel::SpentHeight, true); ui->coins->setColumnHidden(CoinsModel::SpentHeight, true);
ui->coins->setColumnHidden(CoinsModel::Frozen, true); ui->coins->setColumnHidden(CoinsModel::Frozen, true);
if (!m_ctx->currentWallet->viewOnly()) { if (!m_ctx->wallet->viewOnly()) {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, true); ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, true);
} else { } else {
ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, false); ui->coins->setColumnHidden(CoinsModel::KeyImageKnown, false);
@ -233,17 +233,17 @@ CoinsInfo* CoinsWidget::currentEntry() {
void CoinsWidget::freezeCoins(const QVector<int>& indexes) { void CoinsWidget::freezeCoins(const QVector<int>& indexes) {
for (int i : 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(); m_ctx->updateBalance();
} }
void CoinsWidget::thawCoins(const QVector<int> &indexes) { void CoinsWidget::thawCoins(const QVector<int> &indexes) {
for (int i : 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(); m_ctx->updateBalance();
} }

View file

@ -22,7 +22,7 @@ class CoinsWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit CoinsWidget(AppContext *ctx, QWidget *parent = nullptr); explicit CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void setModel(CoinsModel * model, Coins * coins); void setModel(CoinsModel * model, Coins * coins);
~CoinsWidget() override; ~CoinsWidget() override;
@ -54,7 +54,7 @@ private:
}; };
Ui::CoinsWidget *ui; Ui::CoinsWidget *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
QMenu *m_contextMenu; QMenu *m_contextMenu;
QMenu *m_headerMenu; QMenu *m_headerMenu;

View file

@ -1,24 +1,31 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project. // Copyright (c) 2020-2021, The Monero Project.
#ifndef FEATHER_GLOBALS_H #ifndef FEATHER_CONSTANTS_H
#define FEATHER_GLOBALS_H #define FEATHER_CONSTANTS_H
#include <QtGlobal> #include <QtGlobal>
#include <QUrl> #include <QUrl>
namespace globals #include "networktype.h"
namespace constants
{ {
// application constants
static NetworkType::Type networkType; // TODO: compiler moans, also not really a const
// coin constants // coin constants
const std::string coinName = "monero"; const std::string coinName = "monero";
const qreal cdiv = 1e12; const qreal cdiv = 1e12;
const quint32 mixin = 10; const quint32 mixin = 10;
const quint64 kdfRounds = 1; const quint64 kdfRounds = 1;
const QString seedLanguage = "English"; // todo: move me
// donation constants // donation constants
const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f"; const QString donationAddress = "47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f";
const int donationAmount = 25; // euro const int donationAmount = 25; // euro
const int donationBoundary = 15; const int donationBoundary = 25;
// websocket constants // websocket constants
const QUrl websocketUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws")); const QUrl websocketUrl = QUrl(QStringLiteral("ws://7e6egbawekbkxzkv4244pqeqgoo4axko2imgjbedwnn6s5yb6b7oliqd.onion/ws"));
@ -27,4 +34,4 @@ namespace globals
const QString websiteUrl = "https://featherwallet.org"; const QString websiteUrl = "https://featherwallet.org";
} }
#endif //FEATHER_GLOBALS_H #endif //FEATHER_CONSTANTS_H

View file

@ -11,12 +11,23 @@
#include <QMessageBox> #include <QMessageBox>
ContactsWidget::ContactsWidget(QWidget *parent) ContactsWidget::ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::ContactsWidget) , ui(new Ui::ContactsWidget)
, m_ctx(std::move(ctx))
{ {
ui->setupUi(this); 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 // header context menu
ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu); ui->contacts->header()->setContextMenuPolicy(Qt::CustomContextMenu);
m_headerMenu = new QMenu(this); m_headerMenu = new QMenu(this);
@ -68,20 +79,6 @@ void ContactsWidget::payTo() {
emit fillAddress(address); 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) { void ContactsWidget::setShowFullAddresses(bool show) {
m_model->setShowFullAddresses(show); m_model->setShowFullAddresses(show);
} }
@ -104,11 +101,6 @@ void ContactsWidget::showHeaderMenu(const QPoint& position)
void ContactsWidget::newContact(QString address, QString name) void ContactsWidget::newContact(QString address, QString name)
{ {
if (!m_wallet) {
QMessageBox::warning(this, "Error", "No wallet opened.");
return;
}
ContactsDialog dialog{this, address, name}; ContactsDialog dialog{this, address, name};
int ret = dialog.exec(); int ret = dialog.exec();
if (ret != QDialog::Accepted) { if (ret != QDialog::Accepted) {
@ -118,17 +110,17 @@ void ContactsWidget::newContact(QString address, QString name)
address = dialog.getAddress(); address = dialog.getAddress();
name = dialog.getName(); name = dialog.getName();
bool addressValid = WalletManager::addressValid(address, m_wallet->nettype()); bool addressValid = WalletManager::addressValid(address, m_ctx->wallet->nettype());
if (!addressValid) { if (!addressValid) {
QMessageBox::warning(this, "Invalid address", "Invalid address"); QMessageBox::warning(this, "Invalid address", "Invalid address");
return; return;
} }
int num_addresses = m_wallet->addressBook()->count(); int num_addresses = m_ctx->wallet->addressBook()->count();
QString address_entry; QString address_entry;
QString name_entry; QString name_entry;
for (int i=0; i<num_addresses; i++) { for (int i=0; i<num_addresses; i++) {
m_wallet->addressBook()->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(); address_entry = entry.address();
name_entry = entry.description(); 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() void ContactsWidget::deleteContact()

View file

@ -20,8 +20,7 @@ class ContactsWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ContactsWidget(QWidget *parent = nullptr); explicit ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void setModel(AddressBookModel *model, Wallet *wallet);
~ContactsWidget() override; ~ContactsWidget() override;
public slots: public slots:
@ -42,6 +41,7 @@ private slots:
private: private:
Ui::ContactsWidget *ui; Ui::ContactsWidget *ui;
QSharedPointer<AppContext> m_ctx;
QAction *m_showFullAddressesAction; QAction *m_showFullAddressesAction;
QMenu *m_rowMenu; QMenu *m_rowMenu;
@ -49,7 +49,6 @@ private:
QMenu *m_headerMenu; QMenu *m_headerMenu;
AddressBookModel * m_model; AddressBookModel * m_model;
AddressBookProxyModel * m_proxyModel; AddressBookProxyModel * m_proxyModel;
Wallet *m_wallet;
}; };
#endif // CONTACTSWIDGET_H #endif // CONTACTSWIDGET_H

View file

@ -9,15 +9,15 @@
#include "libwalletqt/Transfer.h" #include "libwalletqt/Transfer.h"
#include "utils/utils.h" #include "utils/utils.h"
TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txInfo) TxProofDialog::TxProofDialog(QWidget *parent, QSharedPointer<AppContext> ctx, TransactionInfo *txInfo)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TxProofDialog) , ui(new Ui::TxProofDialog)
, m_wallet(wallet) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
m_txid = txInfo->hash(); m_txid = txInfo->hash();
m_txKey = m_wallet->getTxKey(m_txid); m_txKey = m_ctx->wallet->getTxKey(m_txid);
m_direction = txInfo->direction(); m_direction = txInfo->direction();
for (auto const &t: txInfo->transfers()) { for (auto const &t: txInfo->transfers()) {
@ -25,7 +25,7 @@ TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *t
} }
for (auto const &s: txInfo->subaddrIndex()) { 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 // Due to some logic in core we can't create OutProofs
@ -127,7 +127,7 @@ void TxProofDialog::showWarning(const QString &message) {
void TxProofDialog::getFormattedProof() { void TxProofDialog::getFormattedProof() {
QString message = ui->message->toPlainText(); QString message = ui->message->toPlainText();
QString address = ui->combo_address->currentText(); 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 nettype = nettype.replace(0, 1, nettype[0].toUpper()); // Capitalize first letter
TxProof proof = this->getProof(); TxProof proof = this->getProof();
@ -208,12 +208,12 @@ TxProof TxProofDialog::getProof() {
TxProof proof = [this, message, address]{ TxProof proof = [this, message, address]{
switch (m_mode) { switch (m_mode) {
case Mode::SpendProof: { case Mode::SpendProof: {
return m_wallet->getSpendProof(m_txid, message); return m_ctx->wallet->getSpendProof(m_txid, message);
} }
case Mode::OutProof: case Mode::OutProof:
case Mode::InProof: case Mode::InProof:
default: { // Todo: split this into separate functions default: { // Todo: split this into separate functions
return m_wallet->getTxProof(m_txid, address, message); return m_ctx->wallet->getTxProof(m_txid, address, message);
} }
} }
}(); }();

View file

@ -6,8 +6,8 @@
#include <QDialog> #include <QDialog>
#include "libwalletqt/Wallet.h"
#include "libwalletqt/TransactionInfo.h" #include "libwalletqt/TransactionInfo.h"
#include "appcontext.h"
namespace Ui { namespace Ui {
class TxProofDialog; class TxProofDialog;
@ -18,7 +18,7 @@ class TxProofDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txid); explicit TxProofDialog(QWidget *parent, QSharedPointer<AppContext> ctx, TransactionInfo *txid);
~TxProofDialog() override; ~TxProofDialog() override;
void setTxId(const QString &txid); void setTxId(const QString &txid);
@ -50,7 +50,7 @@ private:
TransactionInfo::Direction m_direction; TransactionInfo::Direction m_direction;
Ui::TxProofDialog *ui; Ui::TxProofDialog *ui;
Wallet *m_wallet; QSharedPointer<AppContext> m_ctx;
}; };
#endif //FEATHER_TXPROOFDIALOG_H #endif //FEATHER_TXPROOFDIALOG_H

View file

@ -7,81 +7,81 @@
#include <QRadioButton> #include <QRadioButton>
WalletCacheDebugDialog::WalletCacheDebugDialog(AppContext *ctx, QWidget *parent) WalletCacheDebugDialog::WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::WalletCacheDebugDialog) , ui(new Ui::WalletCacheDebugDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
ui->output->setFont(ModelUtils::getMonospaceFont()); ui->output->setFont(ModelUtils::getMonospaceFont());
connect(ui->m_blockchain, &QRadioButton::pressed, [this]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ 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]{ connect(ui->m_scanned_pool_txs, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printScannedPoolTxs()); this->setOutput(m_ctx->wallet->printScannedPoolTxs());
}); });
this->adjustSize(); this->adjustSize();

View file

@ -16,13 +16,13 @@ class WalletCacheDebugDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit WalletCacheDebugDialog(AppContext *ctx, QWidget *parent = nullptr); explicit WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~WalletCacheDebugDialog() override; ~WalletCacheDebugDialog() override;
private: private:
void setOutput(const QString &output); void setOutput(const QString &output);
Ui::WalletCacheDebugDialog *ui; Ui::WalletCacheDebugDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
}; };

View file

@ -7,10 +7,10 @@
#include <QMessageBox> #include <QMessageBox>
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex) BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, QSharedPointer<AppContext> ctx, const QString &transactionHex)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::BroadcastTxDialog) , ui(new Ui::BroadcastTxDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -17,7 +17,7 @@ class BroadcastTxDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex = ""); explicit BroadcastTxDialog(QWidget *parent, QSharedPointer<AppContext> ctx, const QString &transactionHex = "");
~BroadcastTxDialog() override; ~BroadcastTxDialog() override;
private slots: private slots:
@ -26,7 +26,7 @@ private slots:
private: private:
Ui::BroadcastTxDialog *ui; Ui::BroadcastTxDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
UtilsNetworking *m_network; UtilsNetworking *m_network;
DaemonRpc *m_rpc; DaemonRpc *m_rpc;
}; };

View file

@ -7,11 +7,12 @@
#include "utils/WebsocketClient.h" #include "utils/WebsocketClient.h"
#include "utils/TorManager.h" #include "utils/TorManager.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
#include "utils/tails.h"
DebugInfoDialog::DebugInfoDialog(AppContext *ctx, QWidget *parent) DebugInfoDialog::DebugInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::DebugInfoDialog) , ui(new Ui::DebugInfoDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -28,7 +29,7 @@ void DebugInfoDialog::updateInfo() {
QString torStatus; QString torStatus;
// Special case for Tails because we know the status of the daemon by polling tails-tor-has-bootstrapped.target // 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) if(torManager()->torConnected)
torStatus = "Connected"; torStatus = "Connected";
else else
@ -46,32 +47,32 @@ void DebugInfoDialog::updateInfo() {
ui->label_featherVersion->setText(QString("%1-%2").arg(FEATHER_VERSION, FEATHER_BRANCH)); 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_moneroVersion->setText(QString("%1-%2").arg(MONERO_VERSION, MONERO_BRANCH));
ui->label_walletHeight->setText(QString::number(m_ctx->currentWallet->blockChainHeight())); ui->label_walletHeight->setText(QString::number(m_ctx->wallet->blockChainHeight()));
ui->label_daemonHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainHeight())); ui->label_daemonHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainHeight()));
ui->label_targetHeight->setText(QString::number(m_ctx->currentWallet->daemonBlockChainTargetHeight())); ui->label_targetHeight->setText(QString::number(m_ctx->wallet->daemonBlockChainTargetHeight()));
ui->label_restoreHeight->setText(QString::number(m_ctx->currentWallet->getWalletCreationHeight())); ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight()));
ui->label_synchronized->setText(m_ctx->currentWallet->isSynchronized() ? "True" : "False"); ui->label_synchronized->setText(m_ctx->wallet->isSynchronized() ? "True" : "False");
auto node = m_ctx->nodes->connection(); auto node = m_ctx->nodes->connection();
ui->label_remoteNode->setText(node.toAddress()); 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_torStatus->setText(torStatus);
ui->label_websocketStatus->setText(Utils::QtEnumToString(websocketNotifier()->websocketClient.webSocket.state()).remove("State")); ui->label_websocketStatus->setText(Utils::QtEnumToString(websocketNotifier()->websocketClient.webSocket.state()).remove("State"));
QString seedType = [this](){ QString seedType = [this](){
if (m_ctx->currentWallet->isHwBacked()) if (m_ctx->wallet->isHwBacked())
return "Hardware"; return "Hardware";
if (m_ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty()) if (m_ctx->wallet->getCacheAttribute("feather.seed").isEmpty())
return "25 word"; return "25 word";
else else
return "14 word"; return "14 word";
}(); }();
QString deviceType = [this](){ QString deviceType = [this](){
if (m_ctx->currentWallet->isHwBacked()) { if (m_ctx->wallet->isHwBacked()) {
if (m_ctx->currentWallet->isLedger()) if (m_ctx->wallet->isLedger())
return "Ledger"; return "Ledger";
else if (m_ctx->currentWallet->isTrezor()) else if (m_ctx->wallet->isTrezor())
return "Trezor"; return "Trezor";
else else
return "Unknown"; 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_seedType->setText(seedType);
ui->label_deviceType->setText(deviceType); ui->label_deviceType->setText(deviceType);
ui->label_viewOnly->setText(m_ctx->currentWallet->viewOnly() ? "True" : "False"); ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False");
ui->label_primaryOnly->setText(m_ctx->currentWallet->balance(0) == m_ctx->currentWallet->balanceAll() ? "True" : "False"); ui->label_primaryOnly->setText(m_ctx->wallet->balance(0) == m_ctx->wallet->balanceAll() ? "True" : "False");
QString os = QSysInfo::prettyProductName(); QString os = QSysInfo::prettyProductName();
if (m_ctx->isTails) { if (TailsOS::detect()) {
os = QString("Tails %1").arg(TailsOS::version()); os = QString("Tails %1").arg(TailsOS::version());
} }
if (m_ctx->isWhonix) { if (WhonixOS::detect()) {
os = QString("Whonix %1").arg(WhonixOS::version()); os = QString("Whonix %1").arg(WhonixOS::version());
} }
ui->label_OS->setText(os); ui->label_OS->setText(os);

View file

@ -17,7 +17,7 @@ class DebugInfoDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit DebugInfoDialog(AppContext *ctx, QWidget *parent = nullptr); explicit DebugInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~DebugInfoDialog() override; ~DebugInfoDialog() override;
private: private:
@ -26,7 +26,7 @@ private:
void updateInfo(); void updateInfo();
Ui::DebugInfoDialog *ui; Ui::DebugInfoDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
QTimer m_updateTimer; QTimer m_updateTimer;
}; };

View file

@ -4,21 +4,20 @@
#include "keysdialog.h" #include "keysdialog.h"
#include "ui_keysdialog.h" #include "ui_keysdialog.h"
KeysDialog::KeysDialog(AppContext *ctx, QWidget *parent) KeysDialog::KeysDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::KeysDialog) , ui(new Ui::KeysDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
auto w = ctx->currentWallet;
QString unavailable = "Unavailable: Key is stored on hardware device"; QString unavailable = "Unavailable: Key is stored on hardware device";
ui->label_restoreHeight->setText(QString::number(w->getWalletCreationHeight())); ui->label_restoreHeight->setText(QString::number(ctx->wallet->getWalletCreationHeight()));
ui->label_primaryAddress->setText(w->address(0, 0)); ui->label_primaryAddress->setText(ctx->wallet->address(0, 0));
ui->label_secretSpendKey->setText(w->isHwBacked() ? unavailable : w->getSecretSpendKey()); ui->label_secretSpendKey->setText(ctx->wallet->isHwBacked() ? unavailable : ctx->wallet->getSecretSpendKey());
ui->label_secretViewKey->setText(w->getSecretViewKey()); ui->label_secretViewKey->setText(ctx->wallet->getSecretViewKey());
ui->label_publicSpendKey->setText(w->getPublicSpendKey()); ui->label_publicSpendKey->setText(ctx->wallet->getPublicSpendKey());
ui->label_publicViewKey->setText(w->getPublicViewKey()); ui->label_publicViewKey->setText(ctx->wallet->getPublicViewKey());
this->adjustSize(); this->adjustSize();
} }

View file

@ -16,7 +16,7 @@ class KeysDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit KeysDialog(AppContext *ctx, QWidget *parent = nullptr); explicit KeysDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~KeysDialog() override; ~KeysDialog() override;
private: private:

View file

@ -4,7 +4,7 @@
#include "passworddialog.h" #include "passworddialog.h"
#include "ui_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) : QDialog(parent)
, ui(new Ui::PasswordDialog) , ui(new Ui::PasswordDialog)
{ {

View file

@ -15,7 +15,7 @@ class PasswordDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword); explicit PasswordDialog(const QString &walletName, bool incorrectPassword, QWidget *parent = nullptr);
~PasswordDialog() override; ~PasswordDialog() override;
QString password = ""; QString password = "";

View file

@ -4,21 +4,23 @@
#include "restoredialog.h" #include "restoredialog.h"
#include "ui_restoredialog.h" #include "ui_restoredialog.h"
RestoreDialog::RestoreDialog(AppContext *ctx, QWidget *parent) #include "constants.h"
RestoreDialog::RestoreDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::RestoreDialog) , ui(new Ui::RestoreDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RestoreDialog::accepted); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &RestoreDialog::accepted);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RestoreDialog::rejected); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &RestoreDialog::rejected);
if(m_ctx->networkType == NetworkType::Type::TESTNET) { if(constants::networkType == NetworkType::Type::TESTNET) {
ui->restoreHeightWidget->hideSlider(); ui->restoreHeightWidget->hideSlider();
} else { } else {
// load restoreHeight lookup db // load restoreHeight lookup db
ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[m_ctx->networkType]); ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[constants::networkType]);
} }
} }

View file

@ -22,7 +22,7 @@ class RestoreDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit RestoreDialog(AppContext *ctx, QWidget *parent = nullptr); explicit RestoreDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void initRestoreHeights(RestoreHeightLookup *lookup); void initRestoreHeights(RestoreHeightLookup *lookup);
int getHeight(); int getHeight();
~RestoreDialog() override; ~RestoreDialog() override;
@ -33,7 +33,7 @@ signals:
private: private:
Ui::RestoreDialog *ui; Ui::RestoreDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
}; };
#endif // RESTOREDIALOG_H #endif // RESTOREDIALOG_H

View file

@ -4,18 +4,19 @@
#include "ui_seeddialog.h" #include "ui_seeddialog.h"
#include "seeddialog.h" #include "seeddialog.h"
SeedDialog::SeedDialog(Wallet *wallet, QWidget *parent) SeedDialog::SeedDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::SeedDialog) , ui(new Ui::SeedDialog)
, m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
ui->label_seedIcon->setPixmap(QPixmap(":/assets/images/seed.png").scaledToWidth(64, Qt::SmoothTransformation)); 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 seedOffset = m_ctx->wallet->getCacheAttribute("feather.seedoffset");
QString seed_14_words = wallet->getCacheAttribute("feather.seed"); QString seed_14_words = m_ctx->wallet->getCacheAttribute("feather.seed");
QString seed_25_words = wallet->getSeed(seedOffset); QString seed_25_words = m_ctx->wallet->getSeed(seedOffset);
if (seed_14_words.isEmpty()) { if (seed_14_words.isEmpty()) {
ui->check_toggleSeedType->hide(); ui->check_toggleSeedType->hide();

View file

@ -5,7 +5,7 @@
#define FEATHER_SEEDDIALOG_H #define FEATHER_SEEDDIALOG_H
#include <QDialog> #include <QDialog>
#include "libwalletqt/Wallet.h" #include "appcontext.h"
namespace Ui { namespace Ui {
class SeedDialog; class SeedDialog;
@ -16,13 +16,14 @@ class SeedDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit SeedDialog(Wallet *wallet, QWidget *parent = nullptr); explicit SeedDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~SeedDialog() override; ~SeedDialog() override;
private: private:
void setSeed(const QString &seed); void setSeed(const QString &seed);
Ui::SeedDialog *ui; Ui::SeedDialog *ui;
QSharedPointer<AppContext> m_ctx;
}; };

View file

@ -3,6 +3,7 @@
#include "splashdialog.h" #include "splashdialog.h"
#include "ui_splashdialog.h" #include "ui_splashdialog.h"
#include "utils/Icons.h"
SplashDialog::SplashDialog(QWidget *parent) SplashDialog::SplashDialog(QWidget *parent)
: QDialog(parent) : QDialog(parent)
@ -10,6 +11,8 @@ SplashDialog::SplashDialog(QWidget *parent)
{ {
ui->setupUi(this); ui->setupUi(this);
this->setWindowIcon(icons()->icon("appicon/64x64"));
QPixmap pixmap = QPixmap(":/assets/images/key.png"); QPixmap pixmap = QPixmap(":/assets/images/key.png");
ui->icon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation)); ui->icon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));

View file

@ -9,11 +9,12 @@
#include <QMessageBox> #include <QMessageBox>
#include "utils/TorManager.h" #include "utils/TorManager.h"
#include "utils/tails.h"
TorInfoDialog::TorInfoDialog(QWidget *parent, AppContext *ctx) TorInfoDialog::TorInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TorInfoDialog) , ui(new Ui::TorInfoDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -18,7 +18,7 @@ class TorInfoDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TorInfoDialog(QWidget *parent, AppContext *ctx); explicit TorInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~TorInfoDialog() override; ~TorInfoDialog() override;
public slots: public slots:
@ -38,7 +38,7 @@ private:
void initPrivacyLevel(); void initPrivacyLevel();
Ui::TorInfoDialog *ui; Ui::TorInfoDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
}; };

View file

@ -17,10 +17,10 @@
#include <QMessageBox> #include <QMessageBox>
#include <QScrollBar> #include <QScrollBar>
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent) TransactionInfoDialog::TransactionInfoDialog(QSharedPointer<AppContext> ctx, TransactionInfo *txInfo, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TransactionInfoDialog) , ui(new Ui::TransactionInfoDialog)
, m_wallet(wallet) , m_ctx(std::move(ctx))
, m_txInfo(txInfo) , m_txInfo(txInfo)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -28,7 +28,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
m_txid = txInfo->hash(); m_txid = txInfo->hash();
ui->label_txid->setText(m_txid); 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()) { if (m_txKey.isEmpty()) {
ui->btn_CopyTxKey->setEnabled(false); ui->btn_CopyTxKey->setEnabled(false);
ui->btn_CopyTxKey->setToolTip("Transaction key unknown"); 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_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey);
connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof); 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); 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]{ connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{
emit resendTranscation(m_txid); emit resendTranscation(m_txid);
}); });
@ -53,7 +53,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
for (const auto& transfer : txInfo->transfers()) { for (const auto& transfer : txInfo->transfers()) {
auto address = transfer->address(); auto address = transfer->address();
auto amount = WalletManager::displayAmount(transfer->amount()); 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(address, Utils::addressTextFormat(index));
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
cursor.insertBlock(); cursor.insertBlock();
@ -63,7 +63,7 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
ui->frameDestinations->hide(); ui->frameDestinations->hide();
} }
m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo); m_txProofDialog = new TxProofDialog(this, m_ctx, txInfo);
QCoreApplication::processEvents(); QCoreApplication::processEvents();
@ -121,8 +121,7 @@ void TransactionInfoDialog::setData(TransactionInfo* tx) {
} }
void TransactionInfoDialog::updateData() { void TransactionInfoDialog::updateData() {
if (!m_wallet) return; TransactionInfo* tx = m_ctx->wallet->history()->transaction(m_txid);
TransactionInfo* tx = m_wallet->history()->transaction(m_txid);
if (!tx) return; if (!tx) return;
this->setData(tx); this->setData(tx);
} }

View file

@ -7,9 +7,7 @@
#include <QDialog> #include <QDialog>
#include <QTextCharFormat> #include <QTextCharFormat>
#include <QtSvg/QSvgWidget> #include <QtSvg/QSvgWidget>
#include "libwalletqt/Coins.h" #include "appcontext.h"
#include "libwalletqt/TransactionInfo.h"
#include "libwalletqt/Wallet.h"
#include "dialog/TxProofDialog.h" #include "dialog/TxProofDialog.h"
namespace Ui { namespace Ui {
@ -21,7 +19,7 @@ class TransactionInfoDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr); explicit TransactionInfoDialog(QSharedPointer<AppContext> ctx, TransactionInfo *txInfo, QWidget *parent = nullptr);
~TransactionInfoDialog() override; ~TransactionInfoDialog() override;
signals: signals:
@ -35,7 +33,7 @@ private:
Ui::TransactionInfoDialog *ui; Ui::TransactionInfoDialog *ui;
Wallet *m_wallet; QSharedPointer<AppContext> m_ctx;
TransactionInfo *m_txInfo; TransactionInfo *m_txInfo;
TxProofDialog *m_txProofDialog; TxProofDialog *m_txProofDialog;
QString m_txKey; QString m_txKey;

View file

@ -12,10 +12,10 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent) TxConfAdvDialog::TxConfAdvDialog(QSharedPointer<AppContext> ctx, const QString &description, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TxConfAdvDialog) , ui(new Ui::TxConfAdvDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
, m_exportUnsignedMenu(new QMenu(this)) , m_exportUnsignedMenu(new QMenu(this))
, m_exportSignedMenu(new QMenu(this)) , m_exportSignedMenu(new QMenu(this))
{ {
@ -30,7 +30,7 @@ TxConfAdvDialog::TxConfAdvDialog(AppContext *ctx, const QString &description, QW
m_exportSignedMenu->addAction("Save to file", this, &TxConfAdvDialog::signedSaveFile); m_exportSignedMenu->addAction("Save to file", this, &TxConfAdvDialog::signedSaveFile);
ui->btn_exportSigned->setMenu(m_exportSignedMenu); ui->btn_exportSigned->setMenu(m_exportSignedMenu);
if (m_ctx->currentWallet->viewOnly()) { if (m_ctx->wallet->viewOnly()) {
ui->btn_exportSigned->hide(); ui->btn_exportSigned->hide();
ui->btn_send->hide(); ui->btn_send->hide();
} }
@ -61,7 +61,7 @@ void TxConfAdvDialog::setTransaction(PendingTransaction *tx) {
ui->total->setText(WalletManager::displayAmount(tx->amount() + ptx->fee())); ui->total->setText(WalletManager::displayAmount(tx->amount() + ptx->fee()));
auto size_str = [this]{ 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())); return QString("Size: %1 bytes (unsigned)").arg(QString::number(m_tx->unsignedTxToBin().size()));
} else { } else {
auto size = m_tx->signedTxToHex(0).size() / 2; auto size = m_tx->signedTxToHex(0).size() / 2;
@ -108,7 +108,7 @@ void TxConfAdvDialog::setupConstructionData(ConstructionInfo *ci) {
for (const auto& o: outputs) { for (const auto& o: outputs) {
auto address = o->address(); auto address = o->address();
auto amount = WalletManager::displayAmount(o->amount()); 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(address, Utils::addressTextFormat(index));
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
cursor.insertBlock(); cursor.insertBlock();
@ -177,9 +177,9 @@ void TxConfAdvDialog::broadcastTransaction() {
void TxConfAdvDialog::closeDialog() { void TxConfAdvDialog::closeDialog() {
if (m_tx != nullptr) if (m_tx != nullptr)
m_ctx->currentWallet->disposeTransaction(m_tx); m_ctx->wallet->disposeTransaction(m_tx);
if (m_utx != nullptr) if (m_utx != nullptr)
m_ctx->currentWallet->disposeTransaction(m_utx); m_ctx->wallet->disposeTransaction(m_utx);
QDialog::reject(); QDialog::reject();
} }

View file

@ -22,7 +22,7 @@ class TxConfAdvDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TxConfAdvDialog(AppContext *ctx, const QString &description, QWidget *parent = nullptr); explicit TxConfAdvDialog(QSharedPointer<AppContext> ctx, const QString &description, QWidget *parent = nullptr);
~TxConfAdvDialog() override; ~TxConfAdvDialog() override;
void setTransaction(PendingTransaction *tx); void setTransaction(PendingTransaction *tx);
@ -43,7 +43,7 @@ private:
void signedSaveFile(); void signedSaveFile();
Ui::TxConfAdvDialog *ui; Ui::TxConfAdvDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
PendingTransaction *m_tx = nullptr; PendingTransaction *m_tx = nullptr;
UnsignedTransaction *m_utx = nullptr; UnsignedTransaction *m_utx = nullptr;
QMenu *m_exportUnsignedMenu; QMenu *m_exportUnsignedMenu;

View file

@ -5,16 +5,16 @@
#include "ui_txconfdialog.h" #include "ui_txconfdialog.h"
#include "model/ModelUtils.h" #include "model/ModelUtils.h"
#include "txconfadvdialog.h" #include "txconfadvdialog.h"
#include "globals.h" #include "constants.h"
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include <QMessageBox> #include <QMessageBox>
TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent) TxConfDialog::TxConfDialog(QSharedPointer<AppContext> ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TxConfDialog) , ui(new Ui::TxConfDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
, m_tx(tx) , m_tx(tx)
, m_address(address) , m_address(address)
, m_description(description) , m_description(description)
@ -37,9 +37,9 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
int maxLength = Utils::maxLength(amounts); int maxLength = Utils::maxLength(amounts);
std::for_each(amounts.begin(), amounts.end(), [maxLength](QString& amount){amount = amount.rightJustified(maxLength, ' ');}); std::for_each(amounts.begin(), amounts.end(), [maxLength](QString& amount){amount = amount.rightJustified(maxLength, ' ');});
QString amount_fiat = convert(tx->amount() / globals::cdiv); QString amount_fiat = convert(tx->amount() / constants::cdiv);
QString fee_fiat = convert(tx->fee() / globals::cdiv); QString fee_fiat = convert(tx->fee() / constants::cdiv);
QString total_fiat = convert((tx->amount() + tx->fee()) / globals::cdiv); QString total_fiat = convert((tx->amount() + tx->fee()) / constants::cdiv);
QVector<QString> amounts_fiat = {amount_fiat, fee_fiat, total_fiat}; QVector<QString> amounts_fiat = {amount_fiat, fee_fiat, total_fiat};
int maxLengthFiat = Utils::maxLength(amounts_fiat); int maxLengthFiat = Utils::maxLength(amounts_fiat);
std::for_each(amounts_fiat.begin(), amounts_fiat.end(), [maxLengthFiat](QString& amount){amount = amount.rightJustified(maxLengthFiat, ' ');}); 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_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)); 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; QString addressExtra;
ui->label_address->setText(ModelUtils::displayAddress(address, 2)); 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); 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(); this->adjustSize();
} }

View file

@ -18,7 +18,7 @@ class TxConfDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr); explicit TxConfDialog(QSharedPointer<AppContext> ctx, PendingTransaction *tx, const QString &address, const QString &description, QWidget *parent = nullptr);
~TxConfDialog() override; ~TxConfDialog() override;
bool showAdvanced = false; bool showAdvanced = false;
@ -27,7 +27,7 @@ private:
void setShowAdvanced(); void setShowAdvanced();
Ui::TxConfDialog *ui; Ui::TxConfDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
PendingTransaction *m_tx; PendingTransaction *m_tx;
QString m_address; QString m_address;
QString m_description; QString m_description;

View file

@ -7,10 +7,10 @@
#include <QMessageBox> #include <QMessageBox>
TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx) TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer<AppContext> ctx)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::TxImportDialog) , ui(new Ui::TxImportDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
, m_loadTimer(new QTimer(this)) , m_loadTimer(new QTimer(this))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -88,7 +88,7 @@ void TxImportDialog::onImport() {
bool pool = tx.value("in_pool").toBool(); bool pool = tx.value("in_pool").toBool();
bool double_spend_seen = tx.value("double_spend_seen").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."); QMessageBox::information(this, "Import transaction", "Transaction imported successfully.");
} else { } else {
QMessageBox::warning(this, "Import transaction", "Transaction import failed."); QMessageBox::warning(this, "Import transaction", "Transaction import failed.");

View file

@ -17,7 +17,7 @@ class TxImportDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit TxImportDialog(QWidget *parent, AppContext *ctx); explicit TxImportDialog(QWidget *parent, QSharedPointer<AppContext> ctx);
~TxImportDialog() override; ~TxImportDialog() override;
private slots: private slots:
@ -27,7 +27,7 @@ private slots:
private: private:
Ui::TxImportDialog *ui; Ui::TxImportDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
UtilsNetworking *m_network; UtilsNetworking *m_network;
DaemonRpc *m_rpc; DaemonRpc *m_rpc;

View file

@ -8,20 +8,21 @@
#include "viewonlydialog.h" #include "viewonlydialog.h"
#include "ui_viewonlydialog.h" #include "ui_viewonlydialog.h"
ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent) ViewOnlyDialog::ViewOnlyDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::ViewOnlyDialog), m_ctx(ctx) , ui(new Ui::ViewOnlyDialog)
, m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
ui->label_restoreHeight->setText(QString::number(ctx->currentWallet->getWalletCreationHeight())); ui->label_restoreHeight->setText(QString::number(m_ctx->wallet->getWalletCreationHeight()));
ui->label_primaryAddress->setText(ctx->currentWallet->address(0, 0)); ui->label_primaryAddress->setText(m_ctx->wallet->address(0, 0));
ui->label_secretViewKey->setText(ctx->currentWallet->getSecretViewKey()); ui->label_secretViewKey->setText(m_ctx->wallet->getSecretViewKey());
connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad); connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboad);
connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet); 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(); this->adjustSize();
} }
@ -40,7 +41,7 @@ void ViewOnlyDialog::onWriteViewOnlyWallet(){
if((bool)passwordDialog.exec()) if((bool)passwordDialog.exec())
passwd = passwordDialog.textValue(); 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."); QMessageBox::information(this, "Information", "View-only wallet successfully written to disk.");
} }

View file

@ -16,7 +16,7 @@ class ViewOnlyDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit ViewOnlyDialog(AppContext *ctx, QWidget *parent = nullptr); explicit ViewOnlyDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~ViewOnlyDialog() override; ~ViewOnlyDialog() override;
private slots: private slots:
@ -24,7 +24,7 @@ private slots:
private: private:
Ui::ViewOnlyDialog *ui; Ui::ViewOnlyDialog *ui;
AppContext *m_ctx = nullptr; QSharedPointer<AppContext> m_ctx;
void copyToClipboad(); void copyToClipboad();
}; };

View file

@ -6,21 +6,20 @@
#include <QDesktopServices> #include <QDesktopServices>
WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent) WalletInfoDialog::WalletInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::WalletInfoDialog) , ui(new Ui::WalletInfoDialog)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
QFileInfo keys(ctx->walletPath); QFileInfo cache(m_ctx->wallet->cachePath());
QFileInfo cache(ctx->currentWallet->path());
ui->label_walletName->setText(keys.fileName().replace(".keys", "")); ui->label_walletName->setText(QFileInfo(m_ctx->wallet->cachePath()).fileName());
ui->label_netType->setText(Utils::QtEnumToString(ctx->currentWallet->nettype())); ui->label_netType->setText(Utils::QtEnumToString(m_ctx->wallet->nettype()));
ui->label_seedType->setText(ctx->currentWallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word"); ui->label_seedType->setText(m_ctx->wallet->getCacheAttribute("feather.seed").isEmpty() ? "25 word" : "14 word");
ui->label_viewOnly->setText(ctx->currentWallet->viewOnly() ? "True" : "False"); ui->label_viewOnly->setText(m_ctx->wallet->viewOnly() ? "True" : "False");
ui->label_path->setText(ctx->walletPath); ui->label_path->setText(m_ctx->wallet->keysPath());
ui->label_cacheSize->setText(QString("%1 MB").arg(QString::number(cache.size() / 1e6, 'f', 2))); ui->label_cacheSize->setText(QString("%1 MB").arg(QString::number(cache.size() / 1e6, 'f', 2)));
connect(ui->btn_openWalletDir, &QPushButton::clicked, this, &WalletInfoDialog::openWalletDir); connect(ui->btn_openWalletDir, &QPushButton::clicked, this, &WalletInfoDialog::openWalletDir);
@ -28,12 +27,12 @@ WalletInfoDialog::WalletInfoDialog(AppContext *ctx, QWidget *parent)
this->adjustSize(); this->adjustSize();
} }
void WalletInfoDialog::openWalletDir() {
QFileInfo file(m_ctx->walletPath);
QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode));
}
WalletInfoDialog::~WalletInfoDialog() { WalletInfoDialog::~WalletInfoDialog() {
delete ui; delete ui;
} }
void WalletInfoDialog::openWalletDir() {
QFileInfo file(m_ctx->wallet->keysPath());
QDesktopServices::openUrl(QUrl(QString("file://%1").arg(file.absolutePath()), QUrl::TolerantMode));
}

View file

@ -17,14 +17,14 @@ class WalletInfoDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit WalletInfoDialog(AppContext *ctx, QWidget *parent = nullptr); explicit WalletInfoDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~WalletInfoDialog() override; ~WalletInfoDialog() override;
private: private:
void openWalletDir(); void openWalletDir();
Ui::WalletInfoDialog *ui; Ui::WalletInfoDialog *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
}; };
#endif //FEATHER_WALLETINFODIALOG_H #endif //FEATHER_WALLETINFODIALOG_H

View file

@ -11,11 +11,13 @@
#include <QMessageBox> #include <QMessageBox>
HistoryWidget::HistoryWidget(QWidget *parent) HistoryWidget::HistoryWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::HistoryWidget) , ui(new Ui::HistoryWidget)
, m_ctx(std::move(ctx))
, m_contextMenu(new QMenu(this)) , m_contextMenu(new QMenu(this))
, m_copyMenu(new QMenu("Copy", this)) , m_copyMenu(new QMenu("Copy", this))
, m_model(m_ctx->wallet->historyModel())
{ {
ui->setupUi(this); ui->setupUi(this);
m_contextMenu->addMenu(m_copyMenu); m_contextMenu->addMenu(m_copyMenu);
@ -45,6 +47,18 @@ HistoryWidget::HistoryWidget(QWidget *parent)
config()->set(Config::showHistorySyncNotice, false); config()->set(Config::showHistorySyncNotice, false);
ui->syncNotice->hide(); 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) { void HistoryWidget::showContextMenu(const QPoint &point) {
@ -59,7 +73,7 @@ void HistoryWidget::showContextMenu(const QPoint &point) {
if (!tx) return; if (!tx) return;
bool unconfirmed = tx->isFailed() || tx->isPending(); 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); 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() void HistoryWidget::resetModel()
{ {
// Save view state // Save view state
@ -108,7 +106,7 @@ void HistoryWidget::showTxDetails() {
auto *tx = ui->history->currentEntry(); auto *tx = ui->history->currentEntry();
if (!tx) return; 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){ connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){
emit resendTransaction(txid); emit resendTransaction(txid);
}); });
@ -128,7 +126,6 @@ void HistoryWidget::setSearchText(const QString &text) {
} }
void HistoryWidget::setSearchFilter(const QString &filter) { void HistoryWidget::setSearchFilter(const QString &filter) {
if (!m_model) return;
m_model->setSearchFilter(filter); m_model->setSearchFilter(filter);
ui->history->setSearchMode(!filter.isEmpty()); ui->history->setSearchMode(!filter.isEmpty());
} }
@ -137,7 +134,7 @@ void HistoryWidget::createTxProof() {
auto *tx = ui->history->currentEntry(); auto *tx = ui->history->currentEntry();
if (!tx) return; if (!tx) return;
auto *dialog = new TxProofDialog(this, m_wallet, tx); auto *dialog = new TxProofDialog(this, m_ctx, tx);
dialog->exec(); dialog->exec();
dialog->deleteLater(); dialog->deleteLater();
} }
@ -162,10 +159,6 @@ void HistoryWidget::copy(copyField field) {
Utils::copyToClipboard(data); Utils::copyToClipboard(data);
} }
void HistoryWidget::onWalletOpened() {
ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool());
}
void HistoryWidget::onWalletRefreshed() { void HistoryWidget::onWalletRefreshed() {
ui->syncNotice->hide(); ui->syncNotice->hide();
} }

View file

@ -8,6 +8,7 @@
#include "model/TransactionHistoryProxyModel.h" #include "model/TransactionHistoryProxyModel.h"
#include "libwalletqt/Coins.h" #include "libwalletqt/Coins.h"
#include "libwalletqt/Wallet.h" #include "libwalletqt/Wallet.h"
#include "appcontext.h"
#include <QWidget> #include <QWidget>
#include <QMenu> #include <QMenu>
@ -21,15 +22,13 @@ class HistoryWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit HistoryWidget(QWidget *parent = nullptr); explicit HistoryWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void setModel(TransactionHistoryProxyModel *model, Wallet *wallet);
~HistoryWidget() override; ~HistoryWidget() override;
public slots: public slots:
void setSearchText(const QString &text); void setSearchText(const QString &text);
void resetModel(); void resetModel();
void onWalletRefreshed(); void onWalletRefreshed();
void onWalletOpened();
signals: signals:
void viewOnBlockExplorer(QString txid); void viewOnBlockExplorer(QString txid);
@ -55,11 +54,10 @@ private:
void showSyncNoticeMsg(); void showSyncNoticeMsg();
Ui::HistoryWidget *ui; Ui::HistoryWidget *ui;
QSharedPointer<AppContext> m_ctx;
QMenu *m_contextMenu; QMenu *m_contextMenu;
QMenu *m_copyMenu; QMenu *m_copyMenu;
TransactionHistory *m_txHistory;
TransactionHistoryProxyModel *m_model; TransactionHistoryProxyModel *m_model;
Wallet *m_wallet = nullptr;
}; };
#endif //FEATHER_HISTORYWIDGET_H #endif //FEATHER_HISTORYWIDGET_H

View file

@ -3,6 +3,9 @@
#include "Wallet.h" #include "Wallet.h"
#include <chrono>
#include <thread>
#include "TransactionHistory.h" #include "TransactionHistory.h"
#include "AddressBook.h" #include "AddressBook.h"
#include "Subaddress.h" #include "Subaddress.h"
@ -174,9 +177,14 @@ SubaddressIndex Wallet::subaddressIndex(const QString &address) const
return SubaddressIndex(i.first, i.second); 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 /* = "" */) //void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */)

View file

@ -76,6 +76,9 @@ class Wallet : public QObject, public PassprasePrompter
Q_OBJECT Q_OBJECT
public: public:
Wallet(QObject * parent = nullptr);
Wallet(Monero::Wallet *w, QObject * parent = nullptr);
~Wallet();
enum Status { enum Status {
Status_Ok = Monero::Wallet::Status_Ok, Status_Ok = Monero::Wallet::Status_Ok,
@ -138,8 +141,11 @@ public:
//! returns the subaddress index of the address //! returns the subaddress index of the address
SubaddressIndex subaddressIndex(const QString &address) const; SubaddressIndex subaddressIndex(const QString &address) const;
//! returns wallet file's path //! returns wallet cache file path
QString path() const; QString cachePath() const;
//! returns wallet keys file path
QString keysPath() const;
//! saves wallet to the file by given path //! saves wallet to the file by given path
//! empty path stores in current location //! empty path stores in current location
@ -465,10 +471,6 @@ signals:
void refreshingChanged() const; void refreshingChanged() const;
private: private:
Wallet(QObject * parent = nullptr);
Wallet(Monero::Wallet *w, QObject * parent = nullptr);
~Wallet();
//! initializes wallet //! initializes wallet
bool init( bool init(
const QString &daemonAddress, const QString &daemonAddress,

View file

@ -68,14 +68,10 @@ Wallet *WalletManager::createWallet(const QString &path, const QString &password
const QString &language, NetworkType::Type nettype, quint64 kdfRounds) const QString &language, NetworkType::Type nettype, quint64 kdfRounds)
{ {
QMutexLocker locker(&m_mutex); 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(), Monero::Wallet * w = m_pimpl->createWallet(path.toStdString(), password.toStdString(),
language.toStdString(), static_cast<Monero::NetworkType>(nettype), kdfRounds); language.toStdString(), static_cast<Monero::NetworkType>(nettype), kdfRounds);
m_currentWallet = new Wallet(w); return new Wallet(w);
return m_currentWallet;
} }
Wallet *WalletManager::openWallet(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds) 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; 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); 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<Monero::NetworkType>(nettype), kdfRounds, &tmpListener); Monero::Wallet * w = m_pimpl->openWallet(path.toStdString(), password.toStdString(), static_cast<Monero::NetworkType>(nettype), kdfRounds, &tmpListener);
w->setListener(nullptr); w->setListener(nullptr);
qDebug() << QString("%1: opened wallet: %2, status: %3").arg(__PRETTY_FUNCTION__).arg(w->address(0, 0).c_str()).arg(w->status()); 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 // move wallet to the GUI thread. Otherwise it wont be emitting signals
if (m_currentWallet->thread() != qApp->thread()) { if (wallet->thread() != qApp->thread()) {
m_currentWallet->moveToThread(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) 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) 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); 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<Monero::NetworkType>(nettype), restoreHeight, kdfRounds, seed_offset.toStdString()); Monero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), password.toStdString(), seed.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight, kdfRounds, seed_offset.toStdString());
m_currentWallet = new Wallet(w); return new Wallet(w);
return m_currentWallet;
} }
Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &password, const QString &language, 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) const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds)
{ {
QMutexLocker locker(&m_mutex); 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<Monero::NetworkType>(nettype), restoreHeight, Monero::Wallet * w = m_pimpl->createWalletFromKeys(path.toStdString(), password.toStdString(), language.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight,
address.toStdString(), viewkey.toStdString(), spendkey.toStdString(), kdfRounds); address.toStdString(), viewkey.toStdString(), spendkey.toStdString(), kdfRounds);
m_currentWallet = new Wallet(w); return new Wallet(w);
return m_currentWallet;
} }
Wallet *WalletManager::createDeterministicWalletFromSpendKey(const QString &path, const QString &password, const QString &language, NetworkType::Type nettype, 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) const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds, const QString &offset_passphrase)
{ {
QMutexLocker locker(&m_mutex); 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<Monero::NetworkType>(nettype), restoreHeight, Monero::Wallet * w = m_pimpl->createDeterministicWalletFromSpendKey(path.toStdString(), password.toStdString(), language.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight,
spendkey.toStdString(), kdfRounds, offset_passphrase.toStdString()); spendkey.toStdString(), kdfRounds, offset_passphrase.toStdString());
m_currentWallet = new Wallet(w); return new Wallet(w);
return m_currentWallet;
} }
Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString &password, NetworkType::Type nettype, 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; 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<Monero::NetworkType>(nettype), Monero::Wallet * w = m_pimpl->createWalletFromDevice(path.toStdString(), password.toStdString(), static_cast<Monero::NetworkType>(nettype),
deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener); deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener);
w->setListener(nullptr); 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 // move wallet to the GUI thread. Otherwise it wont be emitting signals
if (m_currentWallet->thread() != qApp->thread()) { if (wallet->thread() != qApp->thread()) {
m_currentWallet->moveToThread(qApp->thread()); wallet->moveToThread(qApp->thread());
} }
return m_currentWallet; return wallet;
} }
void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype, void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype,
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead) 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 bool WalletManager::walletExists(const QString &path) const
{ {
return m_pimpl->walletExists(path.toStdString()); 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<Monero::NetworkType>(nettype)); return Monero::Wallet::addressValid(address.toStdString(), static_cast<Monero::NetworkType>(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; std::string error;
if(!Monero::Wallet::keyValid(key.toStdString(), address.toStdString(), isViewKey, static_cast<Monero::NetworkType>(nettype), error)){ if(!Monero::Wallet::keyValid(key.toStdString(), address.toStdString(), isViewKey, static_cast<Monero::NetworkType>(nettype), error)){
@ -329,43 +275,6 @@ quint64 WalletManager::blockchainTargetHeight() const
return m_pimpl->blockchainTargetHeight(); 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 bool WalletManager::localDaemonSynced() const
{ {
return blockchainHeight() > 1 && blockchainHeight() >= blockchainTargetHeight(); 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<QString> &unknown_parameters, QString &error) const bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
if (m_currentWallet) // TODO: FIXME
return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); // if (m_currentWallet)
// return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
return false; return false;
} }
@ -435,9 +345,8 @@ QUrl WalletManager::localPathToUrl(const QString &path) const
return QUrl::fromLocalFile(path); return QUrl::fromLocalFile(path);
} }
bool WalletManager::clearWalletCache(const QString &wallet_path) const bool WalletManager::clearWalletCache(const QString &wallet_path)
{ {
QString fileName = wallet_path; QString fileName = wallet_path;
// Make sure wallet file is not .keys // Make sure wallet file is not .keys
fileName.replace(".keys",""); fileName.replace(".keys","");
@ -455,7 +364,6 @@ bool WalletManager::clearWalletCache(const QString &wallet_path) const
WalletManager::WalletManager(QObject *parent) WalletManager::WalletManager(QObject *parent)
: QObject(parent) : QObject(parent)
, m_currentWallet(nullptr)
, m_passphraseReceiver(nullptr) , m_passphraseReceiver(nullptr)
, m_scheduler(this) , m_scheduler(this)
{ {

View file

@ -93,16 +93,7 @@ public:
const QString &deviceName, const QString &deviceName,
quint64 restoreHeight = 0, quint64 restoreHeight = 0,
const QString &subaddressLookahead = ""); 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; //! checks is given filename is a wallet;
Q_INVOKABLE bool walletExists(const QString &path) const; Q_INVOKABLE bool walletExists(const QString &path) const;
@ -127,7 +118,7 @@ public:
Q_INVOKABLE bool paymentIdValid(const QString &payment_id) const; Q_INVOKABLE bool paymentIdValid(const QString &payment_id) const;
Q_INVOKABLE static bool addressValid(const QString &address, NetworkType::Type nettype); 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; Q_INVOKABLE QString paymentIdFromAddress(const QString &address, NetworkType::Type nettype) const;
@ -136,14 +127,9 @@ public:
Q_INVOKABLE quint64 networkDifficulty() const; Q_INVOKABLE quint64 networkDifficulty() const;
Q_INVOKABLE quint64 blockchainHeight() const; Q_INVOKABLE quint64 blockchainHeight() const;
Q_INVOKABLE quint64 blockchainTargetHeight() const; Q_INVOKABLE quint64 blockchainTargetHeight() const;
Q_INVOKABLE double miningHashRate() const;
Q_INVOKABLE bool localDaemonSynced() const; Q_INVOKABLE bool localDaemonSynced() const;
Q_INVOKABLE bool isDaemonLocal(const QString &daemon_address) 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 // QML missing such functionality, implementing these helpers here
Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const; Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const;
Q_INVOKABLE QUrl localPathToUrl(const QString &path) const; Q_INVOKABLE QUrl localPathToUrl(const QString &path) const;
@ -159,10 +145,9 @@ public:
Q_INVOKABLE QString resolveOpenAlias(const QString &address) const; 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<QString> &unknown_parameters, QString &error) const; Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const;
Q_INVOKABLE QVariantMap parse_uri_to_object(const QString &uri) 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 // 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); Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
virtual void onWalletPassphraseNeeded(bool on_device) override; virtual void onWalletPassphraseNeeded(bool on_device) override;
@ -171,7 +156,6 @@ public:
void setProxyAddress(QString address); void setProxyAddress(QString address);
signals: signals:
void walletOpened(Wallet * wallet); void walletOpened(Wallet * wallet);
void walletCreated(Wallet * wallet); void walletCreated(Wallet * wallet);
void walletPassphraseNeeded(bool onDevice); void walletPassphraseNeeded(bool onDevice);
@ -185,15 +169,12 @@ public slots:
private: private:
friend class WalletPassphraseListenerImpl; friend class WalletPassphraseListenerImpl;
explicit WalletManager(QObject *parent = 0); explicit WalletManager(QObject *parent = nullptr);
~WalletManager(); ~WalletManager() override;
bool isMining() const;
static WalletManager *m_instance; static WalletManager *m_instance;
Monero::WalletManager *m_pimpl; Monero::WalletManager *m_pimpl;
mutable QMutex m_mutex; mutable QMutex m_mutex;
QPointer<Wallet> m_currentWallet;
PassphraseReceiver *m_passphraseReceiver; PassphraseReceiver *m_passphraseReceiver;
QMutex m_mutex_passphraseReceiver; QMutex m_mutex_passphraseReceiver;
QString m_proxyAddress; QString m_proxyAddress;

View file

@ -7,8 +7,10 @@
#include <QtGui> #include <QtGui>
#include "config-feather.h" #include "config-feather.h"
#include "constants.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "cli.h" #include "cli.h"
#include "WindowManager.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
#include <windows.h> #include <windows.h>
@ -87,7 +89,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
QCommandLineOption bruteforceDictionairy(QStringList() << "bruteforce-dict", "Bruteforce dictionairy", "file"); QCommandLineOption bruteforceDictionairy(QStringList() << "bruteforce-dict", "Bruteforce dictionairy", "file");
parser.addOption(bruteforceDictionairy); parser.addOption(bruteforceDictionairy);
auto parsed = parser.parse(argv_); bool parsed = parser.parse(argv_);
if (!parsed) { if (!parsed) {
qCritical() << parser.errorText(); qCritical() << parser.errorText();
exit(1); exit(1);
@ -102,33 +104,15 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
bool bruteforcePassword = parser.isSet(bruteforcePasswordOption); bool bruteforcePassword = parser.isSet(bruteforcePasswordOption);
bool cliMode = exportContacts || exportTxHistory || bruteforcePassword; bool cliMode = exportContacts || exportTxHistory || bruteforcePassword;
if(cliMode) { // Setup networkType
QCoreApplication cli_app(argc, argv); if (stagenet)
QCoreApplication::setApplicationName("FeatherWallet"); constants::networkType = NetworkType::STAGENET;
else if (testnet)
auto *ctx = new AppContext(&parser); constants::networkType = NetworkType::TESTNET;
else
auto *cli = new CLI(ctx, &cli_app); constants::networkType = NetworkType::MAINNET;
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 QApplication
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
QApplication::setDesktopSettingsAware(true); // use system font QApplication::setDesktopSettingsAware(true); // use system font
@ -136,8 +120,67 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
QApplication app(argc, argv); QApplication app(argc, argv);
QApplication::setQuitOnLastWindowClosed(false);
QApplication::setApplicationName("FeatherWallet"); 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 parser.process(app); // Parse again for --help and --version
if (!quiet) { if (!quiet) {
@ -153,8 +196,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]); qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]);
} }
auto *ctx = new AppContext(&parser);
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
// For some odd reason, if we don't do this, QPushButton's // For some odd reason, if we don't do this, QPushButton's
// need to be clicked *twice* in order to fire ?! // need to be clicked *twice* in order to fire ?!
@ -166,6 +207,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
qInstallMessageHandler(Utils::applicationLogHandler); qInstallMessageHandler(Utils::applicationLogHandler);
qRegisterMetaType<QVector<QString>>(); qRegisterMetaType<QVector<QString>>();
new MainWindow(ctx); WindowManager windowManager;
return QApplication::exec(); return QApplication::exec();
} }

File diff suppressed because it is too large Load diff

View file

@ -36,9 +36,14 @@
#include "widgets/tickerwidget.h" #include "widgets/tickerwidget.h"
#include "wizard/WalletWizard.h" #include "wizard/WalletWizard.h"
#include "contactswidget.h"
#include "historywidget.h"
#include "sendwidget.h" #include "sendwidget.h"
#include "receivewidget.h"
#include "coinswidget.h" #include "coinswidget.h"
#include "WindowManager.h"
#ifdef HAS_LOCALMONERO #ifdef HAS_LOCALMONERO
#include "widgets/LocalMoneroWidget.h" #include "widgets/LocalMoneroWidget.h"
#endif #endif
@ -47,10 +52,6 @@
#include "widgets/xmrigwidget.h" #include "widgets/xmrigwidget.h"
#endif #endif
#ifdef Q_OS_MAC
#include "src/kdmactouchbar.h"
#endif
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
} }
@ -65,14 +66,19 @@ struct ToggleTab {
Config::ConfigKey configKey; Config::ConfigKey configKey;
}; };
class WindowManager;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr); explicit MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent = nullptr);
~MainWindow() override; ~MainWindow() override;
QString walletName();
QString walletCachePath();
QString walletKeysPath();
enum Tabs { enum Tabs {
HOME = 0, HOME = 0,
HISTORY, HISTORY,
@ -89,44 +95,29 @@ public:
REDDIT REDDIT
}; };
public slots: void showOrHide();
void showWizard(WalletWizard::Page startPage); void bringToFront();
signals:
void closed();
private slots:
// TODO: use a consistent naming convention for slots
// Menu
void menuOpenClicked();
void menuNewRestoreClicked(); void menuNewRestoreClicked();
void menuQuitClicked(); void menuQuitClicked();
void menuSettingsClicked(); void menuSettingsClicked();
void menuAboutClicked(); void menuAboutClicked();
void menuSignVerifyClicked(); void menuSignVerifyClicked();
void menuVerifyTxProof(); 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 menuWalletCloseClicked();
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); void menuTorClicked();
void onDeviceButtonRequest(quint64 code); void menuToggleTabVisible(const QString &key);
void onViewOnBlockExplorer(const QString &txid); void onExportHistoryCSV(bool checked);
void onResendTransaction(const QString &txid); void onExportContactsCSV(bool checked);
void importContacts(); void onCreateDesktopEntry(bool checked);
void showRestoreHeightDialog(); void onReportBug(bool checked);
void importTransaction();
void onDeviceError(const QString &error);
void menuHwDeviceClicked();
void onUpdatesAvailable(const QJsonObject &updates);
// offline tx signing // offline tx signing
void exportKeyImages(); void exportKeyImages();
@ -138,97 +129,99 @@ public slots:
void loadSignedTx(); void loadSignedTx();
void loadSignedTxFromText(); void loadSignedTxFromText();
// libwalletqt void onTorConnectionStateChanged(bool connected);
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<QString> &address);
void onTransactionCommitted(bool status, PendingTransaction *tx, const QStringList& txid);
signals:
void closed();
private slots:
void onInitialNetworkConfigured();
void onCheckUpdatesComplete(const QString &version, const QString &binaryFilename, const QString &hash, const QString &signer); 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 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 onSignedHashesReceived(QNetworkReply *reply, const QString &platformTag, const QString &version);
void onShowDonationNag(); void onShowDonationNag();
void onInitiateTransaction(); void onInitiateTransaction();
void onEndTransaction(); void onEndTransaction();
void onCustomRestoreHeightSet(int height); void onCustomRestoreHeightSet(int height);
void onWalletAboutToClose();
// Menu // libwalletqt
void onExportHistoryCSV(bool checked); void onBalanceUpdated(quint64 balance, quint64 spendable);
void onExportContactsCSV(bool checked); void onSynchronized();
void onCreateDesktopEntry(bool checked); void onWalletOpened();
void onReportBug(bool checked); void onConnectionStatusChanged(int status);
void onCreateTransactionError(const QString &message);
void onCreateTransactionSuccess(PendingTransaction *tx, const QVector<QString> &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: private:
void initSkins();
void initStatusBar(); void initStatusBar();
void initWidgets(); void initWidgets();
void initMenu(); void initMenu();
void initTray();
void initHome(); void initHome();
void initTouchBar();
void initWalletContext(); void initWalletContext();
void initWizard();
void startupWarning(); void startupWarning();
bool autoOpenWallet();
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void cleanupBeforeClose();
QString loadStylesheet(const QString &resource);
void saveGeo(); void saveGeo();
void restoreGeo(); void restoreGeo();
void showDebugInfo(); void showDebugInfo();
void showNodeExhaustedMessage(); void showNodeExhaustedMessage();
void showWSNodeExhaustedMessage(); void showWSNodeExhaustedMessage();
void createUnsignedTxDialog(UnsignedTransaction *tx); void createUnsignedTxDialog(UnsignedTransaction *tx);
void touchbarShowWizard();
void touchbarShowWallet();
void updatePasswordIcon(); void updatePasswordIcon();
void updateNetStats(); void updateNetStats();
void rescanSpent(); void rescanSpent();
void setStatusText(const QString &text, bool override = false, int timeout = 1000); void setStatusText(const QString &text, bool override = false, int timeout = 1000);
void showBalanceDialog(); void showBalanceDialog();
QString statusDots(); QString statusDots();
void bringToFront();
QString getPlatformTag(); QString getPlatformTag();
void displayWalletErrorMsg(const QString &err); void displayWalletErrorMsg(const QString &err);
QString getHardwareDevice(); QString getHardwareDevice();
void setTitle(bool mining); void setTitle(bool mining);
void donationNag();
WalletWizard *createWizard(WalletWizard::Page startPage); void updateRecentlyOpened(const QString &filename);
Ui::MainWindow *ui; Ui::MainWindow *ui;
AppContext *m_ctx; WindowManager *m_windowManager;
QSharedPointer<AppContext> m_ctx;
Settings *m_windowSettings = nullptr; Settings *m_windowSettings = nullptr;
CalcWindow *m_windowCalc = nullptr; CalcWindow *m_windowCalc = nullptr;
RestoreDialog *m_restoreDialog = nullptr; RestoreDialog *m_restoreDialog = nullptr;
XMRigWidget *m_xmrig = nullptr;
SplashDialog *m_splashDialog = nullptr; SplashDialog *m_splashDialog = nullptr;
XMRigWidget *m_xmrig = nullptr;
ContactsWidget *m_contactsWidget = nullptr;
HistoryWidget *m_historyWidget = nullptr;
SendWidget *m_sendWidget = nullptr; SendWidget *m_sendWidget = nullptr;
ReceiveWidget *m_receiveWidget = nullptr;
CoinsWidget *m_coinsWidget = nullptr; CoinsWidget *m_coinsWidget = nullptr;
#ifdef HAS_LOCALMONERO #ifdef HAS_LOCALMONERO
LocalMoneroWidget *m_localMoneroWidget = nullptr; LocalMoneroWidget *m_localMoneroWidget = nullptr;
#endif #endif
QSystemTrayIcon *m_trayIcon;
QMenu m_trayMenu;
QAction *m_trayActionCalc;
QAction *m_trayActionExit;
QAction *m_trayActionSend;
QAction *m_trayActionHistory;
QList<TickerWidget*> m_tickerWidgets; QList<TickerWidget*> m_tickerWidgets;
TickerWidget *m_balanceWidget; TickerWidget *m_balanceWidget;
@ -244,18 +237,8 @@ private:
StatusBarButton *m_statusBtnTor; StatusBarButton *m_statusBtnTor;
StatusBarButton *m_statusBtnHwDevice; StatusBarButton *m_statusBtnHwDevice;
#ifdef Q_OS_MAC
QAction *m_touchbarActionWelcome;
KDMacTouchBar *m_touchbar;
QList<QAction *> m_touchbarWalletItems;
QList<QAction *> m_touchbarWizardItems;
#endif
QSignalMapper *m_tabShowHideSignalMapper; QSignalMapper *m_tabShowHideSignalMapper;
QMap<QString, ToggleTab*> m_tabShowHideMapper; QMap<QString, ToggleTab*> m_tabShowHideMapper;
WalletWizard *m_wizard = nullptr;
QMap<QString, QString> m_skins;
QTimer m_updateBytes; QTimer m_updateBytes;
@ -266,8 +249,7 @@ private:
bool m_showDeviceError = false; bool m_showDeviceError = false;
QTimer m_txTimer; QTimer m_txTimer;
private slots: bool cleanedUp = false;
void menuToggleTabVisible(const QString &key);
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View file

@ -161,8 +161,8 @@
<property name="verticalSpacing"> <property name="verticalSpacing">
<number>9</number> <number>9</number>
</property> </property>
<item row="1" column="0"> <item row="0" column="0">
<widget class="HistoryWidget" name="historyWidget" native="true"/> <layout class="QVBoxLayout" name="historyWidgetLayout"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -208,14 +208,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="ContactsWidget" name="contactWidget" native="true"> <layout class="QVBoxLayout" name="contactsWidgetLayout"/>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -229,7 +222,7 @@
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_5"> <layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0"> <item row="0" column="0">
<widget class="ReceiveWidget" name="receiveWidget" native="true"/> <layout class="QVBoxLayout" name="receiveWidgetLayout"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -349,6 +342,14 @@
<property name="title"> <property name="title">
<string>File</string> <string>File</string>
</property> </property>
<widget class="QMenu" name="menuRecently_open">
<property name="title">
<string>Recently open</string>
</property>
</widget>
<addaction name="menuRecently_open"/>
<addaction name="actionOpen"/>
<addaction name="actionNew_Restore"/>
<addaction name="actionClose"/> <addaction name="actionClose"/>
<addaction name="actionQuit"/> <addaction name="actionQuit"/>
<addaction name="separator"/> <addaction name="separator"/>
@ -548,7 +549,7 @@
</action> </action>
<action name="actionClose"> <action name="actionClose">
<property name="text"> <property name="text">
<string>Close current wallet</string> <string>Close wallet</string>
</property> </property>
</action> </action>
<action name="actionVerifyTxProof"> <action name="actionVerifyTxProof">
@ -721,26 +722,29 @@
<string>Pay to many</string> <string>Pay to many</string>
</property> </property>
</action> </action>
<action name="actionOpen">
<property name="text">
<string>Open wallet</string>
</property>
</action>
<action name="actionNew_Restore">
<property name="text">
<string>New/Restore</string>
</property>
</action>
<action name="actionRecently_open">
<property name="text">
<string>Recently open</string>
</property>
</action>
<action name="actiont">
<property name="text">
<string>t</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>
<customwidget>
<class>ContactsWidget</class>
<extends>QWidget</extends>
<header>contactswidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ReceiveWidget</class>
<extends>QWidget</extends>
<header>receivewidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>HistoryWidget</class>
<extends>QWidget</extends>
<header>historywidget.h</header>
</customwidget>
<customwidget> <customwidget>
<class>CalcWidget</class> <class>CalcWidget</class>
<extends>QWidget</extends> <extends>QWidget</extends>

View file

@ -5,7 +5,7 @@
#include "CoinsInfo.h" #include "CoinsInfo.h"
#include "Coins.h" #include "Coins.h"
#include "ModelUtils.h" #include "ModelUtils.h"
#include "globals.h" #include "constants.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include "utils/Icons.h" #include "utils/Icons.h"
@ -182,9 +182,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
case Amount: case Amount:
{ {
if (role == Qt::UserRole) { 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: case Frozen:
return cInfo.frozen(); return cInfo.frozen();

View file

@ -4,7 +4,7 @@
#include "TransactionHistoryModel.h" #include "TransactionHistoryModel.h"
#include "TransactionHistory.h" #include "TransactionHistory.h"
#include "TransactionInfo.h" #include "TransactionInfo.h"
#include "globals.h" #include "constants.h"
#include "utils/config.h" #include "utils/config.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include "utils/Icons.h" #include "utils/Icons.h"
@ -147,7 +147,7 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
if (role == Qt::UserRole) { if (role == Qt::UserRole) {
return tInfo.balanceDelta(); 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; amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount;
return amount; return amount;
} }
@ -160,7 +160,7 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
if (usd_price == 0.0) if (usd_price == 0.0)
return QVariant("?"); return QVariant("?");
double usd_amount = usd_price * (tInfo.balanceDelta() / globals::cdiv); double usd_amount = usd_price * (tInfo.balanceDelta() / constants::cdiv);
if(this->preferredFiatSymbol != "USD") if(this->preferredFiatSymbol != "USD")
usd_amount = appData()->prices.convert("USD", this->preferredFiatSymbol, usd_amount); usd_amount = appData()->prices.convert("USD", this->preferredFiatSymbol, usd_amount);
if (role == Qt::UserRole) { if (role == Qt::UserRole) {

View file

@ -10,12 +10,31 @@
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
ReceiveWidget::ReceiveWidget(QWidget *parent) : ReceiveWidget::ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
QWidget(parent), : QWidget(parent)
ui(new Ui::ReceiveWidget) , ui(new Ui::ReceiveWidget)
, m_ctx(std::move(ctx))
{ {
ui->setupUi(this); 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 // header context menu
ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu); ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu);
m_headerMenu = new QMenu(this); m_headerMenu = new QMenu(this);
@ -40,29 +59,6 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) :
connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); 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() { void ReceiveWidget::copyAddress() {
QModelIndex index = ui->addresses->currentIndex(); QModelIndex index = ui->addresses->currentIndex();
ModelUtils::copyColumn(&index, SubaddressModel::Address); ModelUtils::copyColumn(&index, SubaddressModel::Address);
@ -103,7 +99,7 @@ void ReceiveWidget::showContextMenu(const QPoint &point) {
menu->addAction("Hide address", this, &ReceiveWidget::hideAddress); menu->addAction("Hide address", this, &ReceiveWidget::hideAddress);
} }
if (m_wallet->isHwBacked()) { if (m_ctx->wallet->isHwBacked()) {
menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice); menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice);
} }
@ -172,15 +168,13 @@ void ReceiveWidget::showAddress()
void ReceiveWidget::showOnDevice() { void ReceiveWidget::showOnDevice() {
Monero::SubaddressRow* row = this->currentEntry(); Monero::SubaddressRow* row = this->currentEntry();
if (!row) return; if (!row) return;
m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRowId(), ""); m_ctx->wallet->deviceShowAddressAsync(m_ctx->wallet->currentSubaddressAccount(), row->getRowId(), "");
} }
void ReceiveWidget::generateSubaddress() { void ReceiveWidget::generateSubaddress() {
if (!m_wallet) return; bool r = m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), "");
bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
if (!r) { 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() { QStringList ReceiveWidget::getHiddenAddresses() {
QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses"); QString data = m_ctx->wallet->getCacheAttribute("feather.hiddenaddresses");
return data.split(","); return data.split(",");
} }
@ -223,14 +217,14 @@ void ReceiveWidget::addHiddenAddress(const QString& address) {
hiddenAddresses.append(address); hiddenAddresses.append(address);
} }
QString data = hiddenAddresses.join(","); QString data = hiddenAddresses.join(",");
m_wallet->setCacheAttribute("feather.hiddenaddresses", data); m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
} }
void ReceiveWidget::removeHiddenAddress(const QString &address) { void ReceiveWidget::removeHiddenAddress(const QString &address) {
QStringList hiddenAddresses = this->getHiddenAddresses(); QStringList hiddenAddresses = this->getHiddenAddresses();
hiddenAddresses.removeAll(address); hiddenAddresses.removeAll(address);
QString data = hiddenAddresses.join(","); QString data = hiddenAddresses.join(",");
m_wallet->setCacheAttribute("feather.hiddenaddresses", data); m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
} }
Monero::SubaddressRow* ReceiveWidget::currentEntry() { Monero::SubaddressRow* ReceiveWidget::currentEntry() {

View file

@ -22,11 +22,9 @@ class ReceiveWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ReceiveWidget(QWidget *parent = nullptr); explicit ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void setModel(SubaddressModel * model, Wallet * wallet);
~ReceiveWidget() override; ~ReceiveWidget() override;
public slots: public slots:
void copyAddress(); void copyAddress();
void copyLabel(); void copyLabel();
@ -51,14 +49,13 @@ private slots:
private: private:
Ui::ReceiveWidget *ui; Ui::ReceiveWidget *ui;
QSharedPointer<AppContext> m_ctx;
QMenu *m_headerMenu; QMenu *m_headerMenu;
QAction *m_showFullAddressesAction; QAction *m_showFullAddressesAction;
QAction *m_showUsedAddressesAction; QAction *m_showUsedAddressesAction;
QAction *m_showTransactionsAction; QAction *m_showTransactionsAction;
Subaddress * m_subaddress;
SubaddressModel * m_model; SubaddressModel * m_model;
SubaddressProxyModel * m_proxyModel; SubaddressProxyModel * m_proxyModel;
Wallet * m_wallet;
void updateQrCode(); void updateQrCode();
void showQrCodeDialog(); void showQrCodeDialog();

View file

@ -5,13 +5,13 @@
#include "sendwidget.h" #include "sendwidget.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "ui_sendwidget.h" #include "ui_sendwidget.h"
#include "globals.h" #include "constants.h"
#include "utils/AppData.h" #include "utils/AppData.h"
SendWidget::SendWidget(AppContext *ctx, QWidget *parent) SendWidget::SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::SendWidget) , ui(new Ui::SendWidget)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -21,11 +21,10 @@ SendWidget::SendWidget(AppContext *ctx, QWidget *parent)
QValidator *validator = new QRegExpValidator(rx, this); QValidator *validator = new QRegExpValidator(rx, this);
ui->lineAmount->setValidator(validator); ui->lineAmount->setValidator(validator);
connect(m_ctx, &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction); connect(m_ctx.get(), &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction);
connect(m_ctx, &AppContext::endTransaction, this, &SendWidget::onEndTransaction); connect(m_ctx.get(), &AppContext::endTransaction, this, &SendWidget::onEndTransaction);
connect(m_ctx, &AppContext::openAliasResolved, this, &SendWidget::onOpenAliasResolved); connect(m_ctx.get(), &AppContext::openAliasResolved, this, &SendWidget::onOpenAliasResolved);
connect(m_ctx, &AppContext::openAliasResolveError, this, &SendWidget::onOpenAliasResolveError); connect(m_ctx.get(), &AppContext::openAliasResolveError, this, &SendWidget::onOpenAliasResolveError);
connect(m_ctx, &AppContext::walletClosed, this, &SendWidget::onWalletClosed);
connect(ui->btnSend, &QPushButton::clicked, this, &SendWidget::sendClicked); connect(ui->btnSend, &QPushButton::clicked, this, &SendWidget::sendClicked);
connect(ui->btnClear, &QPushButton::clicked, this, &SendWidget::clearClicked); 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" "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."); "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(); this->setupComboBox();
} }
@ -107,7 +106,7 @@ void SendWidget::fillAddress(const QString &address) {
} }
void SendWidget::sendClicked() { void SendWidget::sendClicked() {
if (!m_ctx->currentWallet->isConnected()) { if (!m_ctx->wallet->isConnected()) {
QMessageBox::warning(this, "Error", "Unable to create transaction:\n\n" QMessageBox::warning(this, "Error", "Unable to create transaction:\n\n"
"Wallet is not connected to a node.\n" "Wallet is not connected to a node.\n"
"Go to File -> Settings -> Node to manually connect to a node."); "Go to File -> Settings -> Node to manually connect to a node.");
@ -229,7 +228,7 @@ quint64 SendWidget::amount() {
double SendWidget::amountDouble() { double SendWidget::amountDouble() {
quint64 amount = this->amount(); quint64 amount = this->amount();
return amount / globals::cdiv; return amount / constants::cdiv;
} }
void SendWidget::onOpenAliasResolved(const QString &address, const QString &openAlias) { void SendWidget::onOpenAliasResolved(const QString &address, const QString &openAlias) {
@ -252,11 +251,6 @@ void SendWidget::payToMany() {
ui->lineAddress->payToMany(); ui->lineAddress->payToMany();
} }
void SendWidget::onWalletClosed() {
this->clearFields();
ui->btnSend->setEnabled(true);
}
void SendWidget::onInitiateTransaction() { void SendWidget::onInitiateTransaction() {
ui->btnSend->setEnabled(false); ui->btnSend->setEnabled(false);
} }

View file

@ -17,7 +17,7 @@ class SendWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit SendWidget(AppContext *ctx, QWidget *parent = nullptr); explicit SendWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
void fill(const CCSEntry &entry); void fill(const CCSEntry &entry);
void fill(const QString &address, const QString& description, double amount = 0); void fill(const QString &address, const QString& description, double amount = 0);
void fill(double amount); void fill(double amount);
@ -37,7 +37,6 @@ public slots:
void updateConversionLabel(); void updateConversionLabel();
void onOpenAliasResolveError(const QString &err); void onOpenAliasResolveError(const QString &err);
void onOpenAliasResolved(const QString &address, const QString &openAlias); void onOpenAliasResolved(const QString &address, const QString &openAlias);
void onWalletClosed();
void onPreferredFiatCurrencyChanged(); void onPreferredFiatCurrencyChanged();
void onInitiateTransaction(); void onInitiateTransaction();
@ -48,7 +47,7 @@ private:
double amountDouble(); double amountDouble();
Ui::SendWidget *ui; Ui::SendWidget *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
quint64 amount(); quint64 amount();
double conversionAmount(); double conversionAmount();
}; };

View file

@ -7,10 +7,10 @@
#include <QFileDialog> #include <QFileDialog>
Settings::Settings(AppContext *ctx, QWidget *parent) Settings::Settings(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::Settings) , ui(new Ui::Settings)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -89,11 +89,12 @@ Settings::Settings(AppContext *ctx, QWidget *parent)
// setup paths tab // setup paths tab
this->updatePaths(); this->updatePaths();
connect(ui->btn_browseDefaultWalletDir, &QPushButton::clicked, [this]{ connect(ui->btn_browseDefaultWalletDir, &QPushButton::clicked, [this]{
QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", m_ctx->defaultWalletDir, QFileDialog::ShowDirsOnly); QString walletDirOld = config()->get(Config::walletDirectory).toString();
if (walletDir.isEmpty()) return; QString walletDir = QFileDialog::getExistingDirectory(this, "Select wallet directory ", walletDirOld, QFileDialog::ShowDirsOnly);
m_ctx->defaultWalletDir = walletDir; if (walletDir.isEmpty())
return;
config()->set(Config::walletDirectory, walletDir); config()->set(Config::walletDirectory, walletDir);
ui->lineEdit_defaultWalletDir->setText(m_ctx->defaultWalletDir); ui->lineEdit_defaultWalletDir->setText(walletDir);
}); });
// Links tab // Links tab
@ -110,7 +111,7 @@ Settings::Settings(AppContext *ctx, QWidget *parent)
} }
void Settings::updatePaths() { 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_configDir->setText(Config::defaultConfigDir().path());
ui->lineEdit_applicationDir->setText(QCoreApplication::applicationDirPath()); ui->lineEdit_applicationDir->setText(QCoreApplication::applicationDirPath());
} }

View file

@ -20,7 +20,7 @@ class Settings : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit Settings(AppContext *ctx, QWidget *parent = nullptr); explicit Settings(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~Settings() override; ~Settings() override;
signals: signals:
@ -50,7 +50,7 @@ private:
void setupLocalMoneroFrontendCombobox(); void setupLocalMoneroFrontendCombobox();
Ui::Settings *ui; Ui::Settings *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"}; QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"}; QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"};

View file

@ -9,6 +9,7 @@
#include <QRegularExpression> #include <QRegularExpression>
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/tails.h"
#include "appcontext.h" #include "appcontext.h"
#include "config-feather.h" #include "config-feather.h"

View file

@ -8,7 +8,7 @@
#include <QWebSocket> #include <QWebSocket>
#include <QTimer> #include <QTimer>
#include <QPointer> #include <QPointer>
#include "globals.h" #include "constants.h"
class WebsocketClient : public QObject { class WebsocketClient : public QObject {
Q_OBJECT Q_OBJECT
@ -36,7 +36,7 @@ private slots:
private: private:
bool m_connect = false; bool m_connect = false;
QUrl m_url = globals::websocketUrl; QUrl m_url = constants::websocketUrl;
QTimer m_connectionTimer; QTimer m_connectionTimer;
QTimer m_pingTimer; QTimer m_pingTimer;
}; };

View file

@ -20,6 +20,8 @@ QPointer<WebsocketNotifier> WebsocketNotifier::m_instance(nullptr);
void WebsocketNotifier::onWSMessage(const QJsonObject &msg) { void WebsocketNotifier::onWSMessage(const QJsonObject &msg) {
QString cmd = msg.value("cmd").toString(); QString cmd = msg.value("cmd").toString();
m_cache[cmd] = msg;
if (cmd == "blockheights") { if (cmd == "blockheights") {
QJsonObject data = msg.value("data").toObject(); QJsonObject data = msg.value("data").toObject();
int mainnet = data.value("mainnet").toInt(); int mainnet = data.value("mainnet").toInt();
@ -84,6 +86,12 @@ void WebsocketNotifier::onWSMessage(const QJsonObject &msg) {
#endif #endif
} }
void WebsocketNotifier::emitCache() {
for (const auto &msg : m_cache) {
this->onWSMessage(msg);
}
}
void WebsocketNotifier::onWSNodes(const QJsonArray &nodes) { void WebsocketNotifier::onWSNodes(const QJsonArray &nodes) {
// TODO: Refactor, should be filtered client side // TODO: Refactor, should be filtered client side
@ -93,7 +101,7 @@ void WebsocketNotifier::onWSNodes(const QJsonArray &nodes) {
auto nettype = obj.value("nettype"); auto nettype = obj.value("nettype");
auto type = obj.value("type"); auto type = obj.value("type");
auto networkType = config()->get(Config::networkType).toInt(); auto networkType = constants::networkType;
// filter remote node network types // filter remote node network types
if(nettype == "mainnet" && networkType != NetworkType::MAINNET) if(nettype == "mainnet" && networkType != NetworkType::MAINNET)

View file

@ -22,10 +22,10 @@ public:
explicit WebsocketNotifier(QObject *parent); explicit WebsocketNotifier(QObject *parent);
QMap<NetworkType::Type, int> heights; QMap<NetworkType::Type, int> heights;
WebsocketClient websocketClient; WebsocketClient websocketClient;
static WebsocketNotifier* instance(); static WebsocketNotifier* instance();
void emitCache();
signals: signals:
void BlockHeightsReceived(int mainnet, int stagenet); void BlockHeightsReceived(int mainnet, int stagenet);
@ -52,6 +52,8 @@ private slots:
private: private:
static QPointer<WebsocketNotifier> m_instance; static QPointer<WebsocketNotifier> m_instance;
QHash<QString, QJsonObject> m_cache;
}; };
inline WebsocketNotifier* websocketNotifier() inline WebsocketNotifier* websocketNotifier()

View file

@ -17,49 +17,62 @@ struct ConfigDirective
static const QHash<Config::ConfigKey, ConfigDirective> configStrings = { static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
// General // General
{Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, {Config::firstRun, {QS("firstRun"), true}},
{Config::checkForUpdates,{QS("checkForUpdates"), true}},
{Config::warnOnStagenet,{QS("warnOnStagenet"), true}}, {Config::warnOnStagenet,{QS("warnOnStagenet"), true}},
{Config::warnOnTestnet,{QS("warnOnTestnet"), true}}, {Config::warnOnTestnet,{QS("warnOnTestnet"), true}},
{Config::warnOnAlpha,{QS("warnOnAlpha"), true}}, {Config::warnOnAlpha,{QS("warnOnAlpha"), true}},
{Config::homeWidget,{QS("homeWidget"), "ccs"}}, {Config::homeWidget,{QS("homeWidget"), "ccs"}},
{Config::donateBeg,{QS("donateBeg"), 1}}, {Config::donateBeg,{QS("donateBeg"), 1}},
{Config::skin,{QS("skin"), "light"}}, {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
{Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}},
{Config::blockExplorer,{QS("blockExplorer"), "exploremonero.com"}}, {Config::geometry, {QS("geometry"), {}}},
{Config::windowState, {QS("windowState"), {}}},
{Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}},
// Wallets
{Config::walletDirectory,{QS("walletDirectory"), ""}}, {Config::walletDirectory,{QS("walletDirectory"), ""}},
{Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}}, {Config::autoOpenWalletPath,{QS("autoOpenWalletPath"), ""}},
{Config::walletPath,{QS("walletPath"), ""}}, {Config::recentlyOpenedWallets, {QS("recentlyOpenedWallets"), {}}},
{Config::xmrigPath,{QS("xmrigPath"), ""}},
{Config::xmrigPool,{QS("xmrigPool"), "pool.xmr.pt:9000"}}, // Nodes
{Config::nodes,{QS("nodes"), "{}"}}, {Config::nodes,{QS("nodes"), "{}"}},
{Config::websocketEnabled,{QS("websocketEnabled"), true}},
{Config::nodeSource,{QS("nodeSource"), 0}}, {Config::nodeSource,{QS("nodeSource"), 0}},
{Config::useOnionNodes,{QS("useOnionNodes"), false}}, {Config::useOnionNodes,{QS("useOnionNodes"), false}},
// Tabs
{Config::showTabHome,{QS("showTabHome"), true}}, {Config::showTabHome,{QS("showTabHome"), true}},
{Config::showTabCoins,{QS("showTabCoins"), false}}, {Config::showTabCoins,{QS("showTabCoins"), false}},
{Config::showTabExchange, {QS("showTabExchange"), false}}, {Config::showTabExchange, {QS("showTabExchange"), false}},
{Config::showTabXMRig,{QS("showTabXMRig"), false}}, {Config::showTabXMRig,{QS("showTabXMRig"), false}},
{Config::showTabCalc,{QS("showTabCalc"), true}}, {Config::showTabCalc,{QS("showTabCalc"), true}},
{Config::geometry, {QS("geometry"), {}}},
{Config::windowState, {QS("windowState"), {}}}, // Mining
{Config::firstRun, {QS("firstRun"), true}}, {Config::xmrigPath,{QS("xmrigPath"), ""}},
{Config::hideBalance, {QS("hideBalance"), false}}, {Config::xmrigPool,{QS("xmrigPool"), "pool.xmr.pt:9000"}},
{Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}},
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}}, // Settings
{Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}}, {Config::preferredFiatCurrency,{QS("preferredFiatCurrency"), "USD"}},
{Config::skin,{QS("skin"), "light"}},
{Config::amountPrecision, {QS("amountPrecision"), 12}}, {Config::amountPrecision, {QS("amountPrecision"), 12}},
{Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}}, {Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}},
{Config::timeFormat, {QS("timeFormat"), "HH:mm"}}, {Config::timeFormat, {QS("timeFormat"), "HH:mm"}},
{Config::multiBroadcast, {QS("multiBroadcast"), true}}, {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::torPrivacyLevel, {QS("torPrivacyLevel"), 1}},
{Config::socks5Host, {QS("socks5Host"), "127.0.0.1"}}, {Config::socks5Host, {QS("socks5Host"), "127.0.0.1"}},
{Config::socks5Port, {QS("socks5Port"), "9050"}}, {Config::socks5Port, {QS("socks5Port"), "9050"}},
{Config::socks5User, {QS("socks5User"), ""}}, {Config::socks5User, {QS("socks5User"), ""}}, // Unused
{Config::socks5Pass, {QS("socks5Pass"), ""}}, {Config::socks5Pass, {QS("socks5Pass"), ""}}, // Unused
{Config::useLocalTor, {QS("useLocalTor"), false}}, {Config::useLocalTor, {QS("useLocalTor"), false}}
{Config::networkType, {QS("networkType"), NetworkType::Type::MAINNET}},
{Config::localMoneroFrontend, {QS("localMoneroFrontend"), "https://localmonero.co"}}
}; };

View file

@ -20,50 +20,56 @@ public:
enum ConfigKey enum ConfigKey
{ {
warnOnExternalLink, firstRun,
checkForUpdates,
warnOnStagenet, warnOnStagenet,
warnOnTestnet, warnOnTestnet,
warnOnAlpha, warnOnAlpha,
homeWidget, homeWidget,
donateBeg, donateBeg,
showHistorySyncNotice,
geometry,
windowState,
GUI_HistoryViewState,
walletDirectory, // Directory where wallet files are stored
autoOpenWalletPath, autoOpenWalletPath,
skin, recentlyOpenedWallets,
preferredFiatCurrency,
blockExplorer,
walletDirectory,
walletPath,
xmrigPath,
xmrigPool,
nodes, nodes,
websocketEnabled,
nodeSource, nodeSource,
useOnionNodes, useOnionNodes,
showTabHome, showTabHome,
showTabCoins, showTabCoins,
showTabExchange, showTabExchange,
showTabCalc, showTabCalc,
showTabXMRig, showTabXMRig,
geometry,
windowState, xmrigPath,
firstRun, xmrigPool,
hideBalance,
redditFrontend, preferredFiatCurrency,
showHistorySyncNotice, skin,
GUI_HistoryViewState,
amountPrecision, amountPrecision,
portableMode,
dateFormat, dateFormat,
timeFormat, timeFormat,
multiBroadcast, multiBroadcast,
warnOnExternalLink,
hideBalance,
blockExplorer,
redditFrontend,
localMoneroFrontend,
torPrivacyLevel, torPrivacyLevel,
socks5Host, socks5Host,
socks5Port, socks5Port,
socks5User, socks5User,
socks5Pass, socks5Pass,
useLocalTor, // Prevents Feather from starting bundled Tor daemon useLocalTor, // Prevents Feather from starting bundled Tor daemon
networkType,
localMoneroFrontend
}; };
enum PrivacyLevel { enum PrivacyLevel {

View file

@ -1,18 +1,10 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2021, The Monero Project. // Copyright (c) 2014-2021, The Monero Project.
#include <QFile> #include "keysfiles.h"
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QUrl>
#include <QtConcurrent/QtConcurrent>
#include "appcontext.h"
using namespace std::chrono; using namespace std::chrono;
WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) : WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) :
m_fileName(info.fileName()), m_fileName(info.fileName()),
m_modified(info.lastModified().toSecsSinceEpoch()), m_modified(info.lastModified().toSecsSinceEpoch()),
@ -47,9 +39,8 @@ int WalletKeysFiles::networkType() const {
return m_networkType; return m_networkType;
} }
WalletKeysFilesModel::WalletKeysFilesModel(AppContext *ctx, QObject *parent) WalletKeysFilesModel::WalletKeysFilesModel(QObject *parent)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
, m_ctx(ctx)
{ {
this->updateDirectories(); this->updateDirectories();
this->m_walletKeysFilesItemModel = qobject_cast<QAbstractItemModel *>(this); this->m_walletKeysFilesItemModel = qobject_cast<QAbstractItemModel *>(this);
@ -67,20 +58,15 @@ void WalletKeysFilesModel::refresh() {
endResetModel(); endResetModel();
} }
void WalletKeysFilesModel::updateDirectories() { void WalletKeysFilesModel::updateDirectories() { // TODO
this->walletDirectories.clear(); this->walletDirectories.clear();
QDir defaultWalletDir = QDir(Utils::defaultWalletDir()); QDir defaultWalletDir = QDir(Utils::defaultWalletDir());
QString walletDir = defaultWalletDir.path(); QString walletDir = defaultWalletDir.path();
defaultWalletDir.cdUp(); defaultWalletDir.cdUp();
QString walletDirRoot = defaultWalletDir.path(); QString walletDirRoot = defaultWalletDir.path();
this->walletDirectories << walletDir; this->walletDirectories << walletDir;
this->walletDirectories << walletDirRoot; 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 << QDir::homePath();
this->walletDirectories.removeDuplicates(); this->walletDirectories.removeDuplicates();
} }

View file

@ -38,7 +38,7 @@ public:
Modified Modified
}; };
explicit WalletKeysFilesModel(AppContext *ctx, QObject *parent = nullptr); explicit WalletKeysFilesModel(QObject *parent = nullptr);
Q_INVOKABLE void refresh(); Q_INVOKABLE void refresh();
Q_INVOKABLE void clear(); Q_INVOKABLE void clear();
@ -55,7 +55,6 @@ public:
private: private:
void updateDirectories(); void updateDirectories();
AppContext *m_ctx;
QList<WalletKeysFiles> m_walletKeyFiles; QList<WalletKeysFiles> m_walletKeyFiles;
QAbstractItemModel *m_walletKeysFilesItemModel; QAbstractItemModel *m_walletKeysFilesItemModel;
QSortFilterProxyModel m_walletKeysFilesModelProxy; QSortFilterProxyModel m_walletKeysFilesModelProxy;

View file

@ -5,7 +5,83 @@
#include "nodes.h" #include "nodes.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/tails.h"
#include "appcontext.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) Nodes::Nodes(AppContext *ctx, QObject *parent)
: QObject(parent) : QObject(parent)
@ -16,32 +92,13 @@ Nodes::Nodes(AppContext *ctx, QObject *parent)
{ {
this->loadConfig(); this->loadConfig();
connect(m_ctx, &AppContext::walletRefreshed, this, &Nodes::onWalletRefreshed); connect(m_ctx, &AppContext::walletRefreshed, this, &Nodes::onWalletRefreshed);
connect(websocketNotifier(), &WebsocketNotifier::NodesReceived, this, &Nodes::onWSNodesReceived);
} }
void Nodes::loadConfig() { void Nodes::loadConfig() {
auto configNodes = config()->get(Config::nodes).toByteArray(); QStringList customNodes = m_nodes.getNodes(constants::networkType, NodeList::custom);
auto key = QString::number(m_ctx->networkType); for (const auto &node : customNodes) {
if (!Utils::validateJSON(configNodes)) { FeatherNode customNode{node};
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());
customNode.custom = true; customNode.custom = true;
if (m_connection == customNode) { if (m_connection == customNode) {
@ -54,10 +111,9 @@ void Nodes::loadConfig() {
m_customNodes.append(customNode); m_customNodes.append(customNode);
} }
// load cached websocket nodes QStringList websocketNodes = m_nodes.getNodes(constants::networkType, NodeList::ws);
auto ws = obj.value("ws").toArray(); for (const auto &node : websocketNodes) {
for (auto value: ws) { FeatherNode wsNode{node};
auto wsNode = FeatherNode(value.toString());
wsNode.custom = false; wsNode.custom = false;
wsNode.online = true; // assume online wsNode.online = true; // assume online
@ -86,9 +142,9 @@ void Nodes::loadConfig() {
QJsonObject nodes_obj = nodes_json.object(); QJsonObject nodes_obj = nodes_json.object();
QString netKey; QString netKey;
if (m_ctx->networkType == NetworkType::MAINNET) { if (constants::networkType == NetworkType::MAINNET) {
netKey = "mainnet"; netKey = "mainnet";
} else if (m_ctx->networkType == NetworkType::STAGENET) { } else if (constants::networkType == NetworkType::STAGENET) {
netKey = "stagenet"; netKey = "stagenet";
} }
@ -96,30 +152,22 @@ void Nodes::loadConfig() {
QJsonArray nodes_list; QJsonArray nodes_list;
nodes_list = nodes_json[netKey].toObject()["tor"].toArray(); nodes_list = nodes_json[netKey].toObject()["tor"].toArray();
nodes_list.append(nodes_list = nodes_json[netKey].toObject()["clearnet"].toArray()); nodes_list.append(nodes_list = nodes_json[netKey].toObject()["clearnet"].toArray());
for (auto node: nodes_list) { for (auto node: nodes_list) {
auto wsNode = FeatherNode(node.toString()); FeatherNode wsNode(node.toString());
wsNode.custom = false; wsNode.custom = false;
wsNode.online = true; wsNode.online = true;
m_websocketNodes.append(wsNode); 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()); qDebug() << QString("Loaded %1 nodes from hardcoded list").arg(m_websocketNodes.count());
} }
m_configJson[key] = obj;
this->writeConfig();
this->updateModels(); 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() { void Nodes::connectToNode() {
// auto connect // auto connect
m_wsExhaustedWarningEmitted = false; 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"); 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()) 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 // Don't use SSL over Tor
m_ctx->currentWallet->setUseSSL(!node.isOnion()); m_ctx->wallet->setUseSSL(!node.isOnion());
QString proxyAddress; QString proxyAddress;
if (useTorProxy(node)) { 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 = node;
m_connection.isActive = false; m_connection.isActive = false;
@ -162,11 +210,11 @@ void Nodes::connectToNode(const FeatherNode &node) {
void Nodes::autoConnect(bool forceReconnect) { void Nodes::autoConnect(bool forceReconnect) {
// this function is responsible for automatically connecting to a daemon. // 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; return;
} }
Wallet::ConnectionStatus status = m_ctx->currentWallet->connectionStatus(); Wallet::ConnectionStatus status = m_ctx->wallet->connectionStatus();
bool wsMode = (this->source() == NodeSource::websocket); bool wsMode = (this->source() == NodeSource::websocket);
if (wsMode && !m_wsNodesReceived && websocketNodes().count() == 0) { if (wsMode && !m_wsNodesReceived && websocketNodes().count() == 0) {
@ -276,15 +324,12 @@ void Nodes::onWSNodesReceived(QList<FeatherNode> &nodes) {
} }
// cache into config // cache into config
auto key = QString::number(m_ctx->networkType); QStringList wsNodeList;
auto obj = m_configJson.value(key).toObject(); for (const auto &node : m_websocketNodes) {
auto ws = QJsonArray(); wsNodeList << node.toAddress();
for (auto const &node: m_websocketNodes) }
ws.push_back(node.toAddress()); m_nodes.setNodes(wsNodeList, constants::networkType, NodeList::ws);
obj["ws"] = ws;
m_configJson[key] = obj;
this->writeConfig();
this->resetLocalState(); this->resetLocalState();
this->updateModels(); this->updateModels();
} }
@ -297,20 +342,17 @@ void Nodes::onNodeSourceChanged(NodeSource nodeSource) {
void Nodes::setCustomNodes(const QList<FeatherNode> &nodes) { void Nodes::setCustomNodes(const QList<FeatherNode> &nodes) {
m_customNodes.clear(); m_customNodes.clear();
auto key = QString::number(m_ctx->networkType);
auto obj = m_configJson.value(key).toObject();
QStringList nodesList; QStringList nodesList;
for (auto const &node: nodes) { for (auto const &node: nodes) {
if (nodesList.contains(node.toAddress())) continue; if (nodesList.contains(node.toAddress())) // skip duplicates
continue;
nodesList.append(node.toAddress()); nodesList.append(node.toAddress());
m_customNodes.append(node); m_customNodes.append(node);
} }
auto arr = QJsonArray::fromStringList(nodesList); m_nodes.setNodes(nodesList, constants::networkType, NodeList::Type::custom);
obj["custom"] = arr;
m_configJson[key] = obj;
this->writeConfig();
this->resetLocalState(); this->resetLocalState();
this->updateModels(); this->updateModels();
} }

View file

@ -20,6 +20,24 @@ enum NodeSource {
custom 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 { struct FeatherNode {
explicit FeatherNode(QString address = "", int height = 0, int target_height = 0, bool online = false) explicit FeatherNode(QString address = "", int height = 0, int target_height = 0, bool online = false)
: height(height) : height(height)
@ -92,7 +110,6 @@ class Nodes : public QObject {
public: public:
explicit Nodes(AppContext *ctx, QObject *parent = nullptr); explicit Nodes(AppContext *ctx, QObject *parent = nullptr);
void loadConfig(); void loadConfig();
void writeConfig();
NodeSource source(); NodeSource source();
FeatherNode connection(); FeatherNode connection();
@ -122,9 +139,11 @@ private slots:
void onWalletRefreshed(); void onWalletRefreshed();
private: private:
AppContext *m_ctx = nullptr; AppContext *m_ctx;
QJsonObject m_configJson; QJsonObject m_configJson;
NodeList m_nodes;
QStringList m_recentFailures; QStringList m_recentFailures;
QList<FeatherNode> m_customNodes; QList<FeatherNode> m_customNodes;

View file

@ -15,7 +15,7 @@
#include "utils/tails.h" #include "utils/tails.h"
#include "utils/whonix.h" #include "utils/whonix.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include "globals.h" #include "constants.h"
QByteArray Utils::fileGetContents(const QString &path) QByteArray Utils::fileGetContents(const QString &path)
{ {
@ -454,7 +454,7 @@ int Utils::maxLength(const QVector<QString> &array) {
} }
QString Utils::balanceFormat(quint64 balance) { 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("0+$"));
str.remove(QRegExp("\\.$")); str.remove(QRegExp("\\.$"));

View file

@ -7,6 +7,7 @@
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/xmrig.h" #include "utils/xmrig.h"
#include "utils/TorManager.h"
#include "appcontext.h" #include "appcontext.h"
XmRig::XmRig(const QString &configDir, QObject *parent) XmRig::XmRig(const QString &configDir, QObject *parent)

View file

@ -12,10 +12,10 @@
#include <QMessageBox> #include <QMessageBox>
#include <QMenu> #include <QMenu>
LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, AppContext *ctx) LocalMoneroWidget::LocalMoneroWidget(QWidget *parent, QSharedPointer<AppContext> ctx)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::LocalMoneroWidget) , ui(new Ui::LocalMoneroWidget)
, m_ctx(ctx) , m_ctx(std::move(ctx))
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -19,7 +19,7 @@ class LocalMoneroWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit LocalMoneroWidget(QWidget *parent, AppContext *ctx); explicit LocalMoneroWidget(QWidget *parent, QSharedPointer<AppContext> ctx);
~LocalMoneroWidget() override; ~LocalMoneroWidget() override;
public slots: public slots:
@ -45,7 +45,7 @@ private:
Ui::LocalMoneroWidget *ui; Ui::LocalMoneroWidget *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
LocalMoneroApi *m_api; LocalMoneroApi *m_api;
LocalMoneroModel *m_model; LocalMoneroModel *m_model;
UtilsNetworking *m_network; UtilsNetworking *m_network;

View file

@ -156,7 +156,7 @@ void NodeWidget::onCustomAddClicked(){
m_ctx->nodes->setCustomNodes(nodesList); m_ctx->nodes->setCustomNodes(nodesList);
} }
void NodeWidget::setupUI(AppContext *ctx) { void NodeWidget::setupUI(QSharedPointer<AppContext> ctx) {
m_ctx = ctx; m_ctx = ctx;
auto nodeSource = m_ctx->nodes->source(); auto nodeSource = m_ctx->nodes->source();

View file

@ -25,7 +25,7 @@ public:
~NodeWidget(); ~NodeWidget();
void setWSModel(NodeModel *model); void setWSModel(NodeModel *model);
void setCustomModel(NodeModel *model); void setCustomModel(NodeModel *model);
void setupUI(AppContext *ctx); void setupUI(QSharedPointer<AppContext> ctx);
NodeModel* model(); NodeModel* model();
public slots: public slots:
@ -44,7 +44,7 @@ signals:
void nodeSourceChanged(NodeSource nodeSource); void nodeSourceChanged(NodeSource nodeSource);
private: private:
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
Ui::NodeWidget *ui; Ui::NodeWidget *ui;
NodeModel* m_customModel; NodeModel* m_customModel;
NodeModel* m_wsModel; NodeModel* m_wsModel;

View file

@ -8,9 +8,9 @@
#include "restoreheightwidget.h" #include "restoreheightwidget.h"
#include "ui_restoreheightwidget.h" #include "ui_restoreheightwidget.h"
RestoreHeightWidget::RestoreHeightWidget(QWidget *parent) : RestoreHeightWidget::RestoreHeightWidget(QWidget *parent)
QWidget(parent), : QWidget(parent)
ui(new Ui::RestoreHeightWidget) , ui(new Ui::RestoreHeightWidget)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->lineEdit_restoreHeight->setValidator(new QIntValidator(0, 2147483647, this)); ui->lineEdit_restoreHeight->setValidator(new QIntValidator(0, 2147483647, this));

View file

@ -4,16 +4,16 @@
#include "tickerwidget.h" #include "tickerwidget.h"
#include "ui_tickerwidget.h" #include "ui_tickerwidget.h"
#include "globals.h" #include "constants.h"
#include "utils/AppData.h" #include "utils/AppData.h"
TickerWidget::TickerWidget(QWidget *parent, AppContext *ctx, QString symbol, QString title, bool convertBalance, bool hidePercent) : TickerWidget::TickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol, QString title, bool convertBalance, bool hidePercent)
QWidget(parent), : QWidget(parent)
ui(new Ui::TickerWidget), , ui(new Ui::TickerWidget)
m_ctx(ctx), , m_ctx(std::move(ctx))
m_symbol(std::move(symbol)), , m_symbol(std::move(symbol))
m_convertBalance(convertBalance), , m_convertBalance(convertBalance)
m_hidePercent(hidePercent) , m_hidePercent(hidePercent)
{ {
ui->setupUi(this); 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::fiatPricesUpdated, this, &TickerWidget::init);
connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init); connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &TickerWidget::init);
if (convertBalance) if (convertBalance)
connect(m_ctx, &AppContext::balanceUpdated, this, &TickerWidget::init); connect(m_ctx.get(), &AppContext::balanceUpdated, this, &TickerWidget::init);
} }
void TickerWidget::init() { void TickerWidget::init() {
@ -46,7 +47,7 @@ void TickerWidget::init() {
return; 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 amount = m_convertBalance ? walletBalance : 1.0;
double conversion = appData()->prices.convert(m_symbol, fiatCurrency, amount); double conversion = appData()->prices.convert(m_symbol, fiatCurrency, amount);

View file

@ -17,7 +17,7 @@ class TickerWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit TickerWidget(QWidget *parent, AppContext *ctx, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false); explicit TickerWidget(QWidget *parent, QSharedPointer<AppContext> ctx, QString symbol, QString title = "", bool convertBalance = false, bool hidePercent = false);
void setFiatText(QString &fiatCurrency, double amount); void setFiatText(QString &fiatCurrency, double amount);
void setPctText(QString &text, bool positive); void setPctText(QString &text, bool positive);
void setFontSizes(); void setFontSizes();
@ -29,7 +29,7 @@ public slots:
private: private:
Ui::TickerWidget *ui; Ui::TickerWidget *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
QString m_symbol; QString m_symbol;
bool m_convertBalance; bool m_convertBalance;
bool m_hidePercent; bool m_hidePercent;

View file

@ -12,10 +12,10 @@
#include "ui_xmrigwidget.h" #include "ui_xmrigwidget.h"
#include "utils/Icons.h" #include "utils/Icons.h"
XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent) XMRigWidget::XMRigWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::XMRigWidget) , ui(new Ui::XMRigWidget)
, m_ctx(ctx) , m_ctx(std::move(ctx))
, m_XMRig(new XmRig(Config::defaultConfigDir().path())) , m_XMRig(new XmRig(Config::defaultConfigDir().path()))
, m_model(new QStandardItemModel(this)) , m_model(new QStandardItemModel(this))
, m_contextMenu(new QMenu(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::error, this, &XMRigWidget::onProcessError);
connect(m_XMRig, &XmRig::hashrate, this, &XMRigWidget::onHashrate); 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 // table
ui->tableView->setModel(this->m_model); ui->tableView->setModel(this->m_model);
m_contextMenu->addAction(icons()->icon("network.png"), "Download file", this, &XMRigWidget::linkClicked); m_contextMenu->addAction(icons()->icon("network.png"), "Download file", this, &XMRigWidget::linkClicked);
@ -92,16 +89,30 @@ XMRigWidget::XMRigWidget(AppContext *ctx, QWidget *parent)
// username/password // username/password
connect(ui->lineEdit_password, &QLineEdit::editingFinished, [=]() { 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(); m_ctx->storeWallet();
}); });
connect(ui->lineEdit_address, &QLineEdit::editingFinished, [=]() { 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(); m_ctx->storeWallet();
}); });
// checkbox connects // checkbox connects
connect(ui->check_solo, &QCheckBox::stateChanged, this, &XMRigWidget::onSoloChecked); 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() { void XMRigWidget::onWalletClosed() {
@ -111,22 +122,6 @@ void XMRigWidget::onWalletClosed() {
ui->lineEdit_address->setText(""); 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) { void XMRigWidget::onThreadsValueChanged(int threads) {
m_threads = threads; m_threads = threads;
ui->label_threads->setText(QString("CPU threads: %1").arg(m_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(); xmrigPath = config()->get(Config::xmrigPath).toString();
// username is receiving address usually // username is receiving address usually
auto username = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_username"); auto username = m_ctx->wallet->getCacheAttribute("feather.xmrig_username");
auto password = m_ctx->currentWallet->getCacheAttribute("feather.xmrig_password"); auto password = m_ctx->wallet->getCacheAttribute("feather.xmrig_password");
if(username.isEmpty()) { if(username.isEmpty()) {
QString err = "Please specify a receiving address on the Settings screen"; 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(".")) { if(address.contains("cryptonote.social") && !username.contains(".")) {
// cryptonote social requires <addr>.<username>, we'll just grab a few chars from primary addy // cryptonote social requires <addr>.<username>, 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()); m_XMRig->start(xmrigPath, m_threads, address, username, password, ui->relayTor->isChecked(), ui->check_tls->isChecked());

View file

@ -21,13 +21,12 @@ class XMRigWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit XMRigWidget(AppContext *ctx, QWidget *parent = nullptr); explicit XMRigWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
~XMRigWidget() override; ~XMRigWidget() override;
QStandardItemModel *model(); QStandardItemModel *model();
public slots: public slots:
void onWalletClosed(); void onWalletClosed();
void onWalletOpened();
void onStartClicked(); void onStartClicked();
void onStopClicked(); void onStopClicked();
void onClearClicked(); void onClearClicked();
@ -51,7 +50,7 @@ private:
void showContextMenu(const QPoint &pos); void showContextMenu(const QPoint &pos);
Ui::XMRigWidget *ui; Ui::XMRigWidget *ui;
AppContext *m_ctx; QSharedPointer<AppContext> m_ctx;
XmRig * m_XMRig; XmRig * m_XMRig;
QStandardItemModel *m_model; QStandardItemModel *m_model;
QMenu *m_contextMenu; QMenu *m_contextMenu;

View file

@ -7,10 +7,9 @@
#include <QMessageBox> #include <QMessageBox>
PageHardwareDevice::PageHardwareDevice(AppContext *ctx, WizardFields *fields, QWidget *parent) PageHardwareDevice::PageHardwareDevice(WizardFields *fields, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageHardwareDevice) , ui(new Ui::PageHardwareDevice)
, m_ctx(ctx)
, m_fields(fields) , m_fields(fields)
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -21,7 +21,7 @@ class PageHardwareDevice : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageHardwareDevice(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); explicit PageHardwareDevice(WizardFields *fields, QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -29,7 +29,6 @@ public:
private: private:
Ui::PageHardwareDevice *ui; Ui::PageHardwareDevice *ui;
AppContext *m_ctx;
WizardFields *m_fields; WizardFields *m_fields;
}; };

View file

@ -7,10 +7,9 @@
#include <QFileDialog> #include <QFileDialog>
PageMenu::PageMenu(AppContext *ctx, WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent) PageMenu::PageMenu(WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageMenu) , ui(new Ui::PageMenu)
, m_ctx(ctx)
, m_walletKeysFilesModel(wallets) , m_walletKeysFilesModel(wallets)
, m_fields(fields) , m_fields(fields)
{ {

View file

@ -19,7 +19,7 @@ class PageMenu : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageMenu(AppContext *ctx, WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent = nullptr); explicit PageMenu(WizardFields *fields, WalletKeysFilesModel *wallets, QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -29,7 +29,6 @@ signals:
private: private:
Ui::PageMenu *ui; Ui::PageMenu *ui;
AppContext *m_ctx;
WalletKeysFilesModel *m_walletKeysFilesModel; WalletKeysFilesModel *m_walletKeysFilesModel;
WizardFields *m_fields; WizardFields *m_fields;
}; };

View file

@ -4,11 +4,11 @@
#include "PageNetwork.h" #include "PageNetwork.h"
#include "ui_PageNetwork.h" #include "ui_PageNetwork.h"
#include "WalletWizard.h" #include "WalletWizard.h"
#include "constants.h"
PageNetwork::PageNetwork(AppContext *ctx, QWidget *parent) PageNetwork::PageNetwork(QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageNetwork) , ui(new Ui::PageNetwork)
, m_ctx(ctx)
{ {
ui->setupUi(this); ui->setupUi(this);
this->setTitle("Welcome to Feather"); this->setTitle("Welcome to Feather");
@ -35,10 +35,8 @@ bool PageNetwork::validatePage() {
config()->set(Config::nodeSource, id); config()->set(Config::nodeSource, id);
if (id == 1) { if (id == 1) {
QList<FeatherNode> nodes; NodeList nodeList;
FeatherNode node{ui->line_customNode->text()}; nodeList.addNode(ui->line_customNode->text(), constants::networkType, NodeList::Type::custom);
nodes.append(node);
m_ctx->nodes->setCustomNodes(nodes);
} }
return true; return true;

View file

@ -20,14 +20,13 @@ class PageNetwork : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageNetwork(AppContext *ctx, QWidget *parent = nullptr); explicit PageNetwork(QWidget *parent = nullptr);
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
bool isComplete() const override; bool isComplete() const override;
private: private:
Ui::PageNetwork *ui; Ui::PageNetwork *ui;
AppContext *m_ctx;
}; };
#endif //FEATHER_WIZARDNETWORK_H #endif //FEATHER_WIZARDNETWORK_H

View file

@ -5,10 +5,9 @@
#include "ui_PageNetworkTor.h" #include "ui_PageNetworkTor.h"
#include "WalletWizard.h" #include "WalletWizard.h"
PageNetworkTor::PageNetworkTor(AppContext *ctx, QWidget *parent) PageNetworkTor::PageNetworkTor(QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageNetworkTor) , ui(new Ui::PageNetworkTor)
, m_ctx(ctx)
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -17,7 +17,7 @@ class PageNetworkTor : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageNetworkTor(AppContext *ctx, QWidget *parent = nullptr); explicit PageNetworkTor(QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -27,7 +27,6 @@ signals:
private: private:
Ui::PageNetworkTor *ui; Ui::PageNetworkTor *ui;
AppContext *m_ctx;
}; };
#endif //FEATHER_PAGENETWORKTOR_H #endif //FEATHER_PAGENETWORKTOR_H

View file

@ -7,21 +7,21 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, QWidget *parent) #include "constants.h"
#include "WalletWizard.h"
PageOpenWallet::PageOpenWallet(WalletKeysFilesModel *wallets, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageOpenWallet) , ui(new Ui::PageOpenWallet)
, m_ctx(ctx)
, m_walletKeysFilesModel(wallets) , m_walletKeysFilesModel(wallets)
{ {
ui->setupUi(this); ui->setupUi(this);
connect(ui->btnBrowse, &QPushButton::clicked, [=]{ connect(ui->btnBrowse, &QPushButton::clicked, [this]{
// manually browsing for wallet QString walletDir = config()->get(Config::walletDirectory).toString();
auto walletPath = config()->get(Config::walletPath).toString(); QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletDir, "Wallet file (*.keys)");
if (walletPath.isEmpty()) if (path.isEmpty())
walletPath = m_ctx->defaultWalletDir; return;
QString path = QFileDialog::getOpenFileName(this, "Select your wallet file", walletPath, "Wallet file (*.keys)");
if(path.isEmpty()) return;
QFileInfo infoPath(path); QFileInfo infoPath(path);
if(!infoPath.isReadable()) { if(!infoPath.isReadable()) {
@ -30,7 +30,7 @@ PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, Q
} }
if (ui->openOnStartup->isChecked()) 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); emit openWallet(path);
}); });
@ -41,7 +41,7 @@ PageOpenWallet::PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, Q
ui->walletTable->setSelectionBehavior(QAbstractItemView::SelectRows); ui->walletTable->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->walletTable->setContextMenuPolicy(Qt::CustomContextMenu); 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->setSourceModel(m_walletKeysFilesModel);
m_keysProxy->setSortRole(Qt::UserRole); 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){ connect(ui->walletTable->selectionModel(), &QItemSelectionModel::currentRowChanged, [this](QModelIndex current, QModelIndex prev){
this->updatePath(); 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() { void PageOpenWallet::initializePage() {
@ -87,7 +93,7 @@ bool PageOpenWallet::validatePage() {
} }
QString walletPath = index.model()->data(index.siblingAtColumn(WalletKeysFilesModel::ModelColumns::Path), Qt::UserRole).toString(); 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); config()->set(Config::autoOpenWalletPath, autoWallet);
emit openWallet(walletPath); emit openWallet(walletPath);

View file

@ -20,7 +20,7 @@ class PageOpenWallet : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageOpenWallet(AppContext *ctx, WalletKeysFilesModel *wallets, QWidget *parent = nullptr); explicit PageOpenWallet(WalletKeysFilesModel *wallets, QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -32,7 +32,6 @@ private:
void updatePath(); void updatePath();
Ui::PageOpenWallet *ui; Ui::PageOpenWallet *ui;
AppContext *m_ctx;
WalletKeysFilesModel *m_walletKeysFilesModel; WalletKeysFilesModel *m_walletKeysFilesModel;
WalletKeysFilesProxyModel *m_keysProxy; WalletKeysFilesProxyModel *m_keysProxy;
QStandardItemModel *m_model; QStandardItemModel *m_model;

View file

@ -5,10 +5,9 @@
#include "ui_PageSetPassword.h" #include "ui_PageSetPassword.h"
#include "WalletWizard.h" #include "WalletWizard.h"
PageSetPassword::PageSetPassword(AppContext *ctx, WizardFields *fields, QWidget *parent) PageSetPassword::PageSetPassword(WizardFields *fields, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageSetPassword) , ui(new Ui::PageSetPassword)
, m_ctx(ctx)
, m_fields(fields) , m_fields(fields)
{ {
ui->setupUi(this); ui->setupUi(this);

View file

@ -19,7 +19,7 @@ class PageSetPassword : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageSetPassword(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); explicit PageSetPassword(WizardFields *fields, QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -31,7 +31,6 @@ signals:
private: private:
Ui::PageSetPassword *ui; Ui::PageSetPassword *ui;
AppContext *m_ctx;
WizardFields *m_fields; WizardFields *m_fields;
}; };

View file

@ -5,11 +5,11 @@
#include "PageSetRestoreHeight.h" #include "PageSetRestoreHeight.h"
#include "ui_PageSetRestoreHeight.h" #include "ui_PageSetRestoreHeight.h"
#include "WalletWizard.h" #include "WalletWizard.h"
#include "constants.h"
PageSetRestoreHeight::PageSetRestoreHeight(AppContext *ctx, WizardFields *fields, QWidget *parent) PageSetRestoreHeight::PageSetRestoreHeight(WizardFields *fields, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageSetRestoreHeight) , ui(new Ui::PageSetRestoreHeight)
, m_ctx(ctx)
, m_fields(fields) , m_fields(fields)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -61,7 +61,7 @@ void PageSetRestoreHeight::onCreationDateEdited() {
QDateTime restoreDate = date > curDate ? curDate : date; QDateTime restoreDate = date > curDate ? curDate : date;
int timestamp = restoreDate.toSecsSinceEpoch(); 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); ui->line_restoreHeight->setText(restoreHeight);
this->showScanWarning(restoreDate); this->showScanWarning(restoreDate);
@ -77,7 +77,7 @@ void PageSetRestoreHeight::onRestoreHeightEdited() {
return; return;
} }
int timestamp = appData()->restoreHeights[m_ctx->networkType]->restoreHeightToDate(restoreHeight); int timestamp = appData()->restoreHeights[constants::networkType]->restoreHeightToDate(restoreHeight);
auto date = QDateTime::fromSecsSinceEpoch(timestamp); auto date = QDateTime::fromSecsSinceEpoch(timestamp);
ui->line_creationDate->setText(date.toString("yyyy-MM-dd")); ui->line_creationDate->setText(date.toString("yyyy-MM-dd"));

View file

@ -19,7 +19,7 @@ class PageSetRestoreHeight : public QWizardPage
Q_OBJECT Q_OBJECT
public: public:
explicit PageSetRestoreHeight(AppContext *ctx, WizardFields *fields, QWidget *parent = nullptr); explicit PageSetRestoreHeight(WizardFields *fields, QWidget *parent = nullptr);
void initializePage() override; void initializePage() override;
bool validatePage() override; bool validatePage() override;
int nextId() const override; int nextId() const override;
@ -34,7 +34,6 @@ private:
void showWalletAgeWarning(const QDateTime &date); void showWalletAgeWarning(const QDateTime &date);
Ui::PageSetRestoreHeight *ui; Ui::PageSetRestoreHeight *ui;
AppContext *m_ctx;
WizardFields *m_fields; WizardFields *m_fields;
}; };

View file

@ -10,10 +10,9 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *parent) PageWalletFile::PageWalletFile(WizardFields *fields, QWidget *parent)
: QWizardPage(parent) : QWizardPage(parent)
, ui(new Ui::PageWalletFile) , ui(new Ui::PageWalletFile)
, m_ctx(ctx)
, m_fields(fields) , m_fields(fields)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -23,9 +22,9 @@ PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *p
ui->lockIcon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation)); ui->lockIcon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation));
connect(ui->btnChange, &QPushButton::clicked, [=] { 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; if(walletDir.isEmpty()) return;
m_ctx->defaultWalletDir = walletDir;
ui->line_walletDir->setText(walletDir); ui->line_walletDir->setText(walletDir);
config()->set(Config::walletDirectory, walletDir); config()->set(Config::walletDirectory, walletDir);
emit defaultWalletDirChanged(walletDir); emit defaultWalletDirChanged(walletDir);
@ -37,7 +36,7 @@ PageWalletFile::PageWalletFile(AppContext *ctx, WizardFields *fields, QWidget *p
void PageWalletFile::initializePage() { void PageWalletFile::initializePage() {
this->setTitle(m_fields->modeText); 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()); ui->line_walletName->setText(this->defaultWalletName());
} }

Some files were not shown because too many files have changed in this diff Show more