mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-22 19:49:28 +00:00
refactor: consolidate wallet_api into libwalletqt [1/?]
This commit is contained in:
parent
a13ca973cc
commit
769af188e2
46 changed files with 928 additions and 687 deletions
|
@ -299,7 +299,7 @@ void CoinsWidget::freezeCoins(QStringList &pubkeys) {
|
|||
for (auto &pubkey : pubkeys) {
|
||||
m_wallet->coins()->freeze(pubkey);
|
||||
}
|
||||
m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->coins()->refresh();
|
||||
m_wallet->updateBalance();
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void CoinsWidget::thawCoins(QStringList &pubkeys) {
|
|||
for (auto &pubkey : pubkeys) {
|
||||
m_wallet->coins()->thaw(pubkey);
|
||||
}
|
||||
m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->coins()->refresh();
|
||||
m_wallet->updateBalance();
|
||||
}
|
||||
|
||||
|
|
|
@ -135,9 +135,9 @@ void ContactsWidget::newContact(QString address, QString name)
|
|||
QString address_entry;
|
||||
QString name_entry;
|
||||
for (int i=0; i<num_addresses; i++) {
|
||||
m_wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const AddressBookInfo &entry){
|
||||
address_entry = entry.address();
|
||||
name_entry = entry.description();
|
||||
m_wallet->addressBook()->getRow(i, [&address_entry, &name_entry](const ContactRow &entry){
|
||||
address_entry = entry.getAddress();
|
||||
name_entry = entry.getLabel();
|
||||
});
|
||||
|
||||
if (address == address_entry) {
|
||||
|
@ -152,7 +152,7 @@ void ContactsWidget::newContact(QString address, QString name)
|
|||
}
|
||||
}
|
||||
|
||||
m_wallet->addressBook()->addRow(address, "", name);
|
||||
m_wallet->addressBook()->addRow(address, name);
|
||||
}
|
||||
|
||||
void ContactsWidget::deleteContact()
|
||||
|
|
|
@ -86,7 +86,7 @@ void HistoryWidget::showContextMenu(const QPoint &point) {
|
|||
if (!tx) return;
|
||||
|
||||
bool unconfirmed = tx->isFailed() || tx->isPending();
|
||||
if (unconfirmed && tx->direction() != TransactionInfo::Direction_In) {
|
||||
if (unconfirmed && tx->direction() != TransactionRow::Direction_In) {
|
||||
menu.addAction("Resend transaction", this, &HistoryWidget::onResendTransaction);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "dialog/WalletInfoDialog.h"
|
||||
#include "dialog/WalletCacheDebugDialog.h"
|
||||
#include "libwalletqt/AddressBook.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "utils/AppData.h"
|
||||
#include "utils/AsyncTask.h"
|
||||
|
@ -502,20 +502,20 @@ void MainWindow::onWalletOpened() {
|
|||
m_wallet->subaddressModel()->setCurrentSubaddressAccount(m_wallet->currentSubaddressAccount());
|
||||
|
||||
// history page
|
||||
m_wallet->history()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->history()->refresh();
|
||||
|
||||
// coins page
|
||||
m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->coins()->refresh();
|
||||
m_coinsWidget->setModel(m_wallet->coinsModel(), m_wallet->coins());
|
||||
m_wallet->coinsModel()->setCurrentSubaddressAccount(m_wallet->currentSubaddressAccount());
|
||||
|
||||
// Coin labeling uses set_tx_note, so we need to refresh history too
|
||||
connect(m_wallet->coins(), &Coins::descriptionChanged, [this] {
|
||||
m_wallet->history()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->history()->refresh();
|
||||
});
|
||||
// Vice versa
|
||||
connect(m_wallet->history(), &TransactionHistory::txNoteChanged, [this] {
|
||||
m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
|
||||
m_wallet->coins()->refresh();
|
||||
});
|
||||
|
||||
this->updatePasswordIcon();
|
||||
|
@ -898,7 +898,7 @@ void MainWindow::onTransactionCommitted(bool success, PendingTransaction *tx, co
|
|||
msgBox.exec();
|
||||
if (msgBox.clickedButton() == showDetailsButton) {
|
||||
this->showHistoryTab();
|
||||
TransactionInfo *txInfo = m_wallet->history()->transaction(txid.first());
|
||||
TransactionRow *txInfo = m_wallet->history()->transaction(txid.first());
|
||||
auto *dialog = new TxInfoDialog(m_wallet, txInfo, this);
|
||||
connect(dialog, &TxInfoDialog::resendTranscation, this, &MainWindow::onResendTransaction);
|
||||
dialog->show();
|
||||
|
@ -1145,7 +1145,7 @@ void MainWindow::importContacts() {
|
|||
i.next();
|
||||
bool addressValid = WalletManager::addressValid(i.value(), m_wallet->nettype());
|
||||
if(addressValid) {
|
||||
m_wallet->addressBook()->addRow(i.value(), "", i.key());
|
||||
m_wallet->addressBook()->addRow(i.value(), i.key());
|
||||
inserts++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ void AccountSwitcherDialog::switchAccount() {
|
|||
return;
|
||||
}
|
||||
|
||||
m_wallet->switchSubaddressAccount(row->getRowId());
|
||||
m_wallet->switchSubaddressAccount(row->getRow());
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::copyLabel() {
|
||||
|
@ -73,7 +73,7 @@ void AccountSwitcherDialog::copyLabel() {
|
|||
return;
|
||||
}
|
||||
|
||||
Utils::copyToClipboard(QString::fromStdString(row->getLabel()));
|
||||
Utils::copyToClipboard(row->getLabel());
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::copyBalance() {
|
||||
|
@ -82,7 +82,7 @@ void AccountSwitcherDialog::copyBalance() {
|
|||
return;
|
||||
}
|
||||
|
||||
Utils::copyToClipboard(QString::fromStdString(row->getBalance()));
|
||||
Utils::copyToClipboard(row->getBalance());
|
||||
}
|
||||
|
||||
void AccountSwitcherDialog::editLabel() {
|
||||
|
@ -93,6 +93,9 @@ void AccountSwitcherDialog::editLabel() {
|
|||
|
||||
void AccountSwitcherDialog::updateSelection() {
|
||||
QModelIndex index = m_model->index(m_wallet->currentSubaddressAccount(), 0);
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
ui->accounts->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
|
@ -111,7 +114,7 @@ void AccountSwitcherDialog::showContextMenu(const QPoint &point) {
|
|||
menu->popup(ui->accounts->viewport()->mapToGlobal(point));
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* AccountSwitcherDialog::currentEntry() {
|
||||
AccountRow* AccountSwitcherDialog::currentEntry() {
|
||||
QModelIndex index = m_proxyModel->mapToSource(ui->accounts->currentIndex());
|
||||
return m_wallet->subaddressAccountModel()->entryFromIndex(index);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ private:
|
|||
void copyBalance();
|
||||
void editLabel();
|
||||
|
||||
Monero::SubaddressAccountRow* currentEntry();
|
||||
AccountRow* currentEntry();
|
||||
|
||||
QScopedPointer<Ui::AccountSwitcherDialog> ui;
|
||||
Wallet *m_wallet;
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="accounts">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "components.h"
|
||||
#include "libwalletqt/Coins.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
|
||||
namespace Ui {
|
||||
class OutputInfoDialog;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <QDialog>
|
||||
|
||||
#include "components.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
|
||||
namespace Ui {
|
||||
class OutputSweepDialog;
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
#include "config.h"
|
||||
#include "constants.h"
|
||||
#include "libwalletqt/Coins.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
#include "libwalletqt/TransactionHistory.h"
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "utils/Icons.h"
|
||||
#include "utils/Utils.h"
|
||||
|
||||
TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent)
|
||||
TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionRow *txInfo, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::TxInfoDialog)
|
||||
, m_wallet(wallet)
|
||||
|
@ -41,7 +41,7 @@ TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *par
|
|||
|
||||
this->setData(txInfo);
|
||||
|
||||
if ((txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionInfo::Direction_In) {
|
||||
if ((txInfo->isFailed() || txInfo->isPending()) && txInfo->direction() != TransactionRow::Direction_In) {
|
||||
connect(ui->btn_rebroadcastTx, &QPushButton::pressed, [this]{
|
||||
emit resendTranscation(m_txid);
|
||||
});
|
||||
|
@ -49,7 +49,7 @@ TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *par
|
|||
ui->btn_rebroadcastTx->hide();
|
||||
}
|
||||
|
||||
if (txInfo->direction() == TransactionInfo::Direction_In) {
|
||||
if (txInfo->direction() == TransactionRow::Direction_In) {
|
||||
ui->btn_CopyTxKey->setDisabled(true);
|
||||
ui->btn_CopyTxKey->setToolTip("No tx secret key available for incoming transactions.");
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ void TxInfoDialog::adjustHeight(QTextEdit *textEdit, qreal docHeight) {
|
|||
textEdit->verticalScrollBar()->hide();
|
||||
}
|
||||
|
||||
void TxInfoDialog::setData(TransactionInfo *tx) {
|
||||
void TxInfoDialog::setData(TransactionRow *tx) {
|
||||
QString blockHeight = QString::number(tx->blockHeight());
|
||||
|
||||
if (tx->isFailed()) {
|
||||
|
@ -131,13 +131,13 @@ void TxInfoDialog::setData(TransactionInfo *tx) {
|
|||
ui->label_lock->setText("Lock: Outputs are spendable");
|
||||
}
|
||||
|
||||
QString direction = tx->direction() == TransactionInfo::Direction_In ? "received" : "sent";
|
||||
QString direction = tx->direction() == TransactionRow::Direction_In ? "received" : "sent";
|
||||
ui->label_amount->setText(QString("Amount %1: %2 XMR").arg(direction, tx->displayAmount()));
|
||||
|
||||
QString fee;
|
||||
if (tx->isCoinbase())
|
||||
fee = "Not applicable";
|
||||
else if (tx->direction() == TransactionInfo::Direction_In)
|
||||
else if (tx->direction() == TransactionRow::Direction_In)
|
||||
fee = "Paid by sender";
|
||||
else if (tx->fee().isEmpty())
|
||||
fee = "N/A";
|
||||
|
@ -149,7 +149,7 @@ void TxInfoDialog::setData(TransactionInfo *tx) {
|
|||
}
|
||||
|
||||
void TxInfoDialog::updateData() {
|
||||
TransactionInfo *tx = m_wallet->history()->transaction(m_txid);
|
||||
TransactionRow *tx = m_wallet->history()->transaction(m_txid);
|
||||
if (!tx) return;
|
||||
this->setData(tx);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QSvgWidget>
|
||||
|
||||
#include "dialog/TxProofDialog.h"
|
||||
#include "libwalletqt/rows/TransactionRow.h"
|
||||
|
||||
namespace Ui {
|
||||
class TxInfoDialog;
|
||||
|
@ -20,7 +21,7 @@ class TxInfoDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
|
||||
explicit TxInfoDialog(Wallet *wallet, TransactionRow *txInfo, QWidget *parent = nullptr);
|
||||
~TxInfoDialog() override;
|
||||
|
||||
signals:
|
||||
|
@ -30,14 +31,14 @@ private:
|
|||
void copyTxID();
|
||||
void copyTxKey();
|
||||
void createTxProof();
|
||||
void setData(TransactionInfo *tx);
|
||||
void setData(TransactionRow *tx);
|
||||
void updateData();
|
||||
void adjustHeight(QTextEdit *textEdit, qreal docHeight);
|
||||
void viewOnBlockExplorer();
|
||||
|
||||
QScopedPointer<Ui::TxInfoDialog> ui;
|
||||
Wallet *m_wallet;
|
||||
TransactionInfo *m_txInfo;
|
||||
TransactionRow *m_txInfo;
|
||||
TxProofDialog *m_txProofDialog;
|
||||
QString m_txid;
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "utils/Icons.h"
|
||||
#include "utils/Utils.h"
|
||||
|
||||
TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txInfo)
|
||||
TxProofDialog::TxProofDialog(QWidget *parent, Wallet *wallet, TransactionRow *txInfo)
|
||||
: WindowModalDialog(parent)
|
||||
, ui(new Ui::TxProofDialog)
|
||||
, m_wallet(wallet)
|
||||
|
@ -70,7 +70,7 @@ void TxProofDialog::selectSpendProof() {
|
|||
m_mode = Mode::SpendProof;
|
||||
this->resetFrames();
|
||||
|
||||
if (m_direction == TransactionInfo::Direction_In) {
|
||||
if (m_direction == TransactionRow::Direction_In) {
|
||||
this->showWarning("Your wallet did not construct this transaction. Creating a SpendProof is not possible.");
|
||||
return;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void TxProofDialog::selectInProof() {
|
|||
m_mode = Mode::InProof;
|
||||
this->resetFrames();
|
||||
|
||||
if (m_direction == TransactionInfo::Direction_Out) {
|
||||
if (m_direction == TransactionRow::Direction_Out) {
|
||||
this->showWarning("Can't create InProofs for outgoing transactions.");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include <QDialog>
|
||||
|
||||
#include "components.h"
|
||||
#include "libwalletqt/TransactionInfo.h"
|
||||
#include "libwalletqt/Wallet.h"
|
||||
#include "rows/TransactionRow.h"
|
||||
|
||||
namespace Ui {
|
||||
class TxProofDialog;
|
||||
|
@ -19,7 +19,7 @@ class TxProofDialog : public WindowModalDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionInfo *txid);
|
||||
explicit TxProofDialog(QWidget *parent, Wallet *wallet, TransactionRow *txid);
|
||||
~TxProofDialog() override;
|
||||
void setTxId(const QString &txid);
|
||||
void getTxKey();
|
||||
|
@ -52,7 +52,7 @@ private:
|
|||
QString m_txid;
|
||||
QString m_txKey;
|
||||
Mode m_mode;
|
||||
TransactionInfo::Direction m_direction;
|
||||
TransactionRow::Direction m_direction;
|
||||
};
|
||||
|
||||
#endif //FEATHER_TXPROOFDIALOG_H
|
||||
|
|
|
@ -4,48 +4,54 @@
|
|||
#include "AddressBook.h"
|
||||
#include <QDebug>
|
||||
|
||||
AddressBook::AddressBook(Monero::AddressBook *abImpl, QObject *parent)
|
||||
: QObject(parent), m_addressBookImpl(abImpl)
|
||||
AddressBook::AddressBook(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wallet(wallet)
|
||||
, m_wallet2(wallet2)
|
||||
{
|
||||
getAll();
|
||||
this->refresh();
|
||||
}
|
||||
|
||||
QString AddressBook::errorString() const
|
||||
{
|
||||
return QString::fromStdString(m_addressBookImpl->errorString());
|
||||
return m_errorString;
|
||||
}
|
||||
|
||||
int AddressBook::errorCode() const
|
||||
AddressBook::ErrorCode AddressBook::errorCode() const
|
||||
{
|
||||
return m_addressBookImpl->errorCode();
|
||||
return m_errorCode;
|
||||
}
|
||||
|
||||
void AddressBook::getAll()
|
||||
void AddressBook::refresh()
|
||||
{
|
||||
emit refreshStarted();
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
clearRows();
|
||||
|
||||
qDeleteAll(m_rows);
|
||||
// Fetch from Wallet2 and create vector of AddressBookRow objects
|
||||
std::vector<tools::wallet2::address_book_row> rows = m_wallet2->get_address_book();
|
||||
for (qsizetype i = 0; i < rows.size(); ++i) {
|
||||
tools::wallet2::address_book_row *row = &rows.at(i);
|
||||
|
||||
m_addresses.clear();
|
||||
m_rows.clear();
|
||||
std::string address;
|
||||
if (row->m_has_payment_id)
|
||||
address = cryptonote::get_account_integrated_address_as_str(m_wallet2->nettype(), row->m_address, row->m_payment_id);
|
||||
else
|
||||
address = get_account_address_as_str(m_wallet2->nettype(), row->m_is_subaddress, row->m_address);
|
||||
|
||||
for (auto &abr: m_addressBookImpl->getAll()) {
|
||||
m_addresses.insert(QString::fromStdString(abr->getAddress()), m_rows.size());
|
||||
|
||||
m_rows.append(new AddressBookInfo(abr, this));
|
||||
}
|
||||
auto* abr = new ContactRow{this,
|
||||
i,
|
||||
QString::fromStdString(address),
|
||||
QString::fromStdString(row->m_description)};
|
||||
m_rows.push_back(abr);
|
||||
}
|
||||
|
||||
|
||||
emit refreshFinished();
|
||||
}
|
||||
|
||||
bool AddressBook::getRow(int index, std::function<void (AddressBookInfo &)> callback) const
|
||||
bool AddressBook::getRow(int index, std::function<void (ContactRow &)> callback) const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
if (index < 0 || index >= m_rows.size())
|
||||
{
|
||||
return false;
|
||||
|
@ -55,88 +61,58 @@ bool AddressBook::getRow(int index, std::function<void (AddressBookInfo &)> call
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AddressBook::addRow(const QString &address, const QString &payment_id, const QString &description)
|
||||
bool AddressBook::addRow(const QString &address, const QString &description)
|
||||
{
|
||||
// virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0;
|
||||
bool result;
|
||||
m_errorString = "";
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
result = m_addressBookImpl->addRow(address.toStdString(), payment_id.toStdString(), description.toStdString());
|
||||
cryptonote::address_parse_info info;
|
||||
if (!cryptonote::get_account_address_from_str(info, m_wallet2->nettype(), address.toStdString())) {
|
||||
m_errorString = tr("Invalid destination address");
|
||||
m_errorCode = Invalid_Address;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
getAll();
|
||||
}
|
||||
|
||||
return result;
|
||||
bool r = m_wallet2->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : nullptr, description.toStdString(), info.is_subaddress);
|
||||
if (r)
|
||||
refresh();
|
||||
else
|
||||
m_errorCode = General_Error;
|
||||
return r;
|
||||
}
|
||||
|
||||
void AddressBook::setDescription(int index, const QString &description) {
|
||||
bool result;
|
||||
bool AddressBook::setDescription(int index, const QString &description) {
|
||||
m_errorString = "";
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
result = m_addressBookImpl->setDescription(index, description.toStdString());
|
||||
const auto ab = m_wallet2->get_address_book();
|
||||
if (index >= ab.size()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
getAll();
|
||||
emit descriptionChanged();
|
||||
}
|
||||
tools::wallet2::address_book_row entry = ab[index];
|
||||
entry.m_description = description.toStdString();
|
||||
bool r = m_wallet2->set_address_book_row(index, entry.m_address, entry.m_has_payment_id ? &entry.m_payment_id : nullptr, entry.m_description, entry.m_is_subaddress);
|
||||
if (r)
|
||||
refresh();
|
||||
else
|
||||
m_errorCode = General_Error;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool AddressBook::deleteRow(int rowId)
|
||||
{
|
||||
bool result;
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
result = m_addressBookImpl->deleteRow(rowId);
|
||||
}
|
||||
|
||||
// Fetch new data from wallet2.
|
||||
if (result)
|
||||
{
|
||||
getAll();
|
||||
}
|
||||
|
||||
return result;
|
||||
bool r = m_wallet2->delete_address_book_row(rowId);
|
||||
if (r)
|
||||
refresh();
|
||||
return r;
|
||||
}
|
||||
|
||||
quint64 AddressBook::count() const
|
||||
qsizetype AddressBook::count() const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
return m_rows.size();
|
||||
return m_rows.length();
|
||||
}
|
||||
|
||||
QString AddressBook::getDescription(const QString &address) const
|
||||
void AddressBook::clearRows()
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
const QMap<QString, size_t>::const_iterator it = m_addresses.find(address);
|
||||
if (it == m_addresses.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return m_rows.value(*it)->description();
|
||||
}
|
||||
|
||||
QString AddressBook::getAddress(const QString &description) const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
for (const auto &row : m_rows) {
|
||||
if (row->description() == description) {
|
||||
return row->address();
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
qDeleteAll(m_rows);
|
||||
m_rows.clear();
|
||||
}
|
|
@ -5,43 +5,44 @@
|
|||
#define ADDRESSBOOK_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include "AddressBookInfo.h"
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QReadWriteLock>
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "rows/ContactRow.h"
|
||||
#include "Wallet.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
namespace Monero {
|
||||
struct AddressBook;
|
||||
}
|
||||
class AddressBookRow;
|
||||
|
||||
class AddressBook : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE bool getRow(int index, std::function<void (AddressBookInfo &)> callback) const;
|
||||
Q_INVOKABLE bool addRow(const QString &address, const QString &payment_id, const QString &description);
|
||||
Q_INVOKABLE bool deleteRow(int rowId);
|
||||
Q_INVOKABLE void setDescription(int index, const QString &label);
|
||||
quint64 count() const;
|
||||
Q_INVOKABLE QString errorString() const;
|
||||
Q_INVOKABLE int errorCode() const;
|
||||
Q_INVOKABLE QString getDescription(const QString &address) const;
|
||||
Q_INVOKABLE QString getAddress(const QString &description) const;
|
||||
|
||||
public:
|
||||
enum ErrorCode {
|
||||
Status_Ok,
|
||||
General_Error,
|
||||
Invalid_Address,
|
||||
Invalid_Payment_Id
|
||||
};
|
||||
|
||||
Q_ENUM(ErrorCode);
|
||||
|
||||
private:
|
||||
void getAll();
|
||||
bool getRow(int index, std::function<void (ContactRow &)> callback) const;
|
||||
bool addRow(const QString &address, const QString &description);
|
||||
bool deleteRow(int rowId);
|
||||
bool setDescription(int index, const QString &label);
|
||||
qsizetype count() const;
|
||||
QString errorString() const;
|
||||
ErrorCode errorCode() const;
|
||||
|
||||
void refresh();
|
||||
void clearRows();
|
||||
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
|
@ -49,12 +50,15 @@ signals:
|
|||
void descriptionChanged() const;
|
||||
|
||||
private:
|
||||
explicit AddressBook(Monero::AddressBook * abImpl, QObject *parent);
|
||||
explicit AddressBook(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent);
|
||||
friend class Wallet;
|
||||
Monero::AddressBook * m_addressBookImpl;
|
||||
mutable QReadWriteLock m_lock;
|
||||
QList<AddressBookInfo*> m_rows;
|
||||
QMap<QString, size_t> m_addresses;
|
||||
|
||||
Wallet *m_wallet;
|
||||
tools::wallet2 *m_wallet2;
|
||||
QList<ContactRow*> m_rows;
|
||||
|
||||
QString m_errorString;
|
||||
ErrorCode m_errorCode;
|
||||
};
|
||||
|
||||
#endif // ADDRESSBOOK_H
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "AddressBookInfo.h"
|
||||
|
||||
QString AddressBookInfo::address() const {
|
||||
return m_address;
|
||||
}
|
||||
|
||||
QString AddressBookInfo::description() const {
|
||||
return m_description;
|
||||
}
|
||||
|
||||
AddressBookInfo::AddressBookInfo(const Monero::AddressBookRow *pimpl, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_address(QString::fromStdString(pimpl->getAddress()))
|
||||
, m_description(QString::fromStdString(pimpl->getDescription()))
|
||||
{
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#ifndef FEATHER_ADDRESSBOOKINFO_H
|
||||
#define FEATHER_ADDRESSBOOKINFO_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include <QObject>
|
||||
|
||||
class AddressBookInfo : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString address READ address);
|
||||
Q_PROPERTY(QString description READ description);
|
||||
|
||||
public:
|
||||
QString address() const;
|
||||
QString description() const;
|
||||
|
||||
private:
|
||||
explicit AddressBookInfo(const Monero::AddressBookRow *pimpl, QObject *parent = nullptr);
|
||||
|
||||
friend class AddressBook;
|
||||
QString m_address;
|
||||
QString m_description;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_ADDRESSBOOKINFO_H
|
|
@ -2,50 +2,80 @@
|
|||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "Coins.h"
|
||||
#include "rows/CoinsInfo.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "CoinsInfo.h"
|
||||
|
||||
#include <QFile>
|
||||
Coins::Coins(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wallet(wallet)
|
||||
, m_wallet2(wallet2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Coins::coin(int index, std::function<void (CoinsInfo &)> callback)
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
if (index < 0 || index >= m_tinfo.size()) {
|
||||
if (index < 0 || index >= m_rows.size()) {
|
||||
qCritical("%s: no transaction info for index %d", __FUNCTION__, index);
|
||||
qCritical("%s: there's %d transactions in backend", __FUNCTION__, m_pimpl->count());
|
||||
qCritical("%s: there's %lld transactions in backend", __FUNCTION__, m_rows.count());
|
||||
return false;
|
||||
}
|
||||
|
||||
callback(*m_tinfo.value(index));
|
||||
callback(*m_rows.value(index));
|
||||
return true;
|
||||
}
|
||||
|
||||
CoinsInfo* Coins::coin(int index)
|
||||
{
|
||||
return m_tinfo.value(index);
|
||||
return m_rows.value(index);
|
||||
}
|
||||
|
||||
void Coins::refresh(quint32 accountIndex)
|
||||
void Coins::refresh()
|
||||
{
|
||||
emit refreshStarted();
|
||||
|
||||
boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet2->m_transfers_mutex);
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
qDeleteAll(m_tinfo);
|
||||
m_tinfo.clear();
|
||||
clearRows();
|
||||
uint32_t account = m_wallet->currentSubaddressAccount();
|
||||
|
||||
m_pimpl->refresh();
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
if (i->subaddrAccount() != accountIndex) {
|
||||
for (size_t i = 0; i < m_wallet2->get_num_transfer_details(); ++i)
|
||||
{
|
||||
const tools::wallet2::transfer_details &td = m_wallet2->get_transfer_details(i);
|
||||
|
||||
if (td.m_subaddr_index.major != account) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_tinfo.append(new CoinsInfo(i, this));
|
||||
auto ci = new CoinsInfo(this);
|
||||
ci->m_blockHeight = td.m_block_height;
|
||||
ci->m_hash = QString::fromStdString(epee::string_tools::pod_to_hex(td.m_txid));
|
||||
ci->m_internalOutputIndex = td.m_internal_output_index;
|
||||
ci->m_globalOutputIndex = td.m_global_output_index;
|
||||
ci->m_spent = td.m_spent;
|
||||
ci->m_frozen = td.m_frozen;
|
||||
ci->m_spentHeight = td.m_spent_height;
|
||||
ci->m_amount = td.m_amount;
|
||||
ci->m_rct = td.m_rct;
|
||||
ci->m_keyImageKnown = td.m_key_image_known;
|
||||
ci->m_pkIndex = td.m_pk_index;
|
||||
ci->m_subaddrIndex = td.m_subaddr_index.minor;
|
||||
ci->m_subaddrAccount = td.m_subaddr_index.major;
|
||||
ci->m_address = QString::fromStdString(m_wallet2->get_subaddress_as_str(td.m_subaddr_index)); // todo: this is expensive, cache maybe?
|
||||
ci->m_addressLabel = QString::fromStdString(m_wallet2->get_subaddress_label(td.m_subaddr_index));
|
||||
ci->m_keyImage = QString::fromStdString(epee::string_tools::pod_to_hex(td.m_key_image));
|
||||
ci->m_unlockTime = td.m_tx.unlock_time;
|
||||
ci->m_unlocked = m_wallet2->is_transfer_unlocked(td);
|
||||
ci->m_pubKey = QString::fromStdString(epee::string_tools::pod_to_hex(td.get_public_key()));
|
||||
ci->m_coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen);
|
||||
ci->m_description = m_wallet->getCacheAttribute(QString("coin.description:%1").arg(ci->m_pubKey));
|
||||
ci->m_change = m_wallet2->is_change(td);
|
||||
|
||||
m_rows.push_back(ci);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,9 +86,9 @@ void Coins::refreshUnlocked()
|
|||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
for (CoinsInfo* c : m_tinfo) {
|
||||
for (CoinsInfo* c : m_rows) {
|
||||
if (!c->unlocked()) {
|
||||
bool unlocked = m_pimpl->isTransferUnlocked(c->unlockTime(), c->blockHeight());
|
||||
bool unlocked = m_wallet2->is_transfer_unlocked(c->unlockTime(), c->blockHeight());
|
||||
c->setUnlocked(unlocked);
|
||||
}
|
||||
}
|
||||
|
@ -68,18 +98,50 @@ quint64 Coins::count() const
|
|||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
return m_tinfo.count();
|
||||
return m_rows.length();
|
||||
}
|
||||
|
||||
void Coins::freeze(QString &publicKey) const
|
||||
void Coins::freeze(QString &publicKey)
|
||||
{
|
||||
m_pimpl->setFrozen(publicKey.toStdString());
|
||||
crypto::public_key pk;
|
||||
if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
|
||||
{
|
||||
qWarning() << "Invalid public key: " << publicKey;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_wallet2->freeze(pk);
|
||||
refresh();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
qWarning() << "freeze: " << e.what();
|
||||
}
|
||||
|
||||
emit coinFrozen();
|
||||
}
|
||||
|
||||
void Coins::thaw(QString &publicKey) const
|
||||
void Coins::thaw(QString &publicKey)
|
||||
{
|
||||
m_pimpl->thaw(publicKey.toStdString());
|
||||
crypto::public_key pk;
|
||||
if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
|
||||
{
|
||||
qWarning() << "Invalid public key: " << publicKey;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_wallet2->thaw(pk);
|
||||
refresh();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
qWarning() << "thaw: " << e.what();
|
||||
}
|
||||
|
||||
emit coinThawed();
|
||||
}
|
||||
|
||||
|
@ -111,14 +173,12 @@ QVector<CoinsInfo*> Coins::coinsFromKeyImage(const QStringList &keyimages) {
|
|||
|
||||
void Coins::setDescription(const QString &publicKey, quint32 accountIndex, const QString &description)
|
||||
{
|
||||
m_pimpl->setDescription(publicKey.toStdString(), description.toStdString());
|
||||
this->refresh(accountIndex);
|
||||
m_wallet->setCacheAttribute(QString("coin.description:%1").arg(publicKey), description);
|
||||
this->refresh();
|
||||
emit descriptionChanged();
|
||||
}
|
||||
|
||||
Coins::Coins(Monero::Coins *pimpl, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_pimpl(pimpl)
|
||||
{
|
||||
|
||||
void Coins::clearRows() {
|
||||
qDeleteAll(m_rows);
|
||||
m_rows.clear();
|
||||
}
|
|
@ -12,6 +12,9 @@
|
|||
#include <QDateTime>
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
|
||||
#include "Wallet.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
namespace Monero {
|
||||
struct TransactionHistory;
|
||||
}
|
||||
|
@ -25,15 +28,16 @@ Q_OBJECT
|
|||
public:
|
||||
bool coin(int index, std::function<void (CoinsInfo &)> callback);
|
||||
CoinsInfo * coin(int index);
|
||||
void refresh(quint32 accountIndex);
|
||||
void refresh();
|
||||
void refreshUnlocked();
|
||||
void freeze(QString &publicKey) const;
|
||||
void thaw(QString &publicKey) const;
|
||||
void freeze(QString &publicKey);
|
||||
void thaw(QString &publicKey);
|
||||
QVector<CoinsInfo*> coins_from_txid(const QString &txid);
|
||||
QVector<CoinsInfo*> coinsFromKeyImage(const QStringList &keyimages);
|
||||
void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description);
|
||||
|
||||
quint64 count() const;
|
||||
void clearRows();
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
|
@ -43,13 +47,16 @@ signals:
|
|||
void descriptionChanged() const;
|
||||
|
||||
private:
|
||||
explicit Coins(Monero::Coins * pimpl, QObject *parent = nullptr);
|
||||
explicit Coins(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
friend class Wallet;
|
||||
|
||||
Wallet *m_wallet;
|
||||
tools::wallet2 *m_wallet2;
|
||||
QList<CoinsInfo*> m_rows;
|
||||
|
||||
mutable QReadWriteLock m_lock;
|
||||
Monero::Coins * m_pimpl;
|
||||
mutable QList<CoinsInfo*> m_tinfo;
|
||||
};
|
||||
|
||||
#endif //FEATHER_COINS_H
|
||||
|
|
|
@ -12,14 +12,15 @@
|
|||
class Ring : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString keyImage READ keyImage)
|
||||
Q_PROPERTY(std::vector<uint64_t> ringMembers READ ringMembers)
|
||||
private:
|
||||
|
||||
public:
|
||||
explicit Ring(QString _keyImage, std::vector<uint64_t> _ringMembers, QObject *parent = nullptr): QObject(parent), m_keyImage(std::move(_keyImage)), m_ringMembers(std::move(_ringMembers)) {};
|
||||
|
||||
private:
|
||||
friend class TransactionInfo;
|
||||
QString m_keyImage;
|
||||
std::vector<uint64_t> m_ringMembers;
|
||||
|
||||
public:
|
||||
QString keyImage() const { return m_keyImage; }
|
||||
std::vector<uint64_t> ringMembers() const { return m_ringMembers; }
|
||||
|
|
|
@ -159,8 +159,8 @@ void Subaddress::clearRows() {
|
|||
|
||||
SubaddressRow* Subaddress::row(int index) const {
|
||||
return m_rows.value(index);
|
||||
};
|
||||
}
|
||||
|
||||
QString Subaddress::getError() const {
|
||||
return m_errorString;
|
||||
};
|
||||
}
|
|
@ -4,31 +4,15 @@
|
|||
#include "SubaddressAccount.h"
|
||||
#include <QDebug>
|
||||
|
||||
SubaddressAccount::SubaddressAccount(Monero::SubaddressAccount *subaddressAccountImpl, QObject *parent)
|
||||
: QObject(parent), m_subaddressAccountImpl(subaddressAccountImpl)
|
||||
SubaddressAccount::SubaddressAccount(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wallet(wallet)
|
||||
, m_wallet2(wallet2)
|
||||
{
|
||||
getAll();
|
||||
}
|
||||
|
||||
void SubaddressAccount::getAll() const
|
||||
bool SubaddressAccount::getRow(int index, std::function<void (AccountRow &row)> callback) const
|
||||
{
|
||||
emit refreshStarted();
|
||||
|
||||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
m_rows.clear();
|
||||
for (auto &row: m_subaddressAccountImpl->getAll()) {
|
||||
m_rows.append(row);
|
||||
}
|
||||
}
|
||||
|
||||
emit refreshFinished();
|
||||
}
|
||||
|
||||
bool SubaddressAccount::getRow(int index, std::function<void (Monero::SubaddressAccountRow &)> callback) const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
if (index < 0 || index >= m_rows.size())
|
||||
{
|
||||
return false;
|
||||
|
@ -38,32 +22,50 @@ bool SubaddressAccount::getRow(int index, std::function<void (Monero::Subaddress
|
|||
return true;
|
||||
}
|
||||
|
||||
void SubaddressAccount::addRow(const QString &label) const
|
||||
void SubaddressAccount::addRow(const QString &label)
|
||||
{
|
||||
m_subaddressAccountImpl->addRow(label.toStdString());
|
||||
getAll();
|
||||
m_wallet2->add_subaddress_account(label.toStdString());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void SubaddressAccount::setLabel(quint32 accountIndex, const QString &label) const
|
||||
void SubaddressAccount::setLabel(quint32 accountIndex, const QString &label)
|
||||
{
|
||||
m_subaddressAccountImpl->setLabel(accountIndex, label.toStdString());
|
||||
getAll();
|
||||
m_wallet2->set_subaddress_label({accountIndex, 0}, label.toStdString());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void SubaddressAccount::refresh() const
|
||||
void SubaddressAccount::refresh()
|
||||
{
|
||||
m_subaddressAccountImpl->refresh();
|
||||
getAll();
|
||||
emit refreshStarted();
|
||||
|
||||
this->clearRows();
|
||||
for (uint32_t i = 0; i < m_wallet2->get_num_subaddress_accounts(); ++i)
|
||||
{
|
||||
auto *row = new AccountRow{this,
|
||||
i,
|
||||
QString::fromStdString(m_wallet2->get_subaddress_as_str({i,0})),
|
||||
QString::fromStdString(m_wallet2->get_subaddress_label({i,0})),
|
||||
m_wallet2->balance(i, false),
|
||||
m_wallet2->unlocked_balance(i, false)};
|
||||
|
||||
m_rows.append(row);
|
||||
}
|
||||
|
||||
emit refreshFinished();
|
||||
}
|
||||
|
||||
quint64 SubaddressAccount::count() const
|
||||
qsizetype SubaddressAccount::count() const
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
return m_rows.size();
|
||||
return m_rows.length();
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* SubaddressAccount::row(int index) const
|
||||
void SubaddressAccount::clearRows()
|
||||
{
|
||||
qDeleteAll(m_rows);
|
||||
m_rows.clear();
|
||||
}
|
||||
|
||||
AccountRow* SubaddressAccount::row(int index) const
|
||||
{
|
||||
return m_rows.value(index);
|
||||
}
|
|
@ -12,30 +12,40 @@
|
|||
#include <QList>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <wallet/wallet2.h>
|
||||
|
||||
#include "Wallet.h"
|
||||
#include "rows/AccountRow.h"
|
||||
|
||||
class SubaddressAccount : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void getAll() const;
|
||||
Q_INVOKABLE bool getRow(int index, std::function<void (Monero::SubaddressAccountRow &)> callback) const;
|
||||
Q_INVOKABLE void addRow(const QString &label) const;
|
||||
Q_INVOKABLE void setLabel(quint32 accountIndex, const QString &label) const;
|
||||
Q_INVOKABLE void refresh() const;
|
||||
quint64 count() const;
|
||||
Monero::SubaddressAccountRow* row(int index) const;
|
||||
void getAll() const;
|
||||
bool getRow(int index, std::function<void (AccountRow &row)> callback) const;
|
||||
void addRow(const QString &label);
|
||||
|
||||
void setLabel(quint32 accountIndex, const QString &label);
|
||||
|
||||
void refresh();
|
||||
|
||||
qsizetype count() const;
|
||||
void clearRows();
|
||||
|
||||
AccountRow* row(int index) const;
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
void refreshFinished() const;
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
explicit SubaddressAccount(Monero::SubaddressAccount * subaddressAccountImpl, QObject *parent);
|
||||
explicit SubaddressAccount(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent);
|
||||
friend class Wallet;
|
||||
mutable QReadWriteLock m_lock;
|
||||
Monero::SubaddressAccount * m_subaddressAccountImpl;
|
||||
mutable QList<Monero::SubaddressAccountRow*> m_rows;
|
||||
|
||||
Wallet *m_wallet;
|
||||
tools::wallet2 *m_wallet2;
|
||||
QList<AccountRow*> m_rows;
|
||||
};
|
||||
|
||||
#endif // SUBADDRESSACCOUNT_H
|
||||
|
|
|
@ -2,48 +2,49 @@
|
|||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "TransactionHistory.h"
|
||||
#include "TransactionInfo.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "utils/AppData.h"
|
||||
#include "utils/config.h"
|
||||
#include "constants.h"
|
||||
#include "WalletManager.h"
|
||||
#include "Transfer.h"
|
||||
#include "Ring.h"
|
||||
|
||||
bool TransactionHistory::transaction(int index, std::function<void (TransactionInfo &)> callback)
|
||||
bool TransactionHistory::transaction(int index, std::function<void (TransactionRow &)> callback)
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
if (index < 0 || index >= m_tinfo.size()) {
|
||||
if (index < 0 || index >= m_rows.size()) {
|
||||
qCritical("%s: no transaction info for index %d", __FUNCTION__, index);
|
||||
qCritical("%s: there's %d transactions in backend", __FUNCTION__, m_pimpl->count());
|
||||
qCritical("%s: there's %d transactions in backend", __FUNCTION__, this->count());
|
||||
return false;
|
||||
}
|
||||
|
||||
callback(*m_tinfo.value(index));
|
||||
callback(*m_rows.value(index));
|
||||
return true;
|
||||
}
|
||||
|
||||
TransactionInfo* TransactionHistory::transaction(const QString &id)
|
||||
TransactionRow* TransactionHistory::transaction(const QString &id)
|
||||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
auto itr = std::find_if(m_tinfo.begin(), m_tinfo.end(),
|
||||
[&](const TransactionInfo * ti) {
|
||||
auto itr = std::find_if(m_rows.begin(), m_rows.end(),
|
||||
[&](const TransactionRow * ti) {
|
||||
return ti->hash() == id;
|
||||
});
|
||||
return itr != m_tinfo.end() ? *itr : nullptr;
|
||||
return itr != m_rows.end() ? *itr : nullptr;
|
||||
}
|
||||
|
||||
TransactionInfo* TransactionHistory::transaction(int index)
|
||||
TransactionRow* TransactionHistory::transaction(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_tinfo.size()) {
|
||||
if (index < 0 || index >= m_rows.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_tinfo[index];
|
||||
return m_rows[index];
|
||||
}
|
||||
|
||||
void TransactionHistory::refresh(quint32 accountIndex)
|
||||
void TransactionHistory::refresh()
|
||||
{
|
||||
QDateTime firstDateTime = QDate(2014, 4, 18).startOfDay();
|
||||
QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
||||
|
@ -53,55 +54,214 @@ void TransactionHistory::refresh(quint32 accountIndex)
|
|||
{
|
||||
QWriteLocker locker(&m_lock);
|
||||
|
||||
qDeleteAll(m_tinfo);
|
||||
m_tinfo.clear();
|
||||
clearRows();
|
||||
|
||||
quint64 lastTxHeight = 0;
|
||||
m_locked = false;
|
||||
m_minutesToUnlock = 0;
|
||||
|
||||
m_pimpl->refresh();
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
if (i->subaddrAccount() != accountIndex) {
|
||||
|
||||
uint64_t min_height = 0;
|
||||
uint64_t max_height = (uint64_t)-1;
|
||||
uint64_t wallet_height = m_wallet->blockChainHeight();
|
||||
uint32_t account = m_wallet->currentSubaddressAccount();
|
||||
|
||||
// transactions are stored in wallet2:
|
||||
// - confirmed_transfer_details - out transfers
|
||||
// - unconfirmed_transfer_details - pending out transfers
|
||||
// - payment_details - input transfers
|
||||
|
||||
// payments are "input transactions";
|
||||
// one input transaction contains only one transfer. e.g. <transaction_id> - <100XMR>
|
||||
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> in_payments;
|
||||
m_wallet2->get_payments(in_payments, min_height, max_height);
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = in_payments.begin(); i != in_payments.end(); ++i)
|
||||
{
|
||||
const tools::wallet2::payment_details &pd = i->second;
|
||||
if (pd.m_subaddr_index.major != account) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_tinfo.append(new TransactionInfo(i, this));
|
||||
std::string payment_id = epee::string_tools::pod_to_hex(i->first);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
|
||||
const TransactionInfo *ti = m_tinfo.back();
|
||||
// looking for transactions timestamp scope
|
||||
if (ti->timestamp() >= lastDateTime) {
|
||||
lastDateTime = ti->timestamp();
|
||||
auto* t = new TransactionRow();
|
||||
t->m_paymentId = QString::fromStdString(payment_id);
|
||||
t->m_coinbase = pd.m_coinbase;
|
||||
t->m_amount = pd.m_amount;
|
||||
t->m_fee = pd.m_fee;
|
||||
t->m_direction = TransactionRow::Direction_In;
|
||||
t->m_hash = QString::fromStdString(epee::string_tools::pod_to_hex(pd.m_tx_hash));
|
||||
t->m_blockHeight = pd.m_block_height;
|
||||
t->m_description = QString::fromStdString(m_wallet2->get_tx_note(pd.m_tx_hash));
|
||||
t->m_subaddrIndex = { pd.m_subaddr_index.minor };
|
||||
t->m_subaddrAccount = pd.m_subaddr_index.major;
|
||||
t->m_label = QString::fromStdString(m_wallet2->get_subaddress_label(pd.m_subaddr_index));
|
||||
t->m_timestamp = QDateTime::fromSecsSinceEpoch(pd.m_timestamp);
|
||||
t->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0;
|
||||
t->m_unlockTime = pd.m_unlock_time;
|
||||
|
||||
m_rows.append(t);
|
||||
}
|
||||
|
||||
// confirmed output transactions
|
||||
// one output transaction may contain more than one money transfer, e.g.
|
||||
// <transaction_id>:
|
||||
// transfer1: 100XMR to <address_1>
|
||||
// transfer2: 50XMR to <address_2>
|
||||
// fee: fee charged per transaction
|
||||
//
|
||||
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> out_payments;
|
||||
m_wallet2->get_payments_out(out_payments, min_height, max_height);
|
||||
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = out_payments.begin();
|
||||
i != out_payments.end(); ++i) {
|
||||
|
||||
const crypto::hash &hash = i->first;
|
||||
const tools::wallet2::confirmed_transfer_details &pd = i->second;
|
||||
if (pd.m_subaddr_account != account) {
|
||||
continue;
|
||||
}
|
||||
if (ti->timestamp() <= firstDateTime) {
|
||||
firstDateTime = ti->timestamp();
|
||||
|
||||
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
|
||||
uint64_t fee = pd.m_amount_in - pd.m_amount_out;
|
||||
|
||||
|
||||
std::string payment_id = epee::string_tools::pod_to_hex(i->second.m_payment_id);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
|
||||
|
||||
auto* t = new TransactionRow();
|
||||
t->m_paymentId = QString::fromStdString(payment_id);
|
||||
t->m_amount = pd.m_amount_in - change - fee;
|
||||
t->m_fee = fee;
|
||||
t->m_direction = TransactionRow::Direction_Out;
|
||||
t->m_hash = QString::fromStdString(epee::string_tools::pod_to_hex(hash));
|
||||
t->m_blockHeight = pd.m_block_height;
|
||||
t->m_description = QString::fromStdString(m_wallet2->get_tx_note(hash));
|
||||
t->m_subaddrAccount = pd.m_subaddr_account;
|
||||
t->m_label = QString::fromStdString(pd.m_subaddr_indices.size() == 1 ? m_wallet2->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "");
|
||||
t->m_timestamp = QDateTime::fromSecsSinceEpoch(pd.m_timestamp);
|
||||
t->m_confirmations = (wallet_height > pd.m_block_height) ? wallet_height - pd.m_block_height : 0;
|
||||
|
||||
for (uint32_t idx : t->subaddrIndex())
|
||||
{
|
||||
t->m_subaddrIndex.insert(idx);
|
||||
}
|
||||
quint64 requiredConfirmations = (ti->blockHeight() < ti->unlockTime()) ? ti->unlockTime() - ti->blockHeight() : 10;
|
||||
// store last tx height
|
||||
if (ti->confirmations() < requiredConfirmations && ti->blockHeight() >= lastTxHeight) {
|
||||
lastTxHeight = ti->blockHeight();
|
||||
// TODO: Fetch block time and confirmations needed from wallet2?
|
||||
m_minutesToUnlock = (requiredConfirmations - ti->confirmations()) * 2;
|
||||
m_locked = true;
|
||||
|
||||
// single output transaction might contain multiple transfers
|
||||
for (auto const &d: pd.m_dests)
|
||||
{
|
||||
Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id)), this);
|
||||
t->m_transfers.append(transfer);
|
||||
}
|
||||
for (auto const &r: pd.m_rings)
|
||||
{
|
||||
Ring *ring = new Ring(QString::fromStdString(epee::string_tools::pod_to_hex(r.first)), cryptonote::relative_output_offsets_to_absolute(r.second), this);
|
||||
t->m_rings.append(ring);
|
||||
}
|
||||
|
||||
m_rows.append(t);
|
||||
}
|
||||
|
||||
// unconfirmed output transactions
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments_out;
|
||||
m_wallet2->get_unconfirmed_payments_out(upayments_out);
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments_out.begin(); i != upayments_out.end(); ++i) {
|
||||
const tools::wallet2::unconfirmed_transfer_details &pd = i->second;
|
||||
if (pd.m_subaddr_account != account) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const crypto::hash &hash = i->first;
|
||||
uint64_t amount = pd.m_amount_in;
|
||||
uint64_t fee = amount - pd.m_amount_out;
|
||||
std::string payment_id = epee::string_tools::pod_to_hex(i->second.m_payment_id);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
|
||||
|
||||
auto *t = new TransactionRow();
|
||||
t->m_paymentId = QString::fromStdString(payment_id);
|
||||
t->m_amount = amount - pd.m_change - fee;
|
||||
t->m_fee = fee;
|
||||
t->m_direction = TransactionRow::Direction_Out;
|
||||
t->m_failed = is_failed;
|
||||
t->m_pending = true;
|
||||
t->m_hash = QString::fromStdString(epee::string_tools::pod_to_hex(hash));
|
||||
t->m_description = QString::fromStdString(m_wallet2->get_tx_note(hash));
|
||||
t->m_subaddrAccount = pd.m_subaddr_account;
|
||||
t->m_label = QString::fromStdString(pd.m_subaddr_indices.size() == 1 ? m_wallet2->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "");
|
||||
t->m_timestamp = QDateTime::fromSecsSinceEpoch(pd.m_timestamp);
|
||||
t->m_confirmations = 0;
|
||||
for (uint32_t idx : t->subaddrIndex())
|
||||
{
|
||||
t->m_subaddrIndex.insert(idx);
|
||||
}
|
||||
|
||||
for (auto const &d: pd.m_dests)
|
||||
{
|
||||
Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id)), this);
|
||||
t->m_transfers.append(transfer);
|
||||
}
|
||||
for (auto const &r: pd.m_rings)
|
||||
{
|
||||
Ring *ring = new Ring(QString::fromStdString(epee::string_tools::pod_to_hex(r.first)), cryptonote::relative_output_offsets_to_absolute(r.second), this);
|
||||
t->m_rings.append(ring);
|
||||
}
|
||||
|
||||
m_rows.append(t);
|
||||
}
|
||||
|
||||
|
||||
// unconfirmed payments (tx pool)
|
||||
std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> upayments;
|
||||
m_wallet2->get_unconfirmed_payments(upayments);
|
||||
for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
|
||||
const tools::wallet2::payment_details &pd = i->second.m_pd;
|
||||
if (pd.m_subaddr_index.major != account) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string payment_id = epee::string_tools::pod_to_hex(i->first);
|
||||
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
|
||||
payment_id = payment_id.substr(0,16);
|
||||
auto *t = new TransactionRow();
|
||||
t->m_paymentId = QString::fromStdString(payment_id);
|
||||
t->m_amount = pd.m_amount;
|
||||
t->m_direction = TransactionRow::Direction_In;
|
||||
t->m_hash = QString::fromStdString(epee::string_tools::pod_to_hex(pd.m_tx_hash));
|
||||
t->m_blockHeight = pd.m_block_height;
|
||||
t->m_description = QString::fromStdString(m_wallet2->get_tx_note(pd.m_tx_hash));
|
||||
t->m_pending = true;
|
||||
t->m_subaddrIndex = { pd.m_subaddr_index.minor };
|
||||
t->m_subaddrAccount = pd.m_subaddr_index.major;
|
||||
t->m_label = QString::fromStdString(m_wallet2->get_subaddress_label(pd.m_subaddr_index));
|
||||
t->m_timestamp = QDateTime::fromSecsSinceEpoch(pd.m_timestamp);
|
||||
t->m_confirmations = 0;
|
||||
|
||||
m_rows.append(t);
|
||||
|
||||
LOG_PRINT_L1(__FUNCTION__ << ": Unconfirmed payment found " << pd.m_amount);
|
||||
}
|
||||
}
|
||||
|
||||
emit refreshFinished();
|
||||
|
||||
if (m_firstDateTime != firstDateTime) {
|
||||
m_firstDateTime = firstDateTime;
|
||||
emit firstDateTimeChanged();
|
||||
}
|
||||
if (m_lastDateTime != lastDateTime) {
|
||||
m_lastDateTime = lastDateTime;
|
||||
emit lastDateTimeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionHistory::setTxNote(const QString &txid, const QString ¬e)
|
||||
{
|
||||
m_pimpl->setTxNote(txid.toStdString(), note.toStdString());
|
||||
cryptonote::blobdata txid_data;
|
||||
if(!epee::string_tools::parse_hexstr_to_binbuff(txid.toStdString(), txid_data) || txid_data.size() != sizeof(crypto::hash))
|
||||
return;
|
||||
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
|
||||
|
||||
m_wallet2->set_tx_note(htxid, note.toStdString());
|
||||
refresh();
|
||||
emit txNoteChanged();
|
||||
}
|
||||
|
||||
|
@ -109,7 +269,7 @@ quint64 TransactionHistory::count() const
|
|||
{
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
return m_tinfo.count();
|
||||
return m_rows.length();
|
||||
}
|
||||
|
||||
QDateTime TransactionHistory::firstDateTime() const
|
||||
|
@ -133,8 +293,12 @@ bool TransactionHistory::TransactionHistory::locked() const
|
|||
}
|
||||
|
||||
|
||||
TransactionHistory::TransactionHistory(Monero::TransactionHistory *pimpl, QObject *parent)
|
||||
: QObject(parent), m_pimpl(pimpl), m_minutesToUnlock(0), m_locked(false)
|
||||
TransactionHistory::TransactionHistory(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_wallet(wallet)
|
||||
, m_wallet2(wallet2)
|
||||
, m_minutesToUnlock(0)
|
||||
, m_locked(false)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
m_firstDateTime = QDate(2014, 4, 18).startOfDay();
|
||||
|
@ -144,22 +308,25 @@ TransactionHistory::TransactionHistory(Monero::TransactionHistory *pimpl, QObjec
|
|||
m_lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
|
||||
}
|
||||
|
||||
void TransactionHistory::clearRows() {
|
||||
qDeleteAll(m_rows);
|
||||
m_rows.clear();
|
||||
}
|
||||
|
||||
bool TransactionHistory::writeCSV(const QString &path) {
|
||||
QString data;
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
auto transactions = m_pimpl->getAll();
|
||||
auto transactions = m_rows;
|
||||
|
||||
std::sort(transactions.begin(), transactions.end(), [](const Monero::TransactionInfo *info1, const Monero::TransactionInfo *info2){
|
||||
std::sort(m_rows.begin(), m_rows.end(), [](const TransactionRow *info1, const TransactionRow *info2){
|
||||
return info1->blockHeight() < info2->blockHeight();
|
||||
});
|
||||
|
||||
for (const auto &tx : transactions) {
|
||||
TransactionInfo info(tx, this);
|
||||
|
||||
for (const auto &info : transactions) {
|
||||
// collect column data
|
||||
QDateTime timeStamp = info.timestamp();
|
||||
double amount = info.amount();
|
||||
QDateTime timeStamp = info->timestamp();
|
||||
double amount = info->amount();
|
||||
|
||||
// calc historical fiat price
|
||||
QString fiatAmount;
|
||||
|
@ -176,31 +343,31 @@ bool TransactionHistory::writeCSV(const QString &path) {
|
|||
fiatAmount = "\"?\"";
|
||||
|
||||
QString direction = QString("");
|
||||
if (info.direction() == TransactionInfo::Direction_In)
|
||||
if (info->direction() == TransactionRow::Direction_In)
|
||||
direction = QString("in");
|
||||
else if (info.direction() == TransactionInfo::Direction_Out)
|
||||
else if (info->direction() == TransactionRow::Direction_Out)
|
||||
direction = QString("out");
|
||||
else
|
||||
continue; // skip TransactionInfo::Direction_Both
|
||||
|
||||
QString displayAmount = info.displayAmount();
|
||||
QString paymentId = info.paymentId();
|
||||
QString displayAmount = info->displayAmount();
|
||||
QString paymentId = info->paymentId();
|
||||
if (paymentId == "0000000000000000") {
|
||||
paymentId = "";
|
||||
}
|
||||
|
||||
QString date = QString("%1T%2Z").arg(info.date(), info.time()); // ISO 8601
|
||||
QString date = QString("%1T%2Z").arg(info->date(), info->time()); // ISO 8601
|
||||
|
||||
QString balanceDelta = WalletManager::displayAmount(info.balanceDelta());
|
||||
if (info.direction() == TransactionInfo::Direction_Out) {
|
||||
QString balanceDelta = WalletManager::displayAmount(info->balanceDelta());
|
||||
if (info->direction() == TransactionRow::Direction_Out) {
|
||||
balanceDelta = "-" + balanceDelta;
|
||||
}
|
||||
|
||||
// format and write
|
||||
QString line = QString("\n%1,%2,\"%3\",%4,\"%5\",%6,%7,%8,\"%9\",\"%10\",\"%11\",%12,\"%13\"")
|
||||
.arg(QString::number(info.blockHeight()), QString::number(timeStamp.toSecsSinceEpoch()), date,
|
||||
QString::number(info.subaddrAccount()), direction, balanceDelta, info.displayAmount(),
|
||||
info.fee(), info.hash(), info.description(), paymentId, fiatAmount, preferredFiatSymbol);
|
||||
.arg(QString::number(info->blockHeight()), QString::number(timeStamp.toSecsSinceEpoch()), date,
|
||||
QString::number(info->subaddrAccount()), direction, balanceDelta, info->displayAmount(),
|
||||
info->fee(), info->hash(), info->description(), paymentId, fiatAmount, preferredFiatSymbol);
|
||||
data += line;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
#include <QReadWriteLock>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "rows/TransactionRow.h"
|
||||
#include "Wallet.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
namespace Monero {
|
||||
struct TransactionHistory;
|
||||
}
|
||||
|
@ -20,24 +24,20 @@ class TransactionInfo;
|
|||
class TransactionHistory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count)
|
||||
Q_PROPERTY(QDateTime firstDateTime READ firstDateTime NOTIFY firstDateTimeChanged)
|
||||
Q_PROPERTY(QDateTime lastDateTime READ lastDateTime NOTIFY lastDateTimeChanged)
|
||||
Q_PROPERTY(int minutesToUnlock READ minutesToUnlock)
|
||||
Q_PROPERTY(bool locked READ locked)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE bool transaction(int index, std::function<void (TransactionInfo &)> callback);
|
||||
Q_INVOKABLE TransactionInfo * transaction(const QString &id);
|
||||
TransactionInfo* transaction(int index);
|
||||
Q_INVOKABLE void refresh(quint32 accountIndex);
|
||||
Q_INVOKABLE void setTxNote(const QString &txid, const QString ¬e);
|
||||
Q_INVOKABLE bool writeCSV(const QString &path);
|
||||
bool transaction(int index, std::function<void (TransactionRow &)> callback);
|
||||
TransactionRow * transaction(const QString &id);
|
||||
TransactionRow* transaction(int index);
|
||||
void refresh();
|
||||
void setTxNote(const QString &txid, const QString ¬e);
|
||||
bool writeCSV(const QString &path);
|
||||
quint64 count() const;
|
||||
QDateTime firstDateTime() const;
|
||||
QDateTime lastDateTime() const;
|
||||
quint64 minutesToUnlock() const;
|
||||
bool locked() const;
|
||||
void clearRows();
|
||||
|
||||
signals:
|
||||
void refreshStarted() const;
|
||||
|
@ -47,13 +47,16 @@ signals:
|
|||
void txNoteChanged() const;
|
||||
|
||||
private:
|
||||
explicit TransactionHistory(Monero::TransactionHistory * pimpl, QObject *parent = nullptr);
|
||||
explicit TransactionHistory(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
friend class Wallet;
|
||||
mutable QReadWriteLock m_lock;
|
||||
Monero::TransactionHistory * m_pimpl;
|
||||
mutable QList<TransactionInfo*> m_tinfo;
|
||||
|
||||
Wallet *m_wallet;
|
||||
tools::wallet2 *m_wallet2;
|
||||
QList<TransactionRow*> m_rows;
|
||||
|
||||
mutable QDateTime m_firstDateTime;
|
||||
mutable QDateTime m_lastDateTime;
|
||||
mutable int m_minutesToUnlock;
|
||||
|
|
|
@ -1,202 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "TransactionInfo.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "Transfer.h"
|
||||
#include "Ring.h"
|
||||
|
||||
TransactionInfo::Direction TransactionInfo::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
bool TransactionInfo::isPending() const
|
||||
{
|
||||
return m_pending;
|
||||
}
|
||||
|
||||
bool TransactionInfo::isFailed() const
|
||||
{
|
||||
return m_failed;
|
||||
}
|
||||
|
||||
bool TransactionInfo::isCoinbase() const
|
||||
{
|
||||
return m_coinbase;
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::balanceDelta() const
|
||||
{
|
||||
if (m_direction == Direction_In) {
|
||||
return m_amount;
|
||||
}
|
||||
else if (m_direction == Direction_Out) {
|
||||
return m_amount + m_fee;
|
||||
}
|
||||
return m_amount;
|
||||
}
|
||||
|
||||
double TransactionInfo::amount() const
|
||||
{
|
||||
// there's no unsigned uint64 for JS, so better use double
|
||||
return displayAmount().toDouble();
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::atomicAmount() const
|
||||
{
|
||||
return m_amount;
|
||||
}
|
||||
|
||||
QString TransactionInfo::displayAmount() const
|
||||
{
|
||||
return WalletManager::displayAmount(m_amount);
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::atomicFee() const
|
||||
{
|
||||
return m_fee;
|
||||
}
|
||||
|
||||
QString TransactionInfo::fee() const
|
||||
{
|
||||
if(m_fee == 0)
|
||||
return "";
|
||||
return WalletManager::displayAmount(m_fee);
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::blockHeight() const
|
||||
{
|
||||
return m_blockHeight;
|
||||
}
|
||||
|
||||
QString TransactionInfo::description() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
QSet<quint32> TransactionInfo::subaddrIndex() const
|
||||
{
|
||||
return m_subaddrIndex;
|
||||
}
|
||||
|
||||
quint32 TransactionInfo::subaddrAccount() const
|
||||
{
|
||||
return m_subaddrAccount;
|
||||
}
|
||||
|
||||
QString TransactionInfo::label() const
|
||||
{
|
||||
return m_label;
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::confirmations() const
|
||||
{
|
||||
return m_confirmations;
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::confirmationsRequired() const
|
||||
{
|
||||
return (m_blockHeight < m_unlockTime) ? m_unlockTime - m_blockHeight : 10;
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::unlockTime() const
|
||||
{
|
||||
return m_unlockTime;
|
||||
}
|
||||
|
||||
QString TransactionInfo::hash() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
QDateTime TransactionInfo::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
QString TransactionInfo::date() const
|
||||
{
|
||||
return timestamp().date().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionInfo::time() const
|
||||
{
|
||||
return timestamp().time().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionInfo::paymentId() const
|
||||
{
|
||||
return m_paymentId;
|
||||
}
|
||||
|
||||
QString TransactionInfo::destinations_formatted() const
|
||||
{
|
||||
QString destinations;
|
||||
for (auto const& t: m_transfers) {
|
||||
if (!destinations.isEmpty())
|
||||
destinations += "<br> ";
|
||||
destinations += WalletManager::displayAmount(t->amount()) + ": " + t->address();
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
|
||||
QList<QString> TransactionInfo::destinations() const
|
||||
{
|
||||
QList<QString> dests;
|
||||
for (auto const& t: m_transfers) {
|
||||
dests.append(t->address());
|
||||
}
|
||||
return dests;
|
||||
}
|
||||
|
||||
QList<Transfer*> TransactionInfo::transfers() const {
|
||||
return m_transfers;
|
||||
}
|
||||
|
||||
QString TransactionInfo::rings_formatted() const
|
||||
{
|
||||
QString rings;
|
||||
for (auto const& r: m_rings) {
|
||||
rings += r->keyImage() + ": \n";
|
||||
for (uint64_t m : r->ringMembers()){
|
||||
rings += QString::number(m) + " ";
|
||||
}
|
||||
rings += "\n\n";
|
||||
}
|
||||
return rings;
|
||||
}
|
||||
|
||||
TransactionInfo::TransactionInfo(const Monero::TransactionInfo *pimpl, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_amount(pimpl->amount())
|
||||
, m_blockHeight(pimpl->blockHeight())
|
||||
, m_description(QString::fromStdString(pimpl->description()))
|
||||
, m_confirmations(pimpl->confirmations())
|
||||
, m_direction(static_cast<Direction>(pimpl->direction()))
|
||||
, m_failed(pimpl->isFailed())
|
||||
, m_fee(pimpl->fee())
|
||||
, m_hash(QString::fromStdString(pimpl->hash()))
|
||||
, m_label(QString::fromStdString(pimpl->label()))
|
||||
, m_paymentId(QString::fromStdString(pimpl->paymentId()))
|
||||
, m_pending(pimpl->isPending())
|
||||
, m_subaddrAccount(pimpl->subaddrAccount())
|
||||
, m_timestamp(QDateTime::fromSecsSinceEpoch(pimpl->timestamp()))
|
||||
, m_unlockTime(pimpl->unlockTime())
|
||||
, m_coinbase(pimpl->isCoinbase())
|
||||
{
|
||||
for (auto const &t: pimpl->transfers())
|
||||
{
|
||||
Transfer *transfer = new Transfer(t.amount, QString::fromStdString(t.address), this);
|
||||
m_transfers.append(transfer);
|
||||
}
|
||||
for (auto const &r: pimpl->rings())
|
||||
{
|
||||
Ring *ring = new Ring(QString::fromStdString(r.first), r.second, this);
|
||||
m_rings.append(ring);
|
||||
}
|
||||
for (uint32_t i : pimpl->subaddrIndex())
|
||||
{
|
||||
m_subaddrIndex.insert(i);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ class Transfer : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
public:
|
||||
explicit Transfer(uint64_t _amount, QString _address, QObject *parent = 0)
|
||||
: QObject(parent), m_amount(_amount), m_address(std::move(_address)) {};
|
||||
private:
|
||||
|
|
|
@ -32,21 +32,21 @@ namespace {
|
|||
Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_walletImpl(wallet)
|
||||
, m_history(new TransactionHistory(m_walletImpl->history(), this))
|
||||
, m_history(new TransactionHistory(this, wallet->getWallet(), this))
|
||||
, m_historyModel(nullptr)
|
||||
, m_addressBook(new AddressBook(m_walletImpl->addressBook(), this))
|
||||
, m_addressBook(new AddressBook(this, wallet->getWallet(), this))
|
||||
, m_addressBookModel(nullptr)
|
||||
, m_daemonBlockChainHeight(0)
|
||||
, m_daemonBlockChainTargetHeight(0)
|
||||
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
||||
, m_currentSubaddressAccount(0)
|
||||
, m_subaddress(new Subaddress(this, wallet->getWallet(), this))
|
||||
, m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
|
||||
, m_subaddressAccount(new SubaddressAccount(this, wallet->getWallet(), this))
|
||||
, m_refreshNow(false)
|
||||
, m_refreshEnabled(false)
|
||||
, m_scheduler(this)
|
||||
, m_useSSL(true)
|
||||
, m_coins(new Coins(m_walletImpl->coins(), this))
|
||||
, m_coins(new Coins(this, wallet->getWallet(), this))
|
||||
, m_storeTimer(new QTimer(this))
|
||||
{
|
||||
m_walletListener = new WalletListenerImpl(this);
|
||||
|
@ -71,7 +71,7 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
|
|||
}
|
||||
|
||||
connect(this->history(), &TransactionHistory::txNoteChanged, [this]{
|
||||
this->history()->refresh(this->currentSubaddressAccount());
|
||||
this->history()->refresh();
|
||||
});
|
||||
|
||||
connect(this, &Wallet::refreshed, this, &Wallet::onRefreshed);
|
||||
|
@ -185,8 +185,8 @@ void Wallet::switchSubaddressAccount(quint32 accountIndex) {
|
|||
qWarning() << "failed to set " << ATTRIBUTE_SUBADDRESS_ACCOUNT << " cache attribute";
|
||||
}
|
||||
m_subaddress->refresh(m_currentSubaddressAccount);
|
||||
m_history->refresh(m_currentSubaddressAccount);
|
||||
m_coins->refresh(m_currentSubaddressAccount);
|
||||
m_history->refresh();
|
||||
m_coins->refresh();
|
||||
this->subaddressModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
|
||||
this->coinsModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
|
||||
this->updateBalance();
|
||||
|
@ -453,8 +453,8 @@ void Wallet::onRefreshed(bool success, const QString &message) {
|
|||
}
|
||||
|
||||
void Wallet::refreshModels() {
|
||||
m_history->refresh(this->currentSubaddressAccount());
|
||||
m_coins->refresh(this->currentSubaddressAccount());
|
||||
m_history->refresh();
|
||||
m_coins->refresh();
|
||||
bool r = this->subaddress()->refresh(this->currentSubaddressAccount());
|
||||
|
||||
if (!r) {
|
||||
|
@ -776,8 +776,8 @@ void Wallet::onTransactionCommitted(bool success, PendingTransaction *tx, const
|
|||
// Store wallet immediately, so we don't risk losing tx key if wallet crashes
|
||||
this->storeSafer();
|
||||
|
||||
this->history()->refresh(this->currentSubaddressAccount());
|
||||
this->coins()->refresh(this->currentSubaddressAccount());
|
||||
this->history()->refresh();
|
||||
this->coins()->refresh();
|
||||
this->updateBalance();
|
||||
|
||||
if (!success) {
|
||||
|
|
25
src/libwalletqt/rows/AccountRow.cpp
Normal file
25
src/libwalletqt/rows/AccountRow.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "AccountRow.h"
|
||||
#include "WalletManager.h"
|
||||
|
||||
qsizetype AccountRow::getRow() const {
|
||||
return m_row;
|
||||
}
|
||||
|
||||
const QString& AccountRow::getAddress() const {
|
||||
return m_address;
|
||||
}
|
||||
|
||||
const QString& AccountRow::getLabel() const {
|
||||
return m_label;
|
||||
}
|
||||
|
||||
QString AccountRow::getBalance() const {
|
||||
return WalletManager::displayAmount(m_balance);
|
||||
}
|
||||
|
||||
QString AccountRow::getUnlockedBalance() const {
|
||||
return WalletManager::displayAmount(m_unlockedBalance);
|
||||
}
|
36
src/libwalletqt/rows/AccountRow.h
Normal file
36
src/libwalletqt/rows/AccountRow.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#ifndef FEATHER_ACCOUNTROW_H
|
||||
#define FEATHER_ACCOUNTROW_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AccountRow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AccountRow(QObject *parent, qsizetype row, const QString& address, const QString &label, uint64_t balance, uint64_t unlockedBalance)
|
||||
: QObject(parent)
|
||||
, m_row(row)
|
||||
, m_address(address)
|
||||
, m_label(label)
|
||||
, m_balance(balance)
|
||||
, m_unlockedBalance(unlockedBalance) {}
|
||||
|
||||
qsizetype getRow() const;
|
||||
const QString& getAddress() const;
|
||||
const QString& getLabel() const;
|
||||
QString getBalance() const;
|
||||
QString getUnlockedBalance() const;
|
||||
|
||||
private:
|
||||
qsizetype m_row;
|
||||
QString m_address;
|
||||
QString m_label;
|
||||
uint64_t m_balance;
|
||||
uint64_t m_unlockedBalance;
|
||||
};
|
||||
|
||||
#endif //FEATHER_ACCOUNTROW_H
|
|
@ -74,7 +74,15 @@ QString CoinsInfo::address() const {
|
|||
|
||||
QString CoinsInfo::addressLabel() const {
|
||||
if (m_subaddrIndex == 0) {
|
||||
return m_coinbase ? "Coinbase" : "Change";
|
||||
if (m_coinbase) {
|
||||
return "Coinbase";
|
||||
}
|
||||
if (m_change) {
|
||||
return "Change";
|
||||
}
|
||||
if (m_addressLabel == "Primary account") {
|
||||
return "Primary address";
|
||||
}
|
||||
}
|
||||
|
||||
return m_addressLabel;
|
||||
|
@ -108,29 +116,28 @@ QString CoinsInfo::description() const {
|
|||
return m_description;
|
||||
}
|
||||
|
||||
CoinsInfo::CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent)
|
||||
bool CoinsInfo::change() const {
|
||||
return m_change;
|
||||
}
|
||||
|
||||
CoinsInfo::CoinsInfo(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_blockHeight(pimpl->blockHeight())
|
||||
, m_hash(QString::fromStdString(pimpl->hash()))
|
||||
, m_internalOutputIndex(pimpl->internalOutputIndex())
|
||||
, m_globalOutputIndex(pimpl->globalOutputIndex())
|
||||
, m_spent(pimpl->spent())
|
||||
, m_frozen(pimpl->frozen())
|
||||
, m_spentHeight(pimpl->spentHeight())
|
||||
, m_amount(pimpl->amount())
|
||||
, m_rct(pimpl->rct())
|
||||
, m_keyImageKnown(pimpl->keyImageKnown())
|
||||
, m_pkIndex(pimpl->pkIndex())
|
||||
, m_subaddrIndex(pimpl->subaddrIndex())
|
||||
, m_subaddrAccount(pimpl->subaddrAccount())
|
||||
, m_address(QString::fromStdString(pimpl->address()))
|
||||
, m_addressLabel(QString::fromStdString(pimpl->addressLabel()))
|
||||
, m_keyImage(QString::fromStdString(pimpl->keyImage()))
|
||||
, m_unlockTime(pimpl->unlockTime())
|
||||
, m_unlocked(pimpl->unlocked())
|
||||
, m_pubKey(QString::fromStdString(pimpl->pubKey()))
|
||||
, m_coinbase(pimpl->coinbase())
|
||||
, m_description(QString::fromStdString(pimpl->description()))
|
||||
, m_blockHeight(0)
|
||||
, m_internalOutputIndex(0)
|
||||
, m_globalOutputIndex(0)
|
||||
, m_spent(false)
|
||||
, m_frozen(false)
|
||||
, m_spentHeight(0)
|
||||
, m_amount(0)
|
||||
, m_rct(false)
|
||||
, m_keyImageKnown(false)
|
||||
, m_pkIndex(0)
|
||||
, m_subaddrIndex(0)
|
||||
, m_subaddrAccount(0)
|
||||
, m_unlockTime(0)
|
||||
, m_unlocked(false)
|
||||
, m_coinbase(false)
|
||||
, m_change(false)
|
||||
{
|
||||
|
||||
}
|
|
@ -14,28 +14,6 @@ class Coins;
|
|||
class CoinsInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint64 blockHeight READ blockHeight)
|
||||
Q_PROPERTY(QString hash READ hash)
|
||||
Q_PROPERTY(quint64 internalOutputIndex READ internalOutputIndex)
|
||||
Q_PROPERTY(quint64 globalOutputIndex READ globalOutputIndex)
|
||||
Q_PROPERTY(bool spent READ spent)
|
||||
Q_PROPERTY(bool frozen READ frozen)
|
||||
Q_PROPERTY(quint64 spentHeight READ spentHeight)
|
||||
Q_PROPERTY(quint64 amount READ amount)
|
||||
Q_PROPERTY(QString displayAmount READ displayAmount)
|
||||
Q_PROPERTY(bool rct READ rct)
|
||||
Q_PROPERTY(bool keyImageKnown READ keyImageKnown)
|
||||
Q_PROPERTY(quint64 pkIndex READ pkIndex)
|
||||
Q_PROPERTY(quint32 subaddrIndex READ subaddrIndex)
|
||||
Q_PROPERTY(quint32 subaddrAccount READ subaddrAccount)
|
||||
Q_PROPERTY(QString address READ address)
|
||||
Q_PROPERTY(QString addressLabel READ addressLabel)
|
||||
Q_PROPERTY(QString keyImage READ keyImage)
|
||||
Q_PROPERTY(quint64 unlockTime READ unlockTime)
|
||||
Q_PROPERTY(bool unlocked READ unlocked)
|
||||
Q_PROPERTY(QString pubKey READ pubKey)
|
||||
Q_PROPERTY(bool coinbase READ coinbase)
|
||||
Q_PROPERTY(QString description READ description)
|
||||
|
||||
public:
|
||||
quint64 blockHeight() const;
|
||||
|
@ -60,11 +38,13 @@ public:
|
|||
QString pubKey() const;
|
||||
bool coinbase() const;
|
||||
QString description() const;
|
||||
bool change() const;
|
||||
|
||||
void setUnlocked(bool unlocked);
|
||||
|
||||
private:
|
||||
explicit CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent = nullptr);
|
||||
explicit CoinsInfo(QObject *parent);
|
||||
|
||||
private:
|
||||
friend class Coins;
|
||||
|
||||
|
@ -89,6 +69,7 @@ private:
|
|||
QString m_pubKey;
|
||||
bool m_coinbase;
|
||||
QString m_description;
|
||||
bool m_change;
|
||||
};
|
||||
|
||||
#endif //FEATHER_COINSINFO_H
|
16
src/libwalletqt/rows/ContactRow.cpp
Normal file
16
src/libwalletqt/rows/ContactRow.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "ContactRow.h"
|
||||
|
||||
qsizetype ContactRow::getRow() const {
|
||||
return m_row;
|
||||
}
|
||||
|
||||
const QString& ContactRow::getAddress() const {
|
||||
return m_address;
|
||||
}
|
||||
|
||||
const QString& ContactRow::getLabel() const {
|
||||
return m_label;
|
||||
}
|
31
src/libwalletqt/rows/ContactRow.h
Normal file
31
src/libwalletqt/rows/ContactRow.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#ifndef FEATHER_CONTACTROW_H
|
||||
#define FEATHER_CONTACTROW_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class ContactRow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ContactRow(QObject *parent, qsizetype row, const QString& address, const QString &label)
|
||||
: QObject(parent)
|
||||
, m_row(row)
|
||||
, m_address(address)
|
||||
, m_label(label) {}
|
||||
|
||||
qsizetype getRow() const;
|
||||
const QString& getAddress() const;
|
||||
const QString& getLabel() const;
|
||||
|
||||
private:
|
||||
qsizetype m_row;
|
||||
QString m_address;
|
||||
QString m_label;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_CONTACTROW_H
|
183
src/libwalletqt/rows/TransactionRow.cpp
Normal file
183
src/libwalletqt/rows/TransactionRow.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "TransactionRow.h"
|
||||
#include "WalletManager.h"
|
||||
#include "Transfer.h"
|
||||
#include "Ring.h"
|
||||
|
||||
TransactionRow::TransactionRow()
|
||||
: m_direction(TransactionRow::Direction_Out)
|
||||
, m_pending(false)
|
||||
, m_failed(false)
|
||||
, m_coinbase(false)
|
||||
, m_amount(0)
|
||||
, m_fee(0)
|
||||
, m_blockHeight(0)
|
||||
, m_subaddrAccount(0)
|
||||
, m_confirmations(0)
|
||||
, m_unlockTime(0)
|
||||
, m_confirmationsRequired(0)
|
||||
{
|
||||
}
|
||||
|
||||
TransactionRow::Direction TransactionRow::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
bool TransactionRow::isPending() const
|
||||
{
|
||||
return m_pending;
|
||||
}
|
||||
|
||||
bool TransactionRow::isFailed() const
|
||||
{
|
||||
return m_failed;
|
||||
}
|
||||
|
||||
bool TransactionRow::isCoinbase() const
|
||||
{
|
||||
return m_coinbase;
|
||||
}
|
||||
|
||||
quint64 TransactionRow::balanceDelta() const
|
||||
{
|
||||
if (m_direction == Direction_In) {
|
||||
return m_amount;
|
||||
}
|
||||
else if (m_direction == Direction_Out) {
|
||||
return m_amount + m_fee;
|
||||
}
|
||||
return m_amount;
|
||||
}
|
||||
|
||||
double TransactionRow::amount() const
|
||||
{
|
||||
// there's no unsigned uint64 for JS, so better use double
|
||||
return displayAmount().toDouble();
|
||||
}
|
||||
|
||||
quint64 TransactionRow::atomicAmount() const
|
||||
{
|
||||
return m_amount;
|
||||
}
|
||||
|
||||
QString TransactionRow::displayAmount() const
|
||||
{
|
||||
return WalletManager::displayAmount(m_amount);
|
||||
}
|
||||
|
||||
quint64 TransactionRow::atomicFee() const
|
||||
{
|
||||
return m_fee;
|
||||
}
|
||||
|
||||
QString TransactionRow::fee() const
|
||||
{
|
||||
if(m_fee == 0)
|
||||
return "";
|
||||
return WalletManager::displayAmount(m_fee);
|
||||
}
|
||||
|
||||
quint64 TransactionRow::blockHeight() const
|
||||
{
|
||||
return m_blockHeight;
|
||||
}
|
||||
|
||||
QString TransactionRow::description() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
QSet<quint32> TransactionRow::subaddrIndex() const
|
||||
{
|
||||
return m_subaddrIndex;
|
||||
}
|
||||
|
||||
quint32 TransactionRow::subaddrAccount() const
|
||||
{
|
||||
return m_subaddrAccount;
|
||||
}
|
||||
|
||||
QString TransactionRow::label() const
|
||||
{
|
||||
return m_label;
|
||||
}
|
||||
|
||||
quint64 TransactionRow::confirmations() const
|
||||
{
|
||||
return m_confirmations;
|
||||
}
|
||||
|
||||
quint64 TransactionRow::confirmationsRequired() const
|
||||
{
|
||||
return (m_blockHeight < m_unlockTime) ? m_unlockTime - m_blockHeight : 10;
|
||||
}
|
||||
|
||||
quint64 TransactionRow::unlockTime() const
|
||||
{
|
||||
return m_unlockTime;
|
||||
}
|
||||
|
||||
QString TransactionRow::hash() const
|
||||
{
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
QDateTime TransactionRow::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
QString TransactionRow::date() const
|
||||
{
|
||||
return timestamp().date().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionRow::time() const
|
||||
{
|
||||
return timestamp().time().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionRow::paymentId() const
|
||||
{
|
||||
return m_paymentId;
|
||||
}
|
||||
|
||||
QString TransactionRow::destinations_formatted() const
|
||||
{
|
||||
QString destinations;
|
||||
for (auto const& t: m_transfers) {
|
||||
if (!destinations.isEmpty())
|
||||
destinations += "<br> ";
|
||||
destinations += WalletManager::displayAmount(t->amount()) + ": " + t->address();
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
|
||||
QList<QString> TransactionRow::destinations() const
|
||||
{
|
||||
QList<QString> dests;
|
||||
for (auto const& t: m_transfers) {
|
||||
dests.append(t->address());
|
||||
}
|
||||
return dests;
|
||||
}
|
||||
|
||||
QList<Transfer*> TransactionRow::transfers() const {
|
||||
return m_transfers;
|
||||
}
|
||||
|
||||
QString TransactionRow::rings_formatted() const
|
||||
{
|
||||
QString rings;
|
||||
for (auto const& r: m_rings) {
|
||||
rings += r->keyImage() + ": \n";
|
||||
for (uint64_t m : r->ringMembers()){
|
||||
rings += QString::number(m) + " ";
|
||||
}
|
||||
rings += "\n\n";
|
||||
}
|
||||
return rings;
|
||||
}
|
|
@ -1,48 +1,24 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#ifndef TRANSACTIONINFO_H
|
||||
#define TRANSACTIONINFO_H
|
||||
|
||||
#include <wallet/api/wallet2_api.h>
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
#include <QSet>
|
||||
#ifndef FEATHER_TRANSACTIONROW_H
|
||||
#define FEATHER_TRANSACTIONROW_H
|
||||
|
||||
class Transfer;
|
||||
class Ring;
|
||||
|
||||
class TransactionInfo : public QObject
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QDateTime>
|
||||
|
||||
class TransactionRow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(Direction direction READ direction)
|
||||
Q_PROPERTY(bool isPending READ isPending)
|
||||
Q_PROPERTY(bool isFailed READ isFailed)
|
||||
Q_PROPERTY(bool isCoinbase READ isCoinbase)
|
||||
Q_PROPERTY(double amount READ amount)
|
||||
Q_PROPERTY(quint64 atomicAmount READ atomicAmount)
|
||||
Q_PROPERTY(QString displayAmount READ displayAmount)
|
||||
Q_PROPERTY(QString fee READ fee)
|
||||
Q_PROPERTY(quint64 blockHeight READ blockHeight)
|
||||
Q_PROPERTY(QString description READ description)
|
||||
Q_PROPERTY(QSet<quint32> subaddrIndex READ subaddrIndex)
|
||||
Q_PROPERTY(quint32 subaddrAccount READ subaddrAccount)
|
||||
Q_PROPERTY(QString label READ label)
|
||||
Q_PROPERTY(quint64 confirmations READ confirmations)
|
||||
Q_PROPERTY(quint64 confirmationsRequired READ confirmationsRequired)
|
||||
Q_PROPERTY(quint64 unlockTime READ unlockTime)
|
||||
Q_PROPERTY(QString hash READ hash)
|
||||
Q_PROPERTY(QDateTime timestamp READ timestamp)
|
||||
Q_PROPERTY(QString date READ date)
|
||||
Q_PROPERTY(QString time READ time)
|
||||
Q_PROPERTY(QString paymentId READ paymentId)
|
||||
Q_PROPERTY(QString destinations_formatted READ destinations_formatted)
|
||||
Q_PROPERTY(QString rings_formatted READ rings_formatted)
|
||||
|
||||
public:
|
||||
enum Direction {
|
||||
Direction_In = Monero::TransactionInfo::Direction_In,
|
||||
Direction_Out = Monero::TransactionInfo::Direction_Out,
|
||||
Direction_In = 0,
|
||||
Direction_Out = 1,
|
||||
Direction_Both // invalid direction value, used for filtering
|
||||
};
|
||||
|
||||
|
@ -80,7 +56,10 @@ public:
|
|||
QString rings_formatted() const;
|
||||
|
||||
private:
|
||||
explicit TransactionInfo(const Monero::TransactionInfo *pimpl, QObject *parent = nullptr);
|
||||
explicit TransactionRow();
|
||||
|
||||
// TransactionRow(const Monero::TransactionInfo *pimpl, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
friend class TransactionHistory;
|
||||
mutable QList<Transfer*> m_transfers;
|
||||
|
@ -104,4 +83,5 @@ private:
|
|||
bool m_coinbase;
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONINFO_H
|
||||
|
||||
#endif //FEATHER_TRANSACTIONROW_H
|
|
@ -70,12 +70,12 @@ QVariant AddressBookModel::data(const QModelIndex &index, int role) const
|
|||
{
|
||||
QVariant result;
|
||||
|
||||
bool found = m_addressBook->getRow(index.row(), [this, &result, &role, &index](const AddressBookInfo &row) {
|
||||
bool found = m_addressBook->getRow(index.row(), [this, &result, &role, &index](const ContactRow &row) {
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
|
||||
switch (index.column()) {
|
||||
case Address:
|
||||
{
|
||||
QString address = row.address();
|
||||
QString address = row.getAddress();
|
||||
if (!m_showFullAddresses && role != Qt::UserRole) {
|
||||
address = Utils::displayAddress(address);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ QVariant AddressBookModel::data(const QModelIndex &index, int role) const
|
|||
break;
|
||||
}
|
||||
case Description:
|
||||
result = row.description();
|
||||
result = row.getLabel();
|
||||
break;
|
||||
default:
|
||||
qCritical() << "Invalid column" << index.column();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "CoinsModel.h"
|
||||
#include "CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
#include "Coins.h"
|
||||
#include "constants.h"
|
||||
#include "utils/ColorScheme.h"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "CoinsProxyModel.h"
|
||||
#include "CoinsModel.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/rows/CoinsInfo.h"
|
||||
|
||||
CoinsProxyModel::CoinsProxyModel(QObject *parent, Coins *coins)
|
||||
: QSortFilterProxyModel(parent)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "HistoryView.h"
|
||||
|
||||
#include "TransactionHistoryProxyModel.h"
|
||||
#include "libwalletqt/TransactionInfo.h"
|
||||
#include "utils/Utils.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
@ -71,7 +70,7 @@ TransactionHistoryModel* HistoryView::sourceModel()
|
|||
return dynamic_cast<TransactionHistoryModel *>(m_model->sourceModel());
|
||||
}
|
||||
|
||||
TransactionInfo* HistoryView::currentEntry()
|
||||
TransactionRow* HistoryView::currentEntry()
|
||||
{
|
||||
QModelIndexList list = selectionModel()->selectedRows();
|
||||
if (list.size() == 1) {
|
||||
|
@ -199,7 +198,7 @@ void HistoryView::resetViewToDefaults()
|
|||
}
|
||||
|
||||
void HistoryView::keyPressEvent(QKeyEvent *event) {
|
||||
TransactionInfo* tx = this->currentEntry();
|
||||
TransactionRow* tx = this->currentEntry();
|
||||
|
||||
if (event->matches(QKeySequence::Copy) && tx) {
|
||||
Utils::copyToClipboard(tx->hash());
|
||||
|
|
|
@ -18,7 +18,7 @@ class HistoryView : public QTreeView
|
|||
public:
|
||||
explicit HistoryView(QWidget* parent = nullptr);
|
||||
void setHistoryModel(TransactionHistoryProxyModel *model);
|
||||
TransactionInfo* currentEntry();
|
||||
TransactionRow* currentEntry();
|
||||
|
||||
void setSearchMode(bool mode);
|
||||
QByteArray viewState() const;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "utils/Utils.h"
|
||||
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "rows/AccountRow.h"
|
||||
|
||||
SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount)
|
||||
: QAbstractTableModel(parent)
|
||||
|
@ -49,7 +50,7 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const
|
|||
|
||||
QVariant result;
|
||||
|
||||
bool found = m_subaddressAccount->getRow(index.row(), [this, &index, &result, &role](const Monero::SubaddressAccountRow &row) {
|
||||
bool found = m_subaddressAccount->getRow(index.row(), [this, &index, &result, &role](const AccountRow &row) {
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
|
||||
result = parseSubaddressAccountRow(row, index, role);
|
||||
}
|
||||
|
@ -72,7 +73,7 @@ QVariant SubaddressAccountModel::data(const QModelIndex &index, int role) const
|
|||
return result;
|
||||
}
|
||||
|
||||
QVariant SubaddressAccountModel::parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row,
|
||||
QVariant SubaddressAccountModel::parseSubaddressAccountRow(const AccountRow &row,
|
||||
const QModelIndex &index, int role) const
|
||||
{
|
||||
switch (index.column()) {
|
||||
|
@ -82,19 +83,19 @@ QVariant SubaddressAccountModel::parseSubaddressAccountRow(const Monero::Subaddr
|
|||
}
|
||||
return QString("#%1").arg(QString::number(index.row()));
|
||||
case Address:
|
||||
return QString::fromStdString(row.getAddress());
|
||||
return row.getAddress();
|
||||
case Label:
|
||||
return QString::fromStdString(row.getLabel());
|
||||
return row.getLabel();
|
||||
case Balance:
|
||||
if (role == Qt::UserRole) {
|
||||
return WalletManager::amountFromString(QString::fromStdString(row.getBalance()));
|
||||
return WalletManager::amountFromString(row.getBalance());
|
||||
}
|
||||
return QString::fromStdString(row.getBalance());
|
||||
return row.getBalance();
|
||||
case UnlockedBalance:
|
||||
if (role == Qt::UserRole) {
|
||||
return WalletManager::amountFromString(QString::fromStdString(row.getUnlockedBalance()));
|
||||
return WalletManager::amountFromString(row.getUnlockedBalance());
|
||||
}
|
||||
return QString::fromStdString(row.getUnlockedBalance());
|
||||
return row.getUnlockedBalance();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -154,8 +155,7 @@ Qt::ItemFlags SubaddressAccountModel::flags(const QModelIndex &index) const
|
|||
return QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
Monero::SubaddressAccountRow* SubaddressAccountModel::entryFromIndex(const QModelIndex &index) const {
|
||||
Q_ASSERT(index.isValid() && index.row() < m_subaddressAccount->count());
|
||||
AccountRow* SubaddressAccountModel::entryFromIndex(const QModelIndex &index) const {
|
||||
return m_subaddressAccount->row(index.row());
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "rows/AccountRow.h"
|
||||
|
||||
class SubaddressAccount;
|
||||
|
||||
class SubaddressAccountModel : public QAbstractTableModel
|
||||
|
@ -34,14 +36,14 @@ public:
|
|||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
Monero::SubaddressAccountRow* entryFromIndex(const QModelIndex &index) const;
|
||||
AccountRow* entryFromIndex(const QModelIndex &index) const;
|
||||
|
||||
public slots:
|
||||
void startReset();
|
||||
void endReset();
|
||||
|
||||
private:
|
||||
QVariant parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row, const QModelIndex &index, int role) const;
|
||||
QVariant parseSubaddressAccountRow(const AccountRow &row, const QModelIndex &index, int role) const;
|
||||
|
||||
SubaddressAccount *m_subaddressAccount;
|
||||
};
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include "TransactionHistoryModel.h"
|
||||
#include "TransactionHistory.h"
|
||||
#include "TransactionInfo.h"
|
||||
#include "constants.h"
|
||||
#include "utils/config.h"
|
||||
#include "utils/ColorScheme.h"
|
||||
#include "utils/Icons.h"
|
||||
#include "utils/AppData.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "libwalletqt/rows/TransactionRow.h"
|
||||
|
||||
TransactionHistoryModel::TransactionHistoryModel(QObject *parent)
|
||||
: QAbstractTableModel(parent),
|
||||
|
@ -34,7 +34,7 @@ TransactionHistory *TransactionHistoryModel::transactionHistory() const {
|
|||
return m_transactionHistory;
|
||||
}
|
||||
|
||||
TransactionInfo* TransactionHistoryModel::entryFromIndex(const QModelIndex &index) const {
|
||||
TransactionRow* TransactionHistoryModel::entryFromIndex(const QModelIndex &index) const {
|
||||
Q_ASSERT(index.isValid() && index.row() < m_transactionHistory->count());
|
||||
return m_transactionHistory->transaction(index.row());
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
|||
|
||||
QVariant result;
|
||||
|
||||
bool found = m_transactionHistory->transaction(index.row(), [this, &index, &result, &role](const TransactionInfo &tInfo) {
|
||||
bool found = m_transactionHistory->transaction(index.row(), [this, &index, &result, &role](const TransactionRow &tInfo) {
|
||||
if(role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
|
||||
result = parseTransactionInfo(tInfo, index.column(), role);
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
|||
case Column::FiatAmount:
|
||||
case Column::Amount:
|
||||
{
|
||||
if (tInfo.direction() == TransactionInfo::Direction_Out) {
|
||||
if (tInfo.direction() == TransactionRow::Direction_Out) {
|
||||
result = QVariant(QColor("#BC1E1E"));
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
|||
return result;
|
||||
}
|
||||
|
||||
QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tInfo, int column, int role) const
|
||||
QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionRow &tInfo, int column, int role) const
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
|
@ -159,7 +159,7 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
|
|||
return tInfo.balanceDelta();
|
||||
}
|
||||
QString amount = QString::number(tInfo.balanceDelta() / constants::cdiv, 'f', conf()->get(Config::amountPrecision).toInt());
|
||||
amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount;
|
||||
amount = (tInfo.direction() == TransactionRow::Direction_Out) ? "-" + amount : "+" + amount;
|
||||
return amount;
|
||||
}
|
||||
case Column::TxID: {
|
||||
|
@ -227,7 +227,7 @@ bool TransactionHistoryModel::setData(const QModelIndex &index, const QVariant &
|
|||
switch (index.column()) {
|
||||
case Column::Description:
|
||||
{
|
||||
m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionInfo &tInfo){
|
||||
m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionRow &tInfo){
|
||||
hash = tInfo.hash();
|
||||
});
|
||||
m_transactionHistory->setTxNote(hash, value.toString());
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <QIcon>
|
||||
|
||||
class TransactionHistory;
|
||||
class TransactionInfo;
|
||||
class TransactionRow;
|
||||
|
||||
/**
|
||||
* @brief The TransactionHistoryModel class - read-only table model for Transaction History
|
||||
|
@ -33,7 +33,7 @@ public:
|
|||
explicit TransactionHistoryModel(QObject * parent = nullptr);
|
||||
void setTransactionHistory(TransactionHistory * th);
|
||||
TransactionHistory * transactionHistory() const;
|
||||
TransactionInfo* entryFromIndex(const QModelIndex& index) const;
|
||||
TransactionRow* entryFromIndex(const QModelIndex& index) const;
|
||||
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
@ -47,7 +47,7 @@ signals:
|
|||
void transactionHistoryChanged();
|
||||
|
||||
private:
|
||||
QVariant parseTransactionInfo(const TransactionInfo &tInfo, int column, int role) const;
|
||||
QVariant parseTransactionInfo(const TransactionRow &tInfo, int column, int role) const;
|
||||
|
||||
TransactionHistory * m_transactionHistory;
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "TransactionHistoryProxyModel.h"
|
||||
#include "TransactionHistoryModel.h"
|
||||
|
||||
#include "libwalletqt/TransactionInfo.h"
|
||||
#include "libwalletqt/rows/TransactionRow.h"
|
||||
|
||||
TransactionHistoryProxyModel::TransactionHistoryProxyModel(Wallet *wallet, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
|
@ -25,7 +25,7 @@ bool TransactionHistoryProxyModel::filterAcceptsRow(int sourceRow, const QModelI
|
|||
quint32 subaddrAccount;
|
||||
QSet<quint32> subaddrIndex;
|
||||
|
||||
m_history->transaction(sourceRow, [&description, &txid, &subaddrlabel, &subaddrAccount, &subaddrIndex](TransactionInfo &tInfo){
|
||||
m_history->transaction(sourceRow, [&description, &txid, &subaddrlabel, &subaddrAccount, &subaddrIndex](TransactionRow &tInfo){
|
||||
description = tInfo.description();
|
||||
txid = tInfo.hash();
|
||||
subaddrlabel = tInfo.label();
|
||||
|
|
Loading…
Reference in a new issue