From 5f8b8ce97e636ae63fbf8cf525125e8e856d890a Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Tue, 4 Jul 2023 10:55:00 +0200 Subject: [PATCH] qml: show channel backup and explanatory message before local force close, and let user confirm before doing the close operation also show message dialog after close succeeded instead of just closing the channel close dialog --- .../gui/qml/components/CloseChannelDialog.qml | 57 +++++++++++++++++-- .../gui/qml/components/GenericShareDialog.qml | 2 + electrum/gui/qml/qechanneldetails.py | 16 +++++- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/electrum/gui/qml/components/CloseChannelDialog.qml b/electrum/gui/qml/components/CloseChannelDialog.qml index 529ce1c0e..6c7279baa 100644 --- a/electrum/gui/qml/components/CloseChannelDialog.qml +++ b/electrum/gui/qml/components/CloseChannelDialog.qml @@ -19,6 +19,7 @@ ElDialog { iconSource: Qt.resolvedUrl('../../icons/lightning_disconnected.png') property bool _closing: false + property string _closing_method closePolicy: Popup.NoAutoClose @@ -163,12 +164,50 @@ ElDialog { icon.source: '../../icons/closebutton.png' enabled: !_closing onClicked: { - _closing = true - channeldetails.closeChannel(closetypegroup.checkedButton.closetype) + if (closetypegroup.checkedButton.closetype == 'local_force') { + showBackupThenConfirmClose() + } else { + doCloseChannel() + } } - } + } + function showBackupThenConfirmClose() { + var sharedialog = app.genericShareDialog.createObject(app, { + title: qsTr('Save channel backup and force close'), + text_qr: channeldetails.channelBackup(), + text_help: channeldetails.messageForceCloseBackup, + helpTextIconStyle: InfoTextArea.IconStyle.Warn + }) + sharedialog.closed.connect(function() { + confirmCloseChannel() + }) + sharedialog.open() + } + + function confirmCloseChannel() { + var confirmdialog = app.messageDialog.createObject(app, { + title: qsTr('Confirm force close?'), + yesno: true + }) + confirmdialog.accepted.connect(function() { + doCloseChannel() + }) + confirmdialog.open() + } + + function doCloseChannel() { + _closing = true + _closing_method = closetypegroup.checkedButton.closetype + channeldetails.closeChannel(_closing_method) + } + + function showCloseMessage(text) { + var msgdialog = app.messageDialog.createObject(app, { + text: text + }) + msgdialog.open() } ChannelDetails { @@ -176,7 +215,10 @@ ElDialog { wallet: Daemon.currentWallet channelid: dialog.channelid - onChannelChanged : { + onChannelChanged: { + if (!channeldetails.canClose) + return + // init default choice if (channeldetails.canCoopClose) closetypeCoop.checked = true @@ -186,6 +228,13 @@ ElDialog { onChannelCloseSuccess: { _closing = false + if (_closing_method == 'local_force') { + showCloseMessage(qsTr('Channel closed. You may need to wait at least %1 blocks, because of CSV delays').arg(channeldetails.toSelfDelay)) + } else if (_closing_method == 'remote_force') { + showCloseMessage(qsTr('Request sent')) + } else if (_closing_method == 'cooperative') { + showCloseMessage(qsTr('Channel closed')) + } dialog.close() } diff --git a/electrum/gui/qml/components/GenericShareDialog.qml b/electrum/gui/qml/components/GenericShareDialog.qml index 8a9b8e49c..aa85a12e2 100644 --- a/electrum/gui/qml/components/GenericShareDialog.qml +++ b/electrum/gui/qml/components/GenericShareDialog.qml @@ -12,6 +12,7 @@ ElDialog { property string text_qr // if text_qr is undefined text will be used property string text_help + property int helpTextIconStyle: InfoTextArea.IconStyle.Info title: '' @@ -65,6 +66,7 @@ ElDialog { InfoTextArea { Layout.leftMargin: constants.paddingMedium Layout.rightMargin: constants.paddingMedium + iconStyle: helpTextIconStyle visible: dialog.text_help text: dialog.text_help Layout.fillWidth: true diff --git a/electrum/gui/qml/qechanneldetails.py b/electrum/gui/qml/qechanneldetails.py index 233a67731..48585e9a9 100644 --- a/electrum/gui/qml/qechanneldetails.py +++ b/electrum/gui/qml/qechanneldetails.py @@ -13,6 +13,7 @@ from .qewallet import QEWallet from .qetypes import QEAmount from .util import QtEventListener, qt_event_listener, event_listener + class QEChannelDetails(QObject, QtEventListener): _logger = get_logger(__name__) @@ -171,13 +172,26 @@ class QEChannelDetails(QObject, QtEventListener): return self._channel.can_be_deleted() @pyqtProperty(str, notify=channelChanged) - def messageForceClose(self, notify=channelChanged): + def messageForceClose(self): return messages.MSG_REQUEST_FORCE_CLOSE.strip() + @pyqtProperty(str, notify=channelChanged) + def messageForceCloseBackup(self): + return ' '.join([ + _('If you force-close this channel, the funds you have in it will not be available for {} blocks.').format(self.toSelfDelay), + _('During that time, funds will not be recoverable from your seed, and may be lost if you lose your device.'), + _('To prevent that, please save this channel backup.'), + _('It may be imported in another wallet with the same seed.') + ]) + @pyqtProperty(bool, notify=channelChanged) def isBackup(self): return self._channel.is_backup() + @pyqtProperty(int, notify=channelChanged) + def toSelfDelay(self): + return self._channel.config[REMOTE].to_self_delay + @pyqtSlot() def freezeForSending(self): lnworker = self._channel.lnworker