for (auto &pubkey : pubkeys) {
m_wallet->coins()->freeze(pubkey);
}
- m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
+ m_wallet->coins()->refresh();
m_wallet->updateBalance();
}
for (auto &pubkey : pubkeys) {
m_wallet->coins()->thaw(pubkey);
}
- m_wallet->coins()->refresh(m_wallet->currentSubaddressAccount());
+ m_wallet->coins()->refresh();
m_wallet->updateBalance();
}
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) {
}
}
- m_wallet->addressBook()->addRow(address, "", name);
+ m_wallet->addressBook()->addRow(address, name);
}
void ContactsWidget::deleteContact()
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);
}
#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"
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();
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();
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++;
}
}
return;
}
- m_wallet->switchSubaddressAccount(row->getRowId());
+ m_wallet->switchSubaddressAccount(row->getRow());
}
void AccountSwitcherDialog::copyLabel() {
return;
}
- Utils::copyToClipboard(QString::fromStdString(row->getLabel()));
+ Utils::copyToClipboard(row->getLabel());
}
void AccountSwitcherDialog::copyBalance() {
return;
}
- Utils::copyToClipboard(QString::fromStdString(row->getBalance()));
+ Utils::copyToClipboard(row->getBalance());
}
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);
}
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);
}
void copyBalance();
void editLabel();
- Monero::SubaddressAccountRow* currentEntry();
+ AccountRow* currentEntry();
QScopedPointer<Ui::AccountSwitcherDialog> ui;
Wallet *m_wallet;
<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>
#include "components.h"
#include "libwalletqt/Coins.h"
-#include "libwalletqt/CoinsInfo.h"
+#include "libwalletqt/rows/CoinsInfo.h"
namespace Ui {
class OutputInfoDialog;
#include <QDialog>
#include "components.h"
-#include "libwalletqt/CoinsInfo.h"
+#include "libwalletqt/rows/CoinsInfo.h"
namespace Ui {
class OutputSweepDialog;
#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)
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);
});
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.");
}
textEdit->verticalScrollBar()->hide();
}
-void TxInfoDialog::setData(TransactionInfo *tx) {
+void TxInfoDialog::setData(TransactionRow *tx) {
QString blockHeight = QString::number(tx->blockHeight());
if (tx->isFailed()) {
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";
}
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);
}
#include <QSvgWidget>
#include "dialog/TxProofDialog.h"
+#include "libwalletqt/rows/TransactionRow.h"
namespace Ui {
class TxInfoDialog;
Q_OBJECT
public:
- explicit TxInfoDialog(Wallet *wallet, TransactionInfo *txInfo, QWidget *parent = nullptr);
+ explicit TxInfoDialog(Wallet *wallet, TransactionRow *txInfo, QWidget *parent = nullptr);
~TxInfoDialog() override;
signals:
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;
};
#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)
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;
}
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;
}
#include <QDialog>
#include "components.h"
-#include "libwalletqt/TransactionInfo.h"
#include "libwalletqt/Wallet.h"
+#include "rows/TransactionRow.h"
namespace Ui {
class TxProofDialog;
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();
QString m_txid;
QString m_txKey;
Mode m_mode;
- TransactionInfo::Direction m_direction;
+ TransactionRow::Direction m_direction;
};
#endif //FEATHER_TXPROOFDIALOG_H
#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);
-
- qDeleteAll(m_rows);
+ clearRows();
- m_addresses.clear();
- m_rows.clear();
+ // 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);
- for (auto &abr: m_addressBookImpl->getAll()) {
- m_addresses.insert(QString::fromStdString(abr->getAddress()), m_rows.size());
+ 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);
- 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;
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());
- }
-
- if (result)
- {
- getAll();
+ 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;
}
- 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;
-
- {
- QWriteLocker locker(&m_lock);
+bool AddressBook::setDescription(int index, const QString &description) {
+ m_errorString = "";
- 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;
-}
-
-quint64 AddressBook::count() const
-{
- QReadLocker locker(&m_lock);
-
- return m_rows.size();
+ bool r = m_wallet2->delete_address_book_row(rowId);
+ if (r)
+ refresh();
+ return r;
}
-QString AddressBook::getDescription(const QString &address) const
+qsizetype AddressBook::count() const
{
- 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();
+ return m_rows.length();
}
-QString AddressBook::getAddress(const QString &description) const
+void AddressBook::clearRows()
{
- 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();
}
\ No newline at end of file
#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;
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
+++ /dev/null
-// 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()))
-{
-
-}
+++ /dev/null
-// 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
// 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();
+
+ 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);
- m_pimpl->refresh();
- for (const auto i : m_pimpl->getAll()) {
- if (i->subaddrAccount() != accountIndex) {
+ 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);
}
}
{
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);
}
}
{
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();
}
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();
}
\ No newline at end of file
#include <QDateTime>
#include <wallet/api/wallet2_api.h>
+#include "Wallet.h"
+#include "wallet/wallet2.h"
+
namespace Monero {
struct TransactionHistory;
}
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;
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
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; }
SubaddressRow* Subaddress::row(int index) const {
return m_rows.value(index);
-};
+}
QString Subaddress::getError() const {
return m_errorString;
-};
\ No newline at end of file
+}
\ No newline at end of file
#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;
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.length();
+}
- return m_rows.size();
+void SubaddressAccount::clearRows()
+{
+ qDeleteAll(m_rows);
+ m_rows.clear();
}
-Monero::SubaddressAccountRow* SubaddressAccount::row(int index) const
+AccountRow* SubaddressAccount::row(int index) const
{
return m_rows.value(index);
}
\ No newline at end of file
#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
// 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)
{
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);
+
+ 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
+ //
- const TransactionInfo *ti = m_tinfo.back();
- // looking for transactions timestamp scope
- if (ti->timestamp() >= lastDateTime) {
- lastDateTime = ti->timestamp();
+ 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);
+ }
+
+ // 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);
}
- 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;
+ 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);
}
- }
- emit refreshFinished();
+ // 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;
+ }
- if (m_firstDateTime != firstDateTime) {
- m_firstDateTime = firstDateTime;
- emit firstDateTimeChanged();
- }
- if (m_lastDateTime != lastDateTime) {
- m_lastDateTime = lastDateTime;
- emit lastDateTimeChanged();
+ 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();
}
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();
}
{
QReadLocker locker(&m_lock);
- return m_tinfo.count();
+ return m_rows.length();
}
QDateTime TransactionHistory::firstDateTime() 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();
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;
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;
}
#include <QReadWriteLock>
#include <QDateTime>
+#include "rows/TransactionRow.h"
+#include "Wallet.h"
+#include "wallet/wallet2.h"
+
namespace Monero {
struct TransactionHistory;
}
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;
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;
+++ /dev/null
-// 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);
- }
-}
{
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:
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);
}
connect(this->history(), &TransactionHistory::txNoteChanged, [this]{
- this->history()->refresh(this->currentSubaddressAccount());
+ this->history()->refresh();
});
connect(this, &Wallet::refreshed, this, &Wallet::onRefreshed);
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();
}
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) {
// 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) {
--- /dev/null
+// 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);
+}
\ No newline at end of file
--- /dev/null
+// 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
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;
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)
{
}
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;
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;
QString m_pubKey;
bool m_coinbase;
QString m_description;
+ bool m_change;
};
#endif //FEATHER_COINSINFO_H
--- /dev/null
+// 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;
+}
\ No newline at end of file
--- /dev/null
+// 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
--- /dev/null
+// 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;
+}
\ No newline at end of file
// 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
};
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;
bool m_coinbase;
};
-#endif // TRANSACTIONINFO_H
+
+#endif //FEATHER_TRANSACTIONROW_H
{
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);
}
break;
}
case Description:
- result = row.description();
+ result = row.getLabel();
break;
default:
qCritical() << "Invalid column" << index.column();
// 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"
#include "CoinsProxyModel.h"
#include "CoinsModel.h"
-#include "libwalletqt/CoinsInfo.h"
+#include "libwalletqt/rows/CoinsInfo.h"
CoinsProxyModel::CoinsProxyModel(QObject *parent, Coins *coins)
: QSortFilterProxyModel(parent)
#include "HistoryView.h"
#include "TransactionHistoryProxyModel.h"
-#include "libwalletqt/TransactionInfo.h"
#include "utils/Utils.h"
#include <QHeaderView>
return dynamic_cast<TransactionHistoryModel *>(m_model->sourceModel());
}
-TransactionInfo* HistoryView::currentEntry()
+TransactionRow* HistoryView::currentEntry()
{
QModelIndexList list = selectionModel()->selectedRows();
if (list.size() == 1) {
}
void HistoryView::keyPressEvent(QKeyEvent *event) {
- TransactionInfo* tx = this->currentEntry();
+ TransactionRow* tx = this->currentEntry();
if (event->matches(QKeySequence::Copy) && tx) {
Utils::copyToClipboard(tx->hash());
public:
explicit HistoryView(QWidget* parent = nullptr);
void setHistoryModel(TransactionHistoryProxyModel *model);
- TransactionInfo* currentEntry();
+ TransactionRow* currentEntry();
void setSearchMode(bool mode);
QByteArray viewState() const;
#include "utils/Utils.h"
#include "libwalletqt/WalletManager.h"
+#include "rows/AccountRow.h"
SubaddressAccountModel::SubaddressAccountModel(QObject *parent, SubaddressAccount *subaddressAccount)
: QAbstractTableModel(parent)
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);
}
return result;
}
-QVariant SubaddressAccountModel::parseSubaddressAccountRow(const Monero::SubaddressAccountRow &row,
+QVariant SubaddressAccountModel::parseSubaddressAccountRow(const AccountRow &row,
const QModelIndex &index, int role) const
{
switch (index.column()) {
}
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();
}
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());
}
#include <QAbstractTableModel>
#include <QSortFilterProxyModel>
+#include "rows/AccountRow.h"
+
class SubaddressAccount;
class SubaddressAccountModel : public QAbstractTableModel
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;
};
#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),
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());
}
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);
}
case Column::FiatAmount:
case Column::Amount:
{
- if (tInfo.direction() == TransactionInfo::Direction_Out) {
+ if (tInfo.direction() == TransactionRow::Direction_Out) {
result = QVariant(QColor("#BC1E1E"));
}
}
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)
{
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: {
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());
#include <QIcon>
class TransactionHistory;
-class TransactionInfo;
+class TransactionRow;
/**
* @brief The TransactionHistoryModel class - read-only table model for Transaction History
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;
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;
};
#include "TransactionHistoryProxyModel.h"
#include "TransactionHistoryModel.h"
-#include "libwalletqt/TransactionInfo.h"
+#include "libwalletqt/rows/TransactionRow.h"
TransactionHistoryProxyModel::TransactionHistoryProxyModel(Wallet *wallet, QObject *parent)
: QSortFilterProxyModel(parent)
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();