From 6cb6531fd9849e319cfc27157a89c41484c1395f Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Wed, 8 Feb 2023 17:12:20 +0100 Subject: [PATCH] qml: add swap progress dialog --- electrum/gui/qml/components/Channels.qml | 29 +++- electrum/gui/qml/components/SwapDialog.qml | 24 +--- .../gui/qml/components/SwapProgressDialog.qml | 124 ++++++++++++++++++ electrum/gui/qml/qeswaphelper.py | 19 ++- 4 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 electrum/gui/qml/components/SwapProgressDialog.qml diff --git a/electrum/gui/qml/components/Channels.qml b/electrum/gui/qml/components/Channels.qml index ea299d329..85b43ee7a 100644 --- a/electrum/gui/qml/components/Channels.qml +++ b/electrum/gui/qml/components/Channels.qml @@ -112,7 +112,7 @@ Pane { visible: Daemon.currentWallet.lightningCanSend.satsInt > 0 || Daemon.currentWallet.lightningCanReceive.satInt > 0 icon.source: '../../icons/status_waiting.png' onClicked: { - var dialog = swapDialog.createObject(root) + var dialog = swapDialog.createObject(root, { swaphelper: swaphelper }) dialog.open() } } @@ -141,6 +141,26 @@ Pane { } + SwapHelper { + id: swaphelper + wallet: Daemon.currentWallet + onConfirm: { + var dialog = app.messageDialog.createObject(app, {text: message, yesno: true}) + dialog.yesClicked.connect(function() { + dialog.close() + swaphelper.executeSwap(true) + }) + dialog.open() + } + onAuthRequired: { + app.handleAuthRequired(swaphelper, method) + } + onSwapStarted: { + var dialog = swapProgressDialog.createObject(app, { swaphelper: swaphelper }) + dialog.open() + } + } + Component { id: swapDialog SwapDialog { @@ -148,6 +168,13 @@ Pane { } } + Component { + id: swapProgressDialog + SwapProgressDialog { + onClosed: destroy() + } + } + Component { id: openChannelDialog OpenChannelDialog { diff --git a/electrum/gui/qml/components/SwapDialog.qml b/electrum/gui/qml/components/SwapDialog.qml index 32eeaed17..abebaa049 100644 --- a/electrum/gui/qml/components/SwapDialog.qml +++ b/electrum/gui/qml/components/SwapDialog.qml @@ -10,6 +10,8 @@ import "controls" ElDialog { id: root + required property QtObject swaphelper + width: parent.width height: parent.height @@ -194,24 +196,10 @@ ElDialog { } } - SwapHelper { - id: swaphelper - wallet: Daemon.currentWallet - onError: { - var dialog = app.messageDialog.createObject(app, {'text': message}) - dialog.open() - } - onConfirm: { - var dialog = app.messageDialog.createObject(app, {'text': message, 'yesno': true}) - dialog.yesClicked.connect(function() { - dialog.close() - swaphelper.executeSwap(true) - }) - dialog.open() - } - onAuthRequired: { - app.handleAuthRequired(swaphelper, method) + Connections { + target: swaphelper + function onSwapStarted() { + root.close() } - onSwapStarted: root.close() // TODO: show swap progress monitor } } diff --git a/electrum/gui/qml/components/SwapProgressDialog.qml b/electrum/gui/qml/components/SwapProgressDialog.qml new file mode 100644 index 000000000..5cc9feea3 --- /dev/null +++ b/electrum/gui/qml/components/SwapProgressDialog.qml @@ -0,0 +1,124 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.14 +import QtQuick.Controls.Material 2.0 + +import org.electrum 1.0 + +import "controls" + +ElDialog { + id: dialog + + required property QtObject swaphelper + + width: parent.width + height: parent.height + + title: swaphelper.isReverse + ? qsTr('Reverse swap...') + : qsTr('Swap...') + + modal: true + parent: Overlay.overlay + Overlay.modal: Rectangle { + color: "#aa000000" + } + + Item { + id: s + state: '' + states: [ + State { + name: '' + }, + State { + name: 'success' + PropertyChanges { target: spinner; running: false } + PropertyChanges { target: helpText; text: qsTr('Success') } + PropertyChanges { target: icon; source: '../../icons/confirmed.png' } + }, + State { + name: 'failed' + PropertyChanges { target: spinner; running: false } + PropertyChanges { target: helpText; text: qsTr('Failed') } + PropertyChanges { target: errorText; visible: true } + PropertyChanges { target: icon; source: '../../icons/warning.png' } + } + ] + transitions: [ + Transition { + from: '' + to: 'success' + PropertyAnimation { target: helpText; properties: 'text'; duration: 0} + NumberAnimation { target: icon; properties: 'opacity'; from: 0; to: 1; duration: 200 } + NumberAnimation { target: icon; properties: 'scale'; from: 0; to: 1; duration: 500 + easing.type: Easing.OutBack + easing.overshoot: 10 + } + }, + Transition { + from: '' + to: 'failed' + PropertyAnimation { target: helpText; properties: 'text'; duration: 0} + NumberAnimation { target: icon; properties: 'opacity'; from: 0; to: 1; duration: 500 } + } + ] + } + + ColumnLayout { + id: content + anchors.centerIn: parent + width: parent.width + + Item { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: constants.iconSizeXXLarge + Layout.preferredHeight: constants.iconSizeXXLarge + + BusyIndicator { + id: spinner + visible: s.state == '' + width: constants.iconSizeXXLarge + height: constants.iconSizeXXLarge + } + + Image { + id: icon + width: constants.iconSizeXXLarge + height: constants.iconSizeXXLarge + } + } + + Label { + id: helpText + Layout.alignment: Qt.AlignHCenter + text: qsTr('Performing swap...') + font.pixelSize: constants.fontSizeXXLarge + } + + Label { + id: errorText + Layout.preferredWidth: parent.width + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.Wrap + font.pixelSize: constants.fontSizeLarge + } + } + + Connections { + target: swaphelper + function onSwapSuccess() { + console.log('swap succeeded!') + s.state = 'success' + } + function onSwapFailed(message) { + console.log('swap failed: ' + message) + s.state = 'failed' + if (message) + errorText.text = message + } + } + +} diff --git a/electrum/gui/qml/qeswaphelper.py b/electrum/gui/qml/qeswaphelper.py index 4c38e2c8a..2924809d6 100644 --- a/electrum/gui/qml/qeswaphelper.py +++ b/electrum/gui/qml/qeswaphelper.py @@ -18,9 +18,10 @@ from .qewallet import QEWallet class QESwapHelper(AuthMixin, QObject): _logger = get_logger(__name__) - error = pyqtSignal([str], arguments=['message']) confirm = pyqtSignal([str], arguments=['message']) swapStarted = pyqtSignal() + swapSuccess = pyqtSignal() + swapFailed = pyqtSignal([str], arguments=['message']) def __init__(self, parent=None): super().__init__(parent) @@ -302,10 +303,12 @@ class QESwapHelper(AuthMixin, QObject): def swap_task(): try: fut = asyncio.run_coroutine_threadsafe(coro, loop) - result = fut.result() + self.swapStarted.emit() + txid = fut.result() + self.swapSuccess.emit() except Exception as e: self._logger.error(str(e)) - self.error.emit(str(e)) + self.swapFailed.emit(str(e)) threading.Thread(target=swap_task).start() @@ -322,10 +325,15 @@ class QESwapHelper(AuthMixin, QObject): def swap_task(): try: fut = asyncio.run_coroutine_threadsafe(coro, loop) - result = fut.result() + self.swapStarted.emit() + success = fut.result() + if success: + self.swapSuccess.emit() + else: + self.swapFailed.emit('') except Exception as e: self._logger.error(str(e)) - self.error.emit(str(e)) + self.swapFailed.emit(str(e)) threading.Thread(target=swap_task).start() @@ -356,4 +364,3 @@ class QESwapHelper(AuthMixin, QObject): lightning_amount = self._receive_amount onchain_amount = self._send_amount self.do_normal_swap(lightning_amount, onchain_amount) - self.swapStarted.emit()