From 0fb47c87d2ae876d024901815c97d734ddd5801e Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Wed, 8 Nov 2023 18:23:23 +0100 Subject: [PATCH] qml: fixes for CloseChannelDialog; - split RequestForceClose and LocalForceClose options, as request force close is only available if connected. - disable no close policy on dialog, as it locks the user in the dialog if no succesful close is initiated. what this intended to do is keep the backing object QEChannelDetails alive until a result is obtained, to avoid exceptions when emitting the result signal. this is now handled more robustly, the user can leave the dialog without triggering exceptions later. --- .../gui/qml/components/CloseChannelDialog.qml | 10 +++---- electrum/gui/qml/qechanneldetails.py | 29 ++++++++++++++----- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/electrum/gui/qml/components/CloseChannelDialog.qml b/electrum/gui/qml/components/CloseChannelDialog.qml index 8172da48f..cfae22c69 100644 --- a/electrum/gui/qml/components/CloseChannelDialog.qml +++ b/electrum/gui/qml/components/CloseChannelDialog.qml @@ -20,8 +20,6 @@ ElDialog { property string _closing_method - closePolicy: Popup.NoAutoClose - padding: 0 ColumnLayout { @@ -120,14 +118,14 @@ ElDialog { id: closetypeRemoteForce ButtonGroup.group: closetypegroup property string closetype: 'remote_force' - enabled: !channeldetails.isClosing && channeldetails.canForceClose + enabled: !channeldetails.isClosing && channeldetails.canRequestForceClose text: qsTr('Request Force-close') } ElRadioButton { id: closetypeLocalForce ButtonGroup.group: closetypegroup property string closetype: 'local_force' - enabled: !channeldetails.isClosing && channeldetails.canForceClose && !channeldetails.isBackup + enabled: !channeldetails.isClosing && channeldetails.canLocalForceClose && !channeldetails.isBackup text: qsTr('Local Force-close') } } @@ -213,8 +211,10 @@ ElDialog { // init default choice if (channeldetails.canCoopClose) closetypeCoop.checked = true - else + else if (channeldetails.canRequestForceClose) closetypeRemoteForce.checked = true + else + closetypeLocalForce.checked = true } onChannelCloseSuccess: { diff --git a/electrum/gui/qml/qechanneldetails.py b/electrum/gui/qml/qechanneldetails.py index cf1adb97d..973ea54bc 100644 --- a/electrum/gui/qml/qechanneldetails.py +++ b/electrum/gui/qml/qechanneldetails.py @@ -160,15 +160,19 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener): @pyqtProperty(bool, notify=channelChanged) def canClose(self): - return self.canCoopClose or self.canForceClose + return self.canCoopClose or self.canLocalForceClose or self.canRequestForceClose @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 any([o in [ChanCloseOption.LOCAL_FCLOSE, ChanCloseOption.REQUEST_REMOTE_FCLOSE] for o in self._channel.get_close_options()]) + def canLocalForceClose(self): + return ChanCloseOption.LOCAL_FCLOSE in self._channel.get_close_options() + + @pyqtProperty(bool, notify=channelChanged) + def canRequestForceClose(self): + return ChanCloseOption.REQUEST_REMOTE_FCLOSE in self._channel.get_close_options() @pyqtProperty(bool, notify=channelChanged) def canDelete(self): @@ -234,6 +238,18 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener): def do_close_channel(self, closetype): channel_id = self._channel.channel_id + def handle_result(success: bool, msg: str = ''): + try: + if success: + self.channelCloseSuccess.emit() + else: + self.channelCloseFailed.emit(msg) + + self._is_closing = False + self.isClosingChanged.emit() + except RuntimeError: # QEChannelDetails might be deleted at this point if the user closed the dialog. + pass + def do_close(): try: self._is_closing = True @@ -245,13 +261,10 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener): else: self._wallet.wallet.network.run_from_another_thread(self._wallet.wallet.lnworker.close_channel(channel_id)) self._logger.debug('Channel close successful') - self.channelCloseSuccess.emit() + handle_result(True) except Exception as e: self._logger.exception("Could not close channel: " + repr(e)) - self.channelCloseFailed.emit(_('Could not close channel: ') + repr(e)) - finally: - self._is_closing = False - self.isClosingChanged.emit() + handle_result(False, _('Could not close channel: ') + repr(e)) threading.Thread(target=do_close, daemon=True).start()