Browse Source

split user entered fields object from invoice uri parsing object

master
Sander van Grieken 4 years ago
parent
commit
12d726efc2
  1. 9
      electrum/gui/qml/components/ConfirmTxDialog.qml
  2. 58
      electrum/gui/qml/components/Send.qml
  3. 4
      electrum/gui/qml/qeapp.py
  4. 153
      electrum/gui/qml/qeinvoice.py

9
electrum/gui/qml/components/ConfirmTxDialog.qml

@ -17,6 +17,9 @@ Dialog {
property alias amountLabelText: amountLabel.text property alias amountLabelText: amountLabel.text
property alias sendButtonText: sendButton.text property alias sendButtonText: sendButton.text
signal txcancelled
signal txaccepted
title: qsTr('Confirm Transaction') title: qsTr('Confirm Transaction')
// copy these to finalizer // copy these to finalizer
@ -206,7 +209,10 @@ Dialog {
Button { Button {
text: qsTr('Cancel') text: qsTr('Cancel')
onClicked: dialog.close() onClicked: {
txcancelled()
dialog.close()
}
} }
Button { Button {
@ -214,6 +220,7 @@ Dialog {
text: qsTr('Pay') text: qsTr('Pay')
enabled: finalizer.valid enabled: finalizer.valid
onClicked: { onClicked: {
txaccepted()
finalizer.send_onchain() finalizer.send_onchain()
dialog.close() dialog.close()
} }

58
electrum/gui/qml/components/Send.qml

@ -15,6 +15,7 @@ Pane {
recipient.text = '' recipient.text = ''
amount.text = '' amount.text = ''
message.text = '' message.text = ''
is_max.checked = false
} }
GridLayout { GridLayout {
@ -44,8 +45,9 @@ Pane {
wrapMode: Text.Wrap wrapMode: Text.Wrap
placeholderText: qsTr('Paste address or invoice') placeholderText: qsTr('Paste address or invoice')
onTextChanged: { onTextChanged: {
if (activeFocus) //if (activeFocus)
invoice.recipient = text //userEnteredPayment.recipient = text
userEnteredPayment.recipient = recipient.text
} }
} }
@ -79,7 +81,7 @@ Pane {
fiatfield: amountFiat fiatfield: amountFiat
Layout.preferredWidth: parent.width /3 Layout.preferredWidth: parent.width /3
onTextChanged: { 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 id: is_max
text: qsTr('Max') text: qsTr('Max')
onCheckedChanged: { 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.columnSpan: 2
Layout.fillWidth: true Layout.fillWidth: true
onTextChanged: { 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 { Button {
text: qsTr('Save') text: qsTr('Save')
enabled: invoice.canSave enabled: userEnteredPayment.canSave
icon.source: '../../icons/save.png' icon.source: '../../icons/save.png'
onClicked: { onClicked: {
invoice.save_invoice() userEnteredPayment.save_invoice()
invoice.clear() userEnteredPayment.clear()
rootItem.clear() rootItem.clear()
} }
} }
Button { Button {
text: qsTr('Pay now') text: qsTr('Pay now')
enabled: invoice.canPay enabled: userEnteredPayment.canPay
icon.source: '../../icons/confirmed.png' icon.source: '../../icons/confirmed.png'
onClicked: { onClicked: {
invoice.save_invoice()
var dialog = confirmPaymentDialog.createObject(app, { var dialog = confirmPaymentDialog.createObject(app, {
'address': recipient.text, 'address': recipient.text,
'satoshis': Config.unitsToSats(amount.text), 'satoshis': is_max.checked ? MAX : Config.unitsToSats(amount.text),
'message': message.text 'message': message.text
}) })
dialog.txaccepted.connect(function() {
userEnteredPayment.clear()
rootItem.clear()
})
dialog.open() dialog.open()
invoice.clear()
rootItem.clear()
} }
} }
@ -293,6 +296,26 @@ Pane {
FocusScope { id: parkFocus } 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 { Invoice {
id: invoice id: invoice
wallet: Daemon.currentWallet wallet: Daemon.currentWallet
@ -314,11 +337,12 @@ Pane {
} }
} }
onValidationSuccess: { onValidationSuccess: {
// address only -> fill form fields // address only -> fill form fields and clear this instance
// else -> show invoice confirmation dialog // else -> show invoice confirmation dialog
if (invoiceType == Invoice.OnchainOnlyAddress) if (invoiceType == Invoice.OnchainOnlyAddress) {
recipient.text = invoice.recipient recipient.text = invoice.recipient
else { invoice.clear()
} else {
var dialog = invoiceDialog.createObject(rootItem, {'invoice': invoice}) var dialog = invoiceDialog.createObject(rootItem, {'invoice': invoice})
dialog.open() dialog.open()
} }
@ -326,8 +350,8 @@ Pane {
onInvoiceCreateError: console.log(code + ' ' + message) onInvoiceCreateError: console.log(code + ' ' + message)
onInvoiceSaved: { onInvoiceSaved: {
console.log('invoice got saved')
Daemon.currentWallet.invoiceModel.init_model() Daemon.currentWallet.invoiceModel.init_model()
} }
} }
} }

4
electrum/gui/qml/qeapp.py

@ -19,7 +19,7 @@ from .qewalletdb import QEWalletDB
from .qebitcoin import QEBitcoin from .qebitcoin import QEBitcoin
from .qefx import QEFX from .qefx import QEFX
from .qetxfinalizer import QETxFinalizer from .qetxfinalizer import QETxFinalizer
from .qeinvoice import QEInvoice from .qeinvoice import QEInvoice, QEUserEnteredPayment
from .qetypes import QEAmount from .qetypes import QEAmount
from .qeaddressdetails import QEAddressDetails from .qeaddressdetails import QEAddressDetails
from .qetxdetails import QETxDetails from .qetxdetails import QETxDetails
@ -146,6 +146,8 @@ class ElectrumQmlApplication(QGuiApplication):
qmlRegisterType(QEFX, 'org.electrum', 1, 0, 'FX') qmlRegisterType(QEFX, 'org.electrum', 1, 0, 'FX')
qmlRegisterType(QETxFinalizer, 'org.electrum', 1, 0, 'TxFinalizer') qmlRegisterType(QETxFinalizer, 'org.electrum', 1, 0, 'TxFinalizer')
qmlRegisterType(QEInvoice, 'org.electrum', 1, 0, 'Invoice') qmlRegisterType(QEInvoice, 'org.electrum', 1, 0, 'Invoice')
qmlRegisterType(QEUserEnteredPayment, 'org.electrum', 1, 0, 'UserEnteredPayment')
qmlRegisterType(QEAddressDetails, 'org.electrum', 1, 0, 'AddressDetails') qmlRegisterType(QEAddressDetails, 'org.electrum', 1, 0, 'AddressDetails')
qmlRegisterType(QETxDetails, 'org.electrum', 1, 0, 'TxDetails') qmlRegisterType(QETxDetails, 'org.electrum', 1, 0, 'TxDetails')
qmlRegisterType(QEChannelOpener, 'org.electrum', 1, 0, 'ChannelOpener') qmlRegisterType(QEChannelOpener, 'org.electrum', 1, 0, 'ChannelOpener')

153
electrum/gui/qml/qeinvoice.py

@ -305,33 +305,154 @@ class QEInvoice(QObject):
self._wallet.wallet.save_invoice(self._effectiveInvoice) self._wallet.wallet.save_invoice(self._effectiveInvoice)
self.invoiceSaved.emit() 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
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()
if not address: keyChanged = pyqtSignal()
self.invoiceCreateError.emit('fatal', _('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request')) @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 return
if not bitcoin.is_address(address): if not bitcoin.is_address(self._recipient):
self.invoiceCreateError.emit('fatal', _('Invalid Bitcoin address')) self.validationError.emit('recipient', _('Invalid Bitcoin address'))
return return
if amount.isEmpty: if self._amount.isEmpty:
self.invoiceCreateError.emit('fatal', _('Invalid amount')) self.validationError.emit('amount', _('Invalid amount'))
return 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: try:
outputs = [PartialTxOutput.from_address_and_value(address, inv_amt)] outputs = [PartialTxOutput.from_address_and_value(self._recipient, inv_amt)]
invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=message, pr=None, URI=None) self._logger.debug(repr(outputs))
invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=self._message, pr=None, URI=None)
except InvoiceError as e: except InvoiceError as e:
self.invoiceCreateError.emit('fatal', _('Error creating payment') + ':\n' + str(e)) self.invoiceCreateError.emit('fatal', _('Error creating payment') + ':\n' + str(e))
return 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

Loading…
Cancel
Save