mirror of
https://github.com/feather-wallet/feather.git
synced 2024-11-17 09:47:36 +00:00
Merge pull request 'Beta-7' (#359) from tobtoht/feather:fix_comp_warn into master
Reviewed-on: https://git.featherwallet.org/feather/feather/pulls/359
This commit is contained in:
commit
7f70fa908d
180 changed files with 3845 additions and 3147 deletions
|
@ -22,7 +22,7 @@ git clone --branch master --recursive https://git.featherwallet.org/feather/feat
|
|||
cd feather
|
||||
```
|
||||
|
||||
Replace `master` with the desired version tag (e.g. `beta-6`) to build the release binary.
|
||||
Replace `master` with the desired version tag (e.g. `beta-7`) to build the release binary.
|
||||
|
||||
#### 2. Base image
|
||||
|
||||
|
@ -49,9 +49,11 @@ The resulting binary can be found in `build/bin/feather`.
|
|||
First create the standalone binary using the Docker command in the previous step.
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $PWD:/feather -w /feather feather:linux contrib/build-appimage.sh
|
||||
docker run --rm -it -v $PWD:/feather -w /feather/build feather:linux ../contrib/build-appimage.sh
|
||||
```
|
||||
|
||||
The resulting AppImage will be located in `./build`.
|
||||
|
||||
### Windows (reproducible)
|
||||
|
||||
#### 1. Clone
|
||||
|
@ -61,7 +63,7 @@ git clone --branch master --recursive https://git.featherwallet.org/feather/feat
|
|||
cd feather
|
||||
```
|
||||
|
||||
Replace `master` with the desired version tag (e.g. `beta-4`) to build the release binary.
|
||||
Replace `master` with the desired version tag (e.g. `beta-7`) to build the release binary.
|
||||
|
||||
#### 2. Base image
|
||||
|
||||
|
|
|
@ -7,17 +7,19 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
|
|||
set(VERSION_MAJOR "0")
|
||||
set(VERSION_MINOR "1")
|
||||
set(VERSION_REVISION "0")
|
||||
set(VERSION "beta-6")
|
||||
set(VERSION "beta-7")
|
||||
|
||||
option(STATIC "Link libraries statically, requires static Qt")
|
||||
|
||||
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)
|
||||
|
|
|
@ -69,7 +69,7 @@ RUN git clone -b tor-0.4.5.7 --depth 1 https://git.torproject.org/tor.git && \
|
|||
FROM ubuntu:16.04
|
||||
|
||||
ARG THREADS=1
|
||||
ARG QT_VERSION=5.15.2
|
||||
ARG QT_VERSION=v5.15.2
|
||||
|
||||
ENV CFLAGS="-fPIC"
|
||||
ENV CPPFLAGS="-fPIC"
|
||||
|
@ -88,8 +88,6 @@ RUN apt-get update && \
|
|||
# build tools
|
||||
software-properties-common automake pkg-config python \
|
||||
libtool-bin wget zip \
|
||||
# dependencies
|
||||
libusb-1.0-0-dev \
|
||||
# Qt
|
||||
libgl1-mesa-dev libglib2.0-dev mesa-common-dev \
|
||||
# libusb
|
||||
|
@ -112,6 +110,11 @@ RUN add-apt-repository ppa:git-core/ppa && \
|
|||
apt-get install -y git && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/libudev-dev_229-4ubuntu21.31_amd64.deb && \
|
||||
echo "f1f72bd814d1e8ca2828ac004924fba0b54a3299e60f089c6d818262b11750f7 libudev-dev_229-4ubuntu21.31_amd64.deb" | sha256sum -c && \
|
||||
apt install ./libudev-dev_229-4ubuntu21.31_amd64.deb && \
|
||||
rm libudev-dev_229-4ubuntu21.31_amd64.deb
|
||||
|
||||
RUN mkdir appimagetool && \
|
||||
cd appimagetool && \
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage && \
|
||||
|
|
|
@ -4,13 +4,14 @@ set -e
|
|||
unset SOURCE_DATE_EPOCH
|
||||
|
||||
APPDIR="$PWD/feather.AppDir"
|
||||
rm -rf $APPDIR
|
||||
mkdir -p "$APPDIR"
|
||||
mkdir -p "$APPDIR/usr/share/applications/"
|
||||
mkdir -p "$APPDIR/usr/bin"
|
||||
|
||||
cp "$PWD/src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
|
||||
cp "$PWD/src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
|
||||
cp "$PWD/build/bin/feather" "$APPDIR/usr/bin/feather"
|
||||
cp "$PWD/../src/assets/feather.desktop" "$APPDIR/usr/share/applications/feather.desktop"
|
||||
cp "$PWD/../src/assets/images/appicons/64x64.png" "$APPDIR/feather.png"
|
||||
cp "$PWD/bin/feather" "$APPDIR/usr/bin/feather"
|
||||
|
||||
LD_LIBRARY_PATH=/usr/local/lib /linuxdeployqt/squashfs-root/AppRun feather.AppDir/usr/share/applications/feather.desktop -bundle-non-qt-libs
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ file(GLOB SOURCE_FILES
|
|||
"api/*.cpp"
|
||||
"utils/*.h"
|
||||
"utils/*.cpp"
|
||||
"utils/os/*.h"
|
||||
"utils/os/*.cpp"
|
||||
"libwalletqt/*.h"
|
||||
"libwalletqt/*.cpp"
|
||||
"daemon/*.h"
|
||||
|
|
451
src/WindowManager.cpp
Normal file
451
src/WindowManager.cpp
Normal file
|
@ -0,0 +1,451 @@
|
|||
// 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/os/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.";
|
||||
this->close();
|
||||
}
|
||||
|
||||
void WindowManager::close() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
for (const auto &window: m_windows) {
|
||||
window->close();
|
||||
}
|
||||
|
||||
torManager()->stop();
|
||||
m_tray->hide();
|
||||
|
||||
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 defined(Q_OS_LINUX)
|
||||
errMsg += "\n\nNote: On Linux you may need to follow the instructions in the link below before the device can be opened:\n"
|
||||
"<a>https://support.ledger.com/hc/en-us/articles/115005165269-Fix-connection-issues</a>";
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -45,8 +45,8 @@ private slots:
|
|||
private:
|
||||
QString getBuySellUrl(bool buy, const QString ¤cyCode, const QString &countryCode="", const QString &paymentMethod="", const QString &amount = "", int page = 0);
|
||||
|
||||
QString m_baseUrl;
|
||||
UtilsNetworking *m_network;
|
||||
QString m_baseUrl;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
#include "appcontext.h"
|
||||
#include "globals.h"
|
||||
#include "constants.h"
|
||||
|
||||
// libwalletqt
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
|
@ -17,44 +17,35 @@
|
|||
#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();
|
||||
});
|
||||
connect(this->wallet.get(), &Wallet::currentSubaddressAccountChanged, [this]{
|
||||
this->updateBalance();
|
||||
});
|
||||
|
||||
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,104 +53,40 @@ 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);
|
||||
// force trigger preferredFiat signal for history model
|
||||
this->onPreferredFiatCurrencyChanged(config()->get(Config::preferredFiatCurrency).toString());
|
||||
|
||||
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(), ""};
|
||||
connect(this->wallet->history(), &TransactionHistory::txNoteChanged, [this]{
|
||||
this->wallet->history()->refresh(this->wallet->currentSubaddressAccount());
|
||||
});
|
||||
}
|
||||
|
||||
void AppContext::initTor() {
|
||||
if (this->cmdargs->isSet("tor-host"))
|
||||
config()->set(Config::socks5Host, this->cmdargs->value("tor-host"));
|
||||
if (this->cmdargs->isSet("tor-port"))
|
||||
config()->set(Config::socks5Port, this->cmdargs->value("tor-port"));
|
||||
if (this->cmdargs->isSet("use-local-tor"))
|
||||
config()->set(Config::useLocalTor, true);
|
||||
|
||||
torManager()->init();
|
||||
torManager()->start();
|
||||
|
||||
connect(torManager(), &TorManager::connectionStateChanged, &websocketNotifier()->websocketClient, &WebsocketClient::onToggleConnect);
|
||||
|
||||
this->onTorSettingsChanged();
|
||||
}
|
||||
|
||||
void AppContext::initWS() {
|
||||
websocketNotifier()->websocketClient.start();
|
||||
}
|
||||
|
||||
void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
|
||||
// tx cancelled by user
|
||||
double amount = tx->amount() / globals::cdiv;
|
||||
emit createTransactionCancelled(address, amount);
|
||||
this->currentWallet->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
|
||||
}
|
||||
|
||||
qCritical() << "Creating transaction";
|
||||
this->currentWallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
// ################## Transaction creation ##################
|
||||
|
||||
void AppContext::onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all) {
|
||||
// tx creation
|
||||
this->tmpTxDescription = description;
|
||||
|
||||
if(this->currentWallet == nullptr) {
|
||||
emit createTransactionError("Cannot create transaction; no wallet loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!all && amount == 0) {
|
||||
emit createTransactionError("Cannot send nothing");
|
||||
return;
|
||||
}
|
||||
|
||||
auto balance = this->currentWallet->balance();
|
||||
auto unlocked_balance = this->currentWallet->unlockedBalance();
|
||||
if(!all && amount > unlocked_balance) {
|
||||
quint64 unlocked_balance = this->wallet->unlockedBalance();
|
||||
if (!all && amount > unlocked_balance) {
|
||||
emit createTransactionError("Not enough money to spend");
|
||||
return;
|
||||
} else if(unlocked_balance == 0) {
|
||||
} else if (unlocked_balance == 0) {
|
||||
emit createTransactionError("No money to spend");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "creating tx";
|
||||
qInfo() << "Creating transaction";
|
||||
if (all)
|
||||
this->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();
|
||||
}
|
||||
|
@ -167,23 +94,29 @@ 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);
|
||||
qInfo() << "Creating transaction";
|
||||
this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
||||
void AppContext::onSweepOutput(const QString &keyImage, QString address, bool churn, int outputs) {
|
||||
if (churn) {
|
||||
address = this->wallet->address(0, 0); // primary address
|
||||
}
|
||||
|
||||
qInfo() << "Creating transaction";
|
||||
this->wallet->createTransactionSingleAsync(keyImage, address, outputs, this->tx_priority);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
@ -193,70 +126,10 @@ void AppContext::onCreateTransactionError(const QString &msg) {
|
|||
emit endTransaction();
|
||||
}
|
||||
|
||||
void AppContext::closeWallet(bool emitClosedSignal, bool storeWallet) {
|
||||
if (this->currentWallet == nullptr)
|
||||
return;
|
||||
|
||||
emit walletAboutToClose();
|
||||
|
||||
if (storeWallet) {
|
||||
this->storeWallet();
|
||||
}
|
||||
|
||||
this->currentWallet->disconnect();
|
||||
this->walletManager->closeWallet();
|
||||
this->currentWallet = nullptr;
|
||||
|
||||
if (emitClosedSignal)
|
||||
emit walletClosed();
|
||||
}
|
||||
|
||||
void AppContext::onOpenWallet(const QString &path, const QString &password){
|
||||
if(this->currentWallet != nullptr){
|
||||
emit walletOpenedError("There is an active wallet opened.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Utils::fileExists(path)) {
|
||||
emit walletOpenedError(QString("Wallet not found: %1").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.isEmpty()) {
|
||||
this->walletPassword = "";
|
||||
}
|
||||
|
||||
config()->set(Config::firstRun, false);
|
||||
|
||||
this->walletPath = path;
|
||||
this->walletManager->openWalletAsync(path, password, this->networkType, 1);
|
||||
}
|
||||
|
||||
void AppContext::onWalletCreated(Wallet * wallet) {
|
||||
// Currently only called when a wallet is created from device.
|
||||
auto state = wallet->status();
|
||||
if (state != Wallet::Status_Ok) {
|
||||
emit walletCreatedError(wallet->errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
this->onWalletOpened(wallet);
|
||||
}
|
||||
|
||||
void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
|
||||
if(this->currentWallet) {
|
||||
auto *model = this->currentWallet->transactionHistoryModel();
|
||||
if(model != nullptr) {
|
||||
model->preferredFiatSymbol = symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::onAmountPrecisionChanged(int precision) {
|
||||
if (!this->currentWallet) return;
|
||||
auto *model = this->currentWallet->transactionHistoryModel();
|
||||
if (!model) return;
|
||||
model->amountPrecision = precision;
|
||||
void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address) {
|
||||
// tx cancelled by user
|
||||
emit createTransactionCancelled(address, tx->amount());
|
||||
this->wallet->disposeTransaction(tx);
|
||||
}
|
||||
|
||||
void AppContext::commitTransaction(PendingTransaction *tx) {
|
||||
|
@ -266,12 +139,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()) {
|
||||
|
@ -285,6 +158,23 @@ void AppContext::onMultiBroadcast(PendingTransaction *tx) {
|
|||
}
|
||||
}
|
||||
|
||||
// ################## Models ##################
|
||||
|
||||
void AppContext::onPreferredFiatCurrencyChanged(const QString &symbol) {
|
||||
auto *model = this->wallet->transactionHistoryModel();
|
||||
if (model != nullptr) {
|
||||
model->preferredFiatSymbol = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::onAmountPrecisionChanged(int precision) {
|
||||
auto *model = this->wallet->transactionHistoryModel();
|
||||
if (!model) return;
|
||||
model->amountPrecision = precision;
|
||||
}
|
||||
|
||||
// ################## Device ##################
|
||||
|
||||
void AppContext::onDeviceButtonRequest(quint64 code) {
|
||||
emit deviceButtonRequest(code);
|
||||
}
|
||||
|
@ -294,206 +184,40 @@ void AppContext::onDeviceError(const QString &message) {
|
|||
emit deviceError(message);
|
||||
}
|
||||
|
||||
// ################## Misc ##################
|
||||
|
||||
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) {
|
||||
|
@ -504,7 +228,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";
|
||||
|
@ -533,50 +257,30 @@ 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() {}
|
||||
|
||||
// ############################################## LIBWALLET QT #########################################################
|
||||
// ########################################## LIBWALLET QT SIGNALS ####################################################
|
||||
|
||||
void AppContext::onMoneySpent(const QString &txId, quint64 amount) {
|
||||
auto amount_num = amount / globals::cdiv;
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
|
||||
// Outgoing tx included in a block
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
|
||||
}
|
||||
|
||||
void AppContext::onMoneyReceived(const QString &txId, quint64 amount) {
|
||||
// Incoming tx included in a block.
|
||||
auto amount_num = amount / globals::cdiv;
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
|
||||
}
|
||||
|
||||
void AppContext::onUnconfirmedMoneyReceived(const QString &txId, quint64 amount) {
|
||||
// Incoming transaction in pool
|
||||
auto amount_num = amount / globals::cdiv;
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << QString::number(amount_num);
|
||||
// Incoming tx in pool
|
||||
qDebug() << Q_FUNC_INFO << txId << " " << WalletManager::displayAmount(amount);
|
||||
|
||||
if(this->currentWallet->synchronized()) {
|
||||
auto notify = QString("%1 XMR (pending)").arg(amount_num);
|
||||
if (this->wallet->synchronized()) {
|
||||
auto notify = QString("%1 XMR (pending)").arg(WalletManager::displayAmount(amount, false));
|
||||
Utils::desktopNotify("Payment received", notify, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void AppContext::onWalletUpdate() {
|
||||
if (this->currentWallet->synchronized()) {
|
||||
if (this->wallet->synchronized()) {
|
||||
this->refreshModels();
|
||||
this->storeWallet();
|
||||
}
|
||||
|
@ -596,7 +300,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;
|
||||
|
@ -606,10 +310,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
|
||||
}
|
||||
}
|
||||
|
@ -617,7 +320,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) {
|
||||
|
@ -632,7 +335,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;
|
||||
}
|
||||
}
|
||||
|
@ -647,21 +350,21 @@ 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();
|
||||
|
||||
// this tx was a donation to Feather, stop our nagging
|
||||
if(this->donationSending) {
|
||||
if (this->donationSending) {
|
||||
this->donationSending = false;
|
||||
config()->set(Config::donateBeg, -1);
|
||||
}
|
||||
|
@ -671,19 +374,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);
|
||||
}
|
||||
|
@ -699,11 +399,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/os/whonix.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,59 +58,44 @@ 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);
|
||||
void createTransactionCancelled(const QVector<QString> &address, quint64 amount);
|
||||
void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
|
||||
void openAliasResolveError(const QString &msg);
|
||||
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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<file>assets/images/bitcoin.png</file>
|
||||
<file>assets/images/camera_dark.png</file>
|
||||
<file>assets/images/camera_white.png</file>
|
||||
<file>assets/images/change_account.png</file>
|
||||
<file>assets/images/clock1.png</file>
|
||||
<file>assets/images/clock2.png</file>
|
||||
<file>assets/images/clock3.png</file>
|
||||
|
|
|
@ -5,6 +5,8 @@ E-mail: dev@featherwallet.org
|
|||
|
||||
Created by dsc, tobtoht, and contributors.
|
||||
|
||||
Uses icons from the Icons8 icon pack (icons8.com).
|
||||
|
||||
Copyright (c) 2020-<current_year>, The Monero Project
|
||||
|
||||
All rights reserved.
|
||||
|
|
BIN
src/assets/images/change_account.png
Normal file
BIN
src/assets/images/change_account.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -8,10 +8,11 @@
|
|||
#include "utils/ColorScheme.h"
|
||||
#include "utils/AppData.h"
|
||||
#include "utils/config.h"
|
||||
#include "dialog/CalcConfigDialog.h"
|
||||
|
||||
CalcWidget::CalcWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::CalcWidget)
|
||||
CalcWidget::CalcWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::CalcWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -29,115 +30,120 @@ CalcWidget::CalcWidget(QWidget *parent) :
|
|||
ui->lineFrom->setValidator(dv);
|
||||
ui->lineTo->setValidator(dv);
|
||||
|
||||
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::initFiat);
|
||||
connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::initCrypto);;
|
||||
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWidget::onPricesReceived);
|
||||
connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWidget::onPricesReceived);
|
||||
|
||||
connect(ui->lineFrom, &QLineEdit::textEdited, this, [this]{this->convert(false);});
|
||||
connect(ui->lineTo, &QLineEdit::textEdited, this, [this]{this->convert(true);});
|
||||
|
||||
connect(ui->comboCalcFrom, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]{this->convert(false);});
|
||||
connect(ui->comboCalcTo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]{this->convert(false);});
|
||||
|
||||
connect(ui->btn_configure, &QPushButton::clicked, this, &CalcWidget::showCalcConfigureDialog);
|
||||
|
||||
QTimer::singleShot(1, [this]{
|
||||
this->skinChanged();
|
||||
});
|
||||
}
|
||||
|
||||
void CalcWidget::fromChanged(const QString &data) {
|
||||
if(!this->m_comboBoxInit) return;
|
||||
if(this->m_changing){
|
||||
this->m_changing = false;
|
||||
void CalcWidget::convert(bool reverse) {
|
||||
if (!m_comboBoxInit)
|
||||
return;
|
||||
|
||||
auto lineFrom = reverse ? ui->lineTo : ui->lineFrom;
|
||||
auto lineTo = reverse ? ui->lineFrom : ui->lineTo;
|
||||
|
||||
auto comboFrom = reverse ? ui->comboCalcTo : ui->comboCalcFrom;
|
||||
auto comboTo = reverse ? ui->comboCalcFrom : ui->comboCalcTo;
|
||||
|
||||
QString symbolFrom = comboFrom->itemText(comboFrom->currentIndex());
|
||||
QString symbolTo = comboTo->itemText(comboTo->currentIndex());
|
||||
|
||||
if (symbolFrom == symbolTo) {
|
||||
lineTo->setText(lineFrom->text());
|
||||
}
|
||||
|
||||
QString symbolFrom = ui->comboCalcFrom->itemText(ui->comboCalcFrom->currentIndex());
|
||||
QString symbolTo = ui->comboCalcTo->itemText(ui->comboCalcTo->currentIndex());
|
||||
|
||||
if(symbolFrom == symbolTo){
|
||||
ui->lineTo->setText(data);
|
||||
return;
|
||||
}
|
||||
|
||||
QString amount_str = ui->lineFrom->text();
|
||||
if(amount_str.startsWith('.')){
|
||||
ui->lineFrom->setText(ui->lineTo->text());
|
||||
return;
|
||||
}
|
||||
|
||||
double amount = amount_str.toDouble();
|
||||
QString amountStr = lineFrom->text();
|
||||
double amount = amountStr.toDouble();
|
||||
double result = appData()->prices.convert(symbolFrom, symbolTo, amount);
|
||||
|
||||
this->m_changing = true;
|
||||
|
||||
int precision = 10;
|
||||
if (appData()->prices.rates.contains(symbolTo))
|
||||
precision = 2;
|
||||
|
||||
ui->lineTo->setText(QString::number(result, 'f', precision));
|
||||
lineTo->setText(QString::number(result, 'f', precision));
|
||||
}
|
||||
|
||||
void CalcWidget::toChanged(const QString &data) {
|
||||
if(!this->m_comboBoxInit) return;
|
||||
if(this->m_changing){
|
||||
this->m_changing = false;
|
||||
void CalcWidget::onPricesReceived() {
|
||||
if (m_comboBoxInit)
|
||||
return;
|
||||
}
|
||||
|
||||
QString symbolFrom = ui->comboCalcFrom->itemText(
|
||||
ui->comboCalcFrom->currentIndex());
|
||||
QString symbolTo = ui->comboCalcTo->itemText(
|
||||
ui->comboCalcTo->currentIndex());
|
||||
|
||||
if(symbolFrom == symbolTo){
|
||||
ui->lineTo->setText(ui->lineFrom->text());
|
||||
QList<QString> cryptoKeys = appData()->prices.markets.keys();
|
||||
QList<QString> fiatKeys = appData()->prices.rates.keys();
|
||||
if (cryptoKeys.empty() || fiatKeys.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
QString amount_str = ui->lineTo->text();
|
||||
if(amount_str.startsWith('.')){
|
||||
ui->lineTo->setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
double amount = amount_str.toDouble();
|
||||
double result = appData()->prices.convert(symbolTo, symbolFrom, amount);
|
||||
|
||||
this->m_changing = true;
|
||||
|
||||
int precision = 10;
|
||||
if(appData()->prices.rates.contains(symbolFrom))
|
||||
precision = 2;
|
||||
|
||||
ui->lineFrom->setText(QString::number(result, 'f', precision));
|
||||
}
|
||||
|
||||
void CalcWidget::toComboChanged(const QString &data) {
|
||||
this->fromChanged(data);
|
||||
}
|
||||
|
||||
void CalcWidget::initCrypto() {
|
||||
this->initComboBox();
|
||||
}
|
||||
|
||||
void CalcWidget::initFiat() {
|
||||
ui->btn_configure->setEnabled(true);
|
||||
this->initComboBox();
|
||||
m_comboBoxInit = true;
|
||||
}
|
||||
|
||||
void CalcWidget::initComboBox() {
|
||||
if(m_comboBoxInit) return;
|
||||
QList<QString> marketsKeys = appData()->prices.markets.keys();
|
||||
QList<QString> ratesKeys = appData()->prices.rates.keys();
|
||||
if(marketsKeys.count() <= 0 || ratesKeys.count() <= 0) return;
|
||||
QList<QString> cryptoKeys = appData()->prices.markets.keys();
|
||||
QList<QString> fiatKeys = appData()->prices.rates.keys();
|
||||
|
||||
ui->comboCalcFrom->addItems(marketsKeys);
|
||||
ui->comboCalcFrom->insertSeparator(marketsKeys.count());
|
||||
ui->comboCalcFrom->addItems(ratesKeys);
|
||||
ui->comboCalcFrom->setCurrentIndex(marketsKeys.indexOf("XMR"));
|
||||
|
||||
ui->comboCalcTo->addItems(marketsKeys);
|
||||
ui->comboCalcTo->insertSeparator(marketsKeys.count());
|
||||
ui->comboCalcTo->addItems(ratesKeys);
|
||||
QStringList enabledCrypto = config()->get(Config::cryptoSymbols).toStringList();
|
||||
QStringList filteredCryptoKeys;
|
||||
for (const auto& symbol : cryptoKeys) {
|
||||
if (enabledCrypto.contains(symbol)) {
|
||||
filteredCryptoKeys.append(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList enabledFiat = config()->get(Config::fiatSymbols).toStringList();
|
||||
auto preferredFiat = config()->get(Config::preferredFiatCurrency).toString();
|
||||
ui->comboCalcTo->setCurrentText(preferredFiat);
|
||||
if (!enabledFiat.contains(preferredFiat) && fiatKeys.contains(preferredFiat)) {
|
||||
enabledFiat.append(preferredFiat);
|
||||
config()->set(Config::fiatSymbols, enabledFiat);
|
||||
}
|
||||
QStringList filteredFiatKeys;
|
||||
for (const auto &symbol : fiatKeys) {
|
||||
if (enabledFiat.contains(symbol)) {
|
||||
filteredFiatKeys.append(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
this->m_comboBoxInit = true;
|
||||
this->setupComboBox(ui->comboCalcFrom, filteredCryptoKeys, filteredFiatKeys);
|
||||
this->setupComboBox(ui->comboCalcTo, filteredCryptoKeys, filteredFiatKeys);
|
||||
|
||||
ui->comboCalcFrom->setCurrentIndex(ui->comboCalcFrom->findText("XMR"));
|
||||
|
||||
if (!preferredFiat.isEmpty()) {
|
||||
ui->comboCalcTo->setCurrentIndex(ui->comboCalcTo->findText(preferredFiat));
|
||||
} else {
|
||||
ui->comboCalcTo->setCurrentIndex(ui->comboCalcTo->findText("USD"));
|
||||
}
|
||||
}
|
||||
|
||||
void CalcWidget::skinChanged() {
|
||||
ui->imageExchange->setMode(ColorScheme::hasDarkBackground(this));
|
||||
}
|
||||
|
||||
void CalcWidget::showCalcConfigureDialog() {
|
||||
CalcConfigDialog dialog{this};
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
this->initComboBox();
|
||||
}
|
||||
}
|
||||
|
||||
void CalcWidget::setupComboBox(QComboBox *comboBox, const QStringList &crypto, const QStringList &fiat) {
|
||||
comboBox->clear();
|
||||
comboBox->addItems(crypto);
|
||||
comboBox->insertSeparator(comboBox->count());
|
||||
comboBox->addItems(fiat);
|
||||
}
|
||||
|
||||
CalcWidget::~CalcWidget() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef CALC_H
|
||||
#define CALC_H
|
||||
#ifndef FEATHER_CALCWIDGET_H
|
||||
#define FEATHER_CALCWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Ui {
|
||||
class CalcWidget;
|
||||
|
@ -18,23 +19,20 @@ public:
|
|||
explicit CalcWidget(QWidget *parent = nullptr);
|
||||
~CalcWidget() override;
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
|
||||
public slots:
|
||||
void fromChanged(const QString& data);
|
||||
void toChanged(const QString& data);
|
||||
void toComboChanged(const QString& data);
|
||||
void initFiat();
|
||||
void initCrypto();
|
||||
void skinChanged();
|
||||
|
||||
private:
|
||||
Ui::CalcWidget *ui;
|
||||
|
||||
bool m_comboBoxInit = false;
|
||||
private slots:
|
||||
void initComboBox();
|
||||
bool m_changing = false;
|
||||
void showCalcConfigureDialog();
|
||||
void onPricesReceived();
|
||||
|
||||
private:
|
||||
void convert(bool reverse);
|
||||
void setupComboBox(QComboBox *comboBox, const QStringList &crypto, const QStringList &fiat);
|
||||
|
||||
Ui::CalcWidget *ui;
|
||||
bool m_comboBoxInit = false;
|
||||
};
|
||||
|
||||
#endif // CALC_H
|
||||
#endif // FEATHER_CALCWIDGET_H
|
||||
|
|
|
@ -6,33 +6,16 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>737</width>
|
||||
<height>153</height>
|
||||
<width>800</width>
|
||||
<height>132</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
|
@ -40,6 +23,28 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_configure">
|
||||
<property name="text">
|
||||
<string>Configure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
|
@ -47,8 +52,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="horizontalSpacing">
|
||||
|
@ -118,8 +121,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelWarning">
|
||||
<property name="text">
|
||||
|
@ -127,36 +128,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>170</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
@ -167,72 +138,7 @@
|
|||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>lineFrom</sender>
|
||||
<signal>textChanged(QString)</signal>
|
||||
<receiver>CalcWidget</receiver>
|
||||
<slot>fromChanged(QString)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>119</x>
|
||||
<y>77</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>427</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>lineTo</sender>
|
||||
<signal>textChanged(QString)</signal>
|
||||
<receiver>CalcWidget</receiver>
|
||||
<slot>toChanged(QString)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>463</x>
|
||||
<y>86</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>640</x>
|
||||
<y>-4</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>comboCalcFrom</sender>
|
||||
<signal>currentIndexChanged(QString)</signal>
|
||||
<receiver>CalcWidget</receiver>
|
||||
<slot>fromChanged(QString)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>196</x>
|
||||
<y>77</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>330</x>
|
||||
<y>-9</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>comboCalcTo</sender>
|
||||
<signal>currentIndexChanged(QString)</signal>
|
||||
<receiver>CalcWidget</receiver>
|
||||
<slot>toComboChanged(QString)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>574</x>
|
||||
<y>82</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>265</x>
|
||||
<y>-5</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
<slots>
|
||||
<slot>fromChanged(QString)</slot>
|
||||
<slot>toChanged(QString)</slot>
|
||||
|
|
|
@ -8,26 +8,15 @@
|
|||
|
||||
#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
|
||||
|
||||
ui->setupUi(this);
|
||||
this->setWindowIcon(icons()->icon("gnome-calc.png"));
|
||||
|
||||
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &CalcWindow::initFiat);
|
||||
connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &CalcWindow::initCrypto);
|
||||
}
|
||||
|
||||
void CalcWindow::initFiat() {
|
||||
this->ui->calcWidget->initFiat();
|
||||
}
|
||||
|
||||
void CalcWindow::initCrypto() {
|
||||
this->ui->calcWidget->initCrypto();
|
||||
}
|
||||
|
||||
void CalcWindow::closeEvent(QCloseEvent *foo) {
|
||||
|
|
|
@ -21,10 +21,6 @@ public:
|
|||
signals:
|
||||
void closed();
|
||||
|
||||
public slots:
|
||||
void initFiat();
|
||||
void initCrypto();
|
||||
|
||||
private:
|
||||
void closeEvent(QCloseEvent *bar) override;
|
||||
|
||||
|
|
132
src/cli.cpp
132
src/cli.cpp
|
@ -9,48 +9,59 @@
|
|||
#include "model/AddressBookModel.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "utils/brute.h"
|
||||
#include "constants.h"
|
||||
|
||||
CLI::CLI(AppContext *ctx, QObject *parent) :
|
||||
QObject(parent),
|
||||
ctx(ctx) {
|
||||
connect(this->ctx, &AppContext::walletOpened, this, &CLI::onWalletOpened);
|
||||
connect(this->ctx, &AppContext::walletOpenedError, this, &CLI::onWalletOpenedError);
|
||||
connect(this->ctx, &AppContext::walletOpenPasswordNeeded, this, &CLI::onWalletOpenPasswordRequired);
|
||||
}
|
||||
CLI::CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mode(mode)
|
||||
, m_cmdargs(cmdargs)
|
||||
{
|
||||
m_walletManager = WalletManager::instance();
|
||||
connect(m_walletManager, &WalletManager::walletOpened, this, &CLI::onWalletOpened);
|
||||
|
||||
void CLI::run() {
|
||||
if (mode == CLIMode::ExportContacts || mode == CLIMode::ExportTxHistory)
|
||||
if (m_mode == Mode::ExportContacts || m_mode == Mode::ExportTxHistory)
|
||||
{
|
||||
if(!ctx->cmdargs->isSet("wallet-file"))
|
||||
return this->finishedError("--wallet-file argument missing");
|
||||
if(!ctx->cmdargs->isSet("password"))
|
||||
return this->finishedError("--password argument missing");
|
||||
ctx->onOpenWallet(ctx->cmdargs->value("wallet-file"), ctx->cmdargs->value("password"));
|
||||
if (!cmdargs->isSet("wallet-file")) {
|
||||
this->finished("--wallet-file argument missing");
|
||||
return;
|
||||
}
|
||||
else if (mode == CLIMode::BruteforcePassword)
|
||||
if (!cmdargs->isSet("password")) {
|
||||
this->finished("--password argument missing");
|
||||
return;
|
||||
}
|
||||
|
||||
QString walletFile = cmdargs->value("wallet-file");
|
||||
QString password = cmdargs->value("password");
|
||||
|
||||
|
||||
m_walletManager->openWalletAsync(walletFile, password, constants::networkType);
|
||||
}
|
||||
else if (mode == Mode::BruteforcePassword)
|
||||
{
|
||||
QString keys_file = ctx->cmdargs->value("bruteforce-password");
|
||||
QString keys_file = m_cmdargs->value("bruteforce-password");
|
||||
if (!keys_file.endsWith(".keys")) {
|
||||
return this->finishedError("Wallet file does not end with .keys");
|
||||
this->finished("Wallet file does not end with .keys");
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList words;
|
||||
if (ctx->cmdargs->isSet("bruteforce-dict")) {
|
||||
QString data = Utils::barrayToString(Utils::fileOpen(ctx->cmdargs->value("bruteforce-dict")));
|
||||
if (m_cmdargs->isSet("bruteforce-dict")) {
|
||||
QString data = Utils::barrayToString(Utils::fileOpen(m_cmdargs->value("bruteforce-dict")));
|
||||
words = data.split("\n");
|
||||
}
|
||||
|
||||
if (!ctx->cmdargs->isSet("bruteforce-chars")) {
|
||||
return this->finishedError("--bruteforce-chars argument missing");
|
||||
if (!m_cmdargs->isSet("bruteforce-chars")) {
|
||||
this->finished("--bruteforce-chars argument missing");
|
||||
return;
|
||||
}
|
||||
QString chars = ctx->cmdargs->value("bruteforce-chars");
|
||||
QString chars = m_cmdargs->value("bruteforce-chars");
|
||||
|
||||
brute b(chars.toStdString());
|
||||
if (words.isEmpty()) {
|
||||
qDebug() << "No dictionairy specified, bruteforcing all chars";
|
||||
while (true) {
|
||||
QString pass = QString::fromStdString(b.next());
|
||||
if (ctx->walletManager->verifyWalletPassword(keys_file, pass, false)) {
|
||||
if (m_walletManager->verifyWalletPassword(keys_file, pass, false)) {
|
||||
this->finished(QString("Found password: %1").arg(pass));
|
||||
break;
|
||||
}
|
||||
|
@ -60,7 +71,7 @@ void CLI::run() {
|
|||
else {
|
||||
bruteword bb(chars.toStdString());
|
||||
bool foundPass = false;
|
||||
for (auto word: words) {
|
||||
for (const auto& word: words) {
|
||||
if (word.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -71,7 +82,7 @@ void CLI::run() {
|
|||
if (pass == "") {
|
||||
break;
|
||||
}
|
||||
if (ctx->walletManager->verifyWalletPassword(keys_file, pass, false)) {
|
||||
if (m_walletManager->verifyWalletPassword(keys_file, pass, false)) {
|
||||
this->finished(QString("Found password: %1").arg(pass));
|
||||
foundPass = true;
|
||||
break;
|
||||
|
@ -88,50 +99,39 @@ void CLI::run() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLI::onWalletOpened() {
|
||||
if(mode == CLIMode::ExportContacts){
|
||||
auto *model = ctx->currentWallet->addressBookModel();
|
||||
auto fn = ctx->cmdargs->value("export-contacts");
|
||||
if(model->writeCSV(fn))
|
||||
this->finished(QString("Address book exported to %1").arg(fn));
|
||||
else
|
||||
this->finishedError("Address book export failure");
|
||||
} else if(mode == ExportTxHistory) {
|
||||
ctx->currentWallet->history()->refresh(ctx->currentWallet->currentSubaddressAccount());
|
||||
auto *model = ctx->currentWallet->history();
|
||||
auto fn = ctx->cmdargs->value("export-txhistory");
|
||||
if(model->writeCSV(fn))
|
||||
this->finished(QString("Transaction history exported to %1").arg(fn));
|
||||
else
|
||||
this->finishedError("Transaction history export failure");
|
||||
else {
|
||||
this->finished("Invalid mode");
|
||||
}
|
||||
}
|
||||
|
||||
void CLI::onWalletOpenedError(const QString &err) {
|
||||
if(mode == CLIMode::ExportContacts ||
|
||||
mode == CLIMode::ExportTxHistory)
|
||||
return this->finishedError(err);
|
||||
void CLI::onWalletOpened(Wallet *w) {
|
||||
QScopedPointer<Wallet> wallet{w};
|
||||
|
||||
if (wallet->status() != Wallet::Status_Ok) {
|
||||
this->finished(wallet->errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_mode == Mode::ExportContacts) {
|
||||
auto *model = wallet->addressBookModel();
|
||||
QString fileName = m_cmdargs->value("export-contacts");
|
||||
if (model->writeCSV(fileName))
|
||||
this->finished(QString("Contacts exported to %1").arg(fileName));
|
||||
else
|
||||
this->finished("Failed to export contacts");
|
||||
}
|
||||
else if (m_mode == Mode::ExportTxHistory) {
|
||||
wallet->history()->refresh(wallet->currentSubaddressAccount());
|
||||
auto *model = wallet->history();
|
||||
QString fileName = m_cmdargs->value("export-txhistory");
|
||||
if (model->writeCSV(fileName))
|
||||
this->finished(QString("Transaction history exported to %1").arg(fileName));
|
||||
else
|
||||
this->finished("Failed to export transaction history");
|
||||
}
|
||||
}
|
||||
|
||||
void CLI::onWalletOpenPasswordRequired(bool invalidPassword, const QString &path) {
|
||||
if(mode == CLIMode::ExportContacts ||
|
||||
mode == CLIMode::ExportTxHistory)
|
||||
return this->finishedError("invalid password");
|
||||
}
|
||||
|
||||
void CLI::finished(const QString &msg){
|
||||
qInfo() << msg;
|
||||
emit closeApplication();
|
||||
}
|
||||
|
||||
void CLI::finishedError(const QString &err) {
|
||||
qCritical() << err;
|
||||
emit closeApplication();
|
||||
}
|
||||
|
||||
CLI::~CLI() {
|
||||
ctx->disconnect();
|
||||
delete ctx;
|
||||
void CLI::finished(const QString &message) {
|
||||
qInfo() << message;
|
||||
QApplication::quit();
|
||||
}
|
||||
|
|
37
src/cli.h
37
src/cli.h
|
@ -7,37 +7,28 @@
|
|||
#include <QtCore>
|
||||
#include "appcontext.h"
|
||||
|
||||
enum CLIMode {
|
||||
ExportContacts,
|
||||
ExportTxHistory,
|
||||
BruteforcePassword
|
||||
};
|
||||
|
||||
class CLI : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CLIMode mode;
|
||||
explicit CLI(AppContext *ctx, QObject *parent = nullptr);
|
||||
~CLI() override;
|
||||
enum Mode {
|
||||
ExportContacts,
|
||||
ExportTxHistory,
|
||||
BruteforcePassword
|
||||
};
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
|
||||
//libwalletqt
|
||||
void onWalletOpened();
|
||||
void onWalletOpenedError(const QString& err);
|
||||
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);
|
||||
|
||||
private:
|
||||
AppContext *ctx;
|
||||
explicit CLI(Mode mode, QCommandLineParser *cmdargs, QObject *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void finished(const QString &msg);
|
||||
void finishedError(const QString &err);
|
||||
void onWalletOpened(Wallet *wallet);
|
||||
|
||||
signals:
|
||||
void closeApplication();
|
||||
private:
|
||||
void finished(const QString &message);
|
||||
|
||||
Mode m_mode;
|
||||
QCommandLineParser *m_cmdargs;
|
||||
WalletManager *m_walletManager;
|
||||
};
|
||||
|
||||
#endif //FEATHER_CLI_H
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
|
||||
CoinsWidget::CoinsWidget(QWidget *parent)
|
||||
CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::CoinsWidget)
|
||||
, m_ctx(std::move(ctx))
|
||||
, m_headerMenu(new QMenu(this))
|
||||
, m_copyMenu(new QMenu("Copy",this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_ctx = MainWindow::getContext();
|
||||
|
||||
// header context menu
|
||||
ui->coins->header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
@ -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);
|
||||
|
@ -186,10 +186,6 @@ void CoinsWidget::onSweepOutput() {
|
|||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void CoinsWidget::resetModel() {
|
||||
ui->coins->setModel(nullptr);
|
||||
}
|
||||
|
||||
void CoinsWidget::copy(copyField field) {
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
@ -233,17 +229,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,13 +22,10 @@ class CoinsWidget : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CoinsWidget(QWidget *parent = nullptr);
|
||||
explicit CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
|
||||
void setModel(CoinsModel * model, Coins * coins);
|
||||
~CoinsWidget() override;
|
||||
|
||||
public slots:
|
||||
void resetModel();
|
||||
|
||||
private slots:
|
||||
void showHeaderMenu(const QPoint& position);
|
||||
void setShowSpent(bool show);
|
||||
|
@ -54,11 +51,12 @@ private:
|
|||
};
|
||||
|
||||
Ui::CoinsWidget *ui;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
|
||||
QMenu *m_contextMenu;
|
||||
QMenu *m_headerMenu;
|
||||
QMenu *m_copyMenu;
|
||||
QAction *m_showSpentAction;
|
||||
QMenu *m_headerMenu;
|
||||
QAction *m_freezeOutputAction;
|
||||
QAction *m_freezeAllSelectedAction;
|
||||
QAction *m_thawOutputAction;
|
||||
|
@ -68,7 +66,6 @@ private:
|
|||
Coins *m_coins;
|
||||
CoinsModel * m_model;
|
||||
CoinsProxyModel * m_proxyModel;
|
||||
AppContext *m_ctx;
|
||||
|
||||
void showContextMenu(const QPoint & point);
|
||||
void copy(copyField field);
|
||||
|
|
|
@ -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,22 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
|
||||
ContactsWidget::ContactsWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ContactsWidget)
|
||||
ContactsWidget::ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::ContactsWidget)
|
||||
, m_ctx(std::move(ctx))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_ctx = MainWindow::getContext();
|
||||
|
||||
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);
|
||||
|
@ -53,6 +63,15 @@ ContactsWidget::ContactsWidget(QWidget *parent) :
|
|||
connect(ui->search, &QLineEdit::textChanged, this, &ContactsWidget::setSearchFilter);
|
||||
}
|
||||
|
||||
void ContactsWidget::setSearchbarVisible(bool visible) {
|
||||
ui->search->setVisible(visible);
|
||||
}
|
||||
|
||||
void ContactsWidget::focusSearchbar() {
|
||||
ui->search->setFocusPolicy(Qt::StrongFocus);
|
||||
ui->search->setFocus();
|
||||
}
|
||||
|
||||
void ContactsWidget::copyAddress() {
|
||||
QModelIndex index = ui->contacts->currentIndex();
|
||||
ModelUtils::copyColumn(&index, AddressBookModel::Address);
|
||||
|
@ -69,19 +88,6 @@ void ContactsWidget::payTo() {
|
|||
emit fillAddress(address);
|
||||
}
|
||||
|
||||
void ContactsWidget::setModel(AddressBookModel *model)
|
||||
{
|
||||
m_model = model;
|
||||
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);
|
||||
}
|
||||
|
@ -91,11 +97,6 @@ void ContactsWidget::setSearchFilter(const QString &filter) {
|
|||
m_proxyModel->setSearchFilter(filter);
|
||||
}
|
||||
|
||||
void ContactsWidget::resetModel()
|
||||
{
|
||||
ui->contacts->setModel(nullptr);
|
||||
}
|
||||
|
||||
void ContactsWidget::showHeaderMenu(const QPoint& position)
|
||||
{
|
||||
m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses());
|
||||
|
@ -104,24 +105,26 @@ void ContactsWidget::showHeaderMenu(const QPoint& position)
|
|||
|
||||
void ContactsWidget::newContact(QString address, QString name)
|
||||
{
|
||||
auto * dialog = new ContactsDialog(this, address, name);
|
||||
int ret = dialog->exec();
|
||||
if (!ret) return;
|
||||
ContactsDialog dialog{this, address, name};
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
address = dialog->getAddress();
|
||||
name = dialog->getName();
|
||||
address = dialog.getAddress();
|
||||
name = dialog.getName();
|
||||
|
||||
bool addressValid = WalletManager::addressValid(address, m_ctx->currentWallet->nettype());
|
||||
bool addressValid = WalletManager::addressValid(address, m_ctx->wallet->nettype());
|
||||
if (!addressValid) {
|
||||
QMessageBox::warning(this, "Invalid address", "Invalid address");
|
||||
return;
|
||||
}
|
||||
|
||||
int num_addresses = m_ctx->currentWallet->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_ctx->currentWallet->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();
|
||||
});
|
||||
|
@ -138,7 +141,7 @@ void ContactsWidget::newContact(QString address, QString name)
|
|||
}
|
||||
}
|
||||
|
||||
m_ctx->currentWallet->addressBook()->addRow(address, "", name);
|
||||
m_ctx->wallet->addressBook()->addRow(address, "", name);
|
||||
}
|
||||
|
||||
void ContactsWidget::deleteContact()
|
||||
|
|
|
@ -20,10 +20,12 @@ class ContactsWidget : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ContactsWidget(QWidget *parent = nullptr);
|
||||
void setModel(AddressBookModel * model);
|
||||
explicit ContactsWidget(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
|
||||
~ContactsWidget() override;
|
||||
|
||||
void setSearchbarVisible(bool visible);
|
||||
void focusSearchbar();
|
||||
|
||||
public slots:
|
||||
void copyAddress();
|
||||
void copyName();
|
||||
|
@ -32,7 +34,6 @@ public slots:
|
|||
void deleteContact();
|
||||
void setShowFullAddresses(bool show);
|
||||
void setSearchFilter(const QString &filter);
|
||||
void resetModel();
|
||||
|
||||
signals:
|
||||
void fillAddress(QString &address);
|
||||
|
@ -42,7 +43,7 @@ private slots:
|
|||
|
||||
private:
|
||||
Ui::ContactsWidget *ui;
|
||||
AppContext *m_ctx;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
|
||||
QAction *m_showFullAddressesAction;
|
||||
QMenu *m_rowMenu;
|
||||
|
|
108
src/dialog/AccountSwitcherDialog.cpp
Normal file
108
src/dialog/AccountSwitcherDialog.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include "AccountSwitcherDialog.h"
|
||||
#include "ui_AccountSwitcherDialog.h"
|
||||
|
||||
#include "libwalletqt/SubaddressAccount.h"
|
||||
#include "utils/Icons.h"
|
||||
#include "model/ModelUtils.h"
|
||||
#include <QMenu>
|
||||
|
||||
AccountSwitcherDialog::AccountSwitcherDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AccountSwitcherDialog)
|
||||
, m_ctx(std::move(ctx))
|
||||
, m_model(m_ctx->wallet->subaddressAccountModel())
|
||||
, m_proxyModel(new SubaddressAccountProxyModel(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_ctx->wallet->subaddressAccount()->refresh();
|
||||
m_proxyModel->setSourceModel(m_model);
|
||||
|
||||
ui->label_totalBalance->setFont(ModelUtils::getMonospaceFont());
|
||||
ui->label_totalBalance->setText(WalletManager::displayAmount(m_ctx->wallet->balanceAll()));
|
||||
|
||||
ui->accounts->setModel(m_proxyModel);
|
||||
ui->accounts->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->accounts->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
ui->accounts->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
ui->accounts->setSortingEnabled(true);
|
||||
ui->accounts->sortByColumn(SubaddressAccountModel::Column::Number, Qt::AscendingOrder);
|
||||
ui->accounts->hideColumn(SubaddressAccountModel::Column::Address);
|
||||
ui->accounts->hideColumn(SubaddressAccountModel::Column::UnlockedBalance);
|
||||
ui->accounts->setColumnWidth(SubaddressAccountModel::Column::Label, 200);
|
||||
ui->accounts->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
ui->accounts->header()->setSectionResizeMode(SubaddressAccountModel::Label, QHeaderView::Stretch);
|
||||
|
||||
connect(ui->accounts->selectionModel(), &QItemSelectionModel::currentChanged, this, &AccountSwitcherDialog::switchAccount);
|
||||
connect(ui->accounts, &QTreeView::customContextMenuRequested, this, &AccountSwitcherDialog::showContextMenu);
|
||||
|
||||
connect(ui->btn_newAccount, &QPushButton::clicked, [this]{
|
||||
m_ctx->wallet->addSubaddressAccount("New account");
|
||||
m_ctx->wallet->subaddressAccount()->refresh();
|
||||
});
|
||||
|
||||
connect(m_ctx->wallet.get(), &Wallet::currentSubaddressAccountChanged, this, &AccountSwitcherDialog::updateSelection);
|
||||
connect(m_ctx->wallet->subaddressAccount(), &SubaddressAccount::refreshFinished, this, &AccountSwitcherDialog::updateSelection);
|
||||
|
||||
this->updateSelection();
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::switchAccount() {
|
||||
QModelIndex index = ui->accounts->currentIndex();
|
||||
m_ctx->wallet->switchSubaddressAccount(index.row());
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::copyLabel() {
|
||||
auto row = this->currentEntry();
|
||||
if (!row)
|
||||
return;
|
||||
|
||||
Utils::copyToClipboard(QString::fromStdString(row->getLabel()));
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::copyBalance() {
|
||||
auto row = this->currentEntry();
|
||||
if (!row)
|
||||
return;
|
||||
|
||||
Utils::copyToClipboard(QString::fromStdString(row->getBalance()));
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::editLabel() {
|
||||
QModelIndex index = ui->accounts->currentIndex().siblingAtColumn(m_ctx->wallet->subaddressAccountModel()->Column::Label);
|
||||
ui->accounts->setCurrentIndex(index);
|
||||
ui->accounts->edit(index);
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::updateSelection() {
|
||||
qDebug() << "test";
|
||||
QModelIndex index = m_model->index(m_ctx->wallet->currentSubaddressAccount(), 0);
|
||||
ui->accounts->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::showContextMenu(const QPoint &point) {
|
||||
QModelIndex index = ui->accounts->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *menu = new QMenu(ui->accounts);
|
||||
|
||||
menu->addAction("Copy label", this, &AccountSwitcherDialog::copyLabel);
|
||||
menu->addAction("Copy balance", this, &AccountSwitcherDialog::copyBalance);
|
||||
menu->addAction("Edit label", this, &AccountSwitcherDialog::editLabel);
|
||||
|
||||
menu->popup(ui->accounts->viewport()->mapToGlobal(point));
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* AccountSwitcherDialog::currentEntry() {
|
||||
QModelIndex index = ui->accounts->currentIndex();
|
||||
return m_ctx->wallet->subaddressAccountModel()->entryFromIndex(index);
|
||||
}
|
||||
|
||||
AccountSwitcherDialog::~AccountSwitcherDialog() {
|
||||
delete ui;
|
||||
}
|
42
src/dialog/AccountSwitcherDialog.h
Normal file
42
src/dialog/AccountSwitcherDialog.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_ACCOUNTSWITCHERDIALOG_H
|
||||
#define FEATHER_ACCOUNTSWITCHERDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "appcontext.h"
|
||||
|
||||
#include "model/SubaddressAccountModel.h"
|
||||
|
||||
namespace Ui {
|
||||
class AccountSwitcherDialog;
|
||||
}
|
||||
|
||||
class AccountSwitcherDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AccountSwitcherDialog(QSharedPointer<AppContext> ctx, QWidget *parent = nullptr);
|
||||
~AccountSwitcherDialog() override;
|
||||
|
||||
private slots:
|
||||
void showContextMenu(const QPoint& point);
|
||||
void updateSelection();
|
||||
|
||||
private:
|
||||
void switchAccount();
|
||||
void copyLabel();
|
||||
void copyBalance();
|
||||
void editLabel();
|
||||
|
||||
Monero::SubaddressAccountRow* currentEntry();
|
||||
|
||||
Ui::AccountSwitcherDialog *ui;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
SubaddressAccountModel *m_model;
|
||||
SubaddressAccountProxyModel *m_proxyModel;
|
||||
};
|
||||
|
||||
#endif //FEATHER_ACCOUNTSWITCHERDIALOG_H
|
115
src/dialog/AccountSwitcherDialog.ui
Normal file
115
src/dialog/AccountSwitcherDialog.ui
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AccountSwitcherDialog</class>
|
||||
<widget class="QDialog" name="AccountSwitcherDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>521</width>
|
||||
<height>347</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Accounts</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="accounts">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Total balance:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_totalBalance">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_newAccount">
|
||||
<property name="text">
|
||||
<string>New account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AccountSwitcherDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AccountSwitcherDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
102
src/dialog/CalcConfigDialog.cpp
Normal file
102
src/dialog/CalcConfigDialog.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include "CalcConfigDialog.h"
|
||||
#include "ui_CalcConfigDialog.h"
|
||||
#include "AppData.h"
|
||||
#include "utils/config.h"
|
||||
|
||||
CalcConfigDialog::CalcConfigDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::CalcConfigDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
this->fillListWidgets();
|
||||
|
||||
connect(ui->btn_selectAll, &QPushButton::clicked, this, &CalcConfigDialog::selectAll);
|
||||
connect(ui->btn_deselectAll, &QPushButton::clicked, this, &CalcConfigDialog::deselectAll);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]{
|
||||
config()->set(Config::fiatSymbols, this->checkedFiat());
|
||||
config()->set(Config::cryptoSymbols, this->checkedCrypto());
|
||||
this->accept();
|
||||
});
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
QStringList CalcConfigDialog::checkedFiat() {
|
||||
return this->getChecked(ui->list_fiat);
|
||||
}
|
||||
|
||||
QStringList CalcConfigDialog::checkedCrypto() {
|
||||
return this->getChecked(ui->list_crypto);
|
||||
}
|
||||
|
||||
void CalcConfigDialog::selectAll() {
|
||||
this->setCheckState(this->getVisibleListWidget(), Qt::Checked);
|
||||
}
|
||||
|
||||
void CalcConfigDialog::deselectAll() {
|
||||
this->setCheckState(this->getVisibleListWidget(), Qt::Unchecked);
|
||||
}
|
||||
|
||||
void CalcConfigDialog::setCheckState(QListWidget *widget, Qt::CheckState checkState) {
|
||||
QListWidgetItem *item;
|
||||
for (int i=0; i < widget->count(); i++) {
|
||||
item = widget->item(i);
|
||||
item->setCheckState(checkState);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CalcConfigDialog::getChecked(QListWidget *widget) {
|
||||
QStringList checked;
|
||||
QListWidgetItem *item;
|
||||
for (int i=0; i < widget->count(); i++) {
|
||||
item = widget->item(i);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
checked.append(item->text());
|
||||
}
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
|
||||
QListWidget* CalcConfigDialog::getVisibleListWidget() {
|
||||
if (ui->tabWidget->currentIndex() == 0) {
|
||||
return ui->list_fiat;
|
||||
} else {
|
||||
return ui->list_crypto;
|
||||
}
|
||||
}
|
||||
|
||||
void CalcConfigDialog::fillListWidgets() {
|
||||
QStringList cryptoCurrencies = appData()->prices.markets.keys();
|
||||
QStringList fiatCurrencies = appData()->prices.rates.keys();
|
||||
|
||||
QStringList checkedCryptoCurrencies = config()->get(Config::cryptoSymbols).toStringList();
|
||||
QStringList checkedFiatCurrencies = config()->get(Config::fiatSymbols).toStringList();
|
||||
|
||||
ui->list_crypto->addItems(cryptoCurrencies);
|
||||
ui->list_fiat->addItems(fiatCurrencies);
|
||||
|
||||
auto setChecked = [](QListWidget *widget, const QStringList &checked){
|
||||
QListWidgetItem *item;
|
||||
for (int i=0; i < widget->count(); i++) {
|
||||
item = widget->item(i);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
if (checked.contains(item->text())) {
|
||||
item->setCheckState(Qt::Checked);
|
||||
} else {
|
||||
item->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setChecked(ui->list_crypto, checkedCryptoCurrencies);
|
||||
setChecked(ui->list_fiat, checkedFiatCurrencies);
|
||||
}
|
||||
|
||||
CalcConfigDialog::~CalcConfigDialog() {
|
||||
delete ui;
|
||||
}
|
39
src/dialog/CalcConfigDialog.h
Normal file
39
src/dialog/CalcConfigDialog.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_CALCCONFIGDIALOG_H
|
||||
#define FEATHER_CALCCONFIGDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
|
||||
namespace Ui {
|
||||
class CalcConfigDialog;
|
||||
}
|
||||
|
||||
class CalcConfigDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CalcConfigDialog(QWidget *parent = nullptr);
|
||||
~CalcConfigDialog() override;
|
||||
|
||||
QStringList checkedFiat();
|
||||
QStringList checkedCrypto();
|
||||
|
||||
private slots:
|
||||
void selectAll();
|
||||
void deselectAll();
|
||||
|
||||
private:
|
||||
void setCheckState(QListWidget *widget, Qt::CheckState checkState);
|
||||
QStringList getChecked(QListWidget *widget);
|
||||
void fillListWidgets();
|
||||
QListWidget* getVisibleListWidget();
|
||||
|
||||
Ui::CalcConfigDialog *ui;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_CALCCONFIGDIALOG_H
|
153
src/dialog/CalcConfigDialog.ui
Normal file
153
src/dialog/CalcConfigDialog.ui
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CalcConfigDialog</class>
|
||||
<widget class="QDialog" name="CalcConfigDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>509</width>
|
||||
<height>574</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Calc config</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Fiat</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="list_fiat"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Crypto</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="list_crypto"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_selectAll">
|
||||
<property name="text">
|
||||
<string>Select all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_deselectAll">
|
||||
<property name="text">
|
||||
<string>Deselect all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CalcConfigDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CalcConfigDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
40
src/dialog/RestoreHeightDialog.cpp
Normal file
40
src/dialog/RestoreHeightDialog.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include "RestoreHeightDialog.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
RestoreHeightDialog::RestoreHeightDialog(QWidget *parent, quint64 currentRestoreHeight)
|
||||
: QDialog(parent)
|
||||
, m_restoreHeightWidget(new RestoreHeightWidget(this))
|
||||
{
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
|
||||
auto *label = new QLabel(this);
|
||||
label->setText("Enter a wallet creation date or restore height.");
|
||||
|
||||
auto *buttonBox = new QDialogButtonBox(this);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(m_restoreHeightWidget);
|
||||
layout->addWidget(buttonBox);
|
||||
|
||||
this->setLayout(layout);
|
||||
|
||||
if (currentRestoreHeight) {
|
||||
m_restoreHeightWidget->setHeight(currentRestoreHeight);
|
||||
}
|
||||
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
int RestoreHeightDialog::getHeight() {
|
||||
return m_restoreHeightWidget->getHeight();
|
||||
}
|
23
src/dialog/RestoreHeightDialog.h
Normal file
23
src/dialog/RestoreHeightDialog.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef FEATHER_RESTOREHEIGHTDIALOG_H
|
||||
#define FEATHER_RESTOREHEIGHTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "widgets/RestoreHeightWidget.h"
|
||||
|
||||
class RestoreHeightDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RestoreHeightDialog(QWidget *parent = nullptr, quint64 currentRestoreHeight = 0);
|
||||
int getHeight();
|
||||
|
||||
private:
|
||||
RestoreHeightWidget *m_restoreHeightWidget;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_RESTOREHEIGHTDIALOG_H
|
|
@ -8,16 +8,17 @@
|
|||
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/Icons.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 +26,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
|
||||
|
@ -44,6 +45,10 @@ TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *t
|
|||
ui->radio_SpendProof->setChecked(true);
|
||||
ui->label_txid->setText(m_txid);
|
||||
|
||||
ui->btn_copyAddress->setIcon(icons()->icon("copy.png"));
|
||||
connect(ui->btn_copyAddress, &QPushButton::clicked, [this]{
|
||||
Utils::copyToClipboard(ui->combo_address->currentText());
|
||||
});
|
||||
ui->group_summary->hide(); // todo
|
||||
|
||||
this->adjustSize();
|
||||
|
@ -127,7 +132,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 +213,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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<item>
|
||||
<widget class="QRadioButton" name="radio_OutProof">
|
||||
<property name="text">
|
||||
<string>Prove a payment to an address (OutProof)</string>
|
||||
<string>Prove payment to an address (OutProof)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -226,7 +226,31 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_address"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QComboBox" name="combo_address">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_copyAddress">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -34,6 +34,8 @@ signals:
|
|||
private:
|
||||
void setStatus(const QString &msg, bool success = false);
|
||||
|
||||
Ui::UpdateDialog *ui;
|
||||
|
||||
QString m_version;
|
||||
QString m_downloadUrl;
|
||||
QString m_hash;
|
||||
|
@ -44,8 +46,6 @@ private:
|
|||
std::string m_updateZipArchive;
|
||||
|
||||
QNetworkReply *m_reply = nullptr;
|
||||
|
||||
Ui::UpdateDialog *ui;
|
||||
};
|
||||
|
||||
#endif //FEATHER_UPDATEDIALOG_H
|
||||
|
|
|
@ -7,81 +7,81 @@
|
|||
|
||||
#include <QRadioButton>
|
||||
|
||||
WalletCacheDebugDialog::WalletCacheDebugDialog(AppContext *ctx, QWidget *parent)
|
||||
WalletCacheDebugDialog::WalletCacheDebugDialog(QSharedPointer<AppContext> ctx, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_ctx(ctx)
|
||||
, ui(new Ui::WalletCacheDebugDialog)
|
||||
, 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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ public:
|
|||
~AboutDialog() override;
|
||||
|
||||
private:
|
||||
QStringListModel *m_model;
|
||||
Ui::AboutDialog *ui;
|
||||
QStringListModel *m_model;
|
||||
};
|
||||
|
||||
#endif // ABOUT_H
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Balance</string>
|
||||
<string>Account Balance</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
|
||||
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QString &transactionHex)
|
||||
BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, QSharedPointer<AppContext> ctx, const QString &transactionHex)
|
||||
: QDialog(parent)
|
||||
, m_ctx(ctx)
|
||||
, ui(new Ui::BroadcastTxDialog)
|
||||
, m_ctx(std::move(ctx))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
auto node = ctx->nodes->connection();
|
||||
auto node = m_ctx->nodes->connection();
|
||||
m_rpc = new DaemonRpc(this, getNetworkTor(), node.toAddress());
|
||||
|
||||
connect(ui->btn_Broadcast, &QPushButton::clicked, this, &BroadcastTxDialog::broadcastTx);
|
||||
|
@ -32,19 +32,15 @@ BroadcastTxDialog::BroadcastTxDialog(QWidget *parent, AppContext *ctx, const QSt
|
|||
void BroadcastTxDialog::broadcastTx() {
|
||||
QString tx = ui->transaction->toPlainText();
|
||||
|
||||
QString node = [this]{
|
||||
QString node;
|
||||
if (ui->radio_useCustom->isChecked())
|
||||
node = ui->customNode->text();
|
||||
else if (ui->radio_useDefault->isChecked())
|
||||
node = m_ctx->nodes->connection().toAddress();
|
||||
FeatherNode node = ui->radio_useCustom->isChecked() ? FeatherNode(ui->customNode->text()) : m_ctx->nodes->connection();
|
||||
|
||||
if (!node.startsWith("http://"))
|
||||
node = QString("http://%1").arg(node);
|
||||
return node;
|
||||
}();
|
||||
if (node.isLocal()) {
|
||||
m_rpc->setNetwork(getNetworkClearnet());
|
||||
} else {
|
||||
m_rpc->setNetwork(getNetworkTor());
|
||||
}
|
||||
|
||||
m_rpc->setDaemonAddress(node);
|
||||
m_rpc->setDaemonAddress(node.toURL());
|
||||
m_rpc->sendRawTransaction(tx);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,8 +26,8 @@ private slots:
|
|||
|
||||
private:
|
||||
Ui::BroadcastTxDialog *ui;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
UtilsNetworking *m_network;
|
||||
AppContext *m_ctx;
|
||||
DaemonRpc *m_rpc;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
#include "utils/WebsocketClient.h"
|
||||
#include "utils/TorManager.h"
|
||||
#include "utils/WebsocketNotifier.h"
|
||||
#include "utils/os/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,33 @@ 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()));
|
||||
QDateTime restoreDate = appData()->restoreHeights[constants::networkType]->heightToDate(m_ctx->wallet->getWalletCreationHeight());
|
||||
ui->label_restoreHeight->setText(QString("%1 (%2)").arg(QString::number(m_ctx->wallet->getWalletCreationHeight()), restoreDate.toString("yyyy-MM-dd")));
|
||||
ui->label_synchronized->setText(m_ctx->wallet->isSynchronized() ? "True" : "False");
|
||||
|
||||
auto node = m_ctx->nodes->connection();
|
||||
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 +83,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:
|
||||
|
@ -25,10 +25,10 @@ private:
|
|||
void copyToClipboad();
|
||||
void updateInfo();
|
||||
|
||||
QTimer m_updateTimer;
|
||||
AppContext *m_ctx;
|
||||
|
||||
Ui::DebugInfoDialog *ui;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
|
||||
QTimer m_updateTimer;
|
||||
};
|
||||
|
||||
#endif //FEATHER_DEBUGINFODIALOG_H
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -3,13 +3,15 @@
|
|||
|
||||
#include "passworddialog.h"
|
||||
#include "ui_passworddialog.h"
|
||||
#include "utils/Icons.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)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
this->setWindowIcon(icons()->icon("appicons/64x64.png"));
|
||||
ui->label_wallet->setText(QString("Please enter password for wallet: %1").arg(walletName));
|
||||
ui->label_incorrectPassword->setVisible(incorrectPassword);
|
||||
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#include "restoredialog.h"
|
||||
#include "ui_restoredialog.h"
|
||||
|
||||
RestoreDialog::RestoreDialog(AppContext *ctx, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::RestoreDialog)
|
||||
, m_ctx(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) {
|
||||
ui->restoreHeightWidget->hideSlider();
|
||||
} else {
|
||||
// load restoreHeight lookup db
|
||||
ui->restoreHeightWidget->initRestoreHeights(appData()->restoreHeights[m_ctx->networkType]);
|
||||
}
|
||||
}
|
||||
|
||||
int RestoreDialog::getHeight() {
|
||||
return ui->restoreHeightWidget->getHeight();
|
||||
}
|
||||
|
||||
void RestoreDialog::initRestoreHeights(RestoreHeightLookup *lookup) {
|
||||
ui->restoreHeightWidget->initRestoreHeights(lookup);
|
||||
}
|
||||
|
||||
RestoreDialog::~RestoreDialog() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2020-2021, The Monero Project.
|
||||
|
||||
#ifndef RESTOREDIALOG_H
|
||||
#define RESTOREDIALOG_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDialog>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractButton>
|
||||
|
||||
#include "utils/RestoreHeightLookup.h"
|
||||
#include "appcontext.h"
|
||||
|
||||
namespace Ui {
|
||||
class RestoreDialog;
|
||||
}
|
||||
|
||||
class RestoreDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RestoreDialog(AppContext *ctx, QWidget *parent = nullptr);
|
||||
void initRestoreHeights(RestoreHeightLookup *lookup);
|
||||
int getHeight();
|
||||
~RestoreDialog() override;
|
||||
|
||||
signals:
|
||||
void accepted();
|
||||
void rejected();
|
||||
|
||||
private:
|
||||
AppContext *m_ctx;
|
||||
Ui::RestoreDialog *ui;
|
||||
};
|
||||
|
||||
#endif // RESTOREDIALOG_H
|
|
@ -1,56 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RestoreDialog</class>
|
||||
<widget class="QDialog" name="RestoreDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>584</width>
|
||||
<height>99</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>specify restore height</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="RestoreHeightWidget" name="restoreHeightWidget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>RestoreHeightWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/restoreheightwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -3,19 +3,26 @@
|
|||
|
||||
#include "ui_seeddialog.h"
|
||||
#include "seeddialog.h"
|
||||
#include "constants.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);
|
||||
if (m_ctx->wallet->getSeedLanguage().isEmpty()) {
|
||||
qDebug() << "No seed language set, using default";
|
||||
m_ctx->wallet->setSeedLanguage(constants::seedLanguage);
|
||||
}
|
||||
|
||||
QString seedOffset = m_ctx->wallet->getCacheAttribute("feather.seedoffset");
|
||||
QString seed_14_words = m_ctx->wallet->getCacheAttribute("feather.seed");
|
||||
QString seed_25_words = m_ctx->wallet->getSeed(seedOffset);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
SignVerifyDialog::SignVerifyDialog(Wallet *wallet, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_wallet(wallet)
|
||||
, ui(new Ui::SignVerifyDialog)
|
||||
, m_wallet(wallet)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -7,13 +7,16 @@
|
|||
#include <QPushButton>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
|
||||
#include "utils/TorManager.h"
|
||||
#include "utils/os/tails.h"
|
||||
#include "utils/Icons.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);
|
||||
|
||||
|
@ -45,6 +48,9 @@ TorInfoDialog::TorInfoDialog(QWidget *parent, AppContext *ctx)
|
|||
|
||||
ui->label_changes->hide();
|
||||
|
||||
ui->btn_configureInitSync->setIcon(icons()->icon("preferences.svg"));
|
||||
connect(ui->btn_configureInitSync, &QPushButton::clicked, this, &TorInfoDialog::onShowInitSyncConfigDialog);
|
||||
|
||||
#ifndef HAS_TOR_BIN
|
||||
ui->check_useLocalTor->setChecked(true);
|
||||
ui->check_useLocalTor->setEnabled(false);
|
||||
|
@ -118,7 +124,7 @@ void TorInfoDialog::initPrivacyLevel() {
|
|||
}
|
||||
|
||||
if (m_ctx->nodes->connection().isLocal()) {
|
||||
ui->label_notice->setText("You are connected to a local node. Traffic is not routed over Tor.");
|
||||
ui->label_notice->setText("You are connected to a local node. Traffic to node is not routed over Tor.");
|
||||
}
|
||||
else if (Utils::isTorsocks()) {
|
||||
ui->label_notice->setText("Feather was started with torsocks, all traffic is routed over Tor");
|
||||
|
@ -145,6 +151,20 @@ void TorInfoDialog::onStopTor() {
|
|||
torManager()->stop();
|
||||
}
|
||||
|
||||
void TorInfoDialog::onShowInitSyncConfigDialog() {
|
||||
|
||||
int threshold = config()->get(Config::initSyncThreshold).toInt();
|
||||
|
||||
bool ok;
|
||||
int newThreshold = QInputDialog::getInt(this, "Sync threshold",
|
||||
"Synchronize over clearnet if wallet is behind more than x blocks: ",
|
||||
threshold, 0, 10000, 10, &ok);
|
||||
|
||||
if (ok) {
|
||||
config()->set(Config::initSyncThreshold, newThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
TorInfoDialog::~TorInfoDialog() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
@ -29,6 +29,7 @@ private slots:
|
|||
void onApplySettings();
|
||||
void onSettingsChanged();
|
||||
void onStopTor();
|
||||
void onShowInitSyncConfigDialog();
|
||||
|
||||
signals:
|
||||
void torSettingsChanged();
|
||||
|
@ -38,7 +39,7 @@ private:
|
|||
void initPrivacyLevel();
|
||||
|
||||
Ui::TorInfoDialog *ui;
|
||||
AppContext *m_ctx;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tor information</string>
|
||||
<string>Tor settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
|
@ -157,6 +157,19 @@
|
|||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_configureInitSync">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -104,7 +104,7 @@ void TransactionInfoDialog::setData(TransactionInfo* tx) {
|
|||
}
|
||||
|
||||
QString direction = tx->direction() == TransactionInfo::Direction_In ? "received" : "sent";
|
||||
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, tx->displayAmount()));
|
||||
ui->label_amount->setText(QString("Amount %1: %2 XMR").arg(direction, tx->displayAmount()));
|
||||
|
||||
QString fee;
|
||||
if (tx->isCoinbase())
|
||||
|
@ -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,9 +33,9 @@ private:
|
|||
|
||||
Ui::TransactionInfoDialog *ui;
|
||||
|
||||
TxProofDialog *m_txProofDialog;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
TransactionInfo *m_txInfo;
|
||||
Wallet *m_wallet;
|
||||
TxProofDialog *m_txProofDialog;
|
||||
QString m_txKey;
|
||||
QString m_txid;
|
||||
QTimer m_updateTimer;
|
||||
|
|
|
@ -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,17 +7,17 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
|
||||
TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx)
|
||||
TxImportDialog::TxImportDialog(QWidget *parent, QSharedPointer<AppContext> ctx)
|
||||
: QDialog(parent)
|
||||
, m_ctx(ctx)
|
||||
, m_loadTimer(new QTimer(this))
|
||||
, ui(new Ui::TxImportDialog)
|
||||
, m_ctx(std::move(ctx))
|
||||
, m_loadTimer(new QTimer(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->resp->hide();
|
||||
ui->label_loading->hide();
|
||||
|
||||
auto node = ctx->nodes->connection();
|
||||
auto node = m_ctx->nodes->connection();
|
||||
m_rpc = new DaemonRpc(this, getNetworkTor(), node.toAddress());
|
||||
|
||||
connect(ui->btn_load, &QPushButton::clicked, this, &TxImportDialog::loadTx);
|
||||
|
@ -34,12 +34,16 @@ TxImportDialog::TxImportDialog(QWidget *parent, AppContext *ctx)
|
|||
|
||||
void TxImportDialog::loadTx() {
|
||||
QString txid = ui->line_txid->text();
|
||||
QString node = m_ctx->nodes->connection().toAddress();
|
||||
FeatherNode node = m_ctx->nodes->connection();
|
||||
|
||||
if (!node.startsWith("http://"))
|
||||
node = QString("http://%1").arg(node);
|
||||
if (node.isLocal()) {
|
||||
m_rpc->setNetwork(getNetworkClearnet());
|
||||
} else {
|
||||
m_rpc->setNetwork(getNetworkTor());
|
||||
}
|
||||
|
||||
m_rpc->setDaemonAddress(node);
|
||||
qDebug() << node.toURL();
|
||||
m_rpc->setDaemonAddress(node.toURL());
|
||||
m_rpc->getTransactions(QStringList() << txid, false, true);
|
||||
|
||||
ui->label_loading->setText("Loading transaction");
|
||||
|
@ -88,7 +92,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,8 +27,9 @@ private slots:
|
|||
|
||||
private:
|
||||
Ui::TxImportDialog *ui;
|
||||
QSharedPointer<AppContext> m_ctx;
|
||||
|
||||
UtilsNetworking *m_network;
|
||||
AppContext *m_ctx;
|
||||
DaemonRpc *m_rpc;
|
||||
QTimer *m_loadTimer;
|
||||
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "utils/utils.h"
|
||||
#include "model/ModelUtils.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_wallet(wallet)
|
||||
, ui(new Ui::VerifyProofDialog)
|
||||
, m_wallet(wallet)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
@ -48,6 +49,8 @@ VerifyProofDialog::VerifyProofDialog(Wallet *wallet, QWidget *parent)
|
|||
break;
|
||||
}
|
||||
});
|
||||
|
||||
ui->input_formattedProof->setFont(ModelUtils::getMonospaceFont());
|
||||
}
|
||||
|
||||
VerifyProofDialog::~VerifyProofDialog()
|
||||
|
|
|
@ -31,11 +31,11 @@ private:
|
|||
void checkFormattedProof();
|
||||
void proofStatus(bool success, const QString &message);
|
||||
|
||||
QPixmap m_success;
|
||||
QPixmap m_failure;
|
||||
|
||||
Ui::VerifyProofDialog *ui;
|
||||
Wallet *m_wallet;
|
||||
|
||||
QPixmap m_success;
|
||||
QPixmap m_failure;
|
||||
};
|
||||
|
||||
#endif //FEATHER_VERIFYPROOFDIALOG_H
|
||||
|
|
|
@ -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,27 @@ 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::setSearchbarVisible(bool visible) {
|
||||
ui->search->setVisible(visible);
|
||||
}
|
||||
|
||||
void HistoryWidget::focusSearchbar() {
|
||||
ui->search->setFocusPolicy(Qt::StrongFocus);
|
||||
ui->search->setFocus();
|
||||
}
|
||||
|
||||
void HistoryWidget::showContextMenu(const QPoint &point) {
|
||||
|
@ -59,7 +82,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 +102,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 +115,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 +135,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 +143,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 +168,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,16 @@ 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;
|
||||
|
||||
void setSearchbarVisible(bool visible);
|
||||
void focusSearchbar();
|
||||
|
||||
public slots:
|
||||
void setSearchText(const QString &text);
|
||||
void resetModel();
|
||||
void onWalletRefreshed();
|
||||
void onWalletOpened();
|
||||
|
||||
signals:
|
||||
void viewOnBlockExplorer(QString txid);
|
||||
|
@ -55,11 +57,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
|
||||
|
|
|
@ -116,13 +116,6 @@ quint64 AddressBook::count() const
|
|||
return m_rows.size();
|
||||
}
|
||||
|
||||
int AddressBook::lookupPaymentID(const QString &payment_id) const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
return m_addressBookImpl->lookupPaymentID(payment_id.toStdString());
|
||||
}
|
||||
|
||||
QString AddressBook::getDescription(const QString &address) const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
|
|
@ -28,7 +28,6 @@ public:
|
|||
quint64 count() const;
|
||||
Q_INVOKABLE QString errorString() const;
|
||||
Q_INVOKABLE int errorCode() const;
|
||||
Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const;
|
||||
Q_INVOKABLE QString getDescription(const QString &address) const;
|
||||
|
||||
enum ErrorCode {
|
||||
|
|
|
@ -41,6 +41,10 @@ void Coins::refresh(quint32 accountIndex)
|
|||
|
||||
m_pimpl->refresh();
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
if (i->subaddrAccount() != accountIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_tinfo.append(new CoinsInfo(i, this));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#include <QDebug>
|
||||
|
||||
Subaddress::Subaddress(Monero::Subaddress *subaddressImpl, QObject *parent)
|
||||
: QObject(parent), m_subaddressImpl(subaddressImpl), m_unusedLookahead(0)
|
||||
: QObject(parent)
|
||||
, m_subaddressImpl(subaddressImpl)
|
||||
, m_unusedLookahead(0)
|
||||
{
|
||||
getAll();
|
||||
}
|
||||
|
|
|
@ -62,3 +62,8 @@ quint64 SubaddressAccount::count() const
|
|||
|
||||
return m_rows.size();
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* SubaddressAccount::row(int index) const
|
||||
{
|
||||
return m_rows.value(index);
|
||||
}
|
|
@ -22,6 +22,7 @@ public:
|
|||
Q_INVOKABLE void setLabel(quint32 accountIndex, const QString &label) const;
|
||||
Q_INVOKABLE void refresh() const;
|
||||
quint64 count() const;
|
||||
Monero::SubaddressAccountRow* row(int index) const;
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
|
|
|
@ -104,7 +104,6 @@ void TransactionHistory::refresh(quint32 accountIndex)
|
|||
void TransactionHistory::setTxNote(const QString &txid, const QString ¬e)
|
||||
{
|
||||
m_pimpl->setTxNote(txid.toStdString(), note.toStdString());
|
||||
this->refresh(0); // todo: get actual account index
|
||||
emit txNoteChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ private:
|
|||
// history contains locked transfers
|
||||
mutable bool m_locked;
|
||||
|
||||
quint32 lastAccountIndex = 0;
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONHISTORY_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 /* = "" */)
|
||||
|
@ -367,6 +375,8 @@ void Wallet::switchSubaddressAccount(quint32 accountIndex)
|
|||
}
|
||||
m_subaddress->refresh(m_currentSubaddressAccount);
|
||||
m_history->refresh(m_currentSubaddressAccount);
|
||||
m_coins->refresh(m_currentSubaddressAccount);
|
||||
this->subaddressModel()->setCurrentSubaddressAcount(m_currentSubaddressAccount);
|
||||
emit currentSubaddressAccountChanged();
|
||||
}
|
||||
}
|
||||
|
@ -1257,18 +1267,18 @@ void Wallet::onPassphraseEntered(const QString &passphrase, bool enter_on_device
|
|||
Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_walletImpl(w)
|
||||
, m_history(nullptr)
|
||||
, m_history(new TransactionHistory(m_walletImpl->history(), this))
|
||||
, m_historyModel(nullptr)
|
||||
, m_addressBook(nullptr)
|
||||
, m_addressBook(new AddressBook(m_walletImpl->addressBook(), this))
|
||||
, m_addressBookModel(nullptr)
|
||||
, m_daemonBlockChainHeight(0)
|
||||
, m_daemonBlockChainTargetHeight(0)
|
||||
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
||||
, m_disconnected(true)
|
||||
, m_currentSubaddressAccount(0)
|
||||
, m_subaddress(nullptr)
|
||||
, m_subaddress(new Subaddress(m_walletImpl->subaddress(), this))
|
||||
, m_subaddressModel(nullptr)
|
||||
, m_subaddressAccount(nullptr)
|
||||
, m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
|
||||
, m_subaddressAccountModel(nullptr)
|
||||
, m_coinsModel(nullptr)
|
||||
, m_refreshNow(false)
|
||||
|
@ -1276,12 +1286,8 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
|||
, m_refreshing(false)
|
||||
, m_scheduler(this)
|
||||
, m_useSSL(true)
|
||||
, m_coins(new Coins(m_walletImpl->coins(), this))
|
||||
{
|
||||
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
||||
m_addressBook = new AddressBook(m_walletImpl->addressBook(), this);
|
||||
m_subaddress = new Subaddress(m_walletImpl->subaddress(), this);
|
||||
m_subaddressAccount = new SubaddressAccount(m_walletImpl->subaddressAccount(), this);
|
||||
m_coins = new Coins(m_walletImpl->coins(), this);
|
||||
m_walletListener = new WalletListenerImpl(this);
|
||||
m_walletImpl->setListener(m_walletListener);
|
||||
m_currentSubaddressAccount = getCacheAttribute(ATTRIBUTE_SUBADDRESS_ACCOUNT).toUInt();
|
||||
|
@ -1304,19 +1310,6 @@ Wallet::~Wallet()
|
|||
|
||||
m_scheduler.shutdownWaitForFinished();
|
||||
|
||||
delete m_addressBook;
|
||||
m_addressBook = NULL;
|
||||
|
||||
delete m_history;
|
||||
m_history = NULL;
|
||||
delete m_addressBook;
|
||||
m_addressBook = NULL;
|
||||
delete m_subaddress;
|
||||
m_subaddress = NULL;
|
||||
delete m_subaddressAccount;
|
||||
m_subaddressAccount = NULL;
|
||||
delete m_coins;
|
||||
m_coins = NULL;
|
||||
//Monero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl);
|
||||
if(status() == Status_Critical || status() == Status_BadPassword)
|
||||
qDebug("Not storing wallet cache");
|
||||
|
|
|
@ -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
|
||||
|
@ -423,7 +429,7 @@ public:
|
|||
|
||||
// Passphrase entry for hardware wallets
|
||||
void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort=false);
|
||||
virtual void onWalletPassphraseNeeded(bool on_device) override;
|
||||
void onWalletPassphraseNeeded(bool on_device) override;
|
||||
|
||||
quint64 getBytesReceived() const;
|
||||
quint64 getBytesSent() const;
|
||||
|
@ -465,10 +471,6 @@ signals:
|
|||
void refreshingChanged() const;
|
||||
|
||||
private:
|
||||
Wallet(QObject * parent = nullptr);
|
||||
Wallet(Monero::Wallet *w, QObject * parent = 0);
|
||||
~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());
|
||||
|
@ -262,9 +208,21 @@ QString WalletManager::maximumAllowedAmountAsString() const
|
|||
return WalletManager::displayAmount(WalletManager::maximumAllowedAmount());
|
||||
}
|
||||
|
||||
QString WalletManager::displayAmount(quint64 amount)
|
||||
QString WalletManager::displayAmount(quint64 amount, bool trailing_zeroes, int decimals)
|
||||
{
|
||||
return QString::fromStdString(Monero::Wallet::displayAmount(amount));
|
||||
auto amountStr = QString::fromStdString(Monero::Wallet::displayAmount(amount));
|
||||
|
||||
if (decimals < 12) {
|
||||
int i = amountStr.indexOf(".");
|
||||
amountStr.remove(i+decimals+1, 12);
|
||||
}
|
||||
|
||||
if (!trailing_zeroes) {
|
||||
amountStr.remove(QRegExp("0+$"));
|
||||
amountStr.remove(QRegExp("\\.$"));
|
||||
}
|
||||
|
||||
return amountStr;
|
||||
}
|
||||
|
||||
quint64 WalletManager::amountFromString(const QString &amount)
|
||||
|
@ -287,7 +245,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 +287,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 +307,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 +357,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","");
|
||||
|
@ -457,7 +378,6 @@ WalletManager::WalletManager(QObject *parent)
|
|||
: QObject(parent)
|
||||
, m_passphraseReceiver(nullptr)
|
||||
, m_scheduler(this)
|
||||
, m_currentWallet(nullptr)
|
||||
{
|
||||
m_pimpl = Monero::WalletManagerFactory::getWalletManager();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -117,7 +108,7 @@ public:
|
|||
Q_INVOKABLE QString errorString() const;
|
||||
|
||||
//! since we can't call static method from QML, move it to this class
|
||||
Q_INVOKABLE static QString displayAmount(quint64 amount);
|
||||
Q_INVOKABLE static QString displayAmount(quint64 amount, bool trailing_zeroes = true, int decimals = 12);
|
||||
Q_INVOKABLE static quint64 amountFromString(const QString &amount);
|
||||
Q_INVOKABLE static quint64 amountFromDouble(double amount);
|
||||
Q_INVOKABLE quint64 maximumAllowedAmount() 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,16 +169,13 @@ public slots:
|
|||
private:
|
||||
friend class WalletPassphraseListenerImpl;
|
||||
|
||||
explicit WalletManager(QObject *parent = 0);
|
||||
~WalletManager();
|
||||
explicit WalletManager(QObject *parent = nullptr);
|
||||
~WalletManager() override;
|
||||
|
||||
bool isMining() const;
|
||||
|
||||
static WalletManager * m_instance;
|
||||
Monero::WalletManager * m_pimpl;
|
||||
static WalletManager *m_instance;
|
||||
Monero::WalletManager *m_pimpl;
|
||||
mutable QMutex m_mutex;
|
||||
QPointer<Wallet> m_currentWallet;
|
||||
PassphraseReceiver * m_passphraseReceiver;
|
||||
PassphraseReceiver *m_passphraseReceiver;
|
||||
QMutex m_mutex_passphraseReceiver;
|
||||
QString m_proxyAddress;
|
||||
mutable QMutex m_proxyMutex;
|
||||
|
|
107
src/main.cpp
107
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,14 +89,13 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|||
QCommandLineOption bruteforceDictionairy(QStringList() << "bruteforce-dict", "Bruteforce dictionairy", "file");
|
||||
parser.addOption(bruteforceDictionairy);
|
||||
|
||||
auto parsed = parser.parse(argv_);
|
||||
if(!parsed) {
|
||||
bool parsed = parser.parse(argv_);
|
||||
if (!parsed) {
|
||||
qCritical() << parser.errorText();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
bool localTor = parser.isSet(useLocalTorOption);
|
||||
bool stagenet = parser.isSet(stagenetOption);
|
||||
bool testnet = parser.isSet(testnetOption);
|
||||
bool quiet = parser.isSet(quietModeOption);
|
||||
|
@ -103,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
|
||||
|
@ -137,11 +120,70 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
QApplication::setApplicationName("FeatherWallet");
|
||||
|
||||
// Setup config directories
|
||||
QString configDir = Config::defaultConfigDir().path();
|
||||
QString config_dir_tor = QString("%1/%2").arg(configDir).arg("tor");
|
||||
QString config_dir_tordata = QString("%1/%2").arg(configDir).arg("tor/data");
|
||||
QStringList createDirs({configDir, config_dir_tor, config_dir_tordata});
|
||||
for (const auto &d: createDirs) {
|
||||
if (!Utils::dirExists(d)) {
|
||||
qDebug() << QString("Creating directory: %1").arg(d);
|
||||
if (!QDir().mkpath(d)) {
|
||||
qCritical() << "Could not create directory " << d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup logging
|
||||
QString logPath = QString("%1/daemon.log").arg(configDir);
|
||||
Monero::Utils::onStartup();
|
||||
Monero::Wallet::init("", "feather", logPath.toStdString(), true);
|
||||
|
||||
bool logLevelFromEnv;
|
||||
int logLevel = qEnvironmentVariableIntValue("MONERO_LOG_LEVEL", &logLevelFromEnv);
|
||||
|
||||
if (parser.isSet("quiet"))
|
||||
WalletManager::instance()->setLogLevel(-1);
|
||||
else if (logLevelFromEnv && logLevel >= 0 && logLevel <= Monero::WalletManagerFactory::LogLevel_Max)
|
||||
Monero::WalletManagerFactory::setLogLevel(logLevel);
|
||||
|
||||
// Setup wallet directory
|
||||
QString walletDir = config()->get(Config::walletDirectory).toString();
|
||||
if (walletDir.isEmpty()) {
|
||||
walletDir = Utils::defaultWalletDir();
|
||||
config()->set(Config::walletDirectory, walletDir);
|
||||
}
|
||||
if (!QDir().mkpath(walletDir))
|
||||
qCritical() << "Unable to create dir: " << walletDir;
|
||||
|
||||
// Setup Tor config
|
||||
if (parser.isSet("tor-host"))
|
||||
config()->set(Config::socks5Host, parser.value("tor-host"));
|
||||
if (parser.isSet("tor-port"))
|
||||
config()->set(Config::socks5Port, parser.value("tor-port"));
|
||||
if (parser.isSet("use-local-tor"))
|
||||
config()->set(Config::useLocalTor, true);
|
||||
|
||||
if (cliMode) {
|
||||
CLI::Mode mode = [&]{
|
||||
if (exportContacts)
|
||||
return CLI::Mode::ExportContacts;
|
||||
if (exportTxHistory)
|
||||
return CLI::Mode::ExportTxHistory;
|
||||
if (bruteforcePassword)
|
||||
return CLI::Mode::BruteforcePassword;
|
||||
}();
|
||||
|
||||
CLI cli{mode, &parser, &app};
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
||||
parser.process(app); // Parse again for --help and --version
|
||||
|
||||
if(!quiet) {
|
||||
if (!quiet) {
|
||||
QMap<QString, QString> info;
|
||||
info["Qt"] = QT_VERSION_STR;
|
||||
info["Feather"] = FEATHER_VERSION;
|
||||
|
@ -154,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 ?!
|
||||
|
@ -167,6 +207,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|||
qInstallMessageHandler(Utils::applicationLogHandler);
|
||||
qRegisterMetaType<QVector<QString>>();
|
||||
|
||||
auto *mainWindow = new MainWindow(ctx);
|
||||
WindowManager windowManager;
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
189
src/mainwindow.h
189
src/mainwindow.h
|
@ -21,7 +21,7 @@
|
|||
#include "dialog/passwordchangedialog.h"
|
||||
#include "dialog/keysdialog.h"
|
||||
#include "dialog/aboutdialog.h"
|
||||
#include "dialog/restoredialog.h"
|
||||
#include "dialog/RestoreHeightDialog.h"
|
||||
#include "dialog/splashdialog.h"
|
||||
#include "libwalletqt/Wallet.h"
|
||||
#include "model/SubaddressModel.h"
|
||||
|
@ -33,9 +33,17 @@
|
|||
#include "utils/config.h"
|
||||
#include "widgets/ccswidget.h"
|
||||
#include "widgets/redditwidget.h"
|
||||
#include "widgets/tickerwidget.h"
|
||||
#include "widgets/TickerWidget.h"
|
||||
#include "wizard/WalletWizard.h"
|
||||
|
||||
#include "contactswidget.h"
|
||||
#include "historywidget.h"
|
||||
#include "sendwidget.h"
|
||||
#include "receivewidget.h"
|
||||
#include "coinswidget.h"
|
||||
|
||||
#include "WindowManager.h"
|
||||
|
||||
#ifdef HAS_LOCALMONERO
|
||||
#include "widgets/LocalMoneroWidget.h"
|
||||
#endif
|
||||
|
@ -44,10 +52,6 @@
|
|||
#include "widgets/xmrigwidget.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "src/kdmactouchbar.h"
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
@ -62,16 +66,19 @@ struct ToggleTab {
|
|||
Config::ConfigKey configKey;
|
||||
};
|
||||
|
||||
class WindowManager;
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(AppContext *ctx, QWidget *parent = nullptr);
|
||||
static MainWindow *getInstance();
|
||||
static AppContext *getContext();
|
||||
explicit MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
QString walletName();
|
||||
QString walletCachePath();
|
||||
QString walletKeysPath();
|
||||
|
||||
enum Tabs {
|
||||
HOME = 0,
|
||||
HISTORY,
|
||||
|
@ -88,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();
|
||||
|
@ -137,104 +129,110 @@ 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 showAccountSwitcherDialog();
|
||||
|
||||
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);
|
||||
void toggleSearchbar(bool enabled);
|
||||
void onSetStatusText(const QString &text);
|
||||
|
||||
private:
|
||||
void initSkins();
|
||||
void initStatusBar();
|
||||
void initWidgets();
|
||||
void initMenu();
|
||||
void initTray();
|
||||
void initHome();
|
||||
void initTouchBar();
|
||||
void initWalletContext();
|
||||
void initWizard();
|
||||
void startupWarning();
|
||||
bool autoOpenWallet();
|
||||
|
||||
AppContext *m_ctx;
|
||||
|
||||
static MainWindow * pMainWindow;
|
||||
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 updateTitle();
|
||||
void donationNag();
|
||||
void updateRecentlyOpened(const QString &filename);
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
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;
|
||||
QList<PriceTickerWidget*> m_priceTickerWidgets;
|
||||
BalanceTickerWidget *m_balanceTickerWidget;
|
||||
|
||||
// lower status bar
|
||||
QPushButton *m_statusUpdateAvailable;
|
||||
ClickableLabel *m_statusLabelBalance;
|
||||
QLabel *m_statusLabelStatus;
|
||||
QLabel *m_statusLabelNetStats;
|
||||
StatusBarButton *m_statusAccountSwitcher;
|
||||
StatusBarButton *m_statusBtnConnectionStatusIndicator;
|
||||
StatusBarButton *m_statusBtnPassword;
|
||||
StatusBarButton *m_statusBtnPreferences;
|
||||
|
@ -242,18 +240,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;
|
||||
|
||||
|
@ -264,8 +252,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>
|
||||
|
@ -188,29 +188,11 @@
|
|||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="SendWidget" name="sendWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<layout class="QVBoxLayout" name="sendWidgetLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
|
@ -226,7 +208,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ContactsWidget" name="contactWidget" native="true"/>
|
||||
<layout class="QVBoxLayout" name="contactsWidgetLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -240,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>
|
||||
|
@ -254,7 +236,7 @@
|
|||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="CoinsWidget" name="coinsWidget" native="true"/>
|
||||
<layout class="QVBoxLayout" name="coinsWidgetLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -266,11 +248,28 @@
|
|||
<attribute name="title">
|
||||
<string>Calc</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="CalcWidget" name="conversionWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabExchange">
|
||||
<attribute name="icon">
|
||||
|
@ -360,6 +359,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"/>
|
||||
|
@ -413,6 +420,7 @@
|
|||
<addaction name="actionInformation"/>
|
||||
<addaction name="menuAdvanced"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAccount"/>
|
||||
<addaction name="actionPassword"/>
|
||||
<addaction name="actionSeed"/>
|
||||
<addaction name="actionKeys"/>
|
||||
|
@ -470,6 +478,8 @@
|
|||
<addaction name="actionShow_calc"/>
|
||||
<addaction name="actionShow_Exchange"/>
|
||||
<addaction name="actionShow_XMRig"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionShow_Searchbar"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuWallet"/>
|
||||
|
@ -559,7 +569,7 @@
|
|||
</action>
|
||||
<action name="actionClose">
|
||||
<property name="text">
|
||||
<string>Close current wallet</string>
|
||||
<string>Close wallet</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVerifyTxProof">
|
||||
|
@ -732,38 +742,64 @@
|
|||
<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>
|
||||
<action name="actiond">
|
||||
<property name="text">
|
||||
<string>d</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPrimary_account">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Primary account</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAccount">
|
||||
<property name="text">
|
||||
<string>Account</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_Searchbar">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Searchbar</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SendWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>sendwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<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>CoinsWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>coinswidget.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>
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#include "utils/Icons.h"
|
||||
|
||||
AddressBookModel::AddressBookModel(QObject *parent, AddressBook *addressBook)
|
||||
: QAbstractTableModel(parent),
|
||||
m_addressBook(addressBook),
|
||||
m_showFullAddresses(false)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_addressBook(addressBook)
|
||||
, m_showFullAddresses(false)
|
||||
{
|
||||
connect(m_addressBook, &AddressBook::refreshStarted, this, &AddressBookModel::startReset);
|
||||
connect(m_addressBook, &AddressBook::refreshFinished, this, &AddressBookModel::endReset);
|
||||
|
@ -150,11 +150,6 @@ bool AddressBookModel::deleteRow(int row)
|
|||
return m_addressBook->deleteRow(row);
|
||||
}
|
||||
|
||||
int AddressBookModel::lookupPaymentID(const QString &payment_id) const
|
||||
{
|
||||
return m_addressBook->lookupPaymentID(payment_id);
|
||||
}
|
||||
|
||||
bool AddressBookModel::writeCSV(const QString &path) {
|
||||
QString csv = "";
|
||||
for(int i = 0; i < this->rowCount(); i++) {
|
||||
|
|
|
@ -31,7 +31,6 @@ public:
|
|||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
Q_INVOKABLE bool deleteRow(int row);
|
||||
Q_INVOKABLE int lookupPaymentID(const QString &payment_id) const;
|
||||
|
||||
bool isShowFullAddresses() const;
|
||||
void setShowFullAddresses(bool show);
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
#include "CoinsInfo.h"
|
||||
#include "Coins.h"
|
||||
#include "ModelUtils.h"
|
||||
#include "globals.h"
|
||||
#include "constants.h"
|
||||
#include "utils/ColorScheme.h"
|
||||
#include "utils/Icons.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
|
||||
#include <QBrush>
|
||||
|
||||
|
@ -182,9 +183,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
|
|||
case Amount:
|
||||
{
|
||||
if (role == Qt::UserRole) {
|
||||
return cInfo.amount() / globals::cdiv;
|
||||
return cInfo.amount();
|
||||
}
|
||||
return QString::number(cInfo.amount() / globals::cdiv, 'f', 12);
|
||||
return cInfo.displayAmount();
|
||||
}
|
||||
case Frozen:
|
||||
return cInfo.frozen();
|
||||
|
|
|
@ -69,7 +69,15 @@ QVariant NodeModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(role == Qt::BackgroundRole) {
|
||||
else if (role == Qt::ToolTipRole) {
|
||||
switch (index.column()) {
|
||||
case NodeModel::URL: {
|
||||
if (node.isActive)
|
||||
return QString("Feather is connected to this node.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::BackgroundRole) {
|
||||
if (node.isConnecting)
|
||||
return QBrush(ColorScheme::YELLOW.asColor(true));
|
||||
else if (node.isActive)
|
||||
|
|
|
@ -32,9 +32,9 @@ public:
|
|||
|
||||
private:
|
||||
QList<FeatherNode> m_nodes;
|
||||
int m_nodeSource;
|
||||
QIcon m_offline;
|
||||
QIcon m_online;
|
||||
int m_nodeSource;
|
||||
};
|
||||
|
||||
#endif //FEATHER_NODEMODEL_H
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
#include "SubaddressAccount.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFont>
|
||||
#include "ModelUtils.h"
|
||||
|
||||
SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount)
|
||||
: QAbstractListModel(parent), m_subaddressAccount(subaddressAccount)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_subaddressAccount(subaddressAccount)
|
||||
{
|
||||
connect(m_subaddressAccount, &SubaddressAccount::refreshStarted, this, &SubaddressAccountModel::startReset);
|
||||
connect(m_subaddressAccount, &SubaddressAccount::refreshFinished, this, &SubaddressAccountModel::endReset);
|
||||
|
@ -16,13 +19,26 @@ SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccoun
|
|||
void SubaddressAccountModel::startReset(){
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void SubaddressAccountModel::endReset(){
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int SubaddressAccountModel::rowCount(const QModelIndex &) const
|
||||
int SubaddressAccountModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
} else {
|
||||
return m_subaddressAccount->count();
|
||||
}
|
||||
}
|
||||
|
||||
int SubaddressAccountModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return Column::COUNT;
|
||||
}
|
||||
|
||||
QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const
|
||||
|
@ -32,24 +48,17 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const
|
|||
|
||||
QVariant result;
|
||||
|
||||
bool found = m_subaddressAccount->getRow(index.row(), [&result, &role](const Monero::SubaddressAccountRow &row) {
|
||||
switch (role) {
|
||||
case SubaddressAccountAddressRole:
|
||||
result = QString::fromStdString(row.getAddress());
|
||||
break;
|
||||
case SubaddressAccountLabelRole:
|
||||
result = QString::fromStdString(row.getLabel());
|
||||
break;
|
||||
case SubaddressAccountBalanceRole:
|
||||
result = QString::fromStdString(row.getBalance());
|
||||
break;
|
||||
case SubaddressAccountUnlockedBalanceRole:
|
||||
result = QString::fromStdString(row.getUnlockedBalance());
|
||||
break;
|
||||
default:
|
||||
qCritical() << "Unimplemented role" << role;
|
||||
bool found = m_subaddressAccount->getRow(index.row(), [this, &index, &result, &role](const Monero::SubaddressAccountRow &row) {
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
|
||||
result = parseSubaddressAccountRow(row, index, role);
|
||||
}
|
||||
else if (role == Qt::FontRole) {
|
||||
if (index.column() == Column::Balance || index.column() == Column::UnlockedBalance) {
|
||||
result = ModelUtils::getMonospaceFont();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
qCritical("%s: internal error: invalid index %d", __FUNCTION__, index.row());
|
||||
}
|
||||
|
@ -57,15 +66,85 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const
|
|||
return result;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> SubaddressAccountModel::roleNames() const
|
||||
QVariant SubaddressAccountModel::parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row,
|
||||
const QModelIndex &index, int role) const
|
||||
{
|
||||
static QHash<int, QByteArray> roleNames;
|
||||
if (roleNames.empty())
|
||||
{
|
||||
roleNames.insert(SubaddressAccountAddressRole, "address");
|
||||
roleNames.insert(SubaddressAccountLabelRole, "label");
|
||||
roleNames.insert(SubaddressAccountBalanceRole, "balance");
|
||||
roleNames.insert(SubaddressAccountUnlockedBalanceRole, "unlockedBalance");
|
||||
switch (index.column()) {
|
||||
case Number:
|
||||
return QString("#%1").arg(QString::number(index.row()));
|
||||
case Address:
|
||||
return QString::fromStdString(row.getAddress());
|
||||
case Label:
|
||||
return QString::fromStdString(row.getLabel());
|
||||
case Balance:
|
||||
return QString::fromStdString(row.getBalance());
|
||||
case UnlockedBalance:
|
||||
return QString::fromStdString(row.getUnlockedBalance());
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
return roleNames;
|
||||
}
|
||||
|
||||
QVariant SubaddressAccountModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QVariant();
|
||||
}
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section) {
|
||||
case Address:
|
||||
return QString("Address");
|
||||
case Label:
|
||||
return QString("Label");
|
||||
case Balance:
|
||||
return QString("Balance");
|
||||
case UnlockedBalance:
|
||||
return QString("Spendable balance");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SubaddressAccountModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (index.isValid() && role == Qt::EditRole) {
|
||||
const int row = index.row();
|
||||
|
||||
switch (index.column()) {
|
||||
case Label:
|
||||
m_subaddressAccount->setLabel(row, value.toString());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags SubaddressAccountModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::ItemIsEnabled;
|
||||
|
||||
if (index.column() == Label)
|
||||
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
|
||||
|
||||
return QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* SubaddressAccountModel::entryFromIndex(const QModelIndex &index) const {
|
||||
Q_ASSERT(index.isValid() && index.row() < m_subaddressAccount->count());
|
||||
return m_subaddressAccount->row(index.row());
|
||||
}
|
||||
|
||||
SubaddressAccountProxyModel::SubaddressAccountProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
|
@ -4,36 +4,54 @@
|
|||
#ifndef SUBADDRESSACCOUNTMODEL_H
|
||||
#define SUBADDRESSACCOUNTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "Subaddress.h"
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class SubaddressAccount;
|
||||
|
||||
class SubaddressAccountModel : public QAbstractListModel
|
||||
class SubaddressAccountModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SubaddressAccountRowRole {
|
||||
SubaddressAccountRole = Qt::UserRole + 1, // for the SubaddressAccountRow object;
|
||||
SubaddressAccountAddressRole,
|
||||
SubaddressAccountLabelRole,
|
||||
SubaddressAccountBalanceRole,
|
||||
SubaddressAccountUnlockedBalanceRole,
|
||||
enum Column {
|
||||
Number,
|
||||
Address,
|
||||
Label,
|
||||
Balance,
|
||||
UnlockedBalance,
|
||||
COUNT
|
||||
};
|
||||
Q_ENUM(SubaddressAccountRowRole)
|
||||
|
||||
SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
Monero::SubaddressAccountRow* entryFromIndex(const QModelIndex &index) const;
|
||||
|
||||
public slots:
|
||||
void startReset();
|
||||
void endReset();
|
||||
|
||||
private:
|
||||
QVariant parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row, const QModelIndex &index, int role) const;
|
||||
|
||||
SubaddressAccount *m_subaddressAccount;
|
||||
};
|
||||
|
||||
class SubaddressAccountProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SubaddressAccountProxyModel(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // SUBADDRESSACCOUNTMODEL_H
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include <QBrush>
|
||||
|
||||
SubaddressModel::SubaddressModel(QObject *parent, Subaddress *subaddress)
|
||||
: QAbstractTableModel(parent),
|
||||
m_subaddress(subaddress),
|
||||
m_showFullAddresses(false)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_subaddress(subaddress)
|
||||
, m_showFullAddresses(false)
|
||||
{
|
||||
connect(m_subaddress, &Subaddress::refreshStarted, this, &SubaddressModel::startReset);
|
||||
connect(m_subaddress, &Subaddress::refreshFinished, this, &SubaddressModel::endReset);
|
||||
|
@ -143,7 +143,7 @@ bool SubaddressModel::setData(const QModelIndex &index, const QVariant &value, i
|
|||
|
||||
switch (index.column()) {
|
||||
case Label:
|
||||
m_subaddress->setLabel(0, row, value.toString()); // Todo: get actual account index
|
||||
m_subaddress->setLabel(m_currentSubaddressAcount, row, value.toString());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -180,6 +180,10 @@ int SubaddressModel::unusedLookahead() const {
|
|||
return m_subaddress->unusedLookahead();
|
||||
}
|
||||
|
||||
void SubaddressModel::setCurrentSubaddressAcount(quint32 accountIndex) {
|
||||
m_currentSubaddressAcount = accountIndex;
|
||||
}
|
||||
|
||||
Monero::SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const {
|
||||
Q_ASSERT(index.isValid() && index.row() < m_subaddress->count());
|
||||
return m_subaddress->row(index.row());
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue