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

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();
QByteArray data = reply->readAll();
qDebug() << "Response";
qDebug() << data;
for (const auto header : reply->rawHeaderList()) {
qDebug() << header << ": " << reply->rawHeader(header);
}
qDebug() << reply->rawHeaderPairs();
qDebug() << "Request";
for (const auto header : reply->request().rawHeaderList()) {
qDebug() << "header: " << header << ": " << reply->request().rawHeader(header);
}
qDebug() << reply->request().url();
reply->deleteLater();
QJsonObject obj;

View file

@ -5,7 +5,7 @@
#include <QMessageBox>
#include "appcontext.h"
#include "globals.h"
#include "constants.h"
// libwalletqt
#include "libwalletqt/TransactionHistory.h"
@ -17,44 +17,32 @@
#include "utils/WebsocketClient.h"
#include "utils/WebsocketNotifier.h"
WalletKeysFilesModel *AppContext::wallets = nullptr;
QMap<QString, QString> AppContext::txCache;
// This class serves as a business logic layer between MainWindow and libwalletqt.
// This way we don't clutter the GUI with wallet logic,
// and keep libwalletqt (mostly) clean of Feather specific implementation details
AppContext::AppContext(QCommandLineParser *cmdargs) {
this->cmdargs = cmdargs;
AppContext::AppContext(Wallet *wallet)
: wallet(wallet)
, nodes(new Nodes(this, this))
, networkType(constants::networkType)
, m_rpc(new DaemonRpc{this, getNetworkTor(), ""})
{
connect(this->wallet.get(), &Wallet::moneySpent, this, &AppContext::onMoneySpent);
connect(this->wallet.get(), &Wallet::moneyReceived, this, &AppContext::onMoneyReceived);
connect(this->wallet.get(), &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived);
connect(this->wallet.get(), &Wallet::newBlock, this, &AppContext::onWalletNewBlock);
connect(this->wallet.get(), &Wallet::updated, this, &AppContext::onWalletUpdate);
connect(this->wallet.get(), &Wallet::refreshed, this, &AppContext::onWalletRefreshed);
connect(this->wallet.get(), &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted);
connect(this->wallet.get(), &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed);
connect(this->wallet.get(), &Wallet::transactionCreated, this, &AppContext::onTransactionCreated);
connect(this->wallet.get(), &Wallet::deviceError, this, &AppContext::onDeviceError);
connect(this->wallet.get(), &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest);
connect(this->wallet.get(), &Wallet::connectionStatusChanged, [this]{
this->nodes->autoConnect();
});
this->isTails = TailsOS::detect();
this->isWhonix = WhonixOS::detect();
// ----------------- Setup Paths -----------------
QString configDir = Config::defaultConfigDir().path();
createConfigDirectory(configDir);
QString walletDir = config()->get(Config::walletDirectory).toString();
if (walletDir.isEmpty()) {
walletDir = Utils::defaultWalletDir();
}
this->defaultWalletDir = walletDir;
if (!QDir().mkpath(defaultWalletDir))
qCritical() << "Unable to create dir: " << defaultWalletDir;
// ----------------- Network Type -----------------
if (this->cmdargs->isSet("stagenet")) {
this->networkType = NetworkType::STAGENET;
config()->set(Config::networkType, NetworkType::STAGENET);
}
else if (this->cmdargs->isSet("testnet")) {
this->networkType = NetworkType::TESTNET;
config()->set(Config::networkType, NetworkType::TESTNET);
}
else {
this->networkType = NetworkType::MAINNET;
config()->set(Config::networkType, NetworkType::MAINNET);
}
this->nodes = new Nodes(this, this);
connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError);
// Store the wallet every 2 minutes
m_storeTimer.start(2 * 60 * 1000);
@ -62,71 +50,26 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
this->storeWallet();
});
this->walletManager = WalletManager::instance();
QString logPath = QString("%1/daemon.log").arg(configDir);
Monero::Utils::onStartup();
Monero::Wallet::init("", "feather", logPath.toStdString(), true);
this->updateBalance();
bool logLevelFromEnv;
int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv);
if (this->cmdargs->isSet("quiet"))
this->walletManager->setLogLevel(-1);
else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max)
Monero::WalletManagerFactory::setLogLevel(logLevel);
connect(this, &AppContext::createTransactionError, this, &AppContext::onCreateTransactionError);
// libwallet connects
connect(this->walletManager, &WalletManager::walletOpened, this, &AppContext::onWalletOpened);
connect(this->walletManager, &WalletManager::walletCreated, this, &AppContext::onWalletCreated);
connect(this->walletManager, &WalletManager::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest);
connect(this->walletManager, &WalletManager::deviceError, this, &AppContext::onDeviceError);
// TODO: move me
connect(websocketNotifier(), &WebsocketNotifier::NodesReceived, this->nodes, &Nodes::onWSNodesReceived);
m_rpc = new DaemonRpc{this, getNetworkTor(), ""};
}
void AppContext::initTor() {
if (this->cmdargs->isSet("tor-host"))
config()->set(Config::socks5Host, this->cmdargs->value("tor-host"));
if (this->cmdargs->isSet("tor-port"))
config()->set(Config::socks5Port, this->cmdargs->value("tor-port"));
if (this->cmdargs->isSet("use-local-tor"))
config()->set(Config::useLocalTor, true);
torManager()->init();
torManager()->start();
connect(torManager(), &TorManager::connectionStateChanged, &websocketNotifier()->websocketClient, &WebsocketClient::onToggleConnect);
this->onTorSettingsChanged();
}
void AppContext::initWS() {
websocketNotifier()->websocketClient.start();
// force trigger preferredFiat signal for history model
this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
}
void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
// tx cancelled by user
double amount = tx->amount() / globals::cdiv;
double amount = tx->amount() / constants::cdiv;
emit createTransactionCancelled(address, amount);
this->currentWallet->disposeTransaction(tx);
this->wallet->disposeTransaction(tx);
}
void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) {
if(this->currentWallet == nullptr){
qCritical() << "Cannot create transaction; no wallet loaded";
return;
}
if (churn) {
address = this->currentWallet->address(0, 0); // primary address
address = this->wallet->address(0, 0); // primary address
}
qCritical() << "Creating transaction";
this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
emit initiateTransaction();
}
@ -135,17 +78,12 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
// tx creation
this->tmpTxDescription = description;
if(this->currentWallet == nullptr) {
emit createTransactionError("Cannot create transaction; no wallet loaded");
return;
}
if (!all && amount == 0) {
emit createTransactionError("Cannot send nothing");
return;
}
auto unlocked_balance = this->currentWallet->unlockedBalance();
auto unlocked_balance = this->wallet->unlockedBalance();
if(!all && amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend");
return;
@ -154,11 +92,11 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
return;
}
qDebug() << "creating tx";
qDebug() << "Creating tx";
if (all)
this->currentWallet->createTransactionAllAsync(address, "", globals::mixin, this->tx_priority);
this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority);
else
this->currentWallet->createTransactionAsync(address, "", amount, globals::mixin, this->tx_priority);
this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority);
emit initiateTransaction();
}
@ -166,23 +104,18 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description) {
this->tmpTxDescription = description;
if (this->currentWallet == nullptr) {
emit createTransactionError("Cannot create transaction; no wallet loaded");
return;
}
quint64 total_amount = 0;
for (auto &amount : amounts) {
total_amount += amount;
}
auto unlocked_balance = this->currentWallet->unlockedBalance();
auto unlocked_balance = this->wallet->unlockedBalance();
if (total_amount > unlocked_balance) {
emit createTransactionError("Not enough money to spend");
}
qDebug() << "Creating tx";
this->currentWallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
emit initiateTransaction();
}
@ -192,68 +125,15 @@ void AppContext::onCreateTransactionError(const QString &msg) {
emit endTransaction();
}
void AppContext::closeWallet(bool emitClosedSignal, bool storeWallet) {
if (this->currentWallet == nullptr)
return;
emit walletAboutToClose();
if (storeWallet) {
this->storeWallet();
}
this->currentWallet->disconnect();
this->walletManager->closeWallet();
this->currentWallet = nullptr;
if (emitClosedSignal)
emit walletClosed();
}
void AppContext::onOpenWallet(const QString &path, const QString &password){
if(this->currentWallet != nullptr){
emit walletOpenedError("There is an active wallet opened.");
return;
}
if(!Utils::fileExists(path)) {
emit walletOpenedError(QString("Wallet not found: %1").arg(path));
return;
}
if (password.isEmpty()) {
this->walletPassword = "";
}
config()->set(Config::firstRun, false);
this->walletPath = path;
this->walletManager->openWalletAsync(path, password, this->networkType, 1);
}
void AppContext::onWalletCreated(Wallet * wallet) {
// Currently only called when a wallet is created from device.
auto state = wallet->status();
if (state != Wallet::Status_Ok) {
emit walletCreatedError(wallet->errorString());
return;
}
this->onWalletOpened(wallet);
}
void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
if(this->currentWallet) {
auto *model = this->currentWallet->transactionHistoryModel();
auto *model = this->wallet->transactionHistoryModel();
if (model != nullptr) {
model->preferredFiatSymbol = symbol;
}
}
}
void AppContext::onAmountPrecisionChanged(int precision) {
if (!this->currentWallet) return;
auto *model = this->currentWallet->transactionHistoryModel();
auto *model = this->wallet->transactionHistoryModel();
if (!model) return;
model->amountPrecision = precision;
}
@ -265,12 +145,12 @@ void AppContext::commitTransaction(PendingTransaction *tx) {
this->onMultiBroadcast(tx);
}
this->currentWallet->commitTransactionAsync(tx);
this->wallet->commitTransactionAsync(tx);
}
void AppContext::onMultiBroadcast(PendingTransaction *tx) {
int count = tx->txCount();
for (int i = 0; i < count; i++) {
quint64 count = tx->txCount();
for (quint64 i = 0; i < count; i++) {
QString txData = tx->signedTxToHex(i);
for (const auto& node: this->nodes->websocketNodes()) {
@ -294,205 +174,37 @@ void AppContext::onDeviceError(const QString &message) {
}
void AppContext::onTorSettingsChanged() {
if (WhonixOS::detect() || Utils::isTorsocks()) {
if (Utils::isTorsocks()) {
return;
}
// use local tor -> bundled tor
QString host = config()->get(Config::socks5Host).toString();
quint16 port = config()->get(Config::socks5Port).toString().toUShort();
if (!torManager()->isLocalTor()) {
host = torManager()->featherTorHost;
port = torManager()->featherTorPort;
}
QNetworkProxy proxy{QNetworkProxy::Socks5Proxy, host, port};
getNetworkTor()->setProxy(proxy);
websocketNotifier()->websocketClient.webSocket.setProxy(proxy);
this->nodes->connectToNode();
auto privacyLevel = config()->get(Config::torPrivacyLevel).toInt();
qDebug() << "Changed privacyLevel to " << privacyLevel;
}
void AppContext::onInitialNetworkConfigured() {
this->initTor();
this->initWS();
}
void AppContext::onWalletOpened(Wallet *wallet) {
auto state = wallet->status();
if (state != Wallet::Status_Ok) {
auto errMsg = wallet->errorString();
if (state == Wallet::Status_BadPassword) {
this->closeWallet(false);
// Don't show incorrect password when we try with empty password for the first time
bool showIncorrectPassword = m_openWalletTriedOnce;
m_openWalletTriedOnce = true;
emit walletOpenPasswordNeeded(showIncorrectPassword, wallet->path());
}
else if (errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc")) {
qCritical() << errMsg;
this->walletManager->clearWalletCache(this->walletPath);
errMsg = QString("%1\n\nAttempted to clean wallet cache. Please restart Feather.").arg(errMsg);
this->closeWallet(false);
emit walletOpenedError(errMsg);
} else {
this->closeWallet(false);
emit walletOpenedError(errMsg);
}
return;
}
m_openWalletTriedOnce = false;
this->refreshed = false;
this->currentWallet = wallet;
this->walletPath = this->currentWallet->path() + ".keys";
this->walletPassword = this->currentWallet->getPassword();
config()->set(Config::walletPath, this->walletPath);
connect(this->currentWallet, &Wallet::moneySpent, this, &AppContext::onMoneySpent);
connect(this->currentWallet, &Wallet::moneyReceived, this, &AppContext::onMoneyReceived);
connect(this->currentWallet, &Wallet::unconfirmedMoneyReceived, this, &AppContext::onUnconfirmedMoneyReceived);
connect(this->currentWallet, &Wallet::newBlock, this, &AppContext::onWalletNewBlock);
connect(this->currentWallet, &Wallet::updated, this, &AppContext::onWalletUpdate);
connect(this->currentWallet, &Wallet::refreshed, this, &AppContext::onWalletRefreshed);
connect(this->currentWallet, &Wallet::transactionCommitted, this, &AppContext::onTransactionCommitted);
connect(this->currentWallet, &Wallet::heightRefreshed, this, &AppContext::onHeightRefreshed);
connect(this->currentWallet, &Wallet::transactionCreated, this, &AppContext::onTransactionCreated);
connect(this->currentWallet, &Wallet::deviceError, this, &AppContext::onDeviceError);
connect(this->currentWallet, &Wallet::deviceButtonRequest, this, &AppContext::onDeviceButtonRequest);
emit walletOpened();
connect(this->currentWallet, &Wallet::connectionStatusChanged, [this]{
this->nodes->autoConnect();
});
this->nodes->connectToNode();
this->updateBalance();
#ifdef DONATE_BEG
this->donateBeg();
#endif
// force trigger preferredFiat signal for history model
this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
}
void AppContext::createConfigDirectory(const QString &dir) {
QString config_dir_tor = QString("%1/%2").arg(dir).arg("tor");
QString config_dir_tordata = QString("%1/%2").arg(dir).arg("tor/data");
QStringList createDirs({dir, config_dir_tor, config_dir_tordata});
for(const auto &d: createDirs) {
if(!Utils::dirExists(d)) {
qDebug() << QString("Creating directory: %1").arg(d);
if (!QDir().mkpath(d)) {
qCritical() << "Could not create directory " << d;
}
}
}
}
void AppContext::createWallet(FeatherSeed seed, const QString &path, const QString &password, const QString &seedOffset) {
if(Utils::fileExists(path)) {
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(seed.mnemonic.isEmpty()) {
emit walletCreatedError("Mnemonic seed error. Failed to write wallet.");
return;
}
Wallet *wallet = nullptr;
if (seed.seedType == SeedType::TEVADOR) {
wallet = this->walletManager->createDeterministicWalletFromSpendKey(path, password, seed.language, this->networkType, seed.spendKey, seed.restoreHeight, globals::kdfRounds, seedOffset);
wallet->setCacheAttribute("feather.seed", seed.mnemonic.join(" "));
wallet->setCacheAttribute("feather.seedoffset", seedOffset);
}
if (seed.seedType == SeedType::MONERO) {
wallet = this->walletManager->recoveryWallet(path, password, seed.mnemonic.join(" "), seedOffset, this->networkType, seed.restoreHeight, globals::kdfRounds);
}
this->currentWallet = wallet;
if(this->currentWallet == nullptr) {
emit walletCreatedError("Failed to write wallet");
return;
}
this->onWalletOpened(wallet);
}
void AppContext::createWalletFromDevice(const QString &path, const QString &password, int restoreHeight) {
if(Utils::fileExists(path)) {
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
this->walletManager->createWalletFromDeviceAsync(path, password, this->networkType, "Ledger", restoreHeight);
}
void AppContext::createWalletFromKeys(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight, bool deterministic) {
if(Utils::fileExists(path)) {
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!WalletManager::addressValid(address, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid address provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!this->walletManager->keyValid(viewkey, address, true, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid viewkey provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
if(!spendkey.isEmpty() && !this->walletManager->keyValid(spendkey, address, false, this->networkType)) {
auto err = QString("Failed to create wallet. Invalid spendkey provided.").arg(path);
qCritical() << err;
emit walletCreatedError(err);
return;
}
Wallet *wallet = this->walletManager->createWalletFromKeys(path, password, this->seedLanguage, this->networkType, address, viewkey, spendkey, restoreHeight);
this->walletManager->walletOpened(wallet);
}
void AppContext::onSetRestoreHeight(quint64 height){
auto seed = this->currentWallet->getCacheAttribute("feather.seed");
auto seed = this->wallet->getCacheAttribute("feather.seed");
if(!seed.isEmpty()) {
const auto msg = "This wallet has a 14 word mnemonic seed which has the restore height embedded.";
emit setRestoreHeightError(msg);
return;
}
this->currentWallet->setWalletCreationHeight(height);
this->currentWallet->setPassword(this->currentWallet->getPassword()); // trigger .keys write
this->wallet->setWalletCreationHeight(height);
this->wallet->setPassword(this->wallet->getPassword()); // trigger .keys write
// nuke wallet cache
const auto fn = this->currentWallet->path();
this->walletManager->clearWalletCache(fn);
const auto fn = this->wallet->cachePath();
WalletManager::clearWalletCache(fn);
emit customRestoreHeightSet(height);
}
void AppContext::onOpenAliasResolve(const QString &openAlias) {
// @TODO: calling this freezes for about 1-2 seconds :/
const auto result = this->walletManager->resolveOpenAlias(openAlias);
const auto result = WalletManager::instance()->resolveOpenAlias(openAlias);; // TODO: async call
const auto spl = result.split("|");
auto msg = QString("");
if(spl.count() != 2) {
@ -503,7 +215,7 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
const auto &status = spl.at(0);
const auto &address = spl.at(1);
const auto valid = this->walletManager->addressValid(address, this->networkType);
const auto valid = WalletManager::addressValid(address, constants::networkType);
if(status == "false"){
if(valid){
msg = "Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed";
@ -532,50 +244,32 @@ void AppContext::onOpenAliasResolve(const QString &openAlias) {
emit openAliasResolveError(msg);
}
void AppContext::donateBeg() {
if (this->currentWallet == nullptr) return;
if (this->networkType != NetworkType::Type::MAINNET) return;
if (this->currentWallet->viewOnly()) return;
auto donationCounter = config()->get(Config::donateBeg).toInt();
if (donationCounter == -1)
return; // previously donated
donationCounter += 1;
if (donationCounter % globals::donationBoundary == 0) {
emit donationNag();
}
config()->set(Config::donateBeg, donationCounter);
}
AppContext::~AppContext() = default;
// ############################################## LIBWALLET QT #########################################################
// ########################################## LIBWALLET QT SIGNALS ####################################################
void AppContext::onMoneySpent(const QString &txId, quint64 amount) {
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / constants::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
// Incoming tx included in a block.
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / constants::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
}
void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
// Incoming transaction in pool
auto amount_num = amount / globals::cdiv;
auto amount_num = amount / constants::cdiv;
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
if(this->currentWallet->synchronized()) {
if(this->wallet->synchronized()) {
auto notify = QString("%1 XMR (pending)").arg(amount_num);
Utils::desktopNotify("Payment received", notify, 5000);
}
}
void AppContext::onWalletUpdate() {
if (this->currentWallet->synchronized()) {
if (this->wallet->synchronized()) {
this->refreshModels();
this->storeWallet();
}
@ -595,7 +289,7 @@ void AppContext::onWalletRefreshed(bool success, const QString &message) {
this->refreshed = true;
emit walletRefreshed();
// store wallet immediately upon finishing synchronization
this->currentWallet->store();
this->wallet->store();
}
qDebug() << "Wallet refresh status: " << success;
@ -605,10 +299,9 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
// Called whenever a new block gets scanned by the wallet
this->syncStatusUpdated(blockheight, targetHeight);
if (!this->currentWallet) return;
if (this->currentWallet->isSynchronized()) {
this->currentWallet->coins()->refreshUnlocked();
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
if (this->wallet->isSynchronized()) {
this->wallet->coins()->refreshUnlocked();
this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
// Todo: only refresh tx confirmations
}
}
@ -616,7 +309,7 @@ void AppContext::onWalletNewBlock(quint64 blockheight, quint64 targetHeight) {
void AppContext::onHeightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) {
qDebug() << Q_FUNC_INFO << walletHeight << daemonHeight << targetHeight;
if (this->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
if (this->wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected)
return;
if (daemonHeight < targetHeight) {
@ -631,7 +324,7 @@ void AppContext::onTransactionCreated(PendingTransaction *tx, const QVector<QStr
qDebug() << Q_FUNC_INFO;
for (auto &addr : address) {
if (addr == globals::donationAddress) {
if (addr == constants::donationAddress) {
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){
if (status) {
for (const auto &entry: txid) {
this->currentWallet->setUserNote(entry, this->tmpTxDescription);
this->wallet->setUserNote(entry, this->tmpTxDescription);
}
this->tmpTxDescription = "";
}
// Store wallet immediately so we don't risk losing tx key if wallet crashes
this->currentWallet->store();
this->wallet->store();
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
this->updateBalance();
@ -670,19 +363,16 @@ void AppContext::onTransactionCommitted(bool status, PendingTransaction *tx, con
void AppContext::storeWallet() {
// Do not store a synchronizing wallet: store() is NOT thread safe and may crash the wallet
if (this->currentWallet == nullptr || !this->currentWallet->isSynchronized())
if (!this->wallet->isSynchronized())
return;
qDebug() << "Storing wallet";
this->currentWallet->store();
this->wallet->store();
}
void AppContext::updateBalance() {
if (!this->currentWallet)
return;
quint64 balance = this->currentWallet->balance();
quint64 spendable = this->currentWallet->unlockedBalance();
quint64 balance = this->wallet->balance();
quint64 spendable = this->wallet->unlockedBalance();
emit balanceUpdated(balance, spendable);
}
@ -698,11 +388,8 @@ void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
}
void AppContext::refreshModels() {
if (!this->currentWallet)
return;
this->currentWallet->history()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->subaddress()->refresh(this->currentWallet->currentSubaddressAccount());
this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount());
this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
this->wallet->subaddress()->refresh(this->wallet->currentSubaddressAccount());
this->wallet->coins()->refresh(this->wallet->currentSubaddressAccount());
// Todo: set timer for refreshes
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,81 +7,81 @@
#include <QRadioButton>
WalletCacheDebugDialog::WalletCacheDebugDialog(AppContext *ctx, QWidget *parent)
WalletCacheDebugDialog::WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
: QDialog(parent)
, ui(new Ui::WalletCacheDebugDialog)
, m_ctx(ctx)
, m_ctx(std::move(ctx))
{
ui->setupUi(this);
ui->output->setFont(ModelUtils::getMonospaceFont());
connect(ui->m_blockchain, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printBlockchain());
this->setOutput(m_ctx->wallet->printBlockchain());
});
connect(ui->m_transfers, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printTransfers());
this->setOutput(m_ctx->wallet->printTransfers());
});
connect(ui->m_unconfirmed_payments, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printUnconfirmedPayments());
this->setOutput(m_ctx->wallet->printUnconfirmedPayments());
});
connect(ui->m_confirmed_txs, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printConfirmedTransferDetails());
this->setOutput(m_ctx->wallet->printConfirmedTransferDetails());
});
connect(ui->m_unconfirmed_txs, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printUnconfirmedTransferDetails());
this->setOutput(m_ctx->wallet->printUnconfirmedTransferDetails());
});
connect(ui->m_payments, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printPayments());
this->setOutput(m_ctx->wallet->printPayments());
});
connect(ui->m_pub_keys, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printPubKeys());
this->setOutput(m_ctx->wallet->printPubKeys());
});
connect(ui->m_tx_notes, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printTxNotes());
this->setOutput(m_ctx->wallet->printTxNotes());
});
connect(ui->m_subaddresses, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printSubaddresses());
this->setOutput(m_ctx->wallet->printSubaddresses());
});
connect(ui->m_subaddress_labels, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printSubaddressLabels());
this->setOutput(m_ctx->wallet->printSubaddressLabels());
});
connect(ui->m_additional_tx_keys, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printAdditionalTxKeys());
this->setOutput(m_ctx->wallet->printAdditionalTxKeys());
});
connect(ui->m_attributes, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printAttributes());
this->setOutput(m_ctx->wallet->printAttributes());
});
connect(ui->m_key_images, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printKeyImages());
this->setOutput(m_ctx->wallet->printKeyImages());
});
connect(ui->m_account_tags, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printAccountTags());
this->setOutput(m_ctx->wallet->printAccountTags());
});
connect(ui->m_tx_keys, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printTxKeys());
this->setOutput(m_ctx->wallet->printTxKeys());
});
connect(ui->m_address_book, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printAddressBook());
this->setOutput(m_ctx->wallet->printAddressBook());
});
connect(ui->m_scanned_pool_txs, &QRadioButton::pressed, [this]{
this->setOutput(m_ctx->currentWallet->printScannedPoolTxs());
this->setOutput(m_ctx->wallet->printScannedPoolTxs());
});
this->adjustSize();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,7 @@
#include "passworddialog.h"
#include "ui_passworddialog.h"
PasswordDialog::PasswordDialog(QWidget *parent, const QString &walletName, bool incorrectPassword)
PasswordDialog::PasswordDialog(const QString &walletName, bool incorrectPassword, QWidget *parent)
: QDialog(parent)
, ui(new Ui::PasswordDialog)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,16 +5,16 @@
#include "ui_txconfdialog.h"
#include "model/ModelUtils.h"
#include "txconfadvdialog.h"
#include "globals.h"
#include "constants.h"
#include "utils/AppData.h"
#include "utils/ColorScheme.h"
#include <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)
, ui(new Ui::TxConfDialog)
, m_ctx(ctx)
, m_ctx(std::move(ctx))
, m_tx(tx)
, m_address(address)
, m_description(description)
@ -37,9 +37,9 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
int maxLength = Utils::maxLength(amounts);
std::for_each(amounts.begin(), amounts.end(), [maxLength](QString& amount){amount = amount.rightJustified(maxLength, ' ');});
QString amount_fiat = convert(tx->amount() / globals::cdiv);
QString fee_fiat = convert(tx->fee() / globals::cdiv);
QString total_fiat = convert((tx->amount() + tx->fee()) / globals::cdiv);
QString amount_fiat = convert(tx->amount() / constants::cdiv);
QString fee_fiat = convert(tx->fee() / constants::cdiv);
QString total_fiat = convert((tx->amount() + tx->fee()) / constants::cdiv);
QVector<QString> amounts_fiat = {amount_fiat, fee_fiat, total_fiat};
int maxLengthFiat = Utils::maxLength(amounts_fiat);
std::for_each(amounts_fiat.begin(), amounts_fiat.end(), [maxLengthFiat](QString& amount){amount = amount.rightJustified(maxLengthFiat, ' ');});
@ -52,7 +52,7 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
ui->label_fee->setText(QString("%1 (%2 %3)").arg(amounts[1], amounts_fiat[1], preferredCur));
ui->label_total->setText(QString("%1 (%2 %3)").arg(amounts[2], amounts_fiat[2], preferredCur));
auto subaddressIndex = m_ctx->currentWallet->subaddressIndex(address);
auto subaddressIndex = m_ctx->wallet->subaddressIndex(address);
QString addressExtra;
ui->label_address->setText(ModelUtils::displayAddress(address, 2));
@ -76,7 +76,7 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin
connect(ui->btn_Advanced, &QPushButton::clicked, this, &TxConfDialog::setShowAdvanced);
AppContext::txCache[tx->txid()[0]] = tx->signedTxToHex(0);
m_ctx->txCache[tx->txid()[0]] = tx->signedTxToHex(0);
this->adjustSize();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,11 +11,13 @@
#include <QMessageBox>
HistoryWidget::HistoryWidget(QWidget *parent)
HistoryWidget::HistoryWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent)
, ui(new Ui::HistoryWidget)
, m_ctx(std::move(ctx))
, m_contextMenu(new QMenu(this))
, m_copyMenu(new QMenu("Copy", this))
, m_model(m_ctx->wallet->historyModel())
{
ui->setupUi(this);
m_contextMenu->addMenu(m_copyMenu);
@ -45,6 +47,18 @@ HistoryWidget::HistoryWidget(QWidget *parent)
config()->set(Config::showHistorySyncNotice, false);
ui->syncNotice->hide();
});
connect(m_ctx.get(), &AppContext::walletRefreshed, this, &HistoryWidget::onWalletRefreshed);
ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool());
ui->history->setHistoryModel(m_model);
m_ctx->wallet->transactionHistoryModel()->amountPrecision = config()->get(Config::amountPrecision).toInt();
// Load view state
QByteArray historyViewState = QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray());
if (!historyViewState.isEmpty()) {
ui->history->setViewState(historyViewState);
}
}
void HistoryWidget::showContextMenu(const QPoint &point) {
@ -59,7 +73,7 @@ void HistoryWidget::showContextMenu(const QPoint &point) {
if (!tx) return;
bool unconfirmed = tx->isFailed() || tx->isPending();
if (AppContext::txCache.contains(tx->hash()) && unconfirmed && tx->direction() != TransactionInfo::Direction_In) {
if (m_ctx->txCache.contains(tx->hash()) && unconfirmed && tx->direction() != TransactionInfo::Direction_In) {
menu.addAction(icons()->icon("info2.svg"), "Resend transaction", this, &HistoryWidget::onResendTransaction);
}
@ -79,22 +93,6 @@ void HistoryWidget::onResendTransaction() {
}
}
void HistoryWidget::setModel(TransactionHistoryProxyModel *model, Wallet *wallet)
{
m_model = model;
m_wallet = wallet;
m_txHistory = m_wallet->history();
ui->history->setHistoryModel(m_model);
m_wallet->transactionHistoryModel()->amountPrecision = config()->get(Config::amountPrecision).toInt();
// Load view state
QByteArray historyViewState = QByteArray::fromBase64(config()->get(Config::GUI_HistoryViewState).toByteArray());
if (!historyViewState.isEmpty()) {
ui->history->setViewState(historyViewState);
}
}
void HistoryWidget::resetModel()
{
// Save view state
@ -108,7 +106,7 @@ void HistoryWidget::showTxDetails() {
auto *tx = ui->history->currentEntry();
if (!tx) return;
auto *dialog = new TransactionInfoDialog(m_wallet, tx, this);
auto *dialog = new TransactionInfoDialog(m_ctx, tx, this);
connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){
emit resendTransaction(txid);
});
@ -128,7 +126,6 @@ void HistoryWidget::setSearchText(const QString &text) {
}
void HistoryWidget::setSearchFilter(const QString &filter) {
if (!m_model) return;
m_model->setSearchFilter(filter);
ui->history->setSearchMode(!filter.isEmpty());
}
@ -137,7 +134,7 @@ void HistoryWidget::createTxProof() {
auto *tx = ui->history->currentEntry();
if (!tx) return;
auto *dialog = new TxProofDialog(this, m_wallet, tx);
auto *dialog = new TxProofDialog(this, m_ctx, tx);
dialog->exec();
dialog->deleteLater();
}
@ -162,10 +159,6 @@ void HistoryWidget::copy(copyField field) {
Utils::copyToClipboard(data);
}
void HistoryWidget::onWalletOpened() {
ui->syncNotice->setVisible(config()->get(Config::showHistorySyncNotice).toBool());
}
void HistoryWidget::onWalletRefreshed() {
ui->syncNotice->hide();
}

View file

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

View file

@ -3,6 +3,9 @@
#include "Wallet.h"
#include <chrono>
#include <thread>
#include "TransactionHistory.h"
#include "AddressBook.h"
#include "Subaddress.h"
@ -174,9 +177,14 @@ SubaddressIndex Wallet::subaddressIndex(const QString &address) const
return SubaddressIndex(i.first, i.second);
}
QString Wallet::path() const
QString Wallet::cachePath() const
{
return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->path()));
return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->filename()));
}
QString Wallet::keysPath() const
{
return QDir::toNativeSeparators(QString::fromStdString(m_walletImpl->keysFilename()));;
}
//void Wallet::storeAsync(const QJSValue &callback, const QString &path /* = "" */)

View file

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

View file

@ -68,14 +68,10 @@ Wallet *WalletManager::createWallet(const QString &path, const QString &password
const QString &language, NetworkType::Type nettype, quint64 kdfRounds)
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
}
Monero::Wallet * w = m_pimpl->createWallet(path.toStdString(), password.toStdString(),
language.toStdString(), static_cast<Monero::NetworkType>(nettype), kdfRounds);
m_currentWallet = new Wallet(w);
return m_currentWallet;
return new Wallet(w);
}
Wallet *WalletManager::openWallet(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds)
@ -90,24 +86,20 @@ Wallet *WalletManager::openWallet(const QString &path, const QString &password,
this->m_passphraseReceiver = nullptr;
});
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
}
qDebug() << QString("%1: opening wallet at %2, nettype = %3 ").arg(__PRETTY_FUNCTION__).arg(qPrintable(path)).arg(nettype);
Monero::Wallet * w = m_pimpl->openWallet(path.toStdString(), password.toStdString(), static_cast<Monero::NetworkType>(nettype), kdfRounds, &tmpListener);
w->setListener(nullptr);
qDebug() << QString("%1: opened wallet: %2, status: %3").arg(__PRETTY_FUNCTION__).arg(w->address(0, 0).c_str()).arg(w->status());
m_currentWallet = new Wallet(w);
auto wallet = new Wallet(w);
// move wallet to the GUI thread. Otherwise it wont be emitting signals
if (m_currentWallet->thread() != qApp->thread()) {
m_currentWallet->moveToThread(qApp->thread());
if (wallet->thread() != qApp->thread()) {
wallet->moveToThread(qApp->thread());
}
return m_currentWallet;
return wallet;
}
void WalletManager::openWalletAsync(const QString &path, const QString &password, NetworkType::Type nettype, quint64 kdfRounds)
@ -121,13 +113,9 @@ void WalletManager::openWalletAsync(const QString &path, const QString &password
Wallet *WalletManager::recoveryWallet(const QString &path, const QString &password, const QString &seed, const QString &seed_offset, NetworkType::Type nettype, quint64 restoreHeight, quint64 kdfRounds)
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
}
Monero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), password.toStdString(), seed.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight, kdfRounds, seed_offset.toStdString());
m_currentWallet = new Wallet(w);
return m_currentWallet;
return new Wallet(w);
}
Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &password, const QString &language,
@ -135,30 +123,18 @@ Wallet *WalletManager::createWalletFromKeys(const QString &path, const QString &
const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds)
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
m_currentWallet = nullptr;
}
Monero::Wallet * w = m_pimpl->createWalletFromKeys(path.toStdString(), password.toStdString(), language.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight,
address.toStdString(), viewkey.toStdString(), spendkey.toStdString(), kdfRounds);
m_currentWallet = new Wallet(w);
return m_currentWallet;
return new Wallet(w);
}
Wallet *WalletManager::createDeterministicWalletFromSpendKey(const QString &path, const QString &password, const QString &language, NetworkType::Type nettype,
const QString &spendkey, quint64 restoreHeight, quint64 kdfRounds, const QString &offset_passphrase)
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
m_currentWallet = nullptr;
}
Monero::Wallet * w = m_pimpl->createDeterministicWalletFromSpendKey(path.toStdString(), password.toStdString(), language.toStdString(), static_cast<Monero::NetworkType>(nettype), restoreHeight,
spendkey.toStdString(), kdfRounds, offset_passphrase.toStdString());
m_currentWallet = new Wallet(w);
return m_currentWallet;
return new Wallet(w);
}
Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString &password, NetworkType::Type nettype,
@ -174,26 +150,20 @@ Wallet *WalletManager::createWalletFromDevice(const QString &path, const QString
this->m_passphraseReceiver = nullptr;
});
if (m_currentWallet) {
qDebug() << "Closing open m_currentWallet" << m_currentWallet;
delete m_currentWallet;
m_currentWallet = nullptr;
}
Monero::Wallet * w = m_pimpl->createWalletFromDevice(path.toStdString(), password.toStdString(), static_cast<Monero::NetworkType>(nettype),
deviceName.toStdString(), restoreHeight, subaddressLookahead.toStdString(), 1, &tmpListener);
w->setListener(nullptr);
m_currentWallet = new Wallet(w);
auto wallet = new Wallet(w);
// move wallet to the GUI thread. Otherwise it wont be emitting signals
if (m_currentWallet->thread() != qApp->thread()) {
m_currentWallet->moveToThread(qApp->thread());
if (wallet->thread() != qApp->thread()) {
wallet->moveToThread(qApp->thread());
}
return m_currentWallet;
return wallet;
}
void WalletManager::createWalletFromDeviceAsync(const QString &path, const QString &password, NetworkType::Type nettype,
const QString &deviceName, quint64 restoreHeight, const QString &subaddressLookahead)
{
@ -203,30 +173,6 @@ void WalletManager::createWalletFromDeviceAsync(const QString &path, const QStri
});
}
QString WalletManager::closeWallet()
{
QMutexLocker locker(&m_mutex);
qDebug() << Q_FUNC_INFO ;
QString result;
if (m_currentWallet) {
result = m_currentWallet->address(0, 0);
delete m_currentWallet;
m_currentWallet = nullptr;
} else {
qCritical() << "Trying to close non existing wallet " << m_currentWallet;
result = "0";
}
return result;
}
// @TODO: fix
//void WalletManager::closeWalletAsync(const QJSValue& callback)
//{
// m_scheduler.run([this] {
// return QJSValueList({closeWallet()});
// }, callback);
//}
bool WalletManager::walletExists(const QString &path) const
{
return m_pimpl->walletExists(path.toStdString());
@ -287,7 +233,7 @@ bool WalletManager::addressValid(const QString &address, NetworkType::Type netty
return Monero::Wallet::addressValid(address.toStdString(), static_cast<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;
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();
}
double WalletManager::miningHashRate() const
{
return m_pimpl->miningHashRate();
}
bool WalletManager::isMining() const
{
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet == nullptr || !m_currentWallet->connectionStatus())
{
return false;
}
}
return m_pimpl->isMining();
}
void WalletManager::miningStatusAsync()
{
m_scheduler.run([this] {
emit miningStatus(isMining());
});
}
bool WalletManager::startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery)
{
if(threads == 0)
threads = 1;
return m_pimpl->startMining(address.toStdString(), threads, backgroundMining, ignoreBattery);
}
bool WalletManager::stopMining()
{
return m_pimpl->stopMining();
}
bool WalletManager::localDaemonSynced() const
{
return blockchainHeight() > 1 && blockchainHeight() >= blockchainTargetHeight();
@ -386,8 +295,9 @@ QString WalletManager::resolveOpenAlias(const QString &address) const
bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const
{
QMutexLocker locker(&m_mutex);
if (m_currentWallet)
return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
// TODO: FIXME
// if (m_currentWallet)
// return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
return false;
}
@ -435,9 +345,8 @@ QUrl WalletManager::localPathToUrl(const QString &path) const
return QUrl::fromLocalFile(path);
}
bool WalletManager::clearWalletCache(const QString &wallet_path) const
bool WalletManager::clearWalletCache(const QString &wallet_path)
{
QString fileName = wallet_path;
// Make sure wallet file is not .keys
fileName.replace(".keys","");
@ -455,7 +364,6 @@ bool WalletManager::clearWalletCache(const QString &wallet_path) const
WalletManager::WalletManager(QObject *parent)
: QObject(parent)
, m_currentWallet(nullptr)
, m_passphraseReceiver(nullptr)
, m_scheduler(this)
{

View file

@ -93,16 +93,7 @@ public:
const QString &deviceName,
quint64 restoreHeight = 0,
const QString &subaddressLookahead = "");
/*!
* \brief closeWallet - closes current open wallet and frees memory
* \return wallet address
*/
Q_INVOKABLE QString closeWallet();
/*!
* \brief closeWalletAsync - asynchronous version of "closeWallet"
*/
//Q_INVOKABLE void closeWalletAsync(const QJSValue& callback);
//! checks is given filename is a wallet;
Q_INVOKABLE bool walletExists(const QString &path) const;
@ -127,7 +118,7 @@ public:
Q_INVOKABLE bool paymentIdValid(const QString &payment_id) const;
Q_INVOKABLE static bool addressValid(const QString &address, NetworkType::Type nettype);
Q_INVOKABLE bool keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype) const;
Q_INVOKABLE static bool keyValid(const QString &key, const QString &address, bool isViewKey, NetworkType::Type nettype);
Q_INVOKABLE QString paymentIdFromAddress(const QString &address, NetworkType::Type nettype) const;
@ -136,14 +127,9 @@ public:
Q_INVOKABLE quint64 networkDifficulty() const;
Q_INVOKABLE quint64 blockchainHeight() const;
Q_INVOKABLE quint64 blockchainTargetHeight() const;
Q_INVOKABLE double miningHashRate() const;
Q_INVOKABLE bool localDaemonSynced() const;
Q_INVOKABLE bool isDaemonLocal(const QString &daemon_address) const;
Q_INVOKABLE void miningStatusAsync();
Q_INVOKABLE bool startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery);
Q_INVOKABLE bool stopMining();
// QML missing such functionality, implementing these helpers here
Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const;
Q_INVOKABLE QUrl localPathToUrl(const QString &path) const;
@ -159,10 +145,9 @@ public:
Q_INVOKABLE QString resolveOpenAlias(const QString &address) const;
Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const;
Q_INVOKABLE QVariantMap parse_uri_to_object(const QString &uri) const;
// Q_INVOKABLE bool saveQrCode(const QString &, const QString &) const;
// clear/rename wallet cache
Q_INVOKABLE bool clearWalletCache(const QString &fileName) const;
Q_INVOKABLE static bool clearWalletCache(const QString &fileName);
Q_INVOKABLE void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
virtual void onWalletPassphraseNeeded(bool on_device) override;
@ -171,7 +156,6 @@ public:
void setProxyAddress(QString address);
signals:
void walletOpened(Wallet * wallet);
void walletCreated(Wallet * wallet);
void walletPassphraseNeeded(bool onDevice);
@ -185,15 +169,12 @@ public slots:
private:
friend class WalletPassphraseListenerImpl;
explicit WalletManager(QObject *parent = 0);
~WalletManager();
bool isMining() const;
explicit WalletManager(QObject *parent = nullptr);
~WalletManager() override;
static WalletManager *m_instance;
Monero::WalletManager *m_pimpl;
mutable QMutex m_mutex;
QPointer<Wallet> m_currentWallet;
PassphraseReceiver *m_passphraseReceiver;
QMutex m_mutex_passphraseReceiver;
QString m_proxyAddress;

View file

@ -7,8 +7,10 @@
#include <QtGui>
#include "config-feather.h"
#include "constants.h"
#include "mainwindow.h"
#include "cli.h"
#include "WindowManager.h"
#if defined(Q_OS_WIN)
#include <windows.h>
@ -87,7 +89,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
QCommandLineOption bruteforceDictionairy(QStringList() << "bruteforce-dict", "Bruteforce dictionairy", "file");
parser.addOption(bruteforceDictionairy);
auto parsed = parser.parse(argv_);
bool parsed = parser.parse(argv_);
if (!parsed) {
qCritical() << parser.errorText();
exit(1);
@ -102,33 +104,15 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
bool bruteforcePassword = parser.isSet(bruteforcePasswordOption);
bool cliMode = exportContacts || exportTxHistory || bruteforcePassword;
if(cliMode) {
QCoreApplication cli_app(argc, argv);
QCoreApplication::setApplicationName("FeatherWallet");
auto *ctx = new AppContext(&parser);
auto *cli = new CLI(ctx, &cli_app);
QObject::connect(cli, &CLI::closeApplication, &cli_app, &QCoreApplication::quit);
if(exportContacts) {
if(!quiet)
qInfo() << "CLI mode: Address book export";
cli->mode = CLIMode::ExportContacts;
QTimer::singleShot(0, cli, &CLI::run);
} else if(exportTxHistory) {
if(!quiet)
qInfo() << "CLI mode: Transaction history export";
cli->mode = CLIMode::ExportTxHistory;
QTimer::singleShot(0, cli, &CLI::run);
} else if(bruteforcePassword) {
cli->mode = CLIMode::BruteforcePassword;
QTimer::singleShot(0, cli, &CLI::run);
}
return QCoreApplication::exec();
}
// Setup networkType
if (stagenet)
constants::networkType = NetworkType::STAGENET;
else if (testnet)
constants::networkType = NetworkType::TESTNET;
else
constants::networkType = NetworkType::MAINNET;
// Setup QApplication
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
QApplication::setDesktopSettingsAware(true); // use system font
@ -136,8 +120,67 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
QApplication app(argc, argv);
QApplication::setQuitOnLastWindowClosed(false);
QApplication::setApplicationName("FeatherWallet");
// Setup config directories
QString configDir = Config::defaultConfigDir().path();
QString config_dir_tor = QString("%1/%2").arg(configDir).arg("tor");
QString config_dir_tordata = QString("%1/%2").arg(configDir).arg("tor/data");
QStringList createDirs({configDir, config_dir_tor, config_dir_tordata});
for (const auto &d: createDirs) {
if (!Utils::dirExists(d)) {
qDebug() << QString("Creating directory: %1").arg(d);
if (!QDir().mkpath(d)) {
qCritical() << "Could not create directory " << d;
}
}
}
// Setup logging
QString logPath = QString("%1/daemon.log").arg(configDir);
Monero::Utils::onStartup();
Monero::Wallet::init("", "feather", logPath.toStdString(), true);
bool logLevelFromEnv;
int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv);
if (parser.isSet("quiet"))
WalletManager::instance()->setLogLevel(-1);
else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max)
Monero::WalletManagerFactory::setLogLevel(logLevel);
// Setup wallet directory
QString walletDir = config()->get(Config::walletDirectory).toString();
if (walletDir.isEmpty()) {
walletDir = Utils::defaultWalletDir();
config()->set(Config::walletDirectory, walletDir);
}
if (!QDir().mkpath(walletDir))
qCritical() << "Unable to create dir: " << walletDir;
// Setup Tor config
if (parser.isSet("tor-host"))
config()->set(Config::socks5Host, parser.value("tor-host"));
if (parser.isSet("tor-port"))
config()->set(Config::socks5Port, parser.value("tor-port"));
if (parser.isSet("use-local-tor"))
config()->set(Config::useLocalTor, true);
if (cliMode) {
CLI::Mode mode = [&]{
if (exportContacts)
return CLI::Mode::ExportContacts;
if (exportTxHistory)
return CLI::Mode::ExportTxHistory;
if (bruteforcePassword)
return CLI::Mode::BruteforcePassword;
}();
CLI cli{mode, &parser, &app};
return QCoreApplication::exec();
}
parser.process(app); // Parse again for --help and --version
if (!quiet) {
@ -153,8 +196,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]);
}
auto *ctx = new AppContext(&parser);
#if defined(Q_OS_MAC)
// For some odd reason, if we don't do this, QPushButton's
// need to be clicked *twice* in order to fire ?!
@ -166,6 +207,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
qInstallMessageHandler(Utils::applicationLogHandler);
qRegisterMetaType<QVector<QString>>();
new MainWindow(ctx);
WindowManager windowManager;
return QApplication::exec();
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -161,8 +161,8 @@
<property name="verticalSpacing">
<number>9</number>
</property>
<item row="1" column="0">
<widget class="HistoryWidget" name="historyWidget" native="true"/>
<item row="0" column="0">
<layout class="QVBoxLayout" name="historyWidgetLayout"/>
</item>
</layout>
</widget>
@ -208,14 +208,7 @@
</widget>
</item>
<item>
<widget class="ContactsWidget" name="contactWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<layout class="QVBoxLayout" name="contactsWidgetLayout"/>
</item>
</layout>
</widget>
@ -229,7 +222,7 @@
</attribute>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="ReceiveWidget" name="receiveWidget" native="true"/>
<layout class="QVBoxLayout" name="receiveWidgetLayout"/>
</item>
</layout>
</widget>
@ -349,6 +342,14 @@
<property name="title">
<string>File</string>
</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="actionQuit"/>
<addaction name="separator"/>
@ -548,7 +549,7 @@
</action>
<action name="actionClose">
<property name="text">
<string>Close current wallet</string>
<string>Close wallet</string>
</property>
</action>
<action name="actionVerifyTxProof">
@ -721,26 +722,29 @@
<string>Pay to many</string>
</property>
</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>
<layoutdefault spacing="6" margin="11"/>
<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>
<class>CalcWidget</class>
<extends>QWidget</extends>

View file

@ -5,7 +5,7 @@
#include "CoinsInfo.h"
#include "Coins.h"
#include "ModelUtils.h"
#include "globals.h"
#include "constants.h"
#include "utils/ColorScheme.h"
#include "utils/Icons.h"
@ -182,9 +182,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
case Amount:
{
if (role == Qt::UserRole) {
return cInfo.amount() / globals::cdiv;
return cInfo.amount() / constants::cdiv;
}
return QString::number(cInfo.amount() / globals::cdiv, 'f', 12);
return QString::number(cInfo.amount() / constants::cdiv, 'f', 12);
}
case Frozen:
return cInfo.frozen();

View file

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

View file

@ -10,12 +10,31 @@
#include <QMenu>
#include <QMessageBox>
ReceiveWidget::ReceiveWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ReceiveWidget)
ReceiveWidget::ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
: QWidget(parent)
, ui(new Ui::ReceiveWidget)
, m_ctx(std::move(ctx))
{
ui->setupUi(this);
m_model = m_ctx->wallet->subaddressModel();
m_proxyModel = new SubaddressProxyModel(this, m_ctx->wallet->subaddress());
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
ui->addresses->setModel(m_proxyModel);
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
ui->addresses->header()->setSectionResizeMode(SubaddressModel::Address, QHeaderView::Stretch);
ui->addresses->header()->setSectionResizeMode(SubaddressModel::Label, QHeaderView::ResizeToContents);
ui->addresses->header()->setMinimumSectionSize(200);
connect(ui->addresses->selectionModel(), &QItemSelectionModel::currentChanged, [=](QModelIndex current, QModelIndex prev){
this->updateQrCode();
});
connect(m_model, &SubaddressModel::modelReset, [this](){
this->updateQrCode();
});
// header context menu
ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu);
m_headerMenu = new QMenu(this);
@ -40,29 +59,6 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) :
connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses);
}
void ReceiveWidget::setModel(SubaddressModel * model, Wallet * wallet) {
m_wallet = wallet;
m_subaddress = wallet->subaddress();
m_model = model;
m_proxyModel = new SubaddressProxyModel(this, m_subaddress);
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
ui->addresses->setModel(m_proxyModel);
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
ui->addresses->header()->setSectionResizeMode(SubaddressModel::Address, QHeaderView::Stretch);
ui->addresses->header()->setSectionResizeMode(SubaddressModel::Label, QHeaderView::ResizeToContents);
ui->addresses->header()->setMinimumSectionSize(200);
connect(ui->addresses->selectionModel(), &QItemSelectionModel::currentChanged, [=](QModelIndex current, QModelIndex prev){
this->updateQrCode();
});
connect(m_model, &SubaddressModel::modelReset, [this](){
this->updateQrCode();
});
}
void ReceiveWidget::copyAddress() {
QModelIndex index = ui->addresses->currentIndex();
ModelUtils::copyColumn(&index, SubaddressModel::Address);
@ -103,7 +99,7 @@ void ReceiveWidget::showContextMenu(const QPoint &point) {
menu->addAction("Hide address", this, &ReceiveWidget::hideAddress);
}
if (m_wallet->isHwBacked()) {
if (m_ctx->wallet->isHwBacked()) {
menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice);
}
@ -172,15 +168,13 @@ void ReceiveWidget::showAddress()
void ReceiveWidget::showOnDevice() {
Monero::SubaddressRow* row = this->currentEntry();
if (!row) return;
m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRowId(), "");
m_ctx->wallet->deviceShowAddressAsync(m_ctx->wallet->currentSubaddressAccount(), row->getRowId(), "");
}
void ReceiveWidget::generateSubaddress() {
if (!m_wallet) return;
bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
bool r = m_ctx->wallet->subaddress()->addRow(m_ctx->wallet->currentSubaddressAccount(), "");
if (!r) {
QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_wallet->subaddress()->errorString()));
QMessageBox::warning(this, "Warning", QString("Failed to generate subaddress:\n\n%1").arg(m_ctx->wallet->subaddress()->errorString()));
}
}
@ -213,7 +207,7 @@ void ReceiveWidget::showQrCodeDialog() {
}
QStringList ReceiveWidget::getHiddenAddresses() {
QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses");
QString data = m_ctx->wallet->getCacheAttribute("feather.hiddenaddresses");
return data.split(",");
}
@ -223,14 +217,14 @@ void ReceiveWidget::addHiddenAddress(const QString& address) {
hiddenAddresses.append(address);
}
QString data = hiddenAddresses.join(",");
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
}
void ReceiveWidget::removeHiddenAddress(const QString &address) {
QStringList hiddenAddresses = this->getHiddenAddresses();
hiddenAddresses.removeAll(address);
QString data = hiddenAddresses.join(",");
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
m_ctx->wallet->setCacheAttribute("feather.hiddenaddresses", data);
}
Monero::SubaddressRow* ReceiveWidget::currentEntry() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,6 +20,24 @@ enum NodeSource {
custom
};
class NodeList : public QObject {
Q_OBJECT
public:
enum Type {
ws = 0,
custom
};
Q_ENUM(Type)
bool addNode(const QString &node, NetworkType::Type networkType, NodeList::Type source);
void setNodes(const QStringList &nodes, NetworkType::Type networkType, NodeList::Type source);
QStringList getNodes(NetworkType::Type networkType, NodeList::Type source);
private:
void ensureStructure(QJsonObject &obj, NetworkType::Type networkType);
};
struct FeatherNode {
explicit FeatherNode(QString address = "", int height = 0, int target_height = 0, bool online = false)
: height(height)
@ -92,7 +110,6 @@ class Nodes : public QObject {
public:
explicit Nodes(AppContext *ctx, QObject *parent = nullptr);
void loadConfig();
void writeConfig();
NodeSource source();
FeatherNode connection();
@ -122,9 +139,11 @@ private slots:
void onWalletRefreshed();
private:
AppContext *m_ctx = nullptr;
AppContext *m_ctx;
QJsonObject m_configJson;
NodeList m_nodes;
QStringList m_recentFailures;
QList<FeatherNode> m_customNodes;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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