mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-22 19:49:28 +00:00
Allow opening multiple windows
This commit is contained in:
parent
cc01924858
commit
f43949a346
110 changed files with 1839 additions and 1903 deletions
|
@ -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
444
src/WindowManager.cpp
Normal 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
79
src/WindowManager.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
128
src/cli.cpp
128
src/cli.cpp
|
@ -9,48 +9,59 @@
|
|||
#include "model/AddressBookModel.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "utils/brute.h"
|
||||
#include "constants.h"
|
||||
|
||||
CLI::CLI(AppContext *ctx, QObject *parent) :
|
||||
QObject(parent),
|
||||
ctx(ctx) {
|
||||
connect(this->ctx, &AppContext::walletOpened, this, &CLI::onWalletOpened);
|
||||
connect(this->ctx, &AppContext::walletOpenedError, this, &CLI::onWalletOpenedError);
|
||||
connect(this->ctx, &AppContext::walletOpenPasswordNeeded, this, &CLI::onWalletOpenPasswordRequired);
|
||||
CLI::CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mode(mode)
|
||||
, m_cmdargs(cmdargs)
|
||||
{
|
||||
m_walletManager = WalletManager::instance();
|
||||
connect(m_walletManager, &WalletManager::walletOpened, this, &CLI::onWalletOpened);
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
37
src/cli.h
37
src/cli.h
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 /* = "" */)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
102
src/main.cpp
102
src/main.cpp
|
@ -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
164
src/mainwindow.h
164
src/mainwindow.h
|
@ -36,9 +36,14 @@
|
|||
#include "widgets/tickerwidget.h"
|
||||
#include "wizard/WalletWizard.h"
|
||||
|
||||
#include "contactswidget.h"
|
||||
#include "historywidget.h"
|
||||
#include "sendwidget.h"
|
||||
#include "receivewidget.h"
|
||||
#include "coinswidget.h"
|
||||
|
||||
#include "WindowManager.h"
|
||||
|
||||
#ifdef HAS_LOCALMONERO
|
||||
#include "widgets/LocalMoneroWidget.h"
|
||||
#endif
|
||||
|
@ -47,10 +52,6 @@
|
|||
#include "widgets/xmrigwidget.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "src/kdmactouchbar.h"
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
@ -65,14 +66,19 @@ struct ToggleTab {
|
|||
Config::ConfigKey configKey;
|
||||
};
|
||||
|
||||
class WindowManager;
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr);
|
||||
explicit MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
QString walletName();
|
||||
QString walletCachePath();
|
||||
QString walletKeysPath();
|
||||
|
||||
enum Tabs {
|
||||
HOME = 0,
|
||||
HISTORY,
|
||||
|
@ -89,44 +95,29 @@ public:
|
|||
REDDIT
|
||||
};
|
||||
|
||||
public slots:
|
||||
void showWizard(WalletWizard::Page startPage);
|
||||
void showOrHide();
|
||||
void bringToFront();
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
|
||||
private slots:
|
||||
// TODO: use a consistent naming convention for slots
|
||||
// Menu
|
||||
void menuOpenClicked();
|
||||
void menuNewRestoreClicked();
|
||||
void menuQuitClicked();
|
||||
void menuSettingsClicked();
|
||||
void menuAboutClicked();
|
||||
void menuSignVerifyClicked();
|
||||
void menuVerifyTxProof();
|
||||
void showWalletInfoDialog();
|
||||
void showSeedDialog();
|
||||
void showConnectionStatusDialog();
|
||||
void showPasswordDialog();
|
||||
void showKeysDialog();
|
||||
void showViewOnlyDialog();
|
||||
void donateButtonClicked();
|
||||
void showCalcWindow();
|
||||
void payToMany();
|
||||
void showWalletCacheDebugDialog();
|
||||
void showSendTab();
|
||||
void showHistoryTab();
|
||||
void showSendScreen(const CCSEntry &entry);
|
||||
void skinChanged(const QString &skinName);
|
||||
void menuTorClicked();
|
||||
void onBlockchainSync(int height, int target);
|
||||
void onRefreshSync(int height, int target);
|
||||
void onWalletOpenedError(const QString &err);
|
||||
void onWalletCreatedError(const QString &err);
|
||||
void menuWalletCloseClicked();
|
||||
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
|
||||
void onDeviceButtonRequest(quint64 code);
|
||||
void onViewOnBlockExplorer(const QString &txid);
|
||||
void onResendTransaction(const QString &txid);
|
||||
void importContacts();
|
||||
void showRestoreHeightDialog();
|
||||
void importTransaction();
|
||||
void onDeviceError(const QString &error);
|
||||
void menuHwDeviceClicked();
|
||||
void onUpdatesAvailable(const QJsonObject &updates);
|
||||
void menuTorClicked();
|
||||
void menuToggleTabVisible(const QString &key);
|
||||
void onExportHistoryCSV(bool checked);
|
||||
void onExportContactsCSV(bool checked);
|
||||
void onCreateDesktopEntry(bool checked);
|
||||
void onReportBug(bool checked);
|
||||
|
||||
// offline tx signing
|
||||
void exportKeyImages();
|
||||
|
@ -138,97 +129,99 @@ public slots:
|
|||
void loadSignedTx();
|
||||
void loadSignedTxFromText();
|
||||
|
||||
// libwalletqt
|
||||
void onBalanceUpdated(quint64 balance, quint64 spendable);
|
||||
void onSynchronized();
|
||||
void onWalletOpened();
|
||||
void onWalletClosed(WalletWizard::Page page = WalletWizard::Page_Menu);
|
||||
void onConnectionStatusChanged(int status);
|
||||
void onCreateTransactionError(const QString &message);
|
||||
void onCreateTransactionSuccess(PendingTransaction *tx, const QVector<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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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"};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <QRegularExpression>
|
||||
|
||||
#include "utils/utils.h"
|
||||
#include "utils/tails.h"
|
||||
#include "appcontext.h"
|
||||
#include "config-feather.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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("\\.$"));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue