From 3967323842f900c8e20523b02c7dbcb818e13485 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Fri, 10 Nov 2023 13:02:55 +0100 Subject: [PATCH] qml: refactor ChannelDetails. Add funding outpoint --- .../gui/qml/components/ChannelDetails.qml | 303 ++++++++++-------- electrum/gui/qml/qechanneldetails.py | 10 +- 2 files changed, 186 insertions(+), 127 deletions(-) diff --git a/electrum/gui/qml/components/ChannelDetails.qml b/electrum/gui/qml/components/ChannelDetails.qml index 242321d55..a7ad4dd83 100644 --- a/electrum/gui/qml/components/ChannelDetails.qml +++ b/electrum/gui/qml/components/ChannelDetails.qml @@ -56,25 +56,160 @@ Pane { } Label { - text: qsTr('Short channel ID') + text: qsTr('State') color: Material.accentColor } Label { + text: channeldetails.state + color: channeldetails.state == 'OPEN' + ? constants.colorChannelOpen + : Material.foreground + } + + Label { + Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + text: qsTr('Capacity and ratio') + color: Material.accentColor + } + + TextHighlightPane { + Layout.columnSpan: 2 Layout.fillWidth: true - text: channeldetails.shortCid + padding: constants.paddingLarge + + GridLayout { + width: parent.width + columns: 2 + rowSpacing: constants.paddingSmall + + InfoTextArea { + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.bottomMargin: constants.paddingMedium + visible: channeldetails.canSend.msatsInt < 0.5 * channeldetails.localCapacity.msatsInt + && channeldetails.localCapacity.msatsInt > 0.2 * channeldetails.capacity.msatsInt + iconStyle: InfoTextArea.IconStyle.Warn + compact: true + text: [qsTr('The amount available for sending is considerably lower than the local balance.'), + qsTr('This can occur when mempool fees are high.')].join(' ') + } + + ChannelBar { + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.topMargin: constants.paddingLarge + Layout.bottomMargin: constants.paddingXLarge + visible: channeldetails.stateCode != ChannelDetails.Redeemed + && channeldetails.stateCode != ChannelDetails.Closed + && !channeldetails.isBackup + capacity: channeldetails.capacity + localCapacity: channeldetails.localCapacity + remoteCapacity: channeldetails.remoteCapacity + canSend: channeldetails.canSend + canReceive: channeldetails.canReceive + frozenForSending: channeldetails.frozenForSending + frozenForReceiving: channeldetails.frozenForReceiving + } + + Label { + text: qsTr('Capacity') + color: Material.accentColor + } + + FormattedAmount { + amount: channeldetails.capacity + } + + Label { + text: qsTr('Can send') + color: Material.accentColor + } + + RowLayout { + visible: channeldetails.isOpen + FormattedAmount { + visible: !channeldetails.frozenForSending + amount: channeldetails.canSend + singleLine: false + } + Label { + visible: channeldetails.frozenForSending + text: qsTr('n/a (frozen)') + } + Item { + Layout.fillWidth: true + Layout.preferredHeight: 1 + } + Pane { + background: Rectangle { color: Material.dialogColor } + padding: 0 + FlatButton { + Layout.minimumWidth: implicitWidth + text: channeldetails.frozenForSending ? qsTr('Unfreeze') : qsTr('Freeze') + onClicked: channeldetails.freezeForSending() + } + } + } + + Label { + visible: !channeldetails.isOpen + text: qsTr('n/a (channel not open)') + } + + Label { + text: qsTr('Can receive') + color: Material.accentColor + } + + RowLayout { + visible: channeldetails.isOpen + FormattedAmount { + visible: !channeldetails.frozenForReceiving + amount: channeldetails.canReceive + singleLine: false + } + + Label { + visible: channeldetails.frozenForReceiving + text: qsTr('n/a (frozen)') + } + Item { + Layout.fillWidth: true + Layout.preferredHeight: 1 + } + Pane { + background: Rectangle { color: Material.dialogColor } + padding: 0 + FlatButton { + Layout.minimumWidth: implicitWidth + text: channeldetails.frozenForReceiving ? qsTr('Unfreeze') : qsTr('Freeze') + onClicked: channeldetails.freezeForReceiving() + } + } + } + + Label { + visible: !channeldetails.isOpen + text: qsTr('n/a (channel not open)') + } + } + } + + Heading { + Layout.columnSpan: 2 + text: qsTr('Technical properties') } Label { - text: qsTr('State') + text: qsTr('Short channel ID') color: Material.accentColor } Label { - text: channeldetails.state - color: channeldetails.state == 'OPEN' - ? constants.colorChannelOpen - : Material.foreground + Layout.fillWidth: true + text: channeldetails.shortCid } Label { @@ -113,8 +248,9 @@ Pane { } Label { - text: qsTr('Remote node ID') Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + text: qsTr('Remote node ID') color: Material.accentColor } @@ -144,132 +280,47 @@ Pane { } } } - } - - Label { - text: qsTr('Capacity and ratio') - color: Material.accentColor - } - - TextHighlightPane { - Layout.fillWidth: true - padding: constants.paddingLarge - - GridLayout { - width: parent.width - columns: 2 - rowSpacing: constants.paddingSmall - - InfoTextArea { - Layout.columnSpan: 2 - Layout.fillWidth: true - Layout.bottomMargin: constants.paddingMedium - visible: channeldetails.canSend.msatsInt < 0.5 * channeldetails.localCapacity.msatsInt - && channeldetails.localCapacity.msatsInt > 0.2 * channeldetails.capacity.msatsInt - iconStyle: InfoTextArea.IconStyle.Warn - compact: true - text: [qsTr('The amount available for sending is considerably lower than the local balance.'), - qsTr('This can occur when mempool fees are high.')].join(' ') - } - - ChannelBar { - Layout.columnSpan: 2 - Layout.fillWidth: true - Layout.topMargin: constants.paddingLarge - Layout.bottomMargin: constants.paddingXLarge - visible: channeldetails.stateCode != ChannelDetails.Redeemed - && channeldetails.stateCode != ChannelDetails.Closed - && !channeldetails.isBackup - capacity: channeldetails.capacity - localCapacity: channeldetails.localCapacity - remoteCapacity: channeldetails.remoteCapacity - canSend: channeldetails.canSend - canReceive: channeldetails.canReceive - frozenForSending: channeldetails.frozenForSending - frozenForReceiving: channeldetails.frozenForReceiving - } - - Label { - text: qsTr('Capacity') - color: Material.accentColor - } - FormattedAmount { - amount: channeldetails.capacity - } + Label { + Layout.columnSpan: 2 + Layout.topMargin: constants.paddingSmall + text: qsTr('Funding Outpoint') + color: Material.accentColor + } - Label { - text: qsTr('Can send') - color: Material.accentColor - } + TextHighlightPane { + Layout.columnSpan: 2 + Layout.fillWidth: true RowLayout { - visible: channeldetails.isOpen - FormattedAmount { - visible: !channeldetails.frozenForSending - amount: channeldetails.canSend - singleLine: false - } + width: parent.width Label { - visible: channeldetails.frozenForSending - text: qsTr('n/a (frozen)') - } - Item { + text: channeldetails.fundingOutpoint.txid + ':' + channeldetails.fundingOutpoint.index + font.pixelSize: constants.fontSizeLarge + font.family: FixedFont Layout.fillWidth: true - Layout.preferredHeight: 1 - } - Pane { - background: Rectangle { color: Material.dialogColor } - padding: 0 - FlatButton { - Layout.minimumWidth: implicitWidth - text: channeldetails.frozenForSending ? qsTr('Unfreeze') : qsTr('Freeze') - onClicked: channeldetails.freezeForSending() - } - } - } - - Label { - visible: !channeldetails.isOpen - text: qsTr('n/a (channel not open)') - } - - Label { - text: qsTr('Can receive') - color: Material.accentColor - } - - RowLayout { - visible: channeldetails.isOpen - FormattedAmount { - visible: !channeldetails.frozenForReceiving - amount: channeldetails.canReceive - singleLine: false - } + wrapMode: Text.Wrap - Label { - visible: channeldetails.frozenForReceiving - text: qsTr('n/a (frozen)') - } - Item { - Layout.fillWidth: true - Layout.preferredHeight: 1 + TapHandler { + onTapped: { + app.stack.push(Qt.resolvedUrl('TxDetails.qml'), { + txid: channeldetails.fundingOutpoint.txid + }) + } + } } - Pane { - background: Rectangle { color: Material.dialogColor } - padding: 0 - FlatButton { - Layout.minimumWidth: implicitWidth - text: channeldetails.frozenForReceiving ? qsTr('Unfreeze') : qsTr('Freeze') - onClicked: channeldetails.freezeForReceiving() + ToolButton { + icon.source: '../../icons/share.png' + icon.color: 'transparent' + onClicked: { + var dialog = app.genericShareDialog.createObject(root, { + title: qsTr('Funding Outpoint'), + text: channeldetails.fundingOutpoint.txid + ':' + channeldetails.fundingOutpoint.index + }) + dialog.open() } } } - - Label { - visible: !channeldetails.isOpen - text: qsTr('n/a (channel not open)') - } } } @@ -284,6 +335,7 @@ Pane { Layout.preferredWidth: 1 visible: !channeldetails.isBackup text: qsTr('Backup') + icon.source: '../../icons/file.png' onClicked: { var dialog = app.genericShareDialog.createObject(root, { title: qsTr('Channel Backup for %1').arg(channeldetails.shortCid), @@ -293,7 +345,6 @@ Pane { }) dialog.open() } - icon.source: '../../icons/file.png' } FlatButton { @@ -301,11 +352,11 @@ Pane { Layout.preferredWidth: 1 text: qsTr('Close channel'); visible: channeldetails.canClose + icon.source: '../../icons/closebutton.png' onClicked: { var dialog = closechannel.createObject(root, { channelid: channelid }) dialog.open() } - icon.source: '../../icons/closebutton.png' } FlatButton { @@ -313,6 +364,7 @@ Pane { Layout.preferredWidth: 1 text: qsTr('Delete channel'); visible: channeldetails.canDelete + icon.source: '../../icons/delete.png' onClicked: { var dialog = app.messageDialog.createObject(root, { title: qsTr('Are you sure?'), @@ -327,7 +379,6 @@ Pane { }) dialog.open() } - icon.source: '../../icons/delete.png' } } diff --git a/electrum/gui/qml/qechanneldetails.py b/electrum/gui/qml/qechanneldetails.py index 973ea54bc..5f1344158 100644 --- a/electrum/gui/qml/qechanneldetails.py +++ b/electrum/gui/qml/qechanneldetails.py @@ -19,7 +19,7 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener): _logger = get_logger(__name__) @pyqtEnum - class State(IntEnum): # subset, only ones we currently need in UI + class State(IntEnum): # subset, only ones we currently need in UI Closed = ChannelState.CLOSED Redeemed = ChannelState.REDEEMED @@ -113,6 +113,14 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener): return '' return 'Local' if self._channel.constraints.is_initiator else 'Remote' + @pyqtProperty('QVariantMap', notify=channelChanged) + def fundingOutpoint(self): + outpoint = self._channel.funding_outpoint + return { + 'txid': outpoint.txid, + 'index': outpoint.output_index + } + @pyqtProperty(QEAmount, notify=channelChanged) def capacity(self): self._capacity.copyFrom(QEAmount(amount_sat=self._channel.get_capacity()))