From 0c9d4abb82557cf5c452f05259674e37388240b4 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Fri, 4 Nov 2022 13:35:15 +0100 Subject: [PATCH] qml: show 2FA status and billing info in WalletDetails, expose billing schedule setting in config --- electrum/gui/qml/components/WalletDetails.qml | 75 ++++++++++++++++++- electrum/gui/qml/qeconfig.py | 11 +++ electrum/gui/qml/qewallet.py | 9 +++ electrum/plugins/trustedcoin/qml.py | 41 +++++++++- electrum/plugins/trustedcoin/trustedcoin.py | 5 ++ 5 files changed, 138 insertions(+), 3 deletions(-) diff --git a/electrum/gui/qml/components/WalletDetails.qml b/electrum/gui/qml/components/WalletDetails.qml index cfd159b58..c8113c4a7 100644 --- a/electrum/gui/qml/components/WalletDetails.qml +++ b/electrum/gui/qml/components/WalletDetails.qml @@ -163,13 +163,86 @@ Pane { } } + GridLayout { + visible: Daemon.currentWallet && Daemon.currentWallet.walletType == '2fa' + Layout.preferredWidth: parent.width + + columns: 2 + + Label { + text: qsTr('2FA') + color: Material.accentColor + } + + Label { + Layout.fillWidth: true + text: Daemon.currentWallet.canSignWithoutServer + ? qsTr('disabled (can sign without server') + : qsTr('enabled') + } + + Label { + visible: !Daemon.currentWallet.canSignWithoutServer + text: qsTr('Remaining TX') + color: Material.accentColor + } + + Label { + Layout.fillWidth: true + visible: !Daemon.currentWallet.canSignWithoutServer + text: 'tx_remaining' in Daemon.currentWallet.billingInfo + ? Daemon.currentWallet.billingInfo['tx_remaining'] + : qsTr('unknown') + } + + Label { + Layout.columnSpan: 2 + visible: !Daemon.currentWallet.canSignWithoutServer + text: qsTr('Billing') + color: Material.accentColor + } + + ColumnLayout { + Layout.columnSpan: 2 + Layout.leftMargin: constants.paddingMedium + spacing: 0 + + ButtonGroup { + id: billinggroup + onCheckedButtonChanged: { + Config.trustedcoinPrepay = checkedButton.value + } + } + + Repeater { + model: AppController.plugin('trustedcoin').billingModel + delegate: RowLayout { + RadioButton { + ButtonGroup.group: billinggroup + property string value: modelData.value + text: modelData.text + checked: modelData.value == Config.trustedcoinPrepay + } + Label { + text: Config.formatSats(modelData.sats_per_tx) + font.family: FixedFont + } + Label { + text: Config.baseUnit + '/tx' + color: Material.accentColor + } + } + } + } + + } + GridLayout { id: detailsLayout visible: Daemon.currentWallet Layout.preferredWidth: parent.width columns: 2 - Label { text: qsTr('Derivation prefix') visible: Daemon.currentWallet.isDeterministic diff --git a/electrum/gui/qml/qeconfig.py b/electrum/gui/qml/qeconfig.py index c5e71c8a5..4580bdb10 100644 --- a/electrum/gui/qml/qeconfig.py +++ b/electrum/gui/qml/qeconfig.py @@ -166,6 +166,17 @@ class QEConfig(AuthMixin, QObject): self.config.set_key('use_recoverable_channels', useRecoverableChannels) self.useRecoverableChannelsChanged.emit() + trustedcoinPrepayChanged = pyqtSignal() + @pyqtProperty(int, notify=trustedcoinPrepayChanged) + def trustedcoinPrepay(self): + return self.config.get('trustedcoin_prepay', 20) + + @trustedcoinPrepay.setter + def trustedcoinPrepay(self, num_prepay): + if num_prepay != self.config.get('trustedcoin_prepay', 20): + self.config.set_key('trustedcoin_prepay', num_prepay) + self.trustedcoinPrepayChanged.emit() + @pyqtSlot('qint64', result=str) @pyqtSlot('qint64', bool, result=str) @pyqtSlot(QEAmount, result=str) diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py index a24b115e5..2634966b2 100644 --- a/electrum/gui/qml/qewallet.py +++ b/electrum/gui/qml/qewallet.py @@ -301,6 +301,11 @@ class QEWallet(AuthMixin, QObject, QtEventListener): def isLightning(self): return bool(self.wallet.lnworker) + billingInfoChanged = pyqtSignal() + @pyqtProperty('QVariantMap', notify=billingInfoChanged) + def billingInfo(self): + return {} if self.wallet.wallet_type != '2fa' else self.wallet.billing_info + @pyqtProperty(bool, notify=dataChanged) def canHaveLightning(self): return self.wallet.can_have_lightning() @@ -349,6 +354,10 @@ class QEWallet(AuthMixin, QObject, QtEventListener): def masterPubkey(self): return self.wallet.get_master_public_key() + @pyqtProperty(bool, notify=dataChanged) + def canSignWithoutServer(self): + return self.wallet.can_sign_without_server() if self.wallet.wallet_type == '2fa' else True + balanceChanged = pyqtSignal() @pyqtProperty(QEAmount, notify=balanceChanged) diff --git a/electrum/plugins/trustedcoin/qml.py b/electrum/plugins/trustedcoin/qml.py index 85b7e11b0..da6c65324 100644 --- a/electrum/plugins/trustedcoin/qml.py +++ b/electrum/plugins/trustedcoin/qml.py @@ -39,6 +39,8 @@ class Plugin(TrustedCoinPlugin): _otpSecret = '' shortIdChanged = pyqtSignal() _shortId = '' + billingModelChanged = pyqtSignal() + _billingModel = [] _remoteKeyState = '' remoteKeyStateChanged = pyqtSignal() @@ -91,6 +93,27 @@ class Plugin(TrustedCoinPlugin): self._remoteKeyState = new_state self.remoteKeyStateChanged.emit() + @pyqtProperty('QVariantList', notify=billingModelChanged) + def billingModel(self): + return self._billingModel + + def updateBillingInfo(self, wallet): + billingModel = [] + + price_per_tx = wallet.price_per_tx + for k, v in sorted(price_per_tx.items()): + if k == 1: + continue + item = { + 'text': 'Pay every %d transactions' % k, + 'value': k, + 'sats_per_tx': v/k + } + billingModel.append(item) + + self._billingModel = billingModel + self.billingModelChanged.emit() + @pyqtSlot() def fetchTermsAndConditions(self): def fetch_task(): @@ -274,6 +297,8 @@ class Plugin(TrustedCoinPlugin): # extend wizard self.extend_wizard() + # wizard support functions + def extend_wizard(self): wizard = self._app.daemon.newWalletWizard self.logger.debug(repr(wizard)) @@ -367,7 +392,7 @@ class Plugin(TrustedCoinPlugin): wizard_data['x3/'] = k3.dump() - # regular wallet prompt functions + # running wallet functions def prompt_user_for_otp(self, wallet, tx, on_success, on_failure): self.logger.debug('prompt_user_for_otp') @@ -379,7 +404,12 @@ class Plugin(TrustedCoinPlugin): qewallet.request_otp(self.on_otp) def on_otp(self, otp): + if not otp: + self.on_failure(_('No auth code')) + return + self.logger.debug(f'on_otp {otp} for tx {repr(self.tx)}') + try: self.wallet.on_otp(self.tx, otp) except UserFacingException as e: @@ -388,8 +418,15 @@ class Plugin(TrustedCoinPlugin): if e.status_code == 400: # invalid OTP self.on_failure(_('Invalid one-time password.')) else: - self.on_failure(_('Error') + ':\n' + str(e)) + self.on_failure(_('Service Error') + ':\n' + str(e)) except Exception as e: self.on_failure(_('Error') + ':\n' + str(e)) else: self.on_success(self.tx) + + def billing_info_retrieved(self, wallet): + self.logger.info('billing_info_retrieved') + qewallet = QEWallet.getInstanceFor(wallet) + qewallet.billingInfoChanged.emit() + self.so.updateBillingInfo(wallet) + diff --git a/electrum/plugins/trustedcoin/trustedcoin.py b/electrum/plugins/trustedcoin/trustedcoin.py index 34a1be886..20954c204 100644 --- a/electrum/plugins/trustedcoin/trustedcoin.py +++ b/electrum/plugins/trustedcoin/trustedcoin.py @@ -519,8 +519,13 @@ class TrustedCoinPlugin(BasePlugin): wallet.billing_info = billing_info wallet.price_per_tx = dict(billing_info['price_per_tx']) wallet.price_per_tx.pop(1, None) + self.billing_info_retrieved(wallet) return True + def billing_info_retrieved(self, wallet): + # override to handle billing info when it becomes available + pass + def start_request_thread(self, wallet): from threading import Thread if self.requesting is False: