mirror of
https://github.com/feather-wallet/feather.git
synced 2024-11-16 17:27:38 +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)
|
||||
endif()
|
||||
|
||||
set(MONERO_HEAD "e175e02b9b8d289bccab3ff0f3fd70c4dbf8c71f")
|
||||
set(MONERO_HEAD "52acbb68c1a4cc67ee539325a8febc2c144596c4")
|
||||
set(BUILD_GUI_DEPS ON)
|
||||
set(ARCH "x86-64")
|
||||
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 && \
|
||||
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 && \
|
||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||
./autogen.sh && \
|
||||
|
|
|
@ -146,8 +146,7 @@ RUN wget https://github.com/libevent/libevent/releases/download/release-2.1.11-s
|
|||
make -j$THREADS install && \
|
||||
rm -rf $(pwd)
|
||||
|
||||
ENV TOR_VERSION=0.4.5.5-rc
|
||||
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 && \
|
||||
git reset --hard b36a00e9a9d3eb4b2949951afaa72e45fb7e68cd && \
|
||||
./autogen.sh && \
|
||||
|
|
16
README.md
16
README.md
|
@ -1,27 +1,19 @@
|
|||
# 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)
|
||||
* Git: [git.featherwallet.org/feather/feather](https://git.featherwallet.org/feather/feather)
|
||||
* Mail: dev@featherwallet.org
|
||||
* IRC: `#feather` on OFTC
|
||||
* Development builds: [build.featherwallet.org/files](https://build.featherwallet.org/files/)
|
||||
|
||||
Copyright (c) 2020-2021 The Monero Project.
|
||||
|
||||
## 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:
|
||||
|
||||
- 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.
|
||||
See [BUILDING.md](https://git.featherwallet.org/feather/feather/src/branch/master/BUILDING.md) for information on how to build from source.
|
||||
|
||||
## 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);
|
||||
}
|
||||
else {
|
||||
QModelIndex index = ui->coins->indexAt(point);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
||||
int row = m_proxyModel->mapToSource(index).row();
|
||||
|
||||
bool isSpent, isFrozen, isUnlocked;
|
||||
m_coins->coin(row, [&isSpent, &isFrozen, &isUnlocked](CoinsInfo &c) {
|
||||
isSpent = c.spent();
|
||||
isFrozen = c.frozen();
|
||||
isUnlocked = c.unlocked();
|
||||
});
|
||||
bool isSpent = c->spent();
|
||||
bool isFrozen = c->frozen();
|
||||
bool isUnlocked = c->unlocked();
|
||||
|
||||
menu->addMenu(m_copyMenu);
|
||||
|
||||
|
@ -166,44 +159,28 @@ void CoinsWidget::thawAllSelected() {
|
|||
}
|
||||
|
||||
void CoinsWidget::viewOutput() {
|
||||
QModelIndex index = ui->coins->currentIndex();
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
||||
int row = m_proxyModel->mapToSource(index).row();
|
||||
QPointer<CoinsInfo> c;
|
||||
m_coins->coin(row, [&c](CoinsInfo &cInfo) {
|
||||
c = &cInfo;
|
||||
});
|
||||
|
||||
if (c) {
|
||||
auto * dialog = new OutputInfoDialog(c, this);
|
||||
dialog->show();
|
||||
}
|
||||
auto * dialog = new OutputInfoDialog(c, this);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void CoinsWidget::onSweepOutput() {
|
||||
QModelIndex index = ui->coins->currentIndex();
|
||||
int row = m_proxyModel->mapToSource(index).row();
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
||||
QString keyImage;
|
||||
bool keyImageKnown;
|
||||
m_coins->coin(row, [&keyImage, &keyImageKnown](CoinsInfo &c) {
|
||||
keyImageKnown = c.keyImageKnown();
|
||||
keyImage = c.keyImage();
|
||||
});
|
||||
QString keyImage = c->keyImage();
|
||||
|
||||
qCritical() << "key image: " << keyImage;
|
||||
|
||||
if (!keyImageKnown) {
|
||||
if (!c->keyImageKnown()) {
|
||||
QMessageBox::warning(this, "Unable to sweep output", "Unable to sweep output: key image unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
auto * dialog = new OutputSweepDialog(this);
|
||||
auto *dialog = new OutputSweepDialog(this, c);
|
||||
int ret = dialog->exec();
|
||||
if (!ret) return;
|
||||
|
||||
qCritical() << "key image: " << keyImage;
|
||||
|
||||
emit sweepOutput(keyImage, dialog->address(), dialog->churn(), dialog->outputs());
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
@ -213,39 +190,46 @@ void CoinsWidget::resetModel() {
|
|||
}
|
||||
|
||||
void CoinsWidget::copy(copyField field) {
|
||||
QModelIndex index = ui->coins->currentIndex();
|
||||
int row = m_proxyModel->mapToSource(index).row();
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
||||
QString data;
|
||||
m_coins->coin(row, [field, &data](CoinsInfo &c) {
|
||||
switch (field) {
|
||||
case PubKey:
|
||||
data = c.pubKey();
|
||||
break;
|
||||
case KeyImage:
|
||||
data = c.keyImage();
|
||||
break;
|
||||
case TxID:
|
||||
data = c.hash();
|
||||
break;
|
||||
case Address:
|
||||
data = c.address();
|
||||
break;
|
||||
case Label:
|
||||
data = c.addressLabel();
|
||||
break;
|
||||
case Height:
|
||||
data = QString::number(c.blockHeight());
|
||||
break;
|
||||
case Amount:
|
||||
data = c.displayAmount();
|
||||
break;
|
||||
}
|
||||
});
|
||||
switch (field) {
|
||||
case PubKey:
|
||||
data = c->pubKey();
|
||||
break;
|
||||
case KeyImage:
|
||||
data = c->keyImage();
|
||||
break;
|
||||
case TxID:
|
||||
data = c->hash();
|
||||
break;
|
||||
case Address:
|
||||
data = c->address();
|
||||
break;
|
||||
case Label:
|
||||
data = c->addressLabel();
|
||||
break;
|
||||
case Height:
|
||||
data = QString::number(c->blockHeight());
|
||||
break;
|
||||
case Amount:
|
||||
data = c->displayAmount();
|
||||
break;
|
||||
}
|
||||
|
||||
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() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ private:
|
|||
|
||||
void showContextMenu(const QPoint & point);
|
||||
void copy(copyField field);
|
||||
CoinsInfo* currentEntry();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
AboutDialog::AboutDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AboutDialog)
|
||||
, m_model(new QStringListModel(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png"));
|
||||
|
@ -26,8 +27,6 @@ AboutDialog::AboutDialog(QWidget *parent)
|
|||
auto ack_text = Utils::barrayToString(ack);
|
||||
ui->ackText->setText(ack_text);
|
||||
|
||||
m_model = new QStringListModel(this);
|
||||
|
||||
QString contributors = Utils::barrayToString(Utils::fileOpenQRC(":assets/contributors.txt"));
|
||||
QStringList contributor_list = contributors.split("\n");
|
||||
m_model->setStringList(contributor_list);
|
||||
|
|
|
@ -3,15 +3,19 @@
|
|||
|
||||
#include "ui_outputsweepdialog.h"
|
||||
#include "outputsweepdialog.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
|
||||
OutputSweepDialog::OutputSweepDialog(QWidget *parent)
|
||||
OutputSweepDialog::OutputSweepDialog(QWidget *parent, CoinsInfo* coin)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::OutputSweepDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_amount = coin->amount();
|
||||
|
||||
connect(ui->checkBox_churn, &QCheckBox::toggled, [&](bool toggled){
|
||||
ui->lineEdit_address->setEnabled(!toggled);
|
||||
ui->lineEdit_address->setText(toggled ? "Primary address" : "");
|
||||
});
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, [&](){
|
||||
|
@ -20,6 +24,19 @@ OutputSweepDialog::OutputSweepDialog(QWidget *parent)
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define FEATHER_OUTPUTSWEEPDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
|
||||
namespace Ui {
|
||||
class OutputSweepDialog;
|
||||
|
@ -15,7 +16,7 @@ class OutputSweepDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OutputSweepDialog(QWidget *parent = nullptr);
|
||||
explicit OutputSweepDialog(QWidget *parent, CoinsInfo* coin);
|
||||
~OutputSweepDialog() override;
|
||||
|
||||
QString address();
|
||||
|
@ -25,6 +26,8 @@ public:
|
|||
private:
|
||||
Ui::OutputSweepDialog *ui;
|
||||
|
||||
uint64_t m_amount;
|
||||
|
||||
QString m_address;
|
||||
bool m_churn;
|
||||
int m_outputs;
|
||||
|
|
|
@ -6,16 +6,22 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>623</width>
|
||||
<height>231</height>
|
||||
<width>720</width>
|
||||
<height>193</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Sweep output</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
|
@ -36,48 +42,60 @@
|
|||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_churn">
|
||||
<property name="text">
|
||||
<string>Send to self (churn)</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<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>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Advanced options</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<widget class="QLabel" name="label_split">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<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>
|
||||
<property name="text">
|
||||
<string>1.000000000000 XMR ≈ 5x 0.200000000000 XMR</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -7,10 +7,15 @@
|
|||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
#include "utils.h"
|
||||
#include "utils/ColorScheme.h"
|
||||
#include "model/ModelUtils.h"
|
||||
#include "config.h"
|
||||
#include "appcontext.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
|
||||
TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
|
@ -23,32 +28,26 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
|
|||
m_txid = txInfo->hash();
|
||||
ui->label_txid->setText(m_txid);
|
||||
|
||||
QString txKey = m_wallet->getTxKey(txInfo->hash());
|
||||
if (txKey.isEmpty()) {
|
||||
m_txKey = m_wallet->getTxKey(txInfo->hash());
|
||||
if (m_txKey.isEmpty()) {
|
||||
ui->btn_CopyTxKey->setEnabled(false);
|
||||
ui->btn_CopyTxKey->setToolTip("Transaction key unknown");
|
||||
}
|
||||
m_txKey = txKey;
|
||||
|
||||
connect(ui->btn_CopyTxKey, &QPushButton::pressed, this, &TransactionInfoDialog::copyTxKey);
|
||||
connect(ui->btn_createTxProof, &QPushButton::pressed, this, &TransactionInfoDialog::createTxProof);
|
||||
|
||||
QString blockHeight = QString::number(txInfo->blockHeight());
|
||||
if (blockHeight == "0")
|
||||
blockHeight = "Unconfirmed";
|
||||
connect(m_wallet, &Wallet::newBlock, this, &TransactionInfoDialog::updateData);
|
||||
|
||||
ui->label_status->setText(QString("Status: %1 confirmations").arg(txInfo->confirmations()));
|
||||
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));
|
||||
this->setData(txInfo);
|
||||
|
||||
QString direction = txInfo->direction() == TransactionInfo::Direction_In ? "received" : "sent";
|
||||
ui->label_amount->setText(QString("Amount %1: %2").arg(direction, txInfo->displayAmount()));
|
||||
|
||||
QString fee = txInfo->fee().isEmpty() ? "n/a" : txInfo->fee();
|
||||
ui->label_fee->setText(QString("Fee: %1").arg(txInfo->isCoinbase() ? WalletManager::displayAmount(0) : fee));
|
||||
ui->label_unlockTime->setText(QString("Unlock time: %1 (height)").arg(txInfo->unlockTime()));
|
||||
|
||||
qDebug() << m_wallet->coins()->coins_from_txid(txInfo->hash());
|
||||
if (AppContext::txCache.contains(txInfo->hash()) && (txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) {
|
||||
connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{
|
||||
emit resendTranscation(m_txid);
|
||||
});
|
||||
} else {
|
||||
ui->btn_rebroadcastTx->hide();
|
||||
}
|
||||
|
||||
QTextCursor cursor = ui->destinations->textCursor();
|
||||
for (const auto& transfer : txInfo->transfers()) {
|
||||
|
@ -59,15 +58,66 @@ TransactionInfoDialog::TransactionInfoDialog(Wallet *wallet, TransactionInfo *tx
|
|||
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
|
||||
cursor.insertBlock();
|
||||
}
|
||||
|
||||
if (txInfo->transfers().size() == 0) {
|
||||
ui->frameDestinations->hide();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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() {
|
||||
Utils::copyToClipboard(m_txKey);
|
||||
}
|
||||
|
|
|
@ -24,9 +24,14 @@ public:
|
|||
explicit TransactionInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
|
||||
~TransactionInfoDialog() override;
|
||||
|
||||
signals:
|
||||
void resendTranscation(const QString &txid);
|
||||
|
||||
private:
|
||||
void copyTxKey();
|
||||
void createTxProof();
|
||||
void setData(TransactionInfo* tx);
|
||||
void updateData();
|
||||
|
||||
Ui::TransactionInfoDialog *ui;
|
||||
|
||||
|
@ -35,6 +40,7 @@ private:
|
|||
Wallet *m_wallet;
|
||||
QString m_txKey;
|
||||
QString m_txid;
|
||||
QTimer m_updateTimer;
|
||||
};
|
||||
|
||||
#endif //FEATHER_TRANSACTIONINFODIALOG_H
|
||||
|
|
|
@ -6,17 +6,14 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>829</width>
|
||||
<height>493</height>
|
||||
<width>929</width>
|
||||
<height>631</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Transaction</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
|
@ -37,81 +34,46 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
<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>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_amount">
|
||||
<property name="text">
|
||||
<string>Amount received:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_fee">
|
||||
<property name="text">
|
||||
<string>Fee: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_unlockTime">
|
||||
<property name="text">
|
||||
<string>Unlock time:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QLabel" name="label_lock">
|
||||
<property name="text">
|
||||
<string>Lock: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_amount">
|
||||
<property name="text">
|
||||
<string>Amount received:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_fee">
|
||||
<property name="text">
|
||||
<string>Fee: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
@ -154,6 +116,12 @@
|
|||
</property>
|
||||
<item>
|
||||
<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">
|
||||
<string>Destinations:</string>
|
||||
</property>
|
||||
|
@ -162,17 +130,11 @@
|
|||
<item>
|
||||
<widget class="QTextEdit" name="destinations">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -187,7 +149,7 @@
|
|||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
@ -213,6 +175,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_rebroadcastTx">
|
||||
<property name="text">
|
||||
<string>Rebroadcast Transaction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -53,6 +53,9 @@
|
|||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
@ -67,6 +70,9 @@
|
|||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
|
@ -88,6 +94,9 @@
|
|||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -106,6 +115,9 @@
|
|||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -113,6 +125,9 @@
|
|||
<property name="text">
|
||||
<string>Size: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -120,6 +135,9 @@
|
|||
<property name="text">
|
||||
<string>Unlock time: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -127,6 +145,9 @@
|
|||
<property name="text">
|
||||
<string>Ringsize:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -26,7 +26,7 @@ ViewOnlyDialog::ViewOnlyDialog(AppContext *ctx, QWidget *parent)
|
|||
}
|
||||
|
||||
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.endsWith(".keys")) fn += ".keys";
|
||||
|
||||
|
|
|
@ -101,6 +101,9 @@ void HistoryWidget::showTxDetails() {
|
|||
if (!tx) return;
|
||||
|
||||
auto *dialog = new TransactionInfoDialog(m_wallet, tx, this);
|
||||
connect(dialog, &TransactionInfoDialog::resendTranscation, [this](const QString &txid){
|
||||
emit resendTransaction(txid);
|
||||
});
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,11 @@ bool Coins::coin(int index, std::function<void (CoinsInfo &)> callback)
|
|||
return true;
|
||||
}
|
||||
|
||||
CoinsInfo* Coins::coin(int index)
|
||||
{
|
||||
return m_tinfo.value(index);
|
||||
}
|
||||
|
||||
void Coins::refresh(quint32 accountIndex)
|
||||
{
|
||||
emit refreshStarted();
|
||||
|
@ -74,18 +79,17 @@ void Coins::thaw(int index) const
|
|||
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++) {
|
||||
this->coin(i, [&keyimages, &txid](const CoinsInfo &x) {
|
||||
if (x.hash() == txid) {
|
||||
keyimages += x.keyImage();
|
||||
}
|
||||
});
|
||||
CoinsInfo* coin = this->coin(i);
|
||||
if (coin->hash() == txid) {
|
||||
coins.append(coin);
|
||||
}
|
||||
}
|
||||
return keyimages;
|
||||
return coins;
|
||||
}
|
||||
|
||||
Coins::Coins(Monero::Coins *pimpl, QObject *parent)
|
||||
|
|
|
@ -25,11 +25,12 @@ Q_OBJECT
|
|||
|
||||
public:
|
||||
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 refreshUnlocked();
|
||||
Q_INVOKABLE void freeze(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;
|
||||
|
||||
|
|
|
@ -78,3 +78,8 @@ quint64 Subaddress::count() const
|
|||
|
||||
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 quint64 unusedLookahead() const;
|
||||
quint64 count() const;
|
||||
Monero::SubaddressRow* row(int index) const;
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
|
|
|
@ -293,6 +293,11 @@ bool Wallet::viewOnly() const
|
|||
return m_walletImpl->watchOnly();
|
||||
}
|
||||
|
||||
bool Wallet::isDeterministic() const
|
||||
{
|
||||
return m_walletImpl->isDeterministic();
|
||||
}
|
||||
|
||||
quint64 Wallet::balance() const
|
||||
{
|
||||
return balance(m_currentSubaddressAccount);
|
||||
|
@ -400,9 +405,11 @@ void Wallet::refreshHeightAsync()
|
|||
daemonHeightFuture.second.waitForFinished();
|
||||
targetHeightFuture.second.waitForFinished();
|
||||
|
||||
setConnectionStatus(ConnectionStatus_Connected);
|
||||
|
||||
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
||||
if (daemonHeight > 0 && targetHeight > 0) {
|
||||
emit heightRefreshed(walletHeight, daemonHeight, targetHeight);
|
||||
qDebug() << "Setting connection status from refreshHeightAsync";
|
||||
setConnectionStatus(ConnectionStatus_Connected);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -224,6 +224,9 @@ public:
|
|||
//! returns if view only wallet
|
||||
Q_INVOKABLE bool viewOnly() const;
|
||||
|
||||
//! return true if deterministic keys
|
||||
Q_INVOKABLE bool isDeterministic() const;
|
||||
|
||||
Q_INVOKABLE void refreshHeightAsync();
|
||||
|
||||
//! export/import key images
|
||||
|
|
|
@ -597,7 +597,7 @@ void MainWindow::onWalletOpened() {
|
|||
|
||||
// receive page
|
||||
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) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
m_ctx->currentWallet->subaddress()->addRow(m_ctx->currentWallet->currentSubaddressAccount(), "");
|
||||
|
@ -837,6 +837,16 @@ void MainWindow::showWalletInfoDialog() {
|
|||
}
|
||||
|
||||
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);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
|
@ -1303,6 +1313,11 @@ void MainWindow::updateNetStats() {
|
|||
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()) {
|
||||
m_statusLabelNetStats->setText("");
|
||||
return;
|
||||
|
|
|
@ -197,4 +197,9 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in
|
|||
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 headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
CoinsInfo* entryFromIndex(const QModelIndex &index) const;
|
||||
|
||||
public slots:
|
||||
void startReset();
|
||||
void endReset();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "HistoryView.h"
|
||||
|
||||
#include "TransactionHistoryProxyModel.h"
|
||||
#include "libwalletqt/TransactionInfo.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QMenu>
|
||||
|
@ -186,3 +187,14 @@ void HistoryView::resetViewToDefaults()
|
|||
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
|
||||
#define FEATHER_HISTORYVIEW_H
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QTreeView>
|
||||
#include <QActionGroup>
|
||||
|
||||
|
@ -29,6 +30,9 @@ private slots:
|
|||
void fitColumnsToContents();
|
||||
void resetViewToDefaults();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
|
||||
private:
|
||||
TransactionHistoryModel* sourceModel();
|
||||
|
||||
|
|
|
@ -180,3 +180,8 @@ bool SubaddressModel::isShowFullAddresses() const {
|
|||
int SubaddressModel::unusedLookahead() const {
|
||||
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;
|
||||
void setShowFullAddresses(bool show);
|
||||
|
||||
Monero::SubaddressRow* entryFromIndex(const QModelIndex &index) const;
|
||||
|
||||
int unusedLookahead() const;
|
||||
|
||||
public slots:
|
||||
|
|
|
@ -29,6 +29,10 @@ bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &so
|
|||
if (sourceRow == 0 && m_hidePrimary)
|
||||
return false;
|
||||
|
||||
if (!m_showHidden && m_hiddenAddresses.contains(address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_searchRegExp.isEmpty()) {
|
||||
return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp);
|
||||
}
|
||||
|
|
|
@ -22,16 +22,30 @@ public slots:
|
|||
m_searchCaseSensitiveRegExp.setPattern(searchString);
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void setShowUsed(const bool showUsed){
|
||||
m_showUsed = showUsed;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void setShowHidden(const bool showHidden){
|
||||
m_showHidden = showHidden;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void setHiddenAddresses(const QStringList& hiddenAddresses) {
|
||||
m_hiddenAddresses = hiddenAddresses;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
private:
|
||||
Subaddress *m_subaddress;
|
||||
|
||||
QStringList m_hiddenAddresses;
|
||||
QRegExp m_searchRegExp;
|
||||
QRegExp m_searchCaseSensitiveRegExp;
|
||||
bool m_showUsed = false;
|
||||
bool m_showHidden = false;
|
||||
bool m_hidePrimary;
|
||||
};
|
||||
|
||||
|
|
|
@ -141,7 +141,10 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
|
|||
switch (column)
|
||||
{
|
||||
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:
|
||||
return tInfo.description();
|
||||
case Column::Amount:
|
||||
|
|
|
@ -35,13 +35,19 @@ ReceiveWidget::ReceiveWidget(QWidget *parent) :
|
|||
|
||||
connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog);
|
||||
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) {
|
||||
m_subaddress = subaddress;
|
||||
void ReceiveWidget::setModel(SubaddressModel * model, Wallet * wallet) {
|
||||
m_wallet = wallet;
|
||||
m_subaddress = wallet->subaddress();
|
||||
m_model = model;
|
||||
m_proxyModel = new SubaddressProxyModel(this, subaddress);
|
||||
m_proxyModel = new SubaddressProxyModel(this, m_subaddress);
|
||||
m_proxyModel->setSourceModel(m_model);
|
||||
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
||||
|
||||
ui->addresses->setModel(m_proxyModel);
|
||||
|
||||
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
|
||||
|
@ -74,13 +80,13 @@ void ReceiveWidget::editLabel() {
|
|||
}
|
||||
|
||||
void ReceiveWidget::showContextMenu(const QPoint &point) {
|
||||
QModelIndex index = ui->addresses->indexAt(point);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
Monero::SubaddressRow* row = this->currentEntry();
|
||||
if (!row) return;
|
||||
|
||||
QString address = QString::fromStdString(row->getAddress());
|
||||
bool isUsed = row->isUsed();
|
||||
|
||||
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 label", this, &ReceiveWidget::copyLabel);
|
||||
|
@ -90,6 +96,13 @@ void ReceiveWidget::showContextMenu(const QPoint &point) {
|
|||
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));
|
||||
}
|
||||
|
||||
|
@ -117,6 +130,11 @@ void ReceiveWidget::setShowUsedAddresses(bool show) {
|
|||
m_proxyModel->setShowUsed(show);
|
||||
}
|
||||
|
||||
void ReceiveWidget::setShowHiddenAddresses(bool show) {
|
||||
if (!m_proxyModel) return;
|
||||
m_proxyModel->setShowHidden(show);
|
||||
}
|
||||
|
||||
void ReceiveWidget::setSearchFilter(const QString &filter) {
|
||||
if (!m_proxyModel) return;
|
||||
m_proxyModel->setSearchFilter(filter);
|
||||
|
@ -128,6 +146,24 @@ void ReceiveWidget::showHeaderMenu(const QPoint& position)
|
|||
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(){
|
||||
QModelIndex index = ui->addresses->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
|
@ -156,6 +192,36 @@ void ReceiveWidget::showQrCodeDialog() {
|
|||
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() {
|
||||
delete ui;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ Q_OBJECT
|
|||
|
||||
public:
|
||||
explicit ReceiveWidget(QWidget *parent = nullptr);
|
||||
void setModel(SubaddressModel * model, Subaddress * subaddress);
|
||||
void setModel(SubaddressModel * model, Wallet * wallet);
|
||||
~ReceiveWidget() override;
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@ public slots:
|
|||
void showContextMenu(const QPoint& point);
|
||||
void setShowFullAddresses(bool show);
|
||||
void setShowUsedAddresses(bool show);
|
||||
void setShowHiddenAddresses(bool show);
|
||||
void setSearchFilter(const QString &filter);
|
||||
void onShowTransactions();
|
||||
void resetModel();
|
||||
|
@ -44,6 +45,8 @@ signals:
|
|||
|
||||
private slots:
|
||||
void showHeaderMenu(const QPoint& position);
|
||||
void hideAddress();
|
||||
void showAddress();
|
||||
|
||||
private:
|
||||
Ui::ReceiveWidget *ui;
|
||||
|
@ -54,9 +57,14 @@ private:
|
|||
Subaddress * m_subaddress;
|
||||
SubaddressModel * m_model;
|
||||
SubaddressProxyModel * m_proxyModel;
|
||||
Wallet * m_wallet;
|
||||
|
||||
void updateQrCode();
|
||||
void showQrCodeDialog();
|
||||
QStringList getHiddenAddresses();
|
||||
void addHiddenAddress(const QString& address);
|
||||
void removeHiddenAddress(const QString& address);
|
||||
Monero::SubaddressRow* currentEntry();
|
||||
};
|
||||
|
||||
#endif //FEATHER_RECEIVEWIDGET_H
|
||||
|
|
|
@ -82,6 +82,27 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</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>
|
||||
<widget class="QPushButton" name="btn_generateSubaddress">
|
||||
<property name="text">
|
||||
|
|
|
@ -46,7 +46,14 @@
|
|||
</widget>
|
||||
</item>
|
||||
<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 row="1" column="0">
|
||||
<widget class="HelpLabel" name="label_Description">
|
||||
|
|
|
@ -48,10 +48,29 @@ Settings::Settings(QWidget *parent) :
|
|||
}
|
||||
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_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_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
|
||||
QStringList fiatCurrencies;
|
||||
|
@ -110,6 +129,14 @@ void Settings::comboBox_amountPrecisionChanged(int 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() {
|
||||
ui->textLogs->copy();
|
||||
}
|
||||
|
|
|
@ -40,15 +40,18 @@ public slots:
|
|||
void comboBox_blockExplorerChanged(int pos);
|
||||
void comboBox_redditFrontendChanged(int pos);
|
||||
void comboBox_amountPrecisionChanged(int pos);
|
||||
|
||||
private:
|
||||
QStringList m_skins{"Native", "QDarkStyle", "Breeze/Dark", "Breeze/Light"};
|
||||
void comboBox_dateFormatChanged(int pos);
|
||||
void comboBox_timeFormatChanged(int pos);
|
||||
|
||||
private:
|
||||
void setupSkinCombobox();
|
||||
|
||||
AppContext *m_ctx;
|
||||
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
|
||||
|
|
|
@ -161,14 +161,14 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_externalLink">
|
||||
<property name="text">
|
||||
<string>Warn before opening external link</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_hideBalance">
|
||||
<property name="text">
|
||||
<string>Hide balance</string>
|
||||
|
@ -211,6 +211,26 @@
|
|||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox_amountPrecision"/>
|
||||
</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>
|
||||
</widget>
|
||||
<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::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}},
|
||||
{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,
|
||||
GUI_HistoryViewState,
|
||||
amountPrecision,
|
||||
portableMode
|
||||
portableMode,
|
||||
dateFormat,
|
||||
timeFormat
|
||||
};
|
||||
|
||||
~Config() override;
|
||||
|
|
|
@ -82,6 +82,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="check_darkMode">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dark mode</string>
|
||||
</property>
|
||||
|
|
|
@ -26,7 +26,6 @@ public:
|
|||
|
||||
private:
|
||||
AppContext *m_ctx;
|
||||
QLabel *topLabel;
|
||||
Ui::PageNetwork *ui;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ public:
|
|||
int nextId() const override;
|
||||
|
||||
private:
|
||||
void resetWidgets();
|
||||
|
||||
AppContext *m_ctx;
|
||||
WizardFields *m_fields;
|
||||
Ui::PageWalletRestoreKeys *ui;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "PageWalletRestoreSeed.h"
|
||||
#include "ui_PageWalletRestoreSeed.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QMessageBox>
|
||||
|
||||
|
|
Loading…
Reference in a new issue