add initial channel close dialog
This commit is contained in:
@@ -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
Normal file
130
electrum/gui/qml/components/CloseChannelDialog.qml
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user