split user entered fields object from invoice uri parsing object
This commit is contained in:
@@ -17,6 +17,9 @@ Dialog {
|
||||
property alias amountLabelText: amountLabel.text
|
||||
property alias sendButtonText: sendButton.text
|
||||
|
||||
signal txcancelled
|
||||
signal txaccepted
|
||||
|
||||
title: qsTr('Confirm Transaction')
|
||||
|
||||
// copy these to finalizer
|
||||
@@ -206,7 +209,10 @@ Dialog {
|
||||
|
||||
Button {
|
||||
text: qsTr('Cancel')
|
||||
onClicked: dialog.close()
|
||||
onClicked: {
|
||||
txcancelled()
|
||||
dialog.close()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
@@ -214,6 +220,7 @@ Dialog {
|
||||
text: qsTr('Pay')
|
||||
enabled: finalizer.valid
|
||||
onClicked: {
|
||||
txaccepted()
|
||||
finalizer.send_onchain()
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ Pane {
|
||||
recipient.text = ''
|
||||
amount.text = ''
|
||||
message.text = ''
|
||||
is_max.checked = false
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
@@ -44,8 +45,9 @@ Pane {
|
||||
wrapMode: Text.Wrap
|
||||
placeholderText: qsTr('Paste address or invoice')
|
||||
onTextChanged: {
|
||||
if (activeFocus)
|
||||
invoice.recipient = text
|
||||
//if (activeFocus)
|
||||
//userEnteredPayment.recipient = text
|
||||
userEnteredPayment.recipient = recipient.text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +81,7 @@ Pane {
|
||||
fiatfield: amountFiat
|
||||
Layout.preferredWidth: parent.width /3
|
||||
onTextChanged: {
|
||||
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
|
||||
userEnteredPayment.amount = is_max.checked ? MAX : Config.unitsToSats(amount.text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ Pane {
|
||||
id: is_max
|
||||
text: qsTr('Max')
|
||||
onCheckedChanged: {
|
||||
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
|
||||
userEnteredPayment.amount = is_max.checked ? MAX : Config.unitsToSats(amount.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,7 +127,7 @@ Pane {
|
||||
Layout.columnSpan: 2
|
||||
Layout.fillWidth: true
|
||||
onTextChanged: {
|
||||
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
|
||||
userEnteredPayment.message = message.text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,29 +138,30 @@ Pane {
|
||||
|
||||
Button {
|
||||
text: qsTr('Save')
|
||||
enabled: invoice.canSave
|
||||
enabled: userEnteredPayment.canSave
|
||||
icon.source: '../../icons/save.png'
|
||||
onClicked: {
|
||||
invoice.save_invoice()
|
||||
invoice.clear()
|
||||
userEnteredPayment.save_invoice()
|
||||
userEnteredPayment.clear()
|
||||
rootItem.clear()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr('Pay now')
|
||||
enabled: invoice.canPay
|
||||
enabled: userEnteredPayment.canPay
|
||||
icon.source: '../../icons/confirmed.png'
|
||||
onClicked: {
|
||||
invoice.save_invoice()
|
||||
var dialog = confirmPaymentDialog.createObject(app, {
|
||||
'address': recipient.text,
|
||||
'satoshis': Config.unitsToSats(amount.text),
|
||||
'satoshis': is_max.checked ? MAX : Config.unitsToSats(amount.text),
|
||||
'message': message.text
|
||||
})
|
||||
dialog.txaccepted.connect(function() {
|
||||
userEnteredPayment.clear()
|
||||
rootItem.clear()
|
||||
})
|
||||
dialog.open()
|
||||
invoice.clear()
|
||||
rootItem.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,6 +296,26 @@ Pane {
|
||||
FocusScope { id: parkFocus }
|
||||
}
|
||||
|
||||
|
||||
UserEnteredPayment {
|
||||
id: userEnteredPayment
|
||||
wallet: Daemon.currentWallet
|
||||
|
||||
//onValidationError: {
|
||||
//if (recipient.activeFocus) {
|
||||
//// no popups when editing
|
||||
//return
|
||||
//}
|
||||
//var dialog = app.messageDialog.createObject(app, {'text': message })
|
||||
//dialog.open()
|
||||
//// rootItem.clear()
|
||||
//}
|
||||
|
||||
onInvoiceSaved: {
|
||||
Daemon.currentWallet.invoiceModel.init_model()
|
||||
}
|
||||
}
|
||||
|
||||
Invoice {
|
||||
id: invoice
|
||||
wallet: Daemon.currentWallet
|
||||
@@ -314,11 +337,12 @@ Pane {
|
||||
}
|
||||
}
|
||||
onValidationSuccess: {
|
||||
// address only -> fill form fields
|
||||
// address only -> fill form fields and clear this instance
|
||||
// else -> show invoice confirmation dialog
|
||||
if (invoiceType == Invoice.OnchainOnlyAddress)
|
||||
if (invoiceType == Invoice.OnchainOnlyAddress) {
|
||||
recipient.text = invoice.recipient
|
||||
else {
|
||||
invoice.clear()
|
||||
} else {
|
||||
var dialog = invoiceDialog.createObject(rootItem, {'invoice': invoice})
|
||||
dialog.open()
|
||||
}
|
||||
@@ -326,8 +350,8 @@ Pane {
|
||||
onInvoiceCreateError: console.log(code + ' ' + message)
|
||||
|
||||
onInvoiceSaved: {
|
||||
console.log('invoice got saved')
|
||||
Daemon.currentWallet.invoiceModel.init_model()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ from .qewalletdb import QEWalletDB
|
||||
from .qebitcoin import QEBitcoin
|
||||
from .qefx import QEFX
|
||||
from .qetxfinalizer import QETxFinalizer
|
||||
from .qeinvoice import QEInvoice
|
||||
from .qeinvoice import QEInvoice, QEUserEnteredPayment
|
||||
from .qetypes import QEAmount
|
||||
from .qeaddressdetails import QEAddressDetails
|
||||
from .qetxdetails import QETxDetails
|
||||
@@ -146,6 +146,8 @@ class ElectrumQmlApplication(QGuiApplication):
|
||||
qmlRegisterType(QEFX, 'org.electrum', 1, 0, 'FX')
|
||||
qmlRegisterType(QETxFinalizer, 'org.electrum', 1, 0, 'TxFinalizer')
|
||||
qmlRegisterType(QEInvoice, 'org.electrum', 1, 0, 'Invoice')
|
||||
qmlRegisterType(QEUserEnteredPayment, 'org.electrum', 1, 0, 'UserEnteredPayment')
|
||||
|
||||
qmlRegisterType(QEAddressDetails, 'org.electrum', 1, 0, 'AddressDetails')
|
||||
qmlRegisterType(QETxDetails, 'org.electrum', 1, 0, 'TxDetails')
|
||||
qmlRegisterType(QEChannelOpener, 'org.electrum', 1, 0, 'ChannelOpener')
|
||||
|
||||
@@ -305,33 +305,154 @@ class QEInvoice(QObject):
|
||||
self._wallet.wallet.save_invoice(self._effectiveInvoice)
|
||||
self.invoiceSaved.emit()
|
||||
|
||||
@pyqtSlot(str, QEAmount, str)
|
||||
def create_invoice(self, address: str, amount: QEAmount, message: str):
|
||||
# create invoice from user entered fields
|
||||
# (any other type of invoice is created from parsing recipient)
|
||||
self._logger.debug('creating invoice to %s, amount=%s, message=%s' % (address, repr(amount), message))
|
||||
|
||||
self.clear()
|
||||
class QEUserEnteredPayment(QObject):
|
||||
_logger = get_logger(__name__)
|
||||
_wallet = None
|
||||
_recipient = None
|
||||
_message = None
|
||||
_amount = QEAmount()
|
||||
_key = None
|
||||
_canSave = False
|
||||
_canPay = False
|
||||
|
||||
if not address:
|
||||
self.invoiceCreateError.emit('fatal', _('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request'))
|
||||
validationError = pyqtSignal([str,str], arguments=['code','message'])
|
||||
invoiceCreateError = pyqtSignal([str,str], arguments=['code', 'message'])
|
||||
invoiceSaved = pyqtSignal()
|
||||
|
||||
walletChanged = pyqtSignal()
|
||||
@pyqtProperty(QEWallet, notify=walletChanged)
|
||||
def wallet(self):
|
||||
return self._wallet
|
||||
|
||||
@wallet.setter
|
||||
def wallet(self, wallet: QEWallet):
|
||||
if self._wallet != wallet:
|
||||
self._wallet = wallet
|
||||
self.walletChanged.emit()
|
||||
|
||||
recipientChanged = pyqtSignal()
|
||||
@pyqtProperty(str, notify=recipientChanged)
|
||||
def recipient(self):
|
||||
return self._recipient
|
||||
|
||||
@recipient.setter
|
||||
def recipient(self, recipient: str):
|
||||
if self._recipient != recipient:
|
||||
self._recipient = recipient
|
||||
self.validate()
|
||||
self.recipientChanged.emit()
|
||||
|
||||
messageChanged = pyqtSignal()
|
||||
@pyqtProperty(str, notify=messageChanged)
|
||||
def message(self):
|
||||
return self._message
|
||||
|
||||
@message.setter
|
||||
def message(self, message):
|
||||
if self._message != message:
|
||||
self._message = message
|
||||
self.messageChanged.emit()
|
||||
|
||||
amountChanged = pyqtSignal()
|
||||
@pyqtProperty(QEAmount, notify=amountChanged)
|
||||
def amount(self):
|
||||
return self._amount
|
||||
|
||||
@amount.setter
|
||||
def amount(self, amount):
|
||||
if self._amount != amount:
|
||||
self._amount = amount
|
||||
self.validate()
|
||||
self.amountChanged.emit()
|
||||
|
||||
canSaveChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=canSaveChanged)
|
||||
def canSave(self):
|
||||
return self._canSave
|
||||
|
||||
@canSave.setter
|
||||
def canSave(self, canSave):
|
||||
if self._canSave != canSave:
|
||||
self._canSave = canSave
|
||||
self.canSaveChanged.emit()
|
||||
|
||||
canPayChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=canPayChanged)
|
||||
def canPay(self):
|
||||
return self._canPay
|
||||
|
||||
@canPay.setter
|
||||
def canPay(self, canPay):
|
||||
if self._canPay != canPay:
|
||||
self._canPay = canPay
|
||||
self.canPayChanged.emit()
|
||||
|
||||
keyChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=keyChanged)
|
||||
def key(self):
|
||||
return self._key
|
||||
|
||||
@key.setter
|
||||
def key(self, key):
|
||||
if self._key != key:
|
||||
self._key = key
|
||||
self.keyChanged.emit()
|
||||
|
||||
def validate(self):
|
||||
self.canPay = False
|
||||
self.canSave = False
|
||||
self._logger.debug('validate')
|
||||
|
||||
if not self._recipient:
|
||||
self.validationError.emit('recipient', _('Recipient not specified.'))
|
||||
return
|
||||
|
||||
if not bitcoin.is_address(address):
|
||||
self.invoiceCreateError.emit('fatal', _('Invalid Bitcoin address'))
|
||||
if not bitcoin.is_address(self._recipient):
|
||||
self.validationError.emit('recipient', _('Invalid Bitcoin address'))
|
||||
return
|
||||
|
||||
if amount.isEmpty:
|
||||
self.invoiceCreateError.emit('fatal', _('Invalid amount'))
|
||||
if self._amount.isEmpty:
|
||||
self.validationError.emit('amount', _('Invalid amount'))
|
||||
return
|
||||
|
||||
inv_amt = '!' if amount.isMax else (amount.satsInt * 1000) # FIXME msat precision from UI?
|
||||
if self._amount.isMax:
|
||||
self.canPay = True
|
||||
else:
|
||||
self.canSave = True
|
||||
if self.get_max_spendable() >= self._amount.satsInt:
|
||||
self.canPay = True
|
||||
|
||||
def get_max_spendable(self):
|
||||
c, u, x = self._wallet.wallet.get_balance()
|
||||
#TODO determine real max
|
||||
return c
|
||||
|
||||
@pyqtSlot()
|
||||
def save_invoice(self):
|
||||
assert self.canSave
|
||||
assert not self._amount.isMax
|
||||
|
||||
self._logger.debug('saving invoice to %s, amount=%s, message=%s' % (self._recipient, repr(self._amount), self._message))
|
||||
|
||||
inv_amt = self._amount.satsInt
|
||||
|
||||
try:
|
||||
outputs = [PartialTxOutput.from_address_and_value(address, inv_amt)]
|
||||
invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=message, pr=None, URI=None)
|
||||
outputs = [PartialTxOutput.from_address_and_value(self._recipient, inv_amt)]
|
||||
self._logger.debug(repr(outputs))
|
||||
invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=self._message, pr=None, URI=None)
|
||||
except InvoiceError as e:
|
||||
self.invoiceCreateError.emit('fatal', _('Error creating payment') + ':\n' + str(e))
|
||||
return
|
||||
|
||||
self.set_effective_invoice(invoice)
|
||||
self.key = self._wallet.wallet.get_key_for_outgoing_invoice(invoice)
|
||||
self._wallet.wallet.save_invoice(invoice)
|
||||
self.invoiceSaved.emit()
|
||||
|
||||
@pyqtSlot()
|
||||
def clear(self):
|
||||
self._recipient = None
|
||||
self._amount = QEAmount()
|
||||
self._message = None
|
||||
self.canSave = False
|
||||
self.canPay = False
|
||||
|
||||
Reference in New Issue
Block a user