Browse Source

initial create invoice from user input

patch-4
Sander van Grieken 3 years ago
parent
commit
f6a46f3900
  1. 4
      electrum/gui/qml/components/OpenChannel.qml
  2. 78
      electrum/gui/qml/components/Send.qml
  3. 65
      electrum/gui/qml/qeinvoice.py

4
electrum/gui/qml/components/OpenChannel.qml

@ -84,7 +84,7 @@ Pane {
BtcField {
id: amount
fiatfield: amountFiat
Layout.preferredWidth: parent.width /2
Layout.preferredWidth: parent.width /3
onTextChanged: channelopener.amount = Config.unitsToSats(amount.text)
enabled: !is_max.checked
}
@ -111,7 +111,7 @@ Pane {
id: amountFiat
btcfield: amount
visible: Daemon.fx.enabled
Layout.preferredWidth: parent.width /2
Layout.preferredWidth: parent.width /3
enabled: !is_max.checked
}

78
electrum/gui/qml/components/Send.qml

@ -14,6 +14,7 @@ Pane {
function clear() {
recipient.text = ''
amount.text = ''
message.text = ''
}
GridLayout {
@ -21,10 +22,10 @@ Pane {
width: parent.width
rowSpacing: constants.paddingSmall
columnSpacing: constants.paddingSmall
columns: 4
columns: 3
BalanceSummary {
Layout.columnSpan: 4
Layout.columnSpan: 3
Layout.alignment: Qt.AlignHCenter
}
@ -32,20 +33,22 @@ Pane {
text: qsTr('Recipient')
}
TextArea {
id: recipient
Layout.columnSpan: 2
RowLayout {
Layout.fillWidth: true
font.family: FixedFont
wrapMode: Text.Wrap
placeholderText: qsTr('Paste address or invoice')
onTextChanged: {
if (activeFocus)
invoice.recipient = text
Layout.columnSpan: 2
TextArea {
id: recipient
Layout.fillWidth: true
font.family: FixedFont
wrapMode: Text.Wrap
placeholderText: qsTr('Paste address or invoice')
onTextChanged: {
if (activeFocus)
invoice.recipient = text
}
}
}
RowLayout {
spacing: 0
ToolButton {
icon.source: '../../icons/paste.png'
@ -75,15 +78,26 @@ Pane {
id: amount
fiatfield: amountFiat
Layout.preferredWidth: parent.width /3
onTextChanged: {
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
}
}
Label {
text: Config.baseUnit
color: Material.accentColor
RowLayout {
Layout.fillWidth: true
}
Item { width: 1; height: 1 }
Label {
text: Config.baseUnit
color: Material.accentColor
}
Switch {
id: is_max
text: qsTr('Max')
onCheckedChanged: {
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
}
}
}
Item { width: 1; height: 1; visible: Daemon.fx.enabled }
@ -95,54 +109,56 @@ Pane {
}
Label {
Layout.fillWidth: true
visible: Daemon.fx.enabled
text: Daemon.fx.fiatCurrency
color: Material.accentColor
Layout.fillWidth: true
}
Item { visible: Daemon.fx.enabled ; height: 1; width: 1 }
Label {
text: qsTr('Description')
}
TextField {
id: message
font.family: FixedFont
placeholderText: qsTr('Message')
Layout.columnSpan: 3
Layout.columnSpan: 2
Layout.fillWidth: true
onTextChanged: {
invoice.create_invoice(recipient.text, is_max.checked ? MAX : Config.unitsToSats(amount.text), message.text)
}
}
RowLayout {
Layout.columnSpan: 4
Layout.columnSpan: 3
Layout.alignment: Qt.AlignHCenter
spacing: constants.paddingMedium
Button {
text: qsTr('Save')
enabled: invoice.invoiceType != Invoice.Invalid
enabled: invoice.canSave
icon.source: '../../icons/save.png'
onClicked: {
Daemon.currentWallet.create_invoice(recipient.text, amount.text, message.text)
invoice.save_invoice()
invoice.clear()
rootItem.clear()
}
}
Button {
text: qsTr('Pay now')
enabled: invoice.invoiceType != Invoice.Invalid // TODO && has funds
enabled: invoice.canPay
icon.source: '../../icons/confirmed.png'
onClicked: {
var f_amount = parseFloat(amount.text)
if (isNaN(f_amount))
return
invoice.save_invoice()
var dialog = confirmPaymentDialog.createObject(app, {
'address': recipient.text,
'satoshis': Config.unitsToSats(amount.text),
'message': message.text
})
dialog.open()
invoice.clear()
rootItem.clear()
}
}
}
@ -291,6 +307,8 @@ Pane {
dialog.open()
}
}
onInvoiceCreateError: console.log(code + ' ' + message)
onInvoiceSaved: {
console.log('invoice got saved')
Daemon.currentWallet.invoiceModel.init_model()

65
electrum/gui/qml/qeinvoice.py

@ -5,13 +5,13 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
from electrum.logging import get_logger
from electrum.i18n import _
from electrum.keystore import bip39_is_checksum_valid
from electrum.util import (parse_URI, create_bip21_uri, InvalidBitcoinURI, InvoiceError,
maybe_extract_bolt11_invoice)
from electrum.invoices import Invoice
from electrum.invoices import (PR_UNPAID,PR_EXPIRED,PR_UNKNOWN,PR_PAID,PR_INFLIGHT,
PR_FAILED,PR_ROUTING,PR_UNCONFIRMED)
from electrum.transaction import PartialTxOutput
from electrum import bitcoin
from .qewallet import QEWallet
from .qetypes import QEAmount
@ -44,6 +44,8 @@ class QEInvoice(QObject):
_invoiceType = Type.Invalid
_recipient = ''
_effectiveInvoice = None
_canSave = False
_canPay = False
invoiceChanged = pyqtSignal()
invoiceSaved = pyqtSignal()
@ -52,6 +54,8 @@ class QEInvoice(QObject):
validationWarning = pyqtSignal([str,str], arguments=['code', 'message'])
validationError = pyqtSignal([str,str], arguments=['code', 'message'])
invoiceCreateError = pyqtSignal([str,str], arguments=['code', 'message'])
def __init__(self, config, parent=None):
super().__init__(parent)
self.config = config
@ -99,10 +103,7 @@ class QEInvoice(QObject):
self._amount = QEAmount()
if not self._effectiveInvoice:
return self._amount
sats = self._effectiveInvoice.get_amount_sat()
if not sats:
return self._amount
self._amount = QEAmount(amount_sat=sats)
self._amount = QEAmount(from_invoice=self._effectiveInvoice)
return self._amount
@pyqtProperty('quint64', notify=invoiceChanged)
@ -132,12 +133,33 @@ class QEInvoice(QObject):
def address(self):
return self._effectiveInvoice.get_address() if self._effectiveInvoice else ''
@pyqtProperty(bool, notify=invoiceChanged)
def canSave(self):
return self._canSave
@canSave.setter
def canSave(self, _canSave):
if self._canSave != _canSave:
self._canSave = _canSave
self.invoiceChanged.emit()
@pyqtProperty(bool, notify=invoiceChanged)
def canPay(self):
return self._canPay
@canPay.setter
def canPay(self, _canPay):
if self._canPay != _canPay:
self._canPay = _canPay
self.invoiceChanged.emit()
@pyqtSlot()
def clear(self):
self.recipient = ''
self.invoiceSetsAmount = False
self.setInvoiceType(QEInvoice.Type.Invalid)
self._bip21 = None
self._canSave = False
self._canPay = False
self.invoiceChanged.emit()
# don't parse the recipient string, but init qeinvoice from an invoice key
@ -155,6 +177,9 @@ class QEInvoice(QObject):
self.setInvoiceType(QEInvoice.Type.LightningInvoice)
else:
self.setInvoiceType(QEInvoice.Type.OnchainInvoice)
# TODO check if exists?
self.canSave = True
self.canPay = True # TODO
self.invoiceChanged.emit()
self.statusChanged.emit()
@ -257,6 +282,7 @@ class QEInvoice(QObject):
@pyqtSlot()
def save_invoice(self):
self.canSave = False
if not self._effectiveInvoice:
return
# TODO detect duplicate?
@ -265,9 +291,12 @@ class QEInvoice(QObject):
@pyqtSlot(str, QEAmount, str)
def create_invoice(self, address: str, amount: QEAmount, message: str):
# create onchain invoice from user entered fields
# create invoice from user entered fields
# (any other type of invoice is created from parsing recipient)
self._logger.debug('saving invoice to %s' % address)
self._logger.debug('creating invoice to %s, amount=%s, message=%s' % (address, repr(amount), message))
self.clear()
if not address:
self.invoiceCreateError.emit('fatal', _('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request'))
return
@ -276,19 +305,17 @@ class QEInvoice(QObject):
self.invoiceCreateError.emit('fatal', _('Invalid Bitcoin address'))
return
if not self.amount:
if amount.isEmpty:
self.invoiceCreateError.emit('fatal', _('Invalid amount'))
return
inv_amt = '!' if amount.isMax else (amount.satsInt * 1000) # FIXME msat precision from UI?
try:
outputs = [PartialTxOutput.from_address_and_value(address, inv_amt)]
invoice = self._wallet.wallet.create_invoice(outputs=outputs, message=message, pr=None, URI=None)
except InvoiceError as e:
self.invoiceCreateError.emit('fatal', _('Error creating payment') + ':\n' + str(e))
return
#
if self.is_max:
amount = '!'
else:
try:
amount = self.app.get_amount(self.amount)
except:
self.app.show_error(_('Invalid amount') + ':\n' + self.amount)
return
self.set_effective_invoice(invoice)

Loading…
Cancel
Save