diff --git a/electrum/plugins/psbt_nostr/qml.py b/electrum/plugins/psbt_nostr/qml.py
index 46d4ba2fd..7275fc382 100644
--- a/electrum/plugins/psbt_nostr/qml.py
+++ b/electrum/plugins/psbt_nostr/qml.py
@@ -36,14 +36,12 @@ from electrum.util import EventListener, event_listener
from electrum.gui.qml.qewallet import QEWallet
-from .psbt_nostr import PsbtNostrPlugin, CosignerWallet, now
+from .psbt_nostr import PsbtNostrPlugin, CosignerWallet
if TYPE_CHECKING:
from electrum.wallet import Abstract_Wallet
from electrum.gui.qml import ElectrumQmlApplication
-USER_PROMPT_COOLDOWN = 10
-
class QReceiveSignalObject(QObject):
def __init__(self, plugin: 'Plugin'):
@@ -73,12 +71,23 @@ class QReceiveSignalObject(QObject):
return
cosigner_wallet.send_psbt(tx_from_any(tx, deserialize=True), label)
- @pyqtSlot(QEWallet, str)
- def acceptPsbt(self, wallet: 'QEWallet', event_id: str):
+ @pyqtSlot(QEWallet, str, str)
+ def saveTxLabel(self, wallet: 'QEWallet', tx: str, label: str):
cosigner_wallet = self._plugin.cosigner_wallets.get(wallet.wallet)
if not cosigner_wallet:
return
- cosigner_wallet.accept_psbt(event_id)
+ cosigner_wallet.save_tx_label(tx_from_any(tx, deserialize=True), label)
+
+ @pyqtSlot(QEWallet, str)
+ @pyqtSlot(QEWallet, str, bool)
+ def acceptPsbt(self, wallet: 'QEWallet', event_id: str, save_to_wallet: bool = False):
+ cosigner_wallet = self._plugin.cosigner_wallets.get(wallet.wallet)
+ if not cosigner_wallet:
+ return
+ cosigner_wallet.accept_psbt(event_id, save_to_wallet)
+ if save_to_wallet:
+ # let GUI update view through wallet_updated callback
+ util.trigger_callback('wallet_updated', wallet.wallet)
@pyqtSlot(QEWallet, str)
def rejectPsbt(self, wallet: 'QEWallet', event_id: str):
@@ -124,17 +133,12 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
self.register_callbacks()
self.tx = None
- self.user_prompt_cooldown = None
@event_listener
def on_event_psbt_nostr_received(self, wallet, pubkey, event_id, tx: 'PartialTransaction', label: str):
if self.wallet == wallet:
self.tx = tx
- if not (self.user_prompt_cooldown and self.user_prompt_cooldown > now()):
- self.plugin.so.cosignerReceivedPsbt.emit(pubkey, event_id, tx.serialize(), label)
- else:
- self.mark_pending_event_rcvd(event_id)
- self.add_transaction_to_wallet(self.tx, label=label, on_failure=self.on_add_fail)
+ self.plugin.so.cosignerReceivedPsbt.emit(pubkey, event_id, tx.serialize(), label)
def close(self):
super().close()
@@ -158,13 +162,16 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
except Exception as e:
self.plugin.so.sendPsbtFailed.emit(str(e))
- def accept_psbt(self, event_id):
+ def save_tx_label(self, tx, label):
+ self.wallet.set_label(tx.txid(), label)
+
+ def accept_psbt(self, event_id, save: bool = False):
+ if save:
+ self.add_transaction_to_wallet(self.tx, on_failure=self.on_add_fail)
self.mark_pending_event_rcvd(event_id)
def reject_psbt(self, event_id):
- self.user_prompt_cooldown = now() + USER_PROMPT_COOLDOWN
self.mark_pending_event_rcvd(event_id)
- self.add_transaction_to_wallet(self.tx, on_failure=self.on_add_fail)
def on_add_fail(self):
self.logger.error('failed to add tx to wallet')
diff --git a/electrum/plugins/psbt_nostr/qml/PsbtReceiveDialog.qml b/electrum/plugins/psbt_nostr/qml/PsbtReceiveDialog.qml
new file mode 100644
index 000000000..19d1352e4
--- /dev/null
+++ b/electrum/plugins/psbt_nostr/qml/PsbtReceiveDialog.qml
@@ -0,0 +1,91 @@
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+import "../../../gui/qml/components/controls"
+
+ElDialog {
+ id: dialog
+ title: qsTr("PSBT received")
+ iconSource: Qt.resolvedUrl('../../../gui/icons/question.png')
+
+ enum Choice {
+ None,
+ Open,
+ Save
+ }
+
+ property string tx_label
+ property int choice: PsbtReceiveDialog.Choice.None
+
+ // TODO: it might be better to defer popup until no dialogs are shown
+ z: 1 // raise z so it also covers dialogs using overlay as parent
+
+ anchors.centerIn: parent
+
+ padding: 0
+
+ width: rootLayout.width
+
+ ColumnLayout {
+ id: rootLayout
+ width: dialog.parent.width * 2/3
+
+ ColumnLayout {
+ Layout.margins: constants.paddingMedium
+ Layout.fillWidth: true
+
+ TextArea {
+ id: message
+ Layout.fillWidth: true
+ readOnly: true
+ wrapMode: TextInput.WordWrap
+ textFormat: TextEdit.RichText
+ background: Rectangle {
+ color: 'transparent'
+ }
+
+ text: [
+ tx_label
+ ? qsTr('A transaction was received from your cosigner with label:
%1
').arg(tx_label)
+ : qsTr('A transaction was received from your cosigner.'),
+ qsTr('Do you want to open it now?')
+ ].join('
')
+ }
+ }
+
+ ButtonContainer {
+ Layout.fillWidth: true
+
+ FlatButton {
+ Layout.fillWidth: true
+ Layout.preferredWidth: 1
+ text: qsTr('Open')
+ icon.source: Qt.resolvedUrl('../../../gui/icons/confirmed.png')
+ onClicked: {
+ choice = PsbtReceiveDialog.Choice.Open
+ doAccept()
+ }
+ }
+
+ FlatButton {
+ Layout.fillWidth: true
+ Layout.preferredWidth: 1
+ text: qsTr('Discard')
+ icon.source: Qt.resolvedUrl('../../../gui/icons/closebutton.png')
+ onClicked: doReject()
+ }
+ FlatButton {
+ Layout.fillWidth: true
+ Layout.preferredWidth: 1
+ text: qsTr('Save to Wallet')
+ icon.source: Qt.resolvedUrl('../../../gui/icons/wallet.png')
+ onClicked: {
+ choice = PsbtReceiveDialog.Choice.Save
+ doAccept()
+ }
+ }
+ }
+ }
+}
diff --git a/electrum/plugins/psbt_nostr/qml/main.qml b/electrum/plugins/psbt_nostr/qml/main.qml
index 8067d105d..2c2d5f9d6 100644
--- a/electrum/plugins/psbt_nostr/qml/main.qml
+++ b/electrum/plugins/psbt_nostr/qml/main.qml
@@ -8,23 +8,25 @@ Item {
Connections {
target: AppController ? AppController.plugin('psbt_nostr') : null
function onCosignerReceivedPsbt(pubkey, event, tx, label) {
- var dialog = app.messageDialog.createObject(app, {
- text: [
- label
- ? qsTr('A transaction was received from your cosigner with label:
%1').arg(label)
- : qsTr('A transaction was received from your cosigner.'),
- qsTr('Do you want to open it now?')
- ].join('
'),
- yesno: true,
- richText: true
+ var dialog = psbtReceiveDialog.createObject(app, {
+ tx_label: label
})
dialog.accepted.connect(function () {
- var page = app.stack.push(Qt.resolvedUrl('../../../gui/qml/components/TxDetails.qml'), {
- rawtx: tx
- })
- page.closed.connect(function () {
- target.acceptPsbt(Daemon.currentWallet, event)
- })
+ if (dialog.choice == PsbtReceiveDialog.Choice.Open) {
+ console.log('label:' + label)
+ console.log('tx:' + tx)
+ target.saveTxLabel(Daemon.currentWallet, tx, label)
+ var page = app.stack.push(Qt.resolvedUrl('../../../gui/qml/components/TxDetails.qml'), {
+ rawtx: tx
+ })
+ page.closed.connect(function () {
+ target.acceptPsbt(Daemon.currentWallet, event)
+ })
+ } else if (dialog.choice == PsbtReceiveDialog.Choice.Save) {
+ target.acceptPsbt(Daemon.currentWallet, event, true)
+ } else {
+ console.log('choice not set')
+ }
})
dialog.rejected.connect(function () {
target.rejectPsbt(Daemon.currentWallet, event)
@@ -33,6 +35,13 @@ Item {
}
}
+ Component {
+ id: psbtReceiveDialog
+ PsbtReceiveDialog {
+ onClosed: destroy()
+ }
+ }
+
property variant export_tx_button: Component {
FlatButton {
id: psbt_nostr_send_button