Browse Source

add initial channel close dialog

patch-4
Sander van Grieken 3 years ago
parent
commit
e69fc739ca
  1. 21
      electrum/gui/qml/components/ChannelDetails.qml
  2. 130
      electrum/gui/qml/components/CloseChannelDialog.qml
  3. 49
      electrum/gui/qml/qechanneldetails.py
  4. 2
      electrum/gui/qml/qechannellistmodel.py

21
electrum/gui/qml/components/ChannelDetails.qml

@ -31,17 +31,11 @@ Pane {
icon.color: 'transparent' icon.color: 'transparent'
action: Action { action: Action {
text: qsTr('Close channel'); text: qsTr('Close channel');
enabled: false enabled: channeldetails.canClose
onTriggered: {} onTriggered: {
//icon.source: '../../icons/wallet.png' var dialog = closechannel.createObject(root, { 'channelid': channelid })
} dialog.open()
} }
MenuItem {
icon.color: 'transparent'
action: Action {
text: qsTr('Force-close');
enabled: false
onTriggered: {}
//icon.source: '../../icons/wallet.png' //icon.source: '../../icons/wallet.png'
} }
} }
@ -245,4 +239,9 @@ Pane {
id: share id: share
GenericShareDialog {} GenericShareDialog {}
} }
Component {
id: closechannel
CloseChannelDialog {}
}
} }

130
electrum/gui/qml/components/CloseChannelDialog.qml

@ -0,0 +1,130 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import org.electrum 1.0
import "controls"
Dialog {
id: dialog
width: parent.width
height: parent.height
property string channelid
title: qsTr('Close Channel')
standardButtons: closing ? 0 : Dialog.Cancel
modal: true
parent: Overlay.overlay
Overlay.modal: Rectangle {
color: "#aa000000"
}
property bool closing: false
closePolicy: Popup.NoAutoClose
GridLayout {
id: layout
width: parent.width
height: parent.height
columns: 2
Label {
text: qsTr('Channel name')
color: Material.accentColor
}
Label {
text: channeldetails.name
}
Label {
text: qsTr('Short channel ID')
color: Material.accentColor
}
Label {
text: channeldetails.short_cid
}
InfoTextArea {
Layout.columnSpan: 2
text: qsTr(channeldetails.message_force_close)
}
ColumnLayout {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
ButtonGroup {
id: closetypegroup
}
RadioButton {
ButtonGroup.group: closetypegroup
property string closetype: 'cooperative'
checked: true
enabled: !closing && channeldetails.canCoopClose
text: qsTr('Cooperative close')
}
RadioButton {
ButtonGroup.group: closetypegroup
property string closetype: 'force'
enabled: !closing && channeldetails.canForceClose
text: qsTr('Request Force-close')
}
}
Button {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
text: qsTr('Close')
enabled: !closing
onClicked: {
closing = true
channeldetails.close_channel(closetypegroup.checkedButton.closetype)
}
}
ColumnLayout {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
Label {
id: errorText
visible: !closing && errorText
wrapMode: Text.Wrap
Layout.preferredWidth: layout.width
}
Label {
text: qsTr('Closing...')
visible: closing
}
BusyIndicator {
visible: closing
}
}
Item { Layout.fillHeight: true; Layout.preferredWidth: 1 }
}
ChannelDetails {
id: channeldetails
wallet: Daemon.currentWallet
channelid: dialog.channelid
onChannelCloseSuccess: {
closing = false
dialog.close()
}
onChannelCloseFailed: {
closing = false
errorText.text = message
}
}
}

49
electrum/gui/qml/qechanneldetails.py

@ -1,8 +1,13 @@
import asyncio
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
from electrum.i18n import _
from electrum.gui import messages
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.util import register_callback, unregister_callback from electrum.util import register_callback, unregister_callback
from electrum.lnutil import LOCAL, REMOTE from electrum.lnutil import LOCAL, REMOTE
from electrum.lnchannel import ChanCloseOption
from .qewallet import QEWallet from .qewallet import QEWallet
from .qetypes import QEAmount from .qetypes import QEAmount
@ -15,6 +20,8 @@ class QEChannelDetails(QObject):
_channel = None _channel = None
channelChanged = pyqtSignal() channelChanged = pyqtSignal()
channelCloseSuccess = pyqtSignal()
channelCloseFailed = pyqtSignal([str], arguments=['message'])
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -57,7 +64,7 @@ class QEChannelDetails(QObject):
def load(self): def load(self):
lnchannels = self._wallet.wallet.lnworker.channels lnchannels = self._wallet.wallet.lnworker.channels
for channel in lnchannels.values(): for channel in lnchannels.values():
self._logger.debug('%s == %s ?' % (self._channelid, channel.channel_id)) #self._logger.debug('%s == %s ?' % (self._channelid, channel.channel_id))
if self._channelid == channel.channel_id.hex(): if self._channelid == channel.channel_id.hex():
self._channel = channel self._channel = channel
self.channelChanged.emit() self.channelChanged.emit()
@ -115,22 +122,54 @@ class QEChannelDetails(QObject):
def isOpen(self): def isOpen(self):
return self._channel.is_open() return self._channel.is_open()
@pyqtProperty(bool, notify=channelChanged)
def canClose(self):
return self.canCoopClose or self.canForceClose
@pyqtProperty(bool, notify=channelChanged)
def canCoopClose(self):
return ChanCloseOption.COOP_CLOSE in self._channel.get_close_options()
@pyqtProperty(bool, notify=channelChanged)
def canForceClose(self):
return ChanCloseOption.LOCAL_FCLOSE in self._channel.get_close_options()
@pyqtProperty(str, notify=channelChanged)
def message_force_close(self, notify=channelChanged):
return _(messages.MSG_REQUEST_FORCE_CLOSE)
@pyqtSlot() @pyqtSlot()
def freezeForSending(self): def freezeForSending(self):
lnworker = self._channel.lnworker lnworker = self._channel.lnworker
if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id): if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id):
#self.is_frozen_for_sending = not self.is_frozen_for_sending
self._channel.set_frozen_for_sending(not self.frozenForSending) self._channel.set_frozen_for_sending(not self.frozenForSending)
self.channelChanged.emit() self.channelChanged.emit()
else: else:
self._logger.debug('TODO: messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP') self._logger.debug(messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP)
@pyqtSlot() @pyqtSlot()
def freezeForReceiving(self): def freezeForReceiving(self):
lnworker = self._channel.lnworker lnworker = self._channel.lnworker
if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id): if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id):
#self.is_frozen_for_sending = not self.is_frozen_for_sending
self._channel.set_frozen_for_receiving(not self.frozenForReceiving) self._channel.set_frozen_for_receiving(not self.frozenForReceiving)
self.channelChanged.emit() self.channelChanged.emit()
else: else:
self._logger.debug('TODO: messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP') self._logger.debug(messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP)
# this method assumes the qobject is not destroyed before the close either fails or succeeds
@pyqtSlot(str)
def close_channel(self, closetype):
async def do_close(closetype, channel_id):
try:
if closetype == 'force':
await self._wallet.wallet.lnworker.request_force_close(channel_id)
else:
await self._wallet.wallet.lnworker.close_channel(channel_id)
self.channelCloseSuccess.emit()
except Exception as e:
self._logger.exception("Could not close channel: " + repr(e))
self.channelCloseFailed.emit(_('Could not close channel: ') + repr(e))
loop = self._wallet.wallet.network.asyncio_loop
coro = do_close(closetype, self._channel.channel_id)
asyncio.run_coroutine_threadsafe(coro, loop)

2
electrum/gui/qml/qechannellistmodel.py

@ -117,7 +117,7 @@ class QEChannelListModel(QAbstractListModel):
def on_channel_updated(self, channel): def on_channel_updated(self, channel):
i = 0 i = 0
for c in self.channels: for c in self.channels:
if c['cid'] == channel.channel_id: if c['cid'] == channel.channel_id.hex():
self.do_update(i,channel) self.do_update(i,channel)
break break
i = i + 1 i = i + 1

Loading…
Cancel
Save