diff --git a/electrum/gui/qml/components/ExportTxDialog.qml b/electrum/gui/qml/components/ExportTxDialog.qml index 0db305af4..8a555727f 100644 --- a/electrum/gui/qml/components/ExportTxDialog.qml +++ b/electrum/gui/qml/components/ExportTxDialog.qml @@ -8,9 +8,7 @@ import "controls" ElDialog { id: dialog - property QtObject txdetails - - property string text + required property string text property string text_qr // if text_qr is undefined text will be used property string text_help @@ -97,9 +95,4 @@ ElDialog { } } } - - Component.onCompleted: { - text = dialog.txdetails.serializedTx(false) - text_qr = dialog.txdetails.serializedTx(true) - } } diff --git a/electrum/gui/qml/components/TxDetails.qml b/electrum/gui/qml/components/TxDetails.qml index 3561b3516..8f61e901a 100644 --- a/electrum/gui/qml/components/TxDetails.qml +++ b/electrum/gui/qml/components/TxDetails.qml @@ -24,14 +24,6 @@ Pane { app.stack.pop() } - function showExport(helptext) { - var dialog = exportTxDialog.createObject(root, { - txdetails: txdetails, - text_help: helptext - }) - dialog.open() - } - ColumnLayout { anchors.fill: parent spacing: 0 @@ -378,9 +370,24 @@ Pane { Layout.preferredWidth: 1 icon.source: '../../icons/qrcode_white.png' text: qsTr('Share') + enabled: !txdetails.isUnrelated onClicked: { - var dialog = exportTxDialog.createObject(root, { txdetails: txdetails }) - dialog.open() + var msg = '' + if (txdetails.isComplete) { + // TODO: iff offline wallet? + // TODO: or also if just temporarily offline? + msg = qsTr('This transaction is complete. Please share it with an online device') + } else if (txdetails.wallet.isWatchOnly) { + msg = qsTr('This transaction should be signed. Present this QR code to the signing device') + } else if (txdetails.wallet.isMultisig && txdetails.wallet.walletType != '2fa') { + if (txdetails.canSign) { + msg = qsTr('Note: this wallet can sign, but has not signed this transaction yet') + } else { + msg = qsTr('Transaction is partially signed by this wallet. Present this QR code to the next co-signer') + } + } + + app.stack.getRoot().showExport(txdetails.getSerializedTx(false), txdetails.getSerializedTx(true), msg) } } @@ -522,10 +529,4 @@ Pane { } } - Component { - id: exportTxDialog - ExportTxDialog { - onClosed: destroy() - } - } } diff --git a/electrum/gui/qml/components/WalletMainView.qml b/electrum/gui/qml/components/WalletMainView.qml index 91f008575..a6c12bf65 100644 --- a/electrum/gui/qml/components/WalletMainView.qml +++ b/electrum/gui/qml/components/WalletMainView.qml @@ -50,6 +50,19 @@ Item { } } + function showExportByTxid(txid, helptext) { + showExport(Daemon.currentWallet.getSerializedTx(txid, false), Daemon.currentWallet.getSerializedTx(txid, true), helptext) + } + + function showExport(data, data_qr, helptext) { + var dialog = exportTxDialog.createObject(app, { + text: data, + text_qr: data_qr, + text_help: helptext + }) + dialog.open() + } + property QtObject menu: Menu { parent: Overlay.overlay dim: true @@ -251,7 +264,7 @@ Item { if (code == 'ln') { var dialog = app.messageDialog.createObject(app, {text: error, yesno: true}) dialog.yesClicked.connect(function() { - createRequest(true, false) + createRequest(true, false) }) } else if (code == 'reuse_addr') { var dialog = app.messageDialog.createObject(app, {text: error, yesno: true}) @@ -287,6 +300,8 @@ Item { Component { id: invoiceDialog InvoiceDialog { + id: _invoiceDialog + width: parent.width height: parent.height @@ -300,7 +315,11 @@ Item { var canComplete = !Daemon.currentWallet.isWatchOnly && Daemon.currentWallet.canSignWithoutCosigner dialog.txaccepted.connect(function() { if (!canComplete) { - dialog.finalizer.signAndSave() + if (Daemon.currentWallet.isWatchOnly) { + dialog.finalizer.save() + } else { + dialog.finalizer.signAndSave() + } } else { dialog.finalizer.signAndSend() } @@ -317,6 +336,13 @@ Item { } onClosed: destroy() + + Connections { + target: Daemon.currentWallet + function onSaveTxSuccess(txid) { + _invoiceDialog.close() + } + } } } @@ -371,7 +397,7 @@ Item { console.log('rejected') } onClosed: destroy() - } + } } Component { @@ -393,9 +419,13 @@ Item { wallet: Daemon.currentWallet canRbf: true onFinishedSave: { - // tx was (partially) signed and saved. Show QR for co-signers or online wallet - var page = app.stack.push(Qt.resolvedUrl('TxDetails.qml'), { txid: txid }) - page.showExport(qsTr('Transaction created and partially signed by this wallet. Present this QR code to the next co-signer')) + if (wallet.isWatchOnly) { + // tx was saved. Show QR for signer(s) + showExportByTxid(txid, qsTr('Transaction created. Present this QR code to the signing device')) + } else { + // tx was (partially) signed and saved. Show QR for co-signers or online wallet + showExportByTxid(txid, qsTr('Transaction created and partially signed by this wallet. Present this QR code to the next co-signer')) + } _confirmPaymentDialog.destroy() } } @@ -432,5 +462,13 @@ Item { onClosed: destroy() } } + + Component { + id: exportTxDialog + ExportTxDialog { + onClosed: destroy() + } + } + } diff --git a/electrum/gui/qml/qetxdetails.py b/electrum/gui/qml/qetxdetails.py index d4a7e82c9..397db4ba8 100644 --- a/electrum/gui/qml/qetxdetails.py +++ b/electrum/gui/qml/qetxdetails.py @@ -393,8 +393,9 @@ class QETxDetails(QObject, QtEventListener): @pyqtSlot(result=str) @pyqtSlot(bool, result=str) - def serializedTx(self, for_qr=False): + def getSerializedTx(self, for_qr=False): + tx = self._tx if for_qr: - return self._tx.to_qr_data() + return tx.to_qr_data() else: - return str(self._tx) + return str(tx) diff --git a/electrum/gui/qml/qetxfinalizer.py b/electrum/gui/qml/qetxfinalizer.py index 2a53f2416..62b0d8493 100644 --- a/electrum/gui/qml/qetxfinalizer.py +++ b/electrum/gui/qml/qetxfinalizer.py @@ -341,6 +341,15 @@ class QETxFinalizer(TxFeeSlider): self._valid = True self.validChanged.emit() + @pyqtSlot() + def save(self): + if not self._valid or not self._tx: + self._logger.debug('no valid tx') + return + + if self._wallet.save_tx(self._tx): + self.finishedSave.emit(self._tx.txid()) + @pyqtSlot() def signAndSend(self): if not self._valid or not self._tx: @@ -379,18 +388,10 @@ class QETxFinalizer(TxFeeSlider): self._logger.debug('onSigned') self._wallet.transactionSigned.disconnect(self.onSigned) - if not self._wallet.wallet.adb.add_transaction(self._tx): + if not self._wallet.save_tx(self._tx): self._logger.error('Could not save tx') - - self.finishedSave.emit(self._tx.txid()) - - @pyqtSlot(result=str) - @pyqtSlot(bool, result=str) - def serializedTx(self, for_qr=False): - if for_qr: - return self._tx.to_qr_data() else: - return str(self._tx) + self.finishedSave.emit(self._tx.txid()) # mixin for watching an existing TX based on its txid for verified event # requires self._wallet to contain a QEWallet instance diff --git a/electrum/gui/qml/qewallet.py b/electrum/gui/qml/qewallet.py index 20789e020..9e8011448 100644 --- a/electrum/gui/qml/qewallet.py +++ b/electrum/gui/qml/qewallet.py @@ -328,6 +328,10 @@ class QEWallet(AuthMixin, QObject, QtEventListener): def walletType(self): return self.wallet.wallet_type + @pyqtProperty(bool, notify=dataChanged) + def isMultisig(self): + return isinstance(self.wallet, Multisig_Wallet) + @pyqtProperty(bool, notify=dataChanged) def hasSeed(self): return self.wallet.has_seed() @@ -723,3 +727,12 @@ class QEWallet(AuthMixin, QObject, QtEventListener): self._seed = '' self.dataChanged.emit() + + @pyqtSlot(str, result=str) + @pyqtSlot(str, bool, result=str) + def getSerializedTx(self, txid, for_qr=False): + tx = self.wallet.db.get_transaction(txid) + if for_qr: + return tx.to_qr_data() + else: + return str(tx)