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