mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
289f9ab1d2
![https://i.imgur.com/aZAonV4.png](https://i.imgur.com/aZAonV4.png) New fiat columns in the history table: - Historical price (`balance * historical fiat price`) - Historical rate (the historical fiat price at that date) - Current price (`balance * current fiat price`) ![https://i.imgur.com/QkWCLRf.png](https://i.imgur.com/QkWCLRf.png) When preferred fiat is changed (in the settings), the balance fiat display now follows accordingly. Requires https://git.wownero.com/wowlet/wowlet-backend/pulls/19
257 lines
9.6 KiB
C++
257 lines
9.6 KiB
C++
// SPDX-License-Identifier: BSD-3-Clause
|
|
// Copyright (c) 2014-2021, The Monero Project.
|
|
|
|
#include "TransactionHistoryModel.h"
|
|
#include "TransactionHistory.h"
|
|
#include "TransactionInfo.h"
|
|
#include "globals.h"
|
|
#include "utils/ColorScheme.h"
|
|
|
|
TransactionHistoryModel::TransactionHistoryModel(QObject *parent)
|
|
: QAbstractTableModel(parent),
|
|
m_transactionHistory(nullptr)
|
|
{
|
|
m_unconfirmedTx = QIcon(":/assets/images/unconfirmed.png");
|
|
m_warning = QIcon(":/assets/images/warning.png");
|
|
m_clock1 = QIcon(":/assets/images/clock1.png");
|
|
m_clock2 = QIcon(":/assets/images/clock2.png");
|
|
m_clock3 = QIcon(":/assets/images/clock3.png");
|
|
m_clock4 = QIcon(":/assets/images/clock4.png");
|
|
m_clock5 = QIcon(":/assets/images/clock5.png");
|
|
m_confirmedTx = QIcon(":/assets/images/confirmed.png");
|
|
}
|
|
|
|
void TransactionHistoryModel::setTransactionHistory(TransactionHistory *th) {
|
|
beginResetModel();
|
|
m_transactionHistory = th;
|
|
endResetModel();
|
|
|
|
connect(m_transactionHistory, &TransactionHistory::refreshStarted,
|
|
this, &TransactionHistoryModel::beginResetModel);
|
|
connect(m_transactionHistory, &TransactionHistory::refreshFinished,
|
|
this, &TransactionHistoryModel::endResetModel);
|
|
|
|
emit transactionHistoryChanged();
|
|
}
|
|
|
|
TransactionHistory *TransactionHistoryModel::transactionHistory() const {
|
|
return m_transactionHistory;
|
|
}
|
|
|
|
int TransactionHistoryModel::rowCount(const QModelIndex &parent) const {
|
|
if (parent.isValid()) {
|
|
return 0;
|
|
} else {
|
|
return m_transactionHistory ? m_transactionHistory->count() : 0;
|
|
}
|
|
}
|
|
|
|
int TransactionHistoryModel::columnCount(const QModelIndex &parent) const {
|
|
if (parent.isValid()) {
|
|
return 0;
|
|
}
|
|
|
|
// When wowlet is in QtWidgets mode, it will only use the first 5 columns,
|
|
// the rest should be hidden, because it shows in the GUI. So by default we'll
|
|
// use 6 as column count. When in QtQuick (QML) mode, we want to expose more columns
|
|
// so we can change the column count here.
|
|
|
|
return AppContext::isQML ? this->COUNT : 7;
|
|
}
|
|
|
|
QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const {
|
|
if (!m_transactionHistory) {
|
|
return QVariant();
|
|
}
|
|
|
|
if (!index.isValid() || index.row() < 0 || static_cast<quint64>(index.row()) >= m_transactionHistory->count())
|
|
return QVariant();
|
|
|
|
QVariant result;
|
|
|
|
bool found = m_transactionHistory->transaction(index.row(), [this, &index, &result, &role](const TransactionInfo &tInfo) {
|
|
if(role == Qt::DisplayRole || role == Qt::EditRole) {
|
|
result = parseTransactionInfo(tInfo, index.column());
|
|
}
|
|
else if (role == Qt::TextAlignmentRole) {
|
|
switch (index.column()) {
|
|
case TransactionInfoRole::Amount:
|
|
case TransactionInfoRole::HistoricalPrice:
|
|
case TransactionInfoRole::HistoricalRate:
|
|
case TransactionInfoRole::CurrentPrice:
|
|
result = Qt::AlignRight;
|
|
}
|
|
}
|
|
else if (role == Qt::DecorationRole) {
|
|
switch (index.column()) {
|
|
case TransactionInfoRole::Date:
|
|
{
|
|
if (tInfo.isFailed())
|
|
result = QVariant(m_warning);
|
|
else if (tInfo.isPending())
|
|
result = QVariant(m_unconfirmedTx);
|
|
else if (tInfo.confirmations() <= (1.0/5.0 * tInfo.confirmationsRequired()))
|
|
result = QVariant(m_clock1);
|
|
else if (tInfo.confirmations() <= (2.0/5.0 * tInfo.confirmationsRequired()))
|
|
result = QVariant(m_clock2);
|
|
else if (tInfo.confirmations() <= (3.0/5.0 * tInfo.confirmationsRequired()))
|
|
result = QVariant(m_clock3);
|
|
else if (tInfo.confirmations() <= (4.0/5.0 * tInfo.confirmationsRequired()))
|
|
result = QVariant(m_clock4);
|
|
else if (tInfo.confirmations() < tInfo.confirmationsRequired())
|
|
result = QVariant(m_clock5);
|
|
else if (tInfo.confirmations())
|
|
result = QVariant(m_confirmedTx);
|
|
}
|
|
}
|
|
}
|
|
else if (role == Qt::ToolTipRole) {
|
|
switch(index.column()) {
|
|
case TransactionInfoRole::Date:
|
|
{
|
|
if (tInfo.isFailed())
|
|
result = "Transaction failed";
|
|
else if (tInfo.confirmations() < tInfo.confirmationsRequired())
|
|
result = QString("%1/%2 confirmations").arg(QString::number(tInfo.confirmations()), QString::number(tInfo.confirmationsRequired()));
|
|
else
|
|
result = QString("%1 confirmations").arg(QString::number(tInfo.confirmations()));
|
|
}
|
|
}
|
|
}
|
|
else if (role == Qt::ForegroundRole) {
|
|
switch(index.column()) {
|
|
case TransactionInfoRole::Amount:
|
|
{
|
|
if (tInfo.direction() == TransactionInfo::Direction_Out) {
|
|
result = QVariant(QColor("#BC1E1E"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!found) {
|
|
qCritical("%s: internal error: no transaction info for index %d", __FUNCTION__, index.row());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tInfo, int column) const
|
|
{
|
|
switch (column)
|
|
{
|
|
case TransactionInfoRole::TransactionFailedRole:
|
|
return tInfo.isFailed();
|
|
case TransactionInfoRole::TransactionPendingRole:
|
|
return tInfo.isPending();
|
|
case TransactionInfoRole::TransactionConfirmationsRole:
|
|
return tInfo.confirmations();
|
|
case TransactionInfoRole::TransactionConfirmationsRequiredRole:
|
|
return tInfo.confirmationsRequired();
|
|
case TransactionInfoRole::Date:
|
|
return tInfo.timestamp().toString("yyyy-MM-dd HH:mm");
|
|
case TransactionInfoRole::TransactionIsOutRole:
|
|
return tInfo.direction() == TransactionInfo::Direction_Out;
|
|
case TransactionInfoRole::Description: {
|
|
// if this tx is still in the pool, then we wont get the
|
|
// description. We've cached it inside `AppContext::txDescriptionCache`
|
|
// for the time being.
|
|
if(tInfo.isPending()) {
|
|
auto hash = tInfo.hash();
|
|
if (AppContext::txDescriptionCache.contains(hash))
|
|
return AppContext::txDescriptionCache[hash];
|
|
}
|
|
return tInfo.description();
|
|
}
|
|
case TransactionInfoRole::Amount:
|
|
{
|
|
QString amount = QString::number(tInfo.balanceDelta() / globals::cdiv, 'f', 4);
|
|
amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount;
|
|
return amount;
|
|
}
|
|
case TransactionInfoRole::TxID:
|
|
return tInfo.hash();
|
|
case TransactionInfoRole::HistoricalRate: {
|
|
return tInfo.historicalRateStr();
|
|
}
|
|
case TransactionInfoRole::HistoricalPrice:
|
|
{
|
|
return tInfo.historicalPriceStr();
|
|
}
|
|
case TransactionInfoRole::CurrentPrice:
|
|
{
|
|
return tInfo.currentPriceStr();
|
|
}
|
|
default:
|
|
{
|
|
qCritical() << "Unimplemented role";
|
|
return QVariant();
|
|
}
|
|
}
|
|
}
|
|
|
|
QVariant TransactionHistoryModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
|
Q_UNUSED(orientation)
|
|
if (role != Qt::DisplayRole) {
|
|
return QVariant();
|
|
}
|
|
if (orientation == Qt::Horizontal) {
|
|
switch(section) {
|
|
case TransactionInfoRole::Date:
|
|
return QString("Date");
|
|
case TransactionInfoRole::Description:
|
|
return QString("Description");
|
|
case TransactionInfoRole::Amount:
|
|
return QString("Amount");
|
|
case TransactionInfoRole::TxID:
|
|
return QString("Txid");
|
|
case TransactionInfoRole::HistoricalPrice:
|
|
return QString("Historical price");
|
|
case TransactionInfoRole::HistoricalRate:
|
|
return QString("Historical rate");
|
|
case TransactionInfoRole::CurrentPrice:
|
|
return QString("Current price");
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
bool TransactionHistoryModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
|
if (index.isValid() && role == Qt::EditRole) {
|
|
QString hash;
|
|
|
|
switch (index.column()) {
|
|
case TransactionInfoRole::Description:
|
|
{
|
|
m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionInfo &tInfo){
|
|
hash = tInfo.hash();
|
|
});
|
|
m_transactionHistory->setTxNote(hash, value.toString());
|
|
break;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Qt::ItemFlags TransactionHistoryModel::flags(const QModelIndex &index) const {
|
|
bool isPending;
|
|
m_transactionHistory->transaction(index.row(), [this, &isPending](const TransactionInfo &tInfo){
|
|
isPending = tInfo.isPending();
|
|
});
|
|
|
|
if (!index.isValid())
|
|
return Qt::ItemIsEnabled;
|
|
|
|
if (index.column() == Description && !isPending)
|
|
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
|
|
|
|
return QAbstractTableModel::flags(index);
|
|
}
|