From 2881c496718a47d3cce7ede8b39be35db881bd6e Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Wed, 15 Mar 2023 15:18:48 +0100 Subject: [PATCH] qml: move technical details to bottom of InvoiceDialog, add routing hints --- electrum/gui/qml/components/InvoiceDialog.qml | 188 +++++++++++------- electrum/gui/qml/qeinvoice.py | 29 ++- 2 files changed, 134 insertions(+), 83 deletions(-) diff --git a/electrum/gui/qml/components/InvoiceDialog.qml b/electrum/gui/qml/components/InvoiceDialog.qml index d20f35ff9..0bfb4bba0 100644 --- a/electrum/gui/qml/components/InvoiceDialog.qml +++ b/electrum/gui/qml/components/InvoiceDialog.qml @@ -118,82 +118,6 @@ ElDialog { } } - Label { - Layout.columnSpan: 2 - Layout.topMargin: constants.paddingSmall - visible: invoice.invoiceType == Invoice.LightningInvoice - text: qsTr('Remote Pubkey') - color: Material.accentColor - } - - TextHighlightPane { - Layout.columnSpan: 2 - Layout.fillWidth: true - - visible: invoice.invoiceType == Invoice.LightningInvoice - leftPadding: constants.paddingMedium - - RowLayout { - width: parent.width - Label { - id: pubkeyLabel - Layout.fillWidth: true - text: 'pubkey' in invoice.lnprops ? invoice.lnprops.pubkey : '' - font.family: FixedFont - wrapMode: Text.Wrap - } - ToolButton { - icon.source: '../../icons/share.png' - icon.color: 'transparent' - enabled: pubkeyLabel.text - onClicked: { - var dialog = app.genericShareDialog.createObject(app, - { title: qsTr('Node public key'), text: invoice.lnprops.pubkey } - ) - dialog.open() - } - } - } - } - - Label { - Layout.columnSpan: 2 - Layout.topMargin: constants.paddingSmall - visible: invoice.invoiceType == Invoice.LightningInvoice - text: qsTr('Payment hash') - color: Material.accentColor - } - - TextHighlightPane { - Layout.columnSpan: 2 - Layout.fillWidth: true - - visible: invoice.invoiceType == Invoice.LightningInvoice - leftPadding: constants.paddingMedium - - RowLayout { - width: parent.width - Label { - id: paymenthashLabel - Layout.fillWidth: true - text: 'payment_hash' in invoice.lnprops ? invoice.lnprops.payment_hash : '' - font.family: FixedFont - wrapMode: Text.Wrap - } - ToolButton { - icon.source: '../../icons/share.png' - icon.color: 'transparent' - enabled: paymenthashLabel.text - onClicked: { - var dialog = app.genericShareDialog.createObject(app, - { title: qsTr('Payment hash'), text: invoice.lnprops.payment_hash } - ) - dialog.open() - } - } - } - } - Label { Layout.columnSpan: 2 Layout.topMargin: constants.paddingSmall @@ -366,6 +290,118 @@ ElDialog { } + Heading { + Layout.columnSpan: 2 + text: qsTr('Technical properties') + } + + Label { + Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + visible: invoice.invoiceType == Invoice.LightningInvoice + text: qsTr('Remote Pubkey') + color: Material.accentColor + } + + TextHighlightPane { + Layout.columnSpan: 2 + Layout.fillWidth: true + + visible: invoice.invoiceType == Invoice.LightningInvoice + leftPadding: constants.paddingMedium + + RowLayout { + width: parent.width + Label { + id: pubkeyLabel + Layout.fillWidth: true + text: 'pubkey' in invoice.lnprops ? invoice.lnprops.pubkey : '' + font.family: FixedFont + wrapMode: Text.Wrap + } + ToolButton { + icon.source: '../../icons/share.png' + icon.color: 'transparent' + enabled: pubkeyLabel.text + onClicked: { + var dialog = app.genericShareDialog.createObject(app, + { title: qsTr('Node public key'), text: invoice.lnprops.pubkey } + ) + dialog.open() + } + } + } + } + + Label { + Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + visible: invoice.invoiceType == Invoice.LightningInvoice + text: qsTr('Payment hash') + color: Material.accentColor + } + + TextHighlightPane { + Layout.columnSpan: 2 + Layout.fillWidth: true + + visible: invoice.invoiceType == Invoice.LightningInvoice + leftPadding: constants.paddingMedium + + RowLayout { + width: parent.width + Label { + id: paymenthashLabel + Layout.fillWidth: true + text: 'payment_hash' in invoice.lnprops ? invoice.lnprops.payment_hash : '' + font.family: FixedFont + wrapMode: Text.Wrap + } + ToolButton { + icon.source: '../../icons/share.png' + icon.color: 'transparent' + enabled: paymenthashLabel.text + onClicked: { + var dialog = app.genericShareDialog.createObject(app, { + title: qsTr('Payment hash'), + text: invoice.lnprops.payment_hash + }) + dialog.open() + } + } + } + } + + Label { + Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + visible: 'r' in invoice.lnprops && invoice.lnprops.r.length + text: qsTr('Routing hints') + color: Material.accentColor + } + + Repeater { + visible: 'r' in invoice.lnprops && invoice.lnprops.r.length + model: invoice.lnprops.r + + TextHighlightPane { + Layout.columnSpan: 2 + Layout.fillWidth: true + + RowLayout { + width: parent.width + + Label { + text: modelData.scid + } + Label { + Layout.fillWidth: true + text: modelData.node + wrapMode: Text.Wrap + } + } + } + } } } diff --git a/electrum/gui/qml/qeinvoice.py b/electrum/gui/qml/qeinvoice.py index 039151b24..179e658cc 100644 --- a/electrum/gui/qml/qeinvoice.py +++ b/electrum/gui/qml/qeinvoice.py @@ -16,6 +16,7 @@ from electrum.logging import get_logger from electrum.transaction import PartialTxOutput from electrum.util import (parse_URI, InvalidBitcoinURI, InvoiceError, maybe_extract_lightning_payment_identifier) +from electrum.lnutil import format_short_channel_id from electrum.lnurl import decode_lnurl, request_lnurl, callback_lnurl from electrum.bitcoin import COIN from electrum.paymentrequest import PaymentRequest @@ -144,6 +145,7 @@ class QEInvoiceParser(QEInvoice): self._effectiveInvoice = None self._amount = QEAmount() self._userinfo = '' + self._lnprops = {} self._timer = QTimer(self) self._timer.setSingleShot(True) @@ -227,25 +229,36 @@ class QEInvoiceParser(QEInvoice): status = self._wallet.wallet.get_invoice_status(self._effectiveInvoice) return self._effectiveInvoice.get_status_str(status) - # single address only, TODO: n outputs @pyqtProperty(str, notify=invoiceChanged) def address(self): return self._effectiveInvoice.get_address() if self._effectiveInvoice else '' @pyqtProperty('QVariantMap', notify=invoiceChanged) def lnprops(self): + return self._lnprops + + def set_lnprops(self): + self._lnprops = {} if not self.invoiceType == QEInvoice.Type.LightningInvoice: - return {} + return + lnaddr = self._effectiveInvoice._lnaddr - self._logger.debug(str(lnaddr)) - self._logger.debug(str(lnaddr.get_routing_info('t'))) - return { + ln_routing_info = lnaddr.get_routing_info('r') + self._logger.debug(str(ln_routing_info)) + + self._lnprops = { 'pubkey': lnaddr.pubkey.serialize().hex(), 'payment_hash': lnaddr.paymenthash.hex(), - 't': '', #lnaddr.get_routing_info('t')[0][0].hex(), - 'r': '' #lnaddr.get_routing_info('r')[0][0][0].hex() + 'r': [{ + 'node': self.name_for_node_id(x[-1][0]), + 'scid': format_short_channel_id(x[-1][1]) + } for x in ln_routing_info] if ln_routing_info else [] } + def name_for_node_id(self, node_id): + node_info = self._wallet.wallet.lnworker.channel_db.get_node_info_for_node_id(node_id=node_id) + return node_info.alias if node_info.alias else node_id.hex() + @pyqtSlot() def clear(self): self.recipient = '' @@ -276,6 +289,8 @@ class QEInvoiceParser(QEInvoice): else: self.setInvoiceType(QEInvoice.Type.OnchainInvoice) + self.set_lnprops() + self.canSave = True self.determine_can_pay()