mirror of
https://github.com/feather-wallet/feather.git
synced 2025-01-09 12:29:44 +00:00
Coins: manual input selection
This commit is contained in:
parent
b8db796479
commit
3eb6d28221
13 changed files with 195 additions and 35 deletions
|
@ -46,12 +46,14 @@ CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
|||
m_freezeAllSelectedAction = new QAction("Freeze selected", this);
|
||||
m_thawAllSelectedAction = new QAction("Thaw selected", this);
|
||||
|
||||
m_spendAction = new QAction("Spend", this);
|
||||
m_viewOutputAction = new QAction("Details", this);
|
||||
m_sweepOutputAction = new QAction("Sweep output", this);
|
||||
m_sweepOutputsAction = new QAction("Sweep selected outputs", this);
|
||||
|
||||
connect(m_freezeOutputAction, &QAction::triggered, this, &CoinsWidget::freezeAllSelected);
|
||||
connect(m_thawOutputAction, &QAction::triggered, this, &CoinsWidget::thawAllSelected);
|
||||
connect(m_spendAction, &QAction::triggered, this, &CoinsWidget::spendSelected);
|
||||
connect(m_viewOutputAction, &QAction::triggered, this, &CoinsWidget::viewOutput);
|
||||
connect(m_sweepOutputAction, &QAction::triggered, this, &CoinsWidget::onSweepOutputs);
|
||||
connect(m_sweepOutputsAction, &QAction::triggered, this, &CoinsWidget::onSweepOutputs);
|
||||
|
@ -68,6 +70,8 @@ CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
|
|||
});
|
||||
|
||||
connect(ui->search, &QLineEdit::textChanged, this, &CoinsWidget::setSearchFilter);
|
||||
|
||||
connect(m_ctx.get(), &AppContext::selectedInputsChanged, this, &CoinsWidget::selectCoins);
|
||||
}
|
||||
|
||||
void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
|
||||
|
@ -106,6 +110,7 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
|
|||
|
||||
auto *menu = new QMenu(ui->coins);
|
||||
if (list.size() > 1) {
|
||||
menu->addAction(m_spendAction);
|
||||
menu->addAction(m_freezeAllSelectedAction);
|
||||
menu->addAction(m_thawAllSelectedAction);
|
||||
menu->addAction(m_sweepOutputsAction);
|
||||
|
@ -118,6 +123,7 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
|
|||
bool isFrozen = c->frozen();
|
||||
bool isUnlocked = c->unlocked();
|
||||
|
||||
menu->addAction(m_spendAction);
|
||||
menu->addMenu(m_copyMenu);
|
||||
menu->addAction(m_editLabelAction);
|
||||
|
||||
|
@ -174,6 +180,18 @@ void CoinsWidget::thawAllSelected() {
|
|||
this->thawCoins(pubkeys);
|
||||
}
|
||||
|
||||
void CoinsWidget::spendSelected() {
|
||||
QModelIndexList list = ui->coins->selectionModel()->selectedRows();
|
||||
|
||||
QStringList keyimages;
|
||||
for (QModelIndex index: list) {
|
||||
keyimages << m_model->entryFromIndex(m_proxyModel->mapToSource(index))->keyImage();
|
||||
}
|
||||
|
||||
m_ctx->setSelectedInputs(keyimages);
|
||||
this->selectCoins(keyimages);
|
||||
}
|
||||
|
||||
void CoinsWidget::viewOutput() {
|
||||
CoinsInfo* c = this->currentEntry();
|
||||
if (!c) return;
|
||||
|
@ -294,6 +312,11 @@ void CoinsWidget::thawCoins(QStringList &pubkeys) {
|
|||
m_ctx->updateBalance();
|
||||
}
|
||||
|
||||
void CoinsWidget::selectCoins(const QStringList &keyimages) {
|
||||
m_model->setSelected(keyimages);
|
||||
ui->coins->clearSelection();
|
||||
}
|
||||
|
||||
void CoinsWidget::editLabel() {
|
||||
QModelIndex index = ui->coins->currentIndex().siblingAtColumn(m_model->ModelColumn::Label);
|
||||
ui->coins->setCurrentIndex(index);
|
||||
|
|
|
@ -26,6 +26,11 @@ public:
|
|||
void setModel(CoinsModel * model, Coins * coins);
|
||||
~CoinsWidget() override;
|
||||
|
||||
void setSpendSelected(const QStringList &pubkeys);
|
||||
|
||||
signals:
|
||||
void spendSelectedChanged(const QStringList &pubkeys);
|
||||
|
||||
public slots:
|
||||
void setSearchbarVisible(bool visible);
|
||||
void focusSearchbar();
|
||||
|
@ -35,6 +40,7 @@ private slots:
|
|||
void setShowSpent(bool show);
|
||||
void freezeAllSelected();
|
||||
void thawAllSelected();
|
||||
void spendSelected();
|
||||
void viewOutput();
|
||||
void onSweepOutputs();
|
||||
void setSearchFilter(const QString &filter);
|
||||
|
@ -43,6 +49,7 @@ private slots:
|
|||
private:
|
||||
void freezeCoins(QStringList &pubkeys);
|
||||
void thawCoins(QStringList &pubkeys);
|
||||
void selectCoins(const QStringList &pubkeys);
|
||||
|
||||
enum copyField {
|
||||
PubKey = 0,
|
||||
|
@ -60,6 +67,7 @@ private:
|
|||
QMenu *m_contextMenu;
|
||||
QMenu *m_headerMenu;
|
||||
QMenu *m_copyMenu;
|
||||
QAction *m_spendAction;
|
||||
QAction *m_showSpentAction;
|
||||
QAction *m_freezeOutputAction;
|
||||
QAction *m_freezeAllSelectedAction;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "dialog/WalletCacheDebugDialog.h"
|
||||
#include "dialog/UpdateDialog.h"
|
||||
#include "libwalletqt/AddressBook.h"
|
||||
#include "libwalletqt/CoinsInfo.h"
|
||||
#include "libwalletqt/Transfer.h"
|
||||
#include "utils/AppData.h"
|
||||
#include "utils/AsyncTask.h"
|
||||
|
@ -217,6 +218,11 @@ void MainWindow::initWidgets() {
|
|||
#if defined(Q_OS_MACOS)
|
||||
ui->line->hide();
|
||||
#endif
|
||||
|
||||
ui->frame_coinControl->setVisible(false);
|
||||
connect(ui->btn_resetCoinControl, &QPushButton::clicked, [this]{
|
||||
m_ctx->setSelectedInputs({});
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::initMenu() {
|
||||
|
@ -384,6 +390,7 @@ void MainWindow::initWalletContext() {
|
|||
connect(m_ctx.get(), &AppContext::endTransaction, this, &MainWindow::onEndTransaction);
|
||||
connect(m_ctx.get(), &AppContext::customRestoreHeightSet, this, &MainWindow::onCustomRestoreHeightSet);
|
||||
connect(m_ctx.get(), &AppContext::keysCorrupted, this, &MainWindow::onKeysCorrupted);
|
||||
connect(m_ctx.get(), &AppContext::selectedInputsChanged, this, &MainWindow::onSelectedInputsChanged);
|
||||
|
||||
// Nodes
|
||||
connect(m_ctx->nodes, &Nodes::nodeExhausted, this, &MainWindow::showNodeExhaustedMessage);
|
||||
|
@ -1446,6 +1453,24 @@ void MainWindow::onKeysCorrupted() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::onSelectedInputsChanged(const QStringList &selectedInputs) {
|
||||
int numInputs = selectedInputs.size();
|
||||
|
||||
ui->frame_coinControl->setStyleSheet(ColorScheme::GREEN.asStylesheet(true));
|
||||
ui->frame_coinControl->setVisible(numInputs > 0);
|
||||
|
||||
if (numInputs > 0) {
|
||||
quint64 totalAmount = 0;
|
||||
auto coins = m_ctx->wallet->coins()->coinsFromKeyImage(selectedInputs);
|
||||
for (const auto coin : coins) {
|
||||
totalAmount += coin->amount();
|
||||
}
|
||||
|
||||
QString text = QString("Coin control active: %1 selected outputs, %2 XMR").arg(QString::number(numInputs), WalletManager::displayAmount(totalAmount));
|
||||
ui->label_coinControl->setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onExportHistoryCSV(bool checked) {
|
||||
if (m_ctx->wallet == nullptr)
|
||||
return;
|
||||
|
|
|
@ -140,6 +140,7 @@ private slots:
|
|||
void onEndTransaction();
|
||||
void onCustomRestoreHeightSet(int height);
|
||||
void onKeysCorrupted();
|
||||
void onSelectedInputsChanged(const QStringList &selectedInputs);
|
||||
|
||||
// libwalletqt
|
||||
void onBalanceUpdated(quint64 balance, quint64 spendable);
|
||||
|
|
|
@ -343,6 +343,47 @@
|
|||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QFrame" name="frame_coinControl">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_coinControl">
|
||||
<property name="text">
|
||||
<string>Coin control active: </string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_resetCoinControl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
|
|
|
@ -82,9 +82,9 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
|
|||
|
||||
qInfo() << "Creating transaction";
|
||||
if (all)
|
||||
this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority);
|
||||
this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority, m_selectedInputs);
|
||||
else
|
||||
this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority);
|
||||
this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority, m_selectedInputs);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses,
|
|||
}
|
||||
|
||||
qInfo() << "Creating transaction";
|
||||
this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
|
||||
this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority, m_selectedInputs);
|
||||
|
||||
emit initiateTransaction();
|
||||
}
|
||||
|
@ -131,6 +131,9 @@ void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QStri
|
|||
}
|
||||
|
||||
void AppContext::commitTransaction(PendingTransaction *tx, const QString &description) {
|
||||
// Clear list of selected transfers
|
||||
this->setSelectedInputs({});
|
||||
|
||||
// Nodes - even well-connected, properly configured ones - consistently fail to relay transactions
|
||||
// To mitigate transactions failing we just send the transaction to every node we know about over Tor
|
||||
if (config()->get(Config::multiBroadcast).toBool()) {
|
||||
|
@ -180,6 +183,11 @@ void AppContext::onDeviceError(const QString &message) {
|
|||
|
||||
// ################## Misc ##################
|
||||
|
||||
void AppContext::setSelectedInputs(const QStringList &selectedInputs) {
|
||||
m_selectedInputs = selectedInputs;
|
||||
emit selectedInputsChanged(selectedInputs);
|
||||
}
|
||||
|
||||
void AppContext::onTorSettingsChanged() {
|
||||
if (Utils::isTorsocks()) {
|
||||
return;
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
void addCacheTransaction(const QString &txid, const QString &txHex) const;
|
||||
QString getCacheTransaction(const QString &txid) const;
|
||||
|
||||
void setSelectedInputs(const QStringList &selectedInputs);
|
||||
|
||||
public slots:
|
||||
void onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all);
|
||||
void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
|
||||
|
@ -93,10 +95,12 @@ signals:
|
|||
void deviceButtonPressed();
|
||||
void deviceError(const QString &message);
|
||||
void keysCorrupted();
|
||||
void selectedInputsChanged(const QStringList &selectedInputs);
|
||||
|
||||
private:
|
||||
DaemonRpc *m_rpc;
|
||||
QTimer m_storeTimer;
|
||||
QStringList m_selectedInputs;
|
||||
};
|
||||
|
||||
#endif //FEATHER_APPCONTEXT_H
|
||||
|
|
|
@ -96,6 +96,19 @@ QVector<CoinsInfo*> Coins::coins_from_txid(const QString &txid)
|
|||
return coins;
|
||||
}
|
||||
|
||||
QVector<CoinsInfo*> Coins::coinsFromKeyImage(const QStringList &keyimages) {
|
||||
QVector<CoinsInfo*> coins;
|
||||
|
||||
for (int i = 0; i < this->count(); i++) {
|
||||
CoinsInfo* coin = this->coin(i);
|
||||
if (coin->keyImageKnown() && keyimages.contains(coin->keyImage())) {
|
||||
coins.append(coin);
|
||||
}
|
||||
}
|
||||
|
||||
return coins;
|
||||
}
|
||||
|
||||
void Coins::setDescription(const QString &publicKey, quint32 accountIndex, const QString &description)
|
||||
{
|
||||
m_pimpl->setDescription(publicKey.toStdString(), description.toStdString());
|
||||
|
|
|
@ -21,17 +21,17 @@ class CoinsInfo;
|
|||
class Coins : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE bool coin(int index, std::function<void (CoinsInfo &)> callback);
|
||||
Q_INVOKABLE CoinsInfo * coin(int index);
|
||||
Q_INVOKABLE void refresh(quint32 accountIndex);
|
||||
Q_INVOKABLE void refreshUnlocked();
|
||||
Q_INVOKABLE void freeze(QString &publicKey) const;
|
||||
Q_INVOKABLE void thaw(QString &publicKey) const;
|
||||
Q_INVOKABLE QVector<CoinsInfo*> coins_from_txid(const QString &txid);
|
||||
Q_INVOKABLE void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description);
|
||||
bool coin(int index, std::function<void (CoinsInfo &)> callback);
|
||||
CoinsInfo * coin(int index);
|
||||
void refresh(quint32 accountIndex);
|
||||
void refreshUnlocked();
|
||||
void freeze(QString &publicKey) const;
|
||||
void thaw(QString &publicKey) const;
|
||||
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;
|
||||
|
||||
|
|
|
@ -609,14 +609,18 @@ void Wallet::pauseRefresh()
|
|||
|
||||
PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs)
|
||||
{
|
||||
// pauseRefresh();
|
||||
std::set<std::string> preferred_inputs;
|
||||
for (const auto &input : preferredInputs) {
|
||||
preferred_inputs.insert(input.toStdString());
|
||||
}
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
|
||||
dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, nullptr);
|
||||
|
||||
// startRefresh();
|
||||
|
@ -625,17 +629,17 @@ PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QSt
|
|||
|
||||
void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs)
|
||||
{
|
||||
m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] {
|
||||
PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority);
|
||||
m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority, preferredInputs] {
|
||||
PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority, preferredInputs);
|
||||
QVector<QString> address {dst_addr};
|
||||
emit transactionCreated(tx, address);
|
||||
});
|
||||
}
|
||||
|
||||
PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs)
|
||||
{
|
||||
// pauseRefresh();
|
||||
|
||||
|
@ -649,8 +653,14 @@ PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &d
|
|||
amounts.push_back(a);
|
||||
}
|
||||
|
||||
std::set<std::string> preferred_inputs;
|
||||
for (const auto &input : preferredInputs) {
|
||||
preferred_inputs.insert(input.toStdString());
|
||||
}
|
||||
|
||||
// TODO: remove mixin count
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority));
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl);
|
||||
|
||||
// startRefresh();
|
||||
|
@ -658,10 +668,10 @@ PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &d
|
|||
}
|
||||
|
||||
void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs)
|
||||
{
|
||||
m_scheduler.run([this, dst_addr, amount, priority] {
|
||||
PendingTransaction *tx = createTransactionMultiDest(dst_addr, amount, priority);
|
||||
m_scheduler.run([this, dst_addr, amount, priority, preferredInputs] {
|
||||
PendingTransaction *tx = createTransactionMultiDest(dst_addr, amount, priority, preferredInputs);
|
||||
QVector<QString> addresses;
|
||||
for (auto &addr : dst_addr) {
|
||||
addresses.push_back(addr);
|
||||
|
@ -671,14 +681,20 @@ void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, c
|
|||
}
|
||||
|
||||
PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority)
|
||||
quint32 mixin_count, PendingTransaction::Priority priority,
|
||||
const QStringList &preferredInputs)
|
||||
{
|
||||
// pauseRefresh();
|
||||
|
||||
std::set<std::string> preferred_inputs;
|
||||
for (const auto &input : preferredInputs) {
|
||||
preferred_inputs.insert(input.toStdString());
|
||||
}
|
||||
|
||||
std::set<uint32_t> subaddr_indices;
|
||||
Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
|
||||
dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count,
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
|
||||
static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
|
||||
PendingTransaction * result = new PendingTransaction(ptImpl, this);
|
||||
|
||||
// startRefresh();
|
||||
|
@ -687,10 +703,10 @@ PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const
|
|||
|
||||
void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count,
|
||||
PendingTransaction::Priority priority)
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs)
|
||||
{
|
||||
m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] {
|
||||
PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority);
|
||||
m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority, preferredInputs] {
|
||||
PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority, preferredInputs);
|
||||
QVector<QString> address {dst_addr};
|
||||
emit transactionCreated(tx, address);
|
||||
});
|
||||
|
|
|
@ -272,29 +272,32 @@ public:
|
|||
//! creates transaction
|
||||
PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
PendingTransaction::Priority priority,
|
||||
const QStringList &preferredInputs);
|
||||
|
||||
//! creates async transaction
|
||||
void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint64 amount, quint32 mixin_count,
|
||||
PendingTransaction::Priority priority);
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs);
|
||||
|
||||
//! creates multi-destination transaction
|
||||
PendingTransaction * createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority);
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs);
|
||||
|
||||
//! creates async multi-destination transaction
|
||||
void createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
|
||||
PendingTransaction::Priority priority);
|
||||
PendingTransaction::Priority priority, const QStringList &preferredInputs);
|
||||
|
||||
|
||||
//! creates transaction with all outputs
|
||||
PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority);
|
||||
quint32 mixin_count, PendingTransaction::Priority priority,
|
||||
const QStringList &preferredInputs);
|
||||
|
||||
//! creates async transaction with all outputs
|
||||
void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
|
||||
quint32 mixin_count, PendingTransaction::Priority priority);
|
||||
quint32 mixin_count, PendingTransaction::Priority priority,
|
||||
const QStringList &preferredInputs);
|
||||
|
||||
//! creates transaction with single input
|
||||
PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr,
|
||||
|
|
|
@ -61,6 +61,8 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
|
|||
QVariant result;
|
||||
|
||||
bool found = m_coins->coin(index.row(), [this, &index, &result, &role](const CoinsInfo &cInfo) {
|
||||
bool selected = cInfo.keyImageKnown() && m_selected.contains(cInfo.keyImage());
|
||||
|
||||
if(role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
|
||||
result = parseTransactionInfo(cInfo, index.column(), role);
|
||||
}
|
||||
|
@ -74,6 +76,9 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
|
|||
else if (!cInfo.unlocked()) {
|
||||
result = QBrush(ColorScheme::YELLOW.asColor(true));
|
||||
}
|
||||
else if (selected) {
|
||||
result = QBrush(ColorScheme::GREEN.asColor(true));
|
||||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole) {
|
||||
switch (index.column()) {
|
||||
|
@ -122,6 +127,9 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
|
|||
else if (cInfo.spent()) {
|
||||
result = "Output is spent";
|
||||
}
|
||||
else if (selected) {
|
||||
result = "Coin selected to be spent";
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!found) {
|
||||
|
@ -247,6 +255,14 @@ void CoinsModel::setCurrentSubaddressAccount(quint32 accountIndex) {
|
|||
m_currentSubaddressAccount = accountIndex;
|
||||
}
|
||||
|
||||
void CoinsModel::setSelected(const QStringList &keyimages) {
|
||||
m_selected.clear();
|
||||
for (const auto &ki : keyimages) {
|
||||
m_selected.insert(ki);
|
||||
}
|
||||
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
|
||||
}
|
||||
|
||||
CoinsInfo* CoinsModel::entryFromIndex(const QModelIndex &index) const {
|
||||
Q_ASSERT(index.isValid() && index.row() < m_coins->count());
|
||||
return m_coins->coin(index.row());
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
CoinsInfo* entryFromIndex(const QModelIndex &index) const;
|
||||
|
||||
void setCurrentSubaddressAccount(quint32 accountIndex);
|
||||
void setSelected(const QStringList &selected);
|
||||
|
||||
signals:
|
||||
void descriptionChanged();
|
||||
|
@ -61,6 +62,7 @@ private:
|
|||
|
||||
Coins *m_coins;
|
||||
quint32 m_currentSubaddressAccount;
|
||||
QSet<QString> m_selected;
|
||||
};
|
||||
|
||||
#endif //FEATHER_COINSMODEL_H
|
||||
|
|
Loading…
Reference in a new issue