mirror of
https://github.com/feather-wallet/feather.git
synced 2024-11-17 01:37:53 +00:00
Merge pull request 'Misc changes' (#344) from tobtoht/feather:wizard_redesign into master
Reviewed-on: https://git.featherwallet.org/feather/feather/pulls/344
This commit is contained in:
commit
a3351ba6b2
46 changed files with 562 additions and 258 deletions
|
@ -29,7 +29,7 @@ if(DEBUG)
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(MONERO_HEAD "e175e02b9b8d289bccab3ff0f3fd70c4dbf8c71f")
|
set(MONERO_HEAD "52acbb68c1a4cc67ee539325a8febc2c144596c4")
|
||||||
set(BUILD_GUI_DEPS ON)
|
set(BUILD_GUI_DEPS ON)
|
||||||
set(ARCH "x86-64")
|
set(ARCH "x86-64")
|
||||||
set(BUILD_64 ON)
|
set(BUILD_64 ON)
|
||||||
|
|
|
@ -42,7 +42,7 @@ RUN git clone -b v1.2.11 --depth 1 https://github.com/madler/zlib && \
|
||||||
make -j$THREADS install && \
|
make -j$THREADS install && \
|
||||||
rm -rf $(pwd)
|
rm -rf $(pwd)
|
||||||
|
|
||||||
RUN git clone -b tor-0.4.5.5-rc --depth 1 https://git.torproject.org/tor.git && \
|
RUN git clone -b tor-0.4.5.6 --depth 1 https://git.torproject.org/tor.git && \
|
||||||
cd tor && \
|
cd tor && \
|
||||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||||
./autogen.sh && \
|
./autogen.sh && \
|
||||||
|
|
|
@ -146,8 +146,7 @@ RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.11-s
|
||||||
make -j$THREADS install && \
|
make -j$THREADS install && \
|
||||||
rm -rf $(pwd)
|
rm -rf $(pwd)
|
||||||
|
|
||||||
ENV TOR_VERSION=0.4.5.5-rc
|
RUN git clone -b tor-0.4.5.6 --depth 1 https://git.torproject.org/tor.git && \
|
||||||
RUN git clone -b tor-0.4.5.5-rc --depth 1 https://git.torproject.org/tor.git && \
|
|
||||||
cd tor && \
|
cd tor && \
|
||||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||||
./autogen.sh && \
|
./autogen.sh && \
|
||||||
|
|
16
README.md
16
README.md
|
@ -1,27 +1,19 @@
|
||||||
# Feather - a free Monero desktop wallet
|
# Feather - a free Monero desktop wallet
|
||||||
|
|
||||||
[![Build Status](https://build.featherwallet.org/api/badges/feather/feather/status.svg)](https://build.featherwallet.org/feather/feather)
|
Feather is a free, open-source Monero wallet for Linux, Tails, macOS and Windows. It is written in C++ with the Qt framework.
|
||||||
|
|
||||||
Feather is a free, open-source Monero client Linux with ports for Mac OS and Windows written in C++ with the Qt framework.
|
Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
|
||||||
## Development resources
|
## Resources
|
||||||
* Web: [featherwallet.org](https://featherwallet.org)
|
* Web: [featherwallet.org](https://featherwallet.org)
|
||||||
* Git: [git.featherwallet.org/feather/feather](https://git.featherwallet.org/feather/feather)
|
* Git: [git.featherwallet.org/feather/feather](https://git.featherwallet.org/feather/feather)
|
||||||
* Mail: dev@featherwallet.org
|
* Mail: dev@featherwallet.org
|
||||||
* IRC: `#feather` on OFTC
|
* IRC: `#feather` on OFTC
|
||||||
* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/)
|
* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/)
|
||||||
|
|
||||||
Copyright (c) 2020-2021 The Monero Project.
|
|
||||||
|
|
||||||
## Compiling Feather from source
|
## Compiling Feather from source
|
||||||
|
|
||||||
Feather uses Monero, as such it requires the same dependencies as outlined in [Monero's README](https://github.com/monero-project/monero#compiling-monero-from-source). Additionally, Feather uses:
|
See [BUILDING.md](https://git.featherwallet.org/feather/feather/src/branch/master/BUILDING.md) for information on how to build from source.
|
||||||
|
|
||||||
- Qt 5.15.0
|
|
||||||
- libqrencode
|
|
||||||
- openpgp
|
|
||||||
|
|
||||||
See [BUILDING.md](https://git.featherwallet.org/feather/feather/src/branch/master/BUILDING.md) for information on how to compile a build.
|
|
||||||
|
|
||||||
## Supporting the project
|
## Supporting the project
|
||||||
|
|
||||||
|
|
2
monero
2
monero
|
@ -1 +1 @@
|
||||||
Subproject commit e175e02b9b8d289bccab3ff0f3fd70c4dbf8c71f
|
Subproject commit 52acbb68c1a4cc67ee539325a8febc2c144596c4
|
|
@ -89,19 +89,12 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
|
||||||
menu->addAction(m_thawAllSelectedAction);
|
menu->addAction(m_thawAllSelectedAction);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QModelIndex index = ui->coins->indexAt(point);
|
CoinsInfo* c = this->currentEntry();
|
||||||
if (!index.isValid()) {
|
if (!c) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int row = m_proxyModel->mapToSource(index).row();
|
bool isSpent = c->spent();
|
||||||
|
bool isFrozen = c->frozen();
|
||||||
bool isSpent, isFrozen, isUnlocked;
|
bool isUnlocked = c->unlocked();
|
||||||
m_coins->coin(row, [&isSpent, &isFrozen, &isUnlocked](CoinsInfo &c) {
|
|
||||||
isSpent = c.spent();
|
|
||||||
isFrozen = c.frozen();
|
|
||||||
isUnlocked = c.unlocked();
|
|
||||||
});
|
|
||||||
|
|
||||||
menu->addMenu(m_copyMenu);
|
menu->addMenu(m_copyMenu);
|
||||||
|
|
||||||
|
@ -166,44 +159,28 @@ void CoinsWidget::thawAllSelected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoinsWidget::viewOutput() {
|
void CoinsWidget::viewOutput() {
|
||||||
QModelIndex index = ui->coins->currentIndex();
|
CoinsInfo* c = this->currentEntry();
|
||||||
|
if (!c) return;
|
||||||
|
|
||||||
int row = m_proxyModel->mapToSource(index).row();
|
auto * dialog = new OutputInfoDialog(c, this);
|
||||||
QPointer<CoinsInfo> c;
|
dialog->show();
|
||||||
m_coins->coin(row, [&c](CoinsInfo &cInfo) {
|
|
||||||
c = &cInfo;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (c) {
|
|
||||||
auto * dialog = new OutputInfoDialog(c, this);
|
|
||||||
dialog->show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoinsWidget::onSweepOutput() {
|
void CoinsWidget::onSweepOutput() {
|
||||||
QModelIndex index = ui->coins->currentIndex();
|
CoinsInfo* c = this->currentEntry();
|
||||||
int row = m_proxyModel->mapToSource(index).row();
|
if (!c) return;
|
||||||
|
|
||||||
QString keyImage;
|
QString keyImage = c->keyImage();
|
||||||
bool keyImageKnown;
|
|
||||||
m_coins->coin(row, [&keyImage, &keyImageKnown](CoinsInfo &c) {
|
|
||||||
keyImageKnown = c.keyImageKnown();
|
|
||||||
keyImage = c.keyImage();
|
|
||||||
});
|
|
||||||
|
|
||||||
qCritical() << "key image: " << keyImage;
|
if (!c->keyImageKnown()) {
|
||||||
|
|
||||||
if (!keyImageKnown) {
|
|
||||||
QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown");
|
QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto * dialog = new OutputSweepDialog(this);
|
auto *dialog = new OutputSweepDialog(this, c);
|
||||||
int ret = dialog->exec();
|
int ret = dialog->exec();
|
||||||
if (!ret) return;
|
if (!ret) return;
|
||||||
|
|
||||||
qCritical() << "key image: " << keyImage;
|
|
||||||
|
|
||||||
emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs());
|
emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs());
|
||||||
dialog->deleteLater();
|
dialog->deleteLater();
|
||||||
}
|
}
|
||||||
|
@ -213,39 +190,46 @@ void CoinsWidget::resetModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoinsWidget::copy(copyField field) {
|
void CoinsWidget::copy(copyField field) {
|
||||||
QModelIndex index = ui->coins->currentIndex();
|
CoinsInfo* c = this->currentEntry();
|
||||||
int row = m_proxyModel->mapToSource(index).row();
|
if (!c) return;
|
||||||
|
|
||||||
QString data;
|
QString data;
|
||||||
m_coins->coin(row, [field, &data](CoinsInfo &c) {
|
switch (field) {
|
||||||
switch (field) {
|
case PubKey:
|
||||||
case PubKey:
|
data = c->pubKey();
|
||||||
data = c.pubKey();
|
break;
|
||||||
break;
|
case KeyImage:
|
||||||
case KeyImage:
|
data = c->keyImage();
|
||||||
data = c.keyImage();
|
break;
|
||||||
break;
|
case TxID:
|
||||||
case TxID:
|
data = c->hash();
|
||||||
data = c.hash();
|
break;
|
||||||
break;
|
case Address:
|
||||||
case Address:
|
data = c->address();
|
||||||
data = c.address();
|
break;
|
||||||
break;
|
case Label:
|
||||||
case Label:
|
data = c->addressLabel();
|
||||||
data = c.addressLabel();
|
break;
|
||||||
break;
|
case Height:
|
||||||
case Height:
|
data = QString::number(c->blockHeight());
|
||||||
data = QString::number(c.blockHeight());
|
break;
|
||||||
break;
|
case Amount:
|
||||||
case Amount:
|
data = c->displayAmount();
|
||||||
data = c.displayAmount();
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Utils::copyToClipboard(data);
|
Utils::copyToClipboard(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoinsInfo* CoinsWidget::currentEntry() {
|
||||||
|
QModelIndexList list = ui->coins->selectionModel()->selectedRows();
|
||||||
|
if (list.size() == 1) {
|
||||||
|
return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first()));
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CoinsWidget::~CoinsWidget() {
|
CoinsWidget::~CoinsWidget() {
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ private:
|
||||||
|
|
||||||
void showContextMenu(const QPoint & point);
|
void showContextMenu(const QPoint & point);
|
||||||
void copy(copyField field);
|
void copy(copyField field);
|
||||||
|
CoinsInfo* currentEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
AboutDialog::AboutDialog(QWidget *parent)
|
AboutDialog::AboutDialog(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::AboutDialog)
|
, ui(new Ui::AboutDialog)
|
||||||
|
, m_model(new QStringListModel(this))
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
|
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
|
||||||
|
@ -26,8 +27,6 @@ AboutDialog::AboutDialog(QWidget *parent)
|
||||||
auto ack_text = Utils::barrayToString(ack);
|
auto ack_text = Utils::barrayToString(ack);
|
||||||
ui->ackText->setText(ack_text);
|
ui->ackText->setText(ack_text);
|
||||||
|
|
||||||
m_model = new QStringListModel(this);
|
|
||||||
|
|
||||||
QString contributors = Utils::barrayToString(Utils::fileOpenQRC(":assets/contributors.txt"));
|
QString contributors = Utils::barrayToString(Utils::fileOpenQRC(":assets/contributors.txt"));
|
||||||
QStringList contributor_list = contributors.split("\n");
|
QStringList contributor_list = contributors.split("\n");
|
||||||
m_model->setStringList(contributor_list);
|
m_model->setStringList(contributor_list);
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
|
|
||||||
#include "ui_outputsweepdialog.h"
|
#include "ui_outputsweepdialog.h"
|
||||||
#include "outputsweepdialog.h"
|
#include "outputsweepdialog.h"
|
||||||
|
#include "libwalletqt/WalletManager.h"
|
||||||
|
|
||||||
OutputSweepDialog::OutputSweepDialog(QWidget *parent)
|
OutputSweepDialog::OutputSweepDialog(QWidget *parent, CoinsInfo* coin)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::OutputSweepDialog)
|
, ui(new Ui::OutputSweepDialog)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
m_amount = coin->amount();
|
||||||
|
|
||||||
connect(ui->checkBox_churn, &QCheckBox::toggled, [&](bool toggled){
|
connect(ui->checkBox_churn, &QCheckBox::toggled, [&](bool toggled){
|
||||||
ui->lineEdit_address->setEnabled(!toggled);
|
ui->lineEdit_address->setEnabled(!toggled);
|
||||||
|
ui->lineEdit_address->setText(toggled ? "Primary address" : "");
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){
|
||||||
|
@ -20,6 +24,19 @@ OutputSweepDialog::OutputSweepDialog(QWidget *parent)
|
||||||
m_outputs = ui->spinBox_numOutputs->value();
|
m_outputs = ui->spinBox_numOutputs->value();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->spinBox_numOutputs, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value){
|
||||||
|
if (value == 1) {
|
||||||
|
ui->label_split->setText("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString origAmount = WalletManager::displayAmount(m_amount);
|
||||||
|
QString splitAmount = WalletManager::displayAmount(m_amount / value);
|
||||||
|
|
||||||
|
ui->label_split->setText(QString("%1 XMR ≈ %2x %3 XMR").arg(origAmount, QString::number(value), splitAmount));
|
||||||
|
});
|
||||||
|
ui->label_split->setText("");
|
||||||
|
|
||||||
this->adjustSize();
|
this->adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#define FEATHER_OUTPUTSWEEPDIALOG_H
|
#define FEATHER_OUTPUTSWEEPDIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include "libwalletqt/CoinsInfo.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class OutputSweepDialog;
|
class OutputSweepDialog;
|
||||||
|
@ -15,7 +16,7 @@ class OutputSweepDialog : public QDialog
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OutputSweepDialog(QWidget *parent = nullptr);
|
explicit OutputSweepDialog(QWidget *parent, CoinsInfo* coin);
|
||||||
~OutputSweepDialog() override;
|
~OutputSweepDialog() override;
|
||||||
|
|
||||||
QString address();
|
QString address();
|
||||||
|
@ -25,6 +26,8 @@ public:
|
||||||
private:
|
private:
|
||||||
Ui::OutputSweepDialog *ui;
|
Ui::OutputSweepDialog *ui;
|
||||||
|
|
||||||
|
uint64_t m_amount;
|
||||||
|
|
||||||
QString m_address;
|
QString m_address;
|
||||||
bool m_churn;
|
bool m_churn;
|
||||||
int m_outputs;
|
int m_outputs;
|
||||||
|
|
|
@ -6,16 +6,22 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>623</width>
|
<width>720</width>
|
||||||
<height>231</height>
|
<height>193</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Sweep output</string>
|
<string>Sweep output</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -36,48 +42,60 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QCheckBox" name="checkBox_churn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Send to self (churn)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_churn">
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Send to self (churn)</string>
|
<widget class="QLabel" name="label_2">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Number of outputs:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_numOutputs">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<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>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QLabel" name="label_split">
|
||||||
<property name="title">
|
<property name="enabled">
|
||||||
<string>Advanced options</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_2">
|
<property name="text">
|
||||||
<property name="fieldGrowthPolicy">
|
<string>1.000000000000 XMR ≈ 5x 0.200000000000 XMR</string>
|
||||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
</property>
|
||||||
</property>
|
<property name="textInteractionFlags">
|
||||||
<item row="0" column="0">
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
<widget class="QLabel" name="label_2">
|
</property>
|
||||||
<property name="text">
|
|
||||||
<string>Number of outputs:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QSpinBox" name="spinBox_numOutputs">
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>16</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -7,10 +7,15 @@
|
||||||
#include "libwalletqt/CoinsInfo.h"
|
#include "libwalletqt/CoinsInfo.h"
|
||||||
#include "libwalletqt/WalletManager.h"
|
#include "libwalletqt/WalletManager.h"
|
||||||
#include "libwalletqt/Transfer.h"
|
#include "libwalletqt/Transfer.h"
|
||||||
|
#include "libwalletqt/TransactionHistory.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "utils/ColorScheme.h"
|
#include "utils/ColorScheme.h"
|
||||||
|
#include "model/ModelUtils.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "appcontext.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
|
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
|
@ -23,32 +28,26 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
|
||||||
m_txid = txInfo->hash();
|
m_txid = txInfo->hash();
|
||||||
ui->label_txid->setText(m_txid);
|
ui->label_txid->setText(m_txid);
|
||||||
|
|
||||||
QString txKey = m_wallet->getTxKey(txInfo->hash());
|
m_txKey = m_wallet->getTxKey(txInfo->hash());
|
||||||
if (txKey.isEmpty()) {
|
if (m_txKey.isEmpty()) {
|
||||||
ui->btn_CopyTxKey->setEnabled(false);
|
ui->btn_CopyTxKey->setEnabled(false);
|
||||||
ui->btn_CopyTxKey->setToolTip("Transaction key unknown");
|
ui->btn_CopyTxKey->setToolTip("Transaction key unknown");
|
||||||
}
|
}
|
||||||
m_txKey = txKey;
|
|
||||||
|
|
||||||
connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey);
|
connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey);
|
||||||
connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof);
|
connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof);
|
||||||
|
|
||||||
QString blockHeight = QString::number(txInfo->blockHeight());
|
connect(m_wallet, &Wallet::newBlock, this, &TransactionInfoDialog::updateData);
|
||||||
if (blockHeight == "0")
|
|
||||||
blockHeight = "Unconfirmed";
|
|
||||||
|
|
||||||
ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations()));
|
this->setData(txInfo);
|
||||||
ui->label_date->setText(QString("Date: %1").arg(txInfo->timestamp().toString("yyyy-MM-dd HH:mm")));
|
|
||||||
ui->label_blockHeight->setText(QString("Block height: %1").arg(blockHeight));
|
|
||||||
|
|
||||||
QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent";
|
if (AppContext::txCache.contains(txInfo->hash()) && (txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) {
|
||||||
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount()));
|
connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{
|
||||||
|
emit resendTranscation(m_txid);
|
||||||
QString fee = txInfo->fee().isEmpty() ? "n/a" : txInfo->fee();
|
});
|
||||||
ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee));
|
} else {
|
||||||
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime()));
|
ui->btn_rebroadcastTx->hide();
|
||||||
|
}
|
||||||
qDebug() << m_wallet->coins()->coins_from_txid(txInfo->hash());
|
|
||||||
|
|
||||||
QTextCursor cursor = ui->destinations->textCursor();
|
QTextCursor cursor = ui->destinations->textCursor();
|
||||||
for (const auto& transfer : txInfo->transfers()) {
|
for (const auto& transfer : txInfo->transfers()) {
|
||||||
|
@ -59,15 +58,66 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
|
||||||
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
|
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
|
||||||
cursor.insertBlock();
|
cursor.insertBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txInfo->transfers().size() == 0) {
|
if (txInfo->transfers().size() == 0) {
|
||||||
ui->frameDestinations->hide();
|
ui->frameDestinations->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo);
|
m_txProofDialog = new TxProofDialog(this, m_wallet, txInfo);
|
||||||
|
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
|
qreal lineHeight = QFontMetrics(ui->destinations->document()->defaultFont()).height();
|
||||||
|
qreal docHeight = txInfo->transfers().size();
|
||||||
|
int h = int(docHeight * (lineHeight + 2) + 11);
|
||||||
|
h = qMin(qMax(h, 100), 600);
|
||||||
|
ui->destinations->setMinimumHeight(h);
|
||||||
|
ui->destinations->setMaximumHeight(h);
|
||||||
|
ui->destinations->verticalScrollBar()->hide();
|
||||||
|
|
||||||
this->adjustSize();
|
this->adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TransactionInfoDialog::setData(TransactionInfo* tx) {
|
||||||
|
QString blockHeight = QString::number(tx->blockHeight());
|
||||||
|
|
||||||
|
if (tx->isFailed()) {
|
||||||
|
ui->label_status->setText("Status: Failed (node was unable to relay transaction)");
|
||||||
|
}
|
||||||
|
if (blockHeight == "0") {
|
||||||
|
ui->label_status->setText("Status: Unconfirmed (in mempool)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QString dateTimeFormat = QString("%1 %2").arg(config()->get(Config::dateFormat).toString(), config()->get(Config::timeFormat).toString());
|
||||||
|
QString date = tx->timestamp().toString(dateTimeFormat);
|
||||||
|
QString statusText = QString("Status: Included in block %1 (%2 confirmations) on %3").arg(blockHeight, QString::number(tx->confirmations()), date);
|
||||||
|
ui->label_status->setText(statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (tx->confirmationsRequired() > tx->confirmations()) {
|
||||||
|
bool mandatoryLock = tx->confirmationsRequired() == 10;
|
||||||
|
QString confsRequired = QString::number(tx->confirmationsRequired() - tx->confirmations());
|
||||||
|
ui->label_lock->setText(QString("Lock: Outputs become spendable in %1 blocks (%2)").arg(confsRequired, mandatoryLock ? "consensus rule" : "specified by sender"));
|
||||||
|
} else {
|
||||||
|
ui->label_lock->setText("Lock: Outputs are spendable");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString direction = tx->direction() == TransactionInfo::Direction_In ? "received" : "sent";
|
||||||
|
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, tx->displayAmount()));
|
||||||
|
|
||||||
|
QString fee = tx->fee().isEmpty() ? "n/a" : tx->fee();
|
||||||
|
ui->label_fee->setText(QString("Fee: %1 XMR").arg(tx->isCoinbase() ? WalletManager::displayAmount(0) : fee));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransactionInfoDialog::updateData() {
|
||||||
|
if (!m_wallet) return;
|
||||||
|
TransactionInfo* tx = m_wallet->history()->transaction(m_txid);
|
||||||
|
if (!tx) return;
|
||||||
|
this->setData(tx);
|
||||||
|
}
|
||||||
|
|
||||||
void TransactionInfoDialog::copyTxKey() {
|
void TransactionInfoDialog::copyTxKey() {
|
||||||
Utils::copyToClipboard(m_txKey);
|
Utils::copyToClipboard(m_txKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,14 @@ public:
|
||||||
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
|
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
|
||||||
~TransactionInfoDialog() override;
|
~TransactionInfoDialog() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void resendTranscation(const QString &txid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void copyTxKey();
|
void copyTxKey();
|
||||||
void createTxProof();
|
void createTxProof();
|
||||||
|
void setData(TransactionInfo* tx);
|
||||||
|
void updateData();
|
||||||
|
|
||||||
Ui::TransactionInfoDialog *ui;
|
Ui::TransactionInfoDialog *ui;
|
||||||
|
|
||||||
|
@ -35,6 +40,7 @@ private:
|
||||||
Wallet *m_wallet;
|
Wallet *m_wallet;
|
||||||
QString m_txKey;
|
QString m_txKey;
|
||||||
QString m_txid;
|
QString m_txid;
|
||||||
|
QTimer m_updateTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FEATHER_TRANSACTIONINFODIALOG_H
|
#endif //FEATHER_TRANSACTIONINFODIALOG_H
|
||||||
|
|
|
@ -6,17 +6,14 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>829</width>
|
<width>929</width>
|
||||||
<height>493</height>
|
<height>631</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Transaction</string>
|
<string>Transaction</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
@ -37,81 +34,46 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<widget class="QLabel" name="label_status">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="label_status">
|
<string>Status:</string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Status:</string>
|
<property name="textInteractionFlags">
|
||||||
</property>
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
<property name="textInteractionFlags">
|
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_date">
|
|
||||||
<property name="text">
|
|
||||||
<string>Date:</string>
|
|
||||||
</property>
|
|
||||||
<property name="textInteractionFlags">
|
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_blockHeight">
|
|
||||||
<property name="text">
|
|
||||||
<string>Block height:</string>
|
|
||||||
</property>
|
|
||||||
<property name="textInteractionFlags">
|
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<widget class="QLabel" name="label_lock">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="label_amount">
|
<string>Lock: </string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Amount received:</string>
|
<property name="textInteractionFlags">
|
||||||
</property>
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
<property name="textInteractionFlags">
|
</property>
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<widget class="QLabel" name="label_amount">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="label_fee">
|
<string>Amount received:</string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Fee: </string>
|
<property name="textInteractionFlags">
|
||||||
</property>
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
<property name="textInteractionFlags">
|
</property>
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<widget class="QLabel" name="label_fee">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="label_unlockTime">
|
<string>Fee: </string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Unlock time:</string>
|
<property name="textInteractionFlags">
|
||||||
</property>
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
<property name="textInteractionFlags">
|
</property>
|
||||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
</widget>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
@ -154,6 +116,12 @@
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_destinations">
|
<widget class="QLabel" name="label_destinations">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Destinations:</string>
|
<string>Destinations:</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -162,17 +130,11 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTextEdit" name="destinations">
|
<widget class="QTextEdit" name="destinations">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>100</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -187,7 +149,7 @@
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
<property name="sizeType">
|
||||||
<enum>QSizePolicy::Minimum</enum>
|
<enum>QSizePolicy::Expanding</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
|
@ -213,6 +175,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btn_rebroadcastTx">
|
||||||
|
<property name="text">
|
||||||
|
<string>Rebroadcast Transaction</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -53,6 +53,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
|
@ -67,6 +70,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
|
@ -88,6 +94,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -106,6 +115,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Description:</string>
|
<string>Description:</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -113,6 +125,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Size: </string>
|
<string>Size: </string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -120,6 +135,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Unlock time: </string>
|
<string>Unlock time: </string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -127,6 +145,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ringsize:</string>
|
<string>Ringsize:</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -26,7 +26,7 @@ ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewOnlyDialog::onWriteViewOnlyWallet(){
|
void ViewOnlyDialog::onWriteViewOnlyWallet(){
|
||||||
QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", QDir::homePath(), "Monero wallet (*.keys)");
|
QString fn = QFileDialog::getSaveFileName(this, "Save .keys wallet file", Utils::defaultWalletDir(), "Monero wallet (*.keys)");
|
||||||
if(fn.isEmpty()) return;
|
if(fn.isEmpty()) return;
|
||||||
if(!fn.endsWith(".keys")) fn += ".keys";
|
if(!fn.endsWith(".keys")) fn += ".keys";
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,9 @@ void HistoryWidget::showTxDetails() {
|
||||||
if (!tx) return;
|
if (!tx) return;
|
||||||
|
|
||||||
auto *dialog = new TransactionInfoDialog(m_wallet, tx, this);
|
auto *dialog = new TransactionInfoDialog(m_wallet, tx, this);
|
||||||
|
connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){
|
||||||
|
emit resendTransaction(txid);
|
||||||
|
});
|
||||||
dialog->show();
|
dialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,11 @@ bool Coins::coin(int index, std::function<void (CoinsInfo &)> callback)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoinsInfo* Coins::coin(int index)
|
||||||
|
{
|
||||||
|
return m_tinfo.value(index);
|
||||||
|
}
|
||||||
|
|
||||||
void Coins::refresh(quint32 accountIndex)
|
void Coins::refresh(quint32 accountIndex)
|
||||||
{
|
{
|
||||||
emit refreshStarted();
|
emit refreshStarted();
|
||||||
|
@ -74,18 +79,17 @@ void Coins::thaw(int index) const
|
||||||
emit coinThawed();
|
emit coinThawed();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Coins::coins_from_txid(const QString &txid)
|
QVector<CoinsInfo*> Coins::coins_from_txid(const QString &txid)
|
||||||
{
|
{
|
||||||
QStringList keyimages;
|
QVector<CoinsInfo*> coins;
|
||||||
|
|
||||||
for (int i = 0; i < this->count(); i++) {
|
for (int i = 0; i < this->count(); i++) {
|
||||||
this->coin(i, [&keyimages, &txid](const CoinsInfo &x) {
|
CoinsInfo* coin = this->coin(i);
|
||||||
if (x.hash() == txid) {
|
if (coin->hash() == txid) {
|
||||||
keyimages += x.keyImage();
|
coins.append(coin);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return keyimages;
|
return coins;
|
||||||
}
|
}
|
||||||
|
|
||||||
Coins::Coins(Monero::Coins *pimpl, QObject *parent)
|
Coins::Coins(Monero::Coins *pimpl, QObject *parent)
|
||||||
|
|
|
@ -25,11 +25,12 @@ Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE bool coin(int index, std::function<void (CoinsInfo &)> callback);
|
Q_INVOKABLE bool coin(int index, std::function<void (CoinsInfo &)> callback);
|
||||||
|
Q_INVOKABLE CoinsInfo * coin(int index);
|
||||||
Q_INVOKABLE void refresh(quint32 accountIndex);
|
Q_INVOKABLE void refresh(quint32 accountIndex);
|
||||||
Q_INVOKABLE void refreshUnlocked();
|
Q_INVOKABLE void refreshUnlocked();
|
||||||
Q_INVOKABLE void freeze(int index) const;
|
Q_INVOKABLE void freeze(int index) const;
|
||||||
Q_INVOKABLE void thaw(int index) const;
|
Q_INVOKABLE void thaw(int index) const;
|
||||||
Q_INVOKABLE QStringList coins_from_txid(const QString &txid); // Todo: return CoinsInfo vector
|
Q_INVOKABLE QVector<CoinsInfo*> coins_from_txid(const QString &txid);
|
||||||
|
|
||||||
quint64 count() const;
|
quint64 count() const;
|
||||||
|
|
||||||
|
|
|
@ -78,3 +78,8 @@ quint64 Subaddress::count() const
|
||||||
|
|
||||||
return m_rows.size();
|
return m_rows.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Monero::SubaddressRow* Subaddress::row(int index) const
|
||||||
|
{
|
||||||
|
return m_rows.value(index);
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ public:
|
||||||
Q_INVOKABLE void refresh(quint32 accountIndex) const;
|
Q_INVOKABLE void refresh(quint32 accountIndex) const;
|
||||||
Q_INVOKABLE quint64 unusedLookahead() const;
|
Q_INVOKABLE quint64 unusedLookahead() const;
|
||||||
quint64 count() const;
|
quint64 count() const;
|
||||||
|
Monero::SubaddressRow* row(int index) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void refreshStarted() const;
|
void refreshStarted() const;
|
||||||
|
|
|
@ -293,6 +293,11 @@ bool Wallet::viewOnly() const
|
||||||
return m_walletImpl->watchOnly();
|
return m_walletImpl->watchOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::isDeterministic() const
|
||||||
|
{
|
||||||
|
return m_walletImpl->isDeterministic();
|
||||||
|
}
|
||||||
|
|
||||||
quint64 Wallet::balance() const
|
quint64 Wallet::balance() const
|
||||||
{
|
{
|
||||||
return balance(m_currentSubaddressAccount);
|
return balance(m_currentSubaddressAccount);
|
||||||
|
@ -400,9 +405,11 @@ void Wallet::refreshHeightAsync()
|
||||||
daemonHeightFuture.second.waitForFinished();
|
daemonHeightFuture.second.waitForFinished();
|
||||||
targetHeightFuture.second.waitForFinished();
|
targetHeightFuture.second.waitForFinished();
|
||||||
|
|
||||||
setConnectionStatus(ConnectionStatus_Connected);
|
if (daemonHeight > 0 && targetHeight > 0) {
|
||||||
|
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
||||||
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
qDebug() << "Setting connection status from refreshHeightAsync";
|
||||||
|
setConnectionStatus(ConnectionStatus_Connected);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,9 @@ public:
|
||||||
//! returns if view only wallet
|
//! returns if view only wallet
|
||||||
Q_INVOKABLE bool viewOnly() const;
|
Q_INVOKABLE bool viewOnly() const;
|
||||||
|
|
||||||
|
//! return true if deterministic keys
|
||||||
|
Q_INVOKABLE bool isDeterministic() const;
|
||||||
|
|
||||||
Q_INVOKABLE void refreshHeightAsync();
|
Q_INVOKABLE void refreshHeightAsync();
|
||||||
|
|
||||||
//! export/import key images
|
//! export/import key images
|
||||||
|
|
|
@ -597,7 +597,7 @@ void MainWindow::onWalletOpened() {
|
||||||
|
|
||||||
// receive page
|
// receive page
|
||||||
m_ctx->currentWallet->subaddress()->refresh( m_ctx->currentWallet->currentSubaddressAccount());
|
m_ctx->currentWallet->subaddress()->refresh( m_ctx->currentWallet->currentSubaddressAccount());
|
||||||
ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet->subaddress());
|
ui->receiveWidget->setModel( m_ctx->currentWallet->subaddressModel(), m_ctx->currentWallet);
|
||||||
if (m_ctx->currentWallet->subaddress()->count() == 1) {
|
if (m_ctx->currentWallet->subaddress()->count() == 1) {
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), "");
|
m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), "");
|
||||||
|
@ -837,6 +837,16 @@ void MainWindow::showWalletInfoDialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showSeedDialog() {
|
void MainWindow::showSeedDialog() {
|
||||||
|
if (m_ctx->currentWallet->viewOnly()) {
|
||||||
|
QMessageBox::information(this, "Information", "Wallet is view-only and has no seed.\n\nTo obtain wallet keys go to Wallet -> View-Only");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_ctx->currentWallet->isDeterministic()) {
|
||||||
|
QMessageBox::information(this, "Information", "Wallet is non-deterministic and has no seed.\n\nTo obtain wallet keys go to Wallet -> Keys");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto *dialog = new SeedDialog(m_ctx->currentWallet, this);
|
auto *dialog = new SeedDialog(m_ctx->currentWallet, this);
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
dialog->deleteLater();
|
dialog->deleteLater();
|
||||||
|
@ -1303,6 +1313,11 @@ void MainWindow::updateNetStats() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) {
|
||||||
|
m_statusLabelNetStats->setText("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Connected && m_ctx->currentWallet->synchronized()) {
|
if (m_ctx->currentWallet->connectionStatus() == Wallet::ConnectionStatus_Connected && m_ctx->currentWallet->synchronized()) {
|
||||||
m_statusLabelNetStats->setText("");
|
m_statusLabelNetStats->setText("");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -197,4 +197,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinsInfo* CoinsModel::entryFromIndex(const QModelIndex &index) const {
|
||||||
|
Q_ASSERT(index.isValid() && index.row() < m_coins->count());
|
||||||
|
return m_coins->coin(index.row());
|
||||||
}
|
}
|
|
@ -43,6 +43,8 @@ public:
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
|
CoinsInfo* entryFromIndex(const QModelIndex &index) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void startReset();
|
void startReset();
|
||||||
void endReset();
|
void endReset();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "HistoryView.h"
|
#include "HistoryView.h"
|
||||||
|
|
||||||
#include "TransactionHistoryProxyModel.h"
|
#include "TransactionHistoryProxyModel.h"
|
||||||
|
#include "libwalletqt/TransactionInfo.h"
|
||||||
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
@ -186,3 +187,14 @@ void HistoryView::resetViewToDefaults()
|
||||||
fitColumnsToWindow();
|
fitColumnsToWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryView::keyPressEvent(QKeyEvent *event) {
|
||||||
|
TransactionInfo* tx = this->currentEntry();
|
||||||
|
|
||||||
|
if (event->matches(QKeySequence::Copy) && tx) {
|
||||||
|
Utils::copyToClipboard(tx->hash());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QTreeView::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
#ifndef FEATHER_HISTORYVIEW_H
|
#ifndef FEATHER_HISTORYVIEW_H
|
||||||
#define FEATHER_HISTORYVIEW_H
|
#define FEATHER_HISTORYVIEW_H
|
||||||
|
|
||||||
|
#include <QKeyEvent>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
|
||||||
|
@ -29,6 +30,9 @@ private slots:
|
||||||
void fitColumnsToContents();
|
void fitColumnsToContents();
|
||||||
void resetViewToDefaults();
|
void resetViewToDefaults();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TransactionHistoryModel* sourceModel();
|
TransactionHistoryModel* sourceModel();
|
||||||
|
|
||||||
|
|
|
@ -180,3 +180,8 @@ bool SubaddressModel::isShowFullAddresses() const {
|
||||||
int SubaddressModel::unusedLookahead() const {
|
int SubaddressModel::unusedLookahead() const {
|
||||||
return m_subaddress->unusedLookahead();
|
return m_subaddress->unusedLookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Monero::SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const {
|
||||||
|
Q_ASSERT(index.isValid() && index.row() < m_subaddress->count());
|
||||||
|
return m_subaddress->row(index.row());
|
||||||
|
}
|
|
@ -38,6 +38,8 @@ public:
|
||||||
bool isShowFullAddresses() const;
|
bool isShowFullAddresses() const;
|
||||||
void setShowFullAddresses(bool show);
|
void setShowFullAddresses(bool show);
|
||||||
|
|
||||||
|
Monero::SubaddressRow* entryFromIndex(const QModelIndex &index) const;
|
||||||
|
|
||||||
int unusedLookahead() const;
|
int unusedLookahead() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -29,6 +29,10 @@ bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &so
|
||||||
if (sourceRow == 0 && m_hidePrimary)
|
if (sourceRow == 0 && m_hidePrimary)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!m_showHidden && m_hiddenAddresses.contains(address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_searchRegExp.isEmpty()) {
|
if (!m_searchRegExp.isEmpty()) {
|
||||||
return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp);
|
return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,16 +22,30 @@ public slots:
|
||||||
m_searchCaseSensitiveRegExp.setPattern(searchString);
|
m_searchCaseSensitiveRegExp.setPattern(searchString);
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setShowUsed(const bool showUsed){
|
void setShowUsed(const bool showUsed){
|
||||||
m_showUsed = showUsed;
|
m_showUsed = showUsed;
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setShowHidden(const bool showHidden){
|
||||||
|
m_showHidden = showHidden;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHiddenAddresses(const QStringList& hiddenAddresses) {
|
||||||
|
m_hiddenAddresses = hiddenAddresses;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Subaddress *m_subaddress;
|
Subaddress *m_subaddress;
|
||||||
|
|
||||||
|
QStringList m_hiddenAddresses;
|
||||||
QRegExp m_searchRegExp;
|
QRegExp m_searchRegExp;
|
||||||
QRegExp m_searchCaseSensitiveRegExp;
|
QRegExp m_searchCaseSensitiveRegExp;
|
||||||
bool m_showUsed = false;
|
bool m_showUsed = false;
|
||||||
|
bool m_showHidden = false;
|
||||||
bool m_hidePrimary;
|
bool m_hidePrimary;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,10 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case Column::Date:
|
case Column::Date:
|
||||||
return tInfo.timestamp().toString("yyyy-MM-dd HH:mm ");
|
{
|
||||||
|
return tInfo.timestamp().toString(QString("%1 %2 ").arg(config()->get(Config::dateFormat).toString(),
|
||||||
|
config()->get(Config::timeFormat).toString()));
|
||||||
|
}
|
||||||
case Column::Description:
|
case Column::Description:
|
||||||
return tInfo.description();
|
return tInfo.description();
|
||||||
case Column::Amount:
|
case Column::Amount:
|
||||||
|
|
|
@ -35,13 +35,19 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) :
|
||||||
|
|
||||||
connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog);
|
connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog);
|
||||||
connect(ui->label_addressSearch, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter);
|
connect(ui->label_addressSearch, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter);
|
||||||
|
|
||||||
|
connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses);
|
||||||
|
connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::setModel(SubaddressModel * model, Subaddress * subaddress) {
|
void ReceiveWidget::setModel(SubaddressModel * model, Wallet * wallet) {
|
||||||
m_subaddress = subaddress;
|
m_wallet = wallet;
|
||||||
|
m_subaddress = wallet->subaddress();
|
||||||
m_model = model;
|
m_model = model;
|
||||||
m_proxyModel = new SubaddressProxyModel(this, subaddress);
|
m_proxyModel = new SubaddressProxyModel(this, m_subaddress);
|
||||||
m_proxyModel->setSourceModel(m_model);
|
m_proxyModel->setSourceModel(m_model);
|
||||||
|
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
||||||
|
|
||||||
ui->addresses->setModel(m_proxyModel);
|
ui->addresses->setModel(m_proxyModel);
|
||||||
|
|
||||||
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
|
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
|
||||||
|
@ -74,13 +80,13 @@ void ReceiveWidget::editLabel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::showContextMenu(const QPoint &point) {
|
void ReceiveWidget::showContextMenu(const QPoint &point) {
|
||||||
QModelIndex index = ui->addresses->indexAt(point);
|
Monero::SubaddressRow* row = this->currentEntry();
|
||||||
if (!index.isValid()) {
|
if (!row) return;
|
||||||
return;
|
|
||||||
}
|
QString address = QString::fromStdString(row->getAddress());
|
||||||
|
bool isUsed = row->isUsed();
|
||||||
|
|
||||||
auto *menu = new QMenu(ui->addresses);
|
auto *menu = new QMenu(ui->addresses);
|
||||||
bool isUsed = index.model()->data(index.siblingAtColumn(SubaddressModel::isUsed), Qt::UserRole).toBool();
|
|
||||||
|
|
||||||
menu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ReceiveWidget::copyAddress);
|
menu->addAction(QIcon(":/assets/images/copy.png"), "Copy address", this, &ReceiveWidget::copyAddress);
|
||||||
menu->addAction(QIcon(":/assets/images/copy.png"), "Copy label", this, &ReceiveWidget::copyLabel);
|
menu->addAction(QIcon(":/assets/images/copy.png"), "Copy label", this, &ReceiveWidget::copyLabel);
|
||||||
|
@ -90,6 +96,13 @@ void ReceiveWidget::showContextMenu(const QPoint &point) {
|
||||||
menu->addAction(m_showTransactionsAction);
|
menu->addAction(m_showTransactionsAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList hiddenAddresses = this->getHiddenAddresses();
|
||||||
|
if (hiddenAddresses.contains(address)) {
|
||||||
|
menu->addAction("Show address", this, &ReceiveWidget::showAddress);
|
||||||
|
} else {
|
||||||
|
menu->addAction("Hide address", this, &ReceiveWidget::hideAddress);
|
||||||
|
}
|
||||||
|
|
||||||
menu->popup(ui->addresses->viewport()->mapToGlobal(point));
|
menu->popup(ui->addresses->viewport()->mapToGlobal(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +130,11 @@ void ReceiveWidget::setShowUsedAddresses(bool show) {
|
||||||
m_proxyModel->setShowUsed(show);
|
m_proxyModel->setShowUsed(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::setShowHiddenAddresses(bool show) {
|
||||||
|
if (!m_proxyModel) return;
|
||||||
|
m_proxyModel->setShowHidden(show);
|
||||||
|
}
|
||||||
|
|
||||||
void ReceiveWidget::setSearchFilter(const QString &filter) {
|
void ReceiveWidget::setSearchFilter(const QString &filter) {
|
||||||
if (!m_proxyModel) return;
|
if (!m_proxyModel) return;
|
||||||
m_proxyModel->setSearchFilter(filter);
|
m_proxyModel->setSearchFilter(filter);
|
||||||
|
@ -128,6 +146,24 @@ void ReceiveWidget::showHeaderMenu(const QPoint& position)
|
||||||
m_headerMenu->exec(QCursor::pos());
|
m_headerMenu->exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::hideAddress()
|
||||||
|
{
|
||||||
|
Monero::SubaddressRow* row = this->currentEntry();
|
||||||
|
if (!row) return;
|
||||||
|
QString address = QString::fromStdString(row->getAddress());
|
||||||
|
this->addHiddenAddress(address);
|
||||||
|
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::showAddress()
|
||||||
|
{
|
||||||
|
Monero::SubaddressRow* row = this->currentEntry();
|
||||||
|
if (!row) return;
|
||||||
|
QString address = QString::fromStdString(row->getAddress());
|
||||||
|
this->removeHiddenAddress(address);
|
||||||
|
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
||||||
|
}
|
||||||
|
|
||||||
void ReceiveWidget::updateQrCode(){
|
void ReceiveWidget::updateQrCode(){
|
||||||
QModelIndex index = ui->addresses->currentIndex();
|
QModelIndex index = ui->addresses->currentIndex();
|
||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
|
@ -156,6 +192,36 @@ void ReceiveWidget::showQrCodeDialog() {
|
||||||
dialog->deleteLater();
|
dialog->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList ReceiveWidget::getHiddenAddresses() {
|
||||||
|
QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses");
|
||||||
|
return data.split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::addHiddenAddress(const QString& address) {
|
||||||
|
QStringList hiddenAddresses = this->getHiddenAddresses();
|
||||||
|
if (!hiddenAddresses.contains(address)) {
|
||||||
|
hiddenAddresses.append(address);
|
||||||
|
}
|
||||||
|
QString data = hiddenAddresses.join(",");
|
||||||
|
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::removeHiddenAddress(const QString &address) {
|
||||||
|
QStringList hiddenAddresses = this->getHiddenAddresses();
|
||||||
|
hiddenAddresses.removeAll(address);
|
||||||
|
QString data = hiddenAddresses.join(",");
|
||||||
|
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Monero::SubaddressRow* ReceiveWidget::currentEntry() {
|
||||||
|
QModelIndexList list = ui->addresses->selectionModel()->selectedRows();
|
||||||
|
if (list.size() == 1) {
|
||||||
|
return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first()));
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ReceiveWidget::~ReceiveWidget() {
|
ReceiveWidget::~ReceiveWidget() {
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ReceiveWidget(QWidget *parent = nullptr);
|
explicit ReceiveWidget(QWidget *parent = nullptr);
|
||||||
void setModel(SubaddressModel * model, Subaddress * subaddress);
|
void setModel(SubaddressModel * model, Wallet * wallet);
|
||||||
~ReceiveWidget() override;
|
~ReceiveWidget() override;
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ public slots:
|
||||||
void showContextMenu(const QPoint& point);
|
void showContextMenu(const QPoint& point);
|
||||||
void setShowFullAddresses(bool show);
|
void setShowFullAddresses(bool show);
|
||||||
void setShowUsedAddresses(bool show);
|
void setShowUsedAddresses(bool show);
|
||||||
|
void setShowHiddenAddresses(bool show);
|
||||||
void setSearchFilter(const QString &filter);
|
void setSearchFilter(const QString &filter);
|
||||||
void onShowTransactions();
|
void onShowTransactions();
|
||||||
void resetModel();
|
void resetModel();
|
||||||
|
@ -44,6 +45,8 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showHeaderMenu(const QPoint& position);
|
void showHeaderMenu(const QPoint& position);
|
||||||
|
void hideAddress();
|
||||||
|
void showAddress();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ReceiveWidget *ui;
|
Ui::ReceiveWidget *ui;
|
||||||
|
@ -54,9 +57,14 @@ private:
|
||||||
Subaddress * m_subaddress;
|
Subaddress * m_subaddress;
|
||||||
SubaddressModel * m_model;
|
SubaddressModel * m_model;
|
||||||
SubaddressProxyModel * m_proxyModel;
|
SubaddressProxyModel * m_proxyModel;
|
||||||
|
Wallet * m_wallet;
|
||||||
|
|
||||||
void updateQrCode();
|
void updateQrCode();
|
||||||
void showQrCodeDialog();
|
void showQrCodeDialog();
|
||||||
|
QStringList getHiddenAddresses();
|
||||||
|
void addHiddenAddress(const QString& address);
|
||||||
|
void removeHiddenAddress(const QString& address);
|
||||||
|
Monero::SubaddressRow* currentEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FEATHER_RECEIVEWIDGET_H
|
#endif //FEATHER_RECEIVEWIDGET_H
|
||||||
|
|
|
@ -82,6 +82,27 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="check_showUsed">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show used</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="check_showHidden">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show hidden</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btn_generateSubaddress">
|
<widget class="QPushButton" name="btn_generateSubaddress">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -46,7 +46,14 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="PayToEdit" name="lineAddress"/>
|
<widget class="PayToEdit" name="lineAddress">
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QPlainTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="HelpLabel" name="label_Description">
|
<widget class="HelpLabel" name="label_Description">
|
||||||
|
|
|
@ -48,10 +48,29 @@ Settings::Settings(QWidget *parent) :
|
||||||
}
|
}
|
||||||
ui->comboBox_amountPrecision->setCurrentIndex(config()->get(Config::amountPrecision).toInt());
|
ui->comboBox_amountPrecision->setCurrentIndex(config()->get(Config::amountPrecision).toInt());
|
||||||
|
|
||||||
|
// Date format combobox
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
for (const auto & format : m_dateFormats) {
|
||||||
|
ui->comboBox_dateFormat->addItem(now.toString(format));
|
||||||
|
}
|
||||||
|
QString dateFormatSetting = config()->get(Config::dateFormat).toString();
|
||||||
|
if (m_dateFormats.contains(dateFormatSetting))
|
||||||
|
ui->comboBox_dateFormat->setCurrentIndex(m_dateFormats.indexOf(dateFormatSetting));
|
||||||
|
|
||||||
|
// Time format combobox
|
||||||
|
for (const auto & format : m_timeFormats) {
|
||||||
|
ui->comboBox_timeFormat->addItem(now.toString(format));
|
||||||
|
}
|
||||||
|
QString timeFormatSetting = config()->get(Config::timeFormat).toString();
|
||||||
|
if (m_timeFormats.contains(timeFormatSetting))
|
||||||
|
ui->comboBox_timeFormat->setCurrentIndex(m_timeFormats.indexOf(timeFormatSetting));
|
||||||
|
|
||||||
connect(ui->comboBox_skin, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged);
|
connect(ui->comboBox_skin, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_skinChanged);
|
||||||
connect(ui->comboBox_blockExplorer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged);
|
connect(ui->comboBox_blockExplorer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_blockExplorerChanged);
|
||||||
connect(ui->comboBox_redditFrontend, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_redditFrontendChanged);
|
connect(ui->comboBox_redditFrontend, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_redditFrontendChanged);
|
||||||
connect(ui->comboBox_amountPrecision, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_amountPrecisionChanged);
|
connect(ui->comboBox_amountPrecision, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_amountPrecisionChanged);
|
||||||
|
connect(ui->comboBox_dateFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_dateFormatChanged);
|
||||||
|
connect(ui->comboBox_timeFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Settings::comboBox_timeFormatChanged);
|
||||||
|
|
||||||
// setup preferred fiat currency combobox
|
// setup preferred fiat currency combobox
|
||||||
QStringList fiatCurrencies;
|
QStringList fiatCurrencies;
|
||||||
|
@ -110,6 +129,14 @@ void Settings::comboBox_amountPrecisionChanged(int pos) {
|
||||||
emit amountPrecisionChanged(pos);
|
emit amountPrecisionChanged(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::comboBox_dateFormatChanged(int pos) {
|
||||||
|
config()->set(Config::dateFormat, m_dateFormats.at(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::comboBox_timeFormatChanged(int pos) {
|
||||||
|
config()->set(Config::timeFormat, m_timeFormats.at(pos));
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::copyToClipboard() {
|
void Settings::copyToClipboard() {
|
||||||
ui->textLogs->copy();
|
ui->textLogs->copy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,15 +40,18 @@ public slots:
|
||||||
void comboBox_blockExplorerChanged(int pos);
|
void comboBox_blockExplorerChanged(int pos);
|
||||||
void comboBox_redditFrontendChanged(int pos);
|
void comboBox_redditFrontendChanged(int pos);
|
||||||
void comboBox_amountPrecisionChanged(int pos);
|
void comboBox_amountPrecisionChanged(int pos);
|
||||||
|
void comboBox_dateFormatChanged(int pos);
|
||||||
private:
|
void comboBox_timeFormatChanged(int pos);
|
||||||
QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupSkinCombobox();
|
void setupSkinCombobox();
|
||||||
|
|
||||||
AppContext *m_ctx;
|
AppContext *m_ctx;
|
||||||
Ui::Settings *ui;
|
Ui::Settings *ui;
|
||||||
|
|
||||||
|
QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
|
||||||
|
QStringList m_dateFormats{"yyyy-MM-dd", "MM-dd-yyyy", "dd-MM-yyyy"};
|
||||||
|
QStringList m_timeFormats{"hh:mm", "hh:mm ap"};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|
|
@ -161,14 +161,14 @@
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QCheckBox" name="checkBox_externalLink">
|
<widget class="QCheckBox" name="checkBox_externalLink">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Warn before opening external link</string>
|
<string>Warn before opening external link</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="8" column="0">
|
||||||
<widget class="QCheckBox" name="checkBox_hideBalance">
|
<widget class="QCheckBox" name="checkBox_hideBalance">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Hide balance</string>
|
<string>Hide balance</string>
|
||||||
|
@ -211,6 +211,26 @@
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QComboBox" name="comboBox_amountPrecision"/>
|
<widget class="QComboBox" name="comboBox_amountPrecision"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Date format:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QComboBox" name="comboBox_dateFormat"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Time format:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QComboBox" name="comboBox_timeFormat"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tab_node">
|
<widget class="QWidget" name="tab_node">
|
||||||
|
|
|
@ -48,7 +48,9 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
||||||
{Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}},
|
{Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}},
|
||||||
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
|
{Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
|
||||||
{Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}},
|
{Config::GUI_HistoryViewState, {QS("GUI_HistoryViewState"), {}}},
|
||||||
{Config::amountPrecision, {QS("amountPrecision"), 4}}
|
{Config::amountPrecision, {QS("amountPrecision"), 4}},
|
||||||
|
{Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}},
|
||||||
|
{Config::timeFormat, {QS("timeFormat"), "HH:mm"}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,9 @@ public:
|
||||||
showHistorySyncNotice,
|
showHistorySyncNotice,
|
||||||
GUI_HistoryViewState,
|
GUI_HistoryViewState,
|
||||||
amountPrecision,
|
amountPrecision,
|
||||||
portableMode
|
portableMode,
|
||||||
|
dateFormat,
|
||||||
|
timeFormat
|
||||||
};
|
};
|
||||||
|
|
||||||
~Config() override;
|
~Config() override;
|
||||||
|
|
|
@ -82,6 +82,9 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="check_darkMode">
|
<widget class="QCheckBox" name="check_darkMode">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Dark mode</string>
|
<string>Dark mode</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -26,7 +26,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AppContext *m_ctx;
|
AppContext *m_ctx;
|
||||||
QLabel *topLabel;
|
|
||||||
Ui::PageNetwork *ui;
|
Ui::PageNetwork *ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,6 @@ public:
|
||||||
int nextId() const override;
|
int nextId() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetWidgets();
|
|
||||||
|
|
||||||
AppContext *m_ctx;
|
AppContext *m_ctx;
|
||||||
WizardFields *m_fields;
|
WizardFields *m_fields;
|
||||||
Ui::PageWalletRestoreKeys *ui;
|
Ui::PageWalletRestoreKeys *ui;
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "PageWalletRestoreSeed.h"
|
#include "PageWalletRestoreSeed.h"
|
||||||
#include "ui_PageWalletRestoreSeed.h"
|
#include "ui_PageWalletRestoreSeed.h"
|
||||||
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue