From acb88f21c12f8d1ce13f872b5ea75639752f5d50 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Fri, 30 Sep 2022 15:40:05 +0200 Subject: [PATCH] implement success and failure paths, keep dialog over multiple tries --- electrum/gui/qml/components/OtpDialog.qml | 63 +++++++++++++++---- .../gui/qml/components/WalletMainView.qml | 2 +- electrum/gui/qml/qewallet.py | 12 +++- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/electrum/gui/qml/components/OtpDialog.qml b/electrum/gui/qml/components/OtpDialog.qml index 70f9c6f65..e971d4c24 100644 --- a/electrum/gui/qml/components/OtpDialog.qml +++ b/electrum/gui/qml/components/OtpDialog.qml @@ -10,13 +10,13 @@ import "controls" ElDialog { id: dialog - title: qsTr('OTP auth') + title: qsTr('Trustedcoin') + iconSource: '../../../icons/trustedcoin-status.png' property string otpauth - // property var lnurlData - // property InvoiceParser invoiceParser - // property alias lnurlData: dialog.invoiceParser.lnurlData + property bool _waiting: false + property string _otpError standardButtons: Dialog.Cancel @@ -26,28 +26,67 @@ ElDialog { color: "#aa000000" } - GridLayout { - columns: 2 - implicitWidth: parent.width + focus: true + + ColumnLayout { + width: parent.width Label { - text: qsTr('code') + text: qsTr('Enter Authenticator code') + font.pixelSize: constants.fontSizeLarge + Layout.alignment: Qt.AlignHCenter } TextField { id: otpEdit + Layout.preferredWidth: fontMetrics.advanceWidth(passwordCharacter) * 6 + Layout.alignment: Qt.AlignHCenter + font.pixelSize: constants.fontSizeXXLarge + maximumLength: 6 + inputMethodHints: Qt.ImhSensitiveData | Qt.ImhDigitsOnly + echoMode: TextInput.Password + focus: true + onTextChanged: { + if (activeFocus) + _otpError = '' + } + } + + Label { + opacity: _otpError ? 1 : 0 + text: _otpError + color: constants.colorError + Layout.alignment: Qt.AlignHCenter } Button { Layout.columnSpan: 2 Layout.alignment: Qt.AlignHCenter - text: qsTr('Proceed') + text: qsTr('Submit') + enabled: !_waiting onClicked: { - // dialog.close() - otpauth = otpEdit.text - dialog.accept() + _waiting = true + Daemon.currentWallet.submitOtp(otpEdit.text) } } + } + + Connections { + target: Daemon.currentWallet + function onOtpSuccess() { + _waiting = false + otpauth = otpEdit.text + dialog.accept() + } + function onOtpFailed(code, message) { + _waiting = false + _otpError = message + otpEdit.text = '' + } + } + FontMetrics { + id: fontMetrics + font: otpEdit.font } } diff --git a/electrum/gui/qml/components/WalletMainView.qml b/electrum/gui/qml/components/WalletMainView.qml index 21523695b..1ab844005 100644 --- a/electrum/gui/qml/components/WalletMainView.qml +++ b/electrum/gui/qml/components/WalletMainView.qml @@ -321,7 +321,7 @@ Item { Component { id: otpDialog OtpDialog { - width: parent.width * 0.9 + width: parent.width * 2/3 anchors.centerIn: parent onClosed: destroy() diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py index 9080f9e84..83aa4054a 100644 --- a/electrum/gui/qml/qewallet.py +++ b/electrum/gui/qml/qewallet.py @@ -66,6 +66,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener): broadcastFailed = pyqtSignal([str,str,str], arguments=['txid','code','reason']) labelsUpdated = pyqtSignal() otpRequested = pyqtSignal() + otpSuccess = pyqtSignal() + otpFailed = pyqtSignal([str,str], arguments=['code','message']) _network_signal = pyqtSignal(str, object) @@ -426,7 +428,8 @@ class QEWallet(AuthMixin, QObject, QtEventListener): @auth_protect def sign(self, tx, *, broadcast: bool = False): - sign_hook = run_hook('tc_sign_wrapper', self.wallet, tx, partial(self.on_sign_complete, broadcast), None) + sign_hook = run_hook('tc_sign_wrapper', self.wallet, tx, partial(self.on_sign_complete, broadcast), + self.on_sign_failed) if sign_hook: self.do_sign(tx, False) self._logger.debug('plugin needs to sign tx too') @@ -454,16 +457,21 @@ class QEWallet(AuthMixin, QObject, QtEventListener): if broadcast: self.broadcast(tx) + # this assumes a 2fa wallet, but there are no other tc_sign_wrapper hooks, so that's ok def on_sign_complete(self, broadcast, tx): + self.otpSuccess.emit() if broadcast: self.broadcast(tx) + def on_sign_failed(self, error): + self.otpFailed.emit('error', error) + def request_otp(self, on_submit): self._otp_on_submit = on_submit self.otpRequested.emit() @pyqtSlot(str) - def finish_otp(self, otp): + def submitOtp(self, otp): self._otp_on_submit(otp) def broadcast(self, tx):