Merge pull request #135

111248f Make the new sweep functions use async transactions (moneromooo.monero)
c779b37 Support for sweeping all outputs (moneromooo.monero)
2143392 Add a button to sweep unmixable outputs (moneromooo.monero)
This commit is contained in:
Riccardo Spagni 2016-11-13 11:33:32 +02:00
commit 2fed96d048
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD
5 changed files with 181 additions and 28 deletions

View File

@ -52,6 +52,7 @@ Rectangle {
signal paymentClicked(string address, string paymentId, string amount, int mixinCount, int priority, string description) signal paymentClicked(string address, string paymentId, string amount, int mixinCount, int priority, string description)
signal sweepUnmixableClicked()
signal generatePaymentIdInvoked() signal generatePaymentIdInvoked()
signal checkPaymentClicked(string address, string txid, string txkey); signal checkPaymentClicked(string address, string txid, string txkey);
@ -308,5 +309,9 @@ Rectangle {
console.log("MiddlePanel: paymentClicked") console.log("MiddlePanel: paymentClicked")
paymentClicked(address, paymentId, amount, mixinCount, priority, description) paymentClicked(address, paymentId, amount, mixinCount, priority, description)
} }
onSweepUnmixableClicked : {
console.log("MiddlePanel: sweepUnmixableClicked")
sweepUnmixableClicked()
}
} }
} }

105
main.qml
View File

@ -157,6 +157,7 @@ ApplicationWindow {
middlePanel.checkPaymentClicked.disconnect(handleCheckPayment); middlePanel.checkPaymentClicked.disconnect(handleCheckPayment);
} }
middlePanel.paymentClicked.connect(handlePayment); middlePanel.paymentClicked.connect(handlePayment);
middlePanel.sweepUnmixableClicked.connect(handleSweepUnmixable);
// basicPanel.paymentClicked.connect(handlePayment); // basicPanel.paymentClicked.connect(handlePayment);
middlePanel.checkPaymentClicked.connect(handleCheckPayment); middlePanel.checkPaymentClicked.connect(handleCheckPayment);
@ -385,6 +386,14 @@ ApplicationWindow {
// deleting transaction object, we don't want memleaks // deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction); currentWallet.disposeTransaction(transaction);
} else if (transaction.txCount == 0) {
informationPopup.title = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open()
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else { } else {
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount) console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
+ ", fee: " + walletManager.displayAmount(transaction.fee)); + ", fee: " + walletManager.displayAmount(transaction.fee));
@ -393,13 +402,13 @@ ApplicationWindow {
transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString
transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n") transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n")
+ qsTr("\nAddress: ") + address + (address === "" ? "" : (qsTr("\nAddress: ") + address))
+ qsTr("\nPayment ID: ") + paymentId + (paymentId === "" ? "" : (qsTr("\nPayment ID: ") + paymentId))
+ qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount) + qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount)
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee) + qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee)
+ qsTr("\n\nMixin: ") + mixinCount + qsTr("\n\nMixin: ") + mixinCount
+ qsTr("\n\Number of transactions: ") + transaction.txCount + qsTr("\n\Number of transactions: ") + transaction.txCount
+ qsTr("\n\nDescription: ") + transactionDescription + (transactionDescription === "" ? "" : (qsTr("\n\nDescription: ") + transactionDescription))
+ translationManager.emptyString + translationManager.emptyString
transactionConfirmationPopup.icon = StandardIcon.Question transactionConfirmationPopup.icon = StandardIcon.Question
transactionConfirmationPopup.open() transactionConfirmationPopup.open()
@ -422,33 +431,77 @@ ApplicationWindow {
transactionDescription = description; transactionDescription = description;
// validate amount; // validate amount;
var amountxmr = walletManager.amountFromString(amount); if (amount !== "(all)") {
console.log("integer amount: ", amountxmr); var amountxmr = walletManager.amountFromString(amount);
console.log("integer unlocked",currentWallet.unlockedBalance) console.log("integer amount: ", amountxmr);
if (amountxmr <= 0) { console.log("integer unlocked",currentWallet.unlockedBalance)
informationPopup.title = qsTr("Error") + translationManager.emptyString; if (amountxmr <= 0) {
informationPopup.text = qsTr("Amount is wrong: expected number from %1 to %2") informationPopup.title = qsTr("Error") + translationManager.emptyString;
.arg(walletManager.displayAmount(0)) informationPopup.text = qsTr("Amount is wrong: expected number from %1 to %2")
.arg(walletManager.maximumAllowedAmountAsSting()) .arg(walletManager.displayAmount(0))
+ translationManager.emptyString .arg(walletManager.maximumAllowedAmountAsSting())
+ translationManager.emptyString
informationPopup.icon = StandardIcon.Critical informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null informationPopup.onCloseCallback = null
informationPopup.open() informationPopup.open()
return; return;
} else if (amountxmr > currentWallet.unlockedBalance) { } else if (amountxmr > currentWallet.unlockedBalance) {
informationPopup.title = qsTr("Error") + translationManager.emptyString; informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("insufficient funds. Unlocked balance: %1") informationPopup.text = qsTr("insufficient funds. Unlocked balance: %1")
.arg(walletManager.displayAmount(currentWallet.unlockedBalance)) .arg(walletManager.displayAmount(currentWallet.unlockedBalance))
+ translationManager.emptyString + translationManager.emptyString
informationPopup.icon = StandardIcon.Critical informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null informationPopup.onCloseCallback = null
informationPopup.open() informationPopup.open()
return; return;
}
} }
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority); if (amount === "(all)")
currentWallet.createTransactionAllAsync(address, paymentId, amountxmr, mixinCount, priority);
else
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
}
function handleSweepUnmixable() {
console.log("Creating transaction: ")
transaction = currentWallet.createSweepUnmixableTransaction();
if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't create transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else if (transaction.txCount == 0) {
informationPopup.title = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open()
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else {
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
+ ", fee: " + walletManager.displayAmount(transaction.fee));
// here we show confirmation popup;
transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString
transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n")
+ qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount)
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee)
+ translationManager.emptyString
transactionConfirmationPopup.icon = StandardIcon.Question
transactionConfirmationPopup.open()
// committing transaction
}
} }
// called after user confirms transaction // called after user confirms transaction

View File

@ -35,6 +35,7 @@ Rectangle {
id: root id: root
signal paymentClicked(string address, string paymentId, string amount, int mixinCount, signal paymentClicked(string address, string paymentId, string amount, int mixinCount,
int priority, string description) int priority, string description)
signal sweepUnmixableClicked()
color: "#F0EEEE" color: "#F0EEEE"
@ -88,7 +89,7 @@ Rectangle {
LineEdit { LineEdit {
id: amountLine id: amountLine
placeholderText: qsTr("") + translationManager.emptyString placeholderText: qsTr("") + translationManager.emptyString
width: parent.width - 37 - 17 width: parent.width - 37 - 17 - 60
validator: DoubleValidator { validator: DoubleValidator {
bottom: 0.0 bottom: 0.0
top: 18446744.073709551615 top: 18446744.073709551615
@ -97,6 +98,21 @@ Rectangle {
locale: "C" locale: "C"
} }
} }
StandardButton {
id: amountAllButton
//anchors.left: amountLine.right
//anchors.top: amountLine.top
//anchors.bottom: amountLine.bottom
width: 60
text: qsTr("or ALL") + translationManager.emptyString
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C"
pressedColor: "#FF4304"
enabled : true
onClicked: amountLine.text = "(all)"
}
} }
ListModel { ListModel {
@ -295,4 +311,24 @@ Rectangle {
} }
} }
StandardButton {
id: sweepUnmixableButton
anchors.right: parent.right
anchors.top: descriptionLine.bottom
anchors.rightMargin: 17
anchors.topMargin: 17
width: 60*2
text: qsTr("SWEEP UNMIXABLE") + translationManager.emptyString
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#FF6C3C"
pressedColor: "#FF4304"
enabled : true
onClicked: {
console.log("Transfer: sweepUnmixableClicked")
root.sweepUnmixableClicked()
}
}
} }

View File

@ -216,7 +216,6 @@ PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QSt
return result; return result;
} }
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)
@ -233,7 +232,51 @@ void Wallet::createTransactionAsync(const QString &dst_addr, const QString &paym
}); });
} }
PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count, PendingTransaction::Priority priority)
{
Bitmonero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
dst_addr.toStdString(), payment_id.toStdString(), Bitmonero::optional<uint64_t>(), mixin_count,
static_cast<Bitmonero::PendingTransaction::Priority>(priority));
PendingTransaction * result = new PendingTransaction(ptImpl, this);
return result;
}
void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count,
PendingTransaction::Priority priority)
{
QFuture<PendingTransaction*> future = QtConcurrent::run(this, &Wallet::createTransactionAll,
dst_addr, payment_id, mixin_count, priority);
QFutureWatcher<PendingTransaction*> * watcher = new QFutureWatcher<PendingTransaction*>();
watcher->setFuture(future);
connect(watcher, &QFutureWatcher<PendingTransaction*>::finished,
this, [this, watcher,dst_addr,payment_id,mixin_count]() {
QFuture<PendingTransaction*> future = watcher->future();
watcher->deleteLater();
emit transactionCreated(future.result(),dst_addr,payment_id,mixin_count);
});
}
PendingTransaction *Wallet::createSweepUnmixableTransaction()
{
Bitmonero::PendingTransaction * ptImpl = m_walletImpl->createSweepUnmixableTransaction();
PendingTransaction * result = new PendingTransaction(ptImpl, this);
return result;
}
void Wallet::createSweepUnmixableTransactionAsync()
{
QFuture<PendingTransaction*> future = QtConcurrent::run(this, &Wallet::createSweepUnmixableTransaction);
QFutureWatcher<PendingTransaction*> * watcher = new QFutureWatcher<PendingTransaction*>();
watcher->setFuture(future);
connect(watcher, &QFutureWatcher<PendingTransaction*>::finished,
this, [this, watcher]() {
QFuture<PendingTransaction*> future = watcher->future();
watcher->deleteLater();
emit transactionCreated(future.result(),"","",0);
});
}
void Wallet::disposeTransaction(PendingTransaction *t) void Wallet::disposeTransaction(PendingTransaction *t)
{ {

View File

@ -126,10 +126,26 @@ public:
Q_INVOKABLE PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id, Q_INVOKABLE 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);
//! creates async transaction //! creates async transaction
Q_INVOKABLE void createTransactionAsync(const QString &dst_addr, const QString &payment_id, Q_INVOKABLE 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);
//! creates transaction with all outputs
Q_INVOKABLE PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count, PendingTransaction::Priority priority);
//! creates async transaction with all outputs
Q_INVOKABLE void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
quint32 mixin_count, PendingTransaction::Priority priority);
//! creates sweep unmixable transaction
Q_INVOKABLE PendingTransaction * createSweepUnmixableTransaction();
//! creates async sweep unmixable transaction
Q_INVOKABLE void createSweepUnmixableTransactionAsync();
//! deletes transaction and frees memory //! deletes transaction and frees memory
Q_INVOKABLE void disposeTransaction(PendingTransaction * t); Q_INVOKABLE void disposeTransaction(PendingTransaction * t);