Merge pull request #9800 from accumulator/psbt_nostr_qml_choices
Psbt nostr qml choices
This commit is contained in:
@@ -36,14 +36,12 @@ from electrum.util import EventListener, event_listener
|
|||||||
|
|
||||||
from electrum.gui.qml.qewallet import QEWallet
|
from electrum.gui.qml.qewallet import QEWallet
|
||||||
|
|
||||||
from .psbt_nostr import PsbtNostrPlugin, CosignerWallet, now
|
from .psbt_nostr import PsbtNostrPlugin, CosignerWallet
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from electrum.wallet import Abstract_Wallet
|
from electrum.wallet import Abstract_Wallet
|
||||||
from electrum.gui.qml import ElectrumQmlApplication
|
from electrum.gui.qml import ElectrumQmlApplication
|
||||||
|
|
||||||
USER_PROMPT_COOLDOWN = 10
|
|
||||||
|
|
||||||
|
|
||||||
class QReceiveSignalObject(QObject):
|
class QReceiveSignalObject(QObject):
|
||||||
def __init__(self, plugin: 'Plugin'):
|
def __init__(self, plugin: 'Plugin'):
|
||||||
@@ -73,12 +71,23 @@ class QReceiveSignalObject(QObject):
|
|||||||
return
|
return
|
||||||
cosigner_wallet.send_psbt(tx_from_any(tx, deserialize=True), label)
|
cosigner_wallet.send_psbt(tx_from_any(tx, deserialize=True), label)
|
||||||
|
|
||||||
@pyqtSlot(QEWallet, str)
|
@pyqtSlot(QEWallet, str, str)
|
||||||
def acceptPsbt(self, wallet: 'QEWallet', event_id: str):
|
def saveTxLabel(self, wallet: 'QEWallet', tx: str, label: str):
|
||||||
cosigner_wallet = self._plugin.cosigner_wallets.get(wallet.wallet)
|
cosigner_wallet = self._plugin.cosigner_wallets.get(wallet.wallet)
|
||||||
if not cosigner_wallet:
|
if not cosigner_wallet:
|
||||||
return
|
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)
|
@pyqtSlot(QEWallet, str)
|
||||||
def rejectPsbt(self, wallet: 'QEWallet', event_id: str):
|
def rejectPsbt(self, wallet: 'QEWallet', event_id: str):
|
||||||
@@ -124,17 +133,12 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
|
|||||||
self.register_callbacks()
|
self.register_callbacks()
|
||||||
|
|
||||||
self.tx = None
|
self.tx = None
|
||||||
self.user_prompt_cooldown = None
|
|
||||||
|
|
||||||
@event_listener
|
@event_listener
|
||||||
def on_event_psbt_nostr_received(self, wallet, pubkey, event_id, tx: 'PartialTransaction', label: str):
|
def on_event_psbt_nostr_received(self, wallet, pubkey, event_id, tx: 'PartialTransaction', label: str):
|
||||||
if self.wallet == wallet:
|
if self.wallet == wallet:
|
||||||
self.tx = tx
|
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)
|
||||||
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)
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
super().close()
|
super().close()
|
||||||
@@ -158,13 +162,16 @@ class QmlCosignerWallet(EventListener, CosignerWallet):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.plugin.so.sendPsbtFailed.emit(str(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)
|
self.mark_pending_event_rcvd(event_id)
|
||||||
|
|
||||||
def reject_psbt(self, event_id):
|
def reject_psbt(self, event_id):
|
||||||
self.user_prompt_cooldown = now() + USER_PROMPT_COOLDOWN
|
|
||||||
self.mark_pending_event_rcvd(event_id)
|
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):
|
def on_add_fail(self):
|
||||||
self.logger.error('failed to add tx to wallet')
|
self.logger.error('failed to add tx to wallet')
|
||||||
|
|||||||
91
electrum/plugins/psbt_nostr/qml/PsbtReceiveDialog.qml
Normal file
91
electrum/plugins/psbt_nostr/qml/PsbtReceiveDialog.qml
Normal file
@@ -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: <br/><b>%1</b><br/>').arg(tx_label)
|
||||||
|
: qsTr('A transaction was received from your cosigner.'),
|
||||||
|
qsTr('Do you want to open it now?')
|
||||||
|
].join('<br/>')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,23 +8,25 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: AppController ? AppController.plugin('psbt_nostr') : null
|
target: AppController ? AppController.plugin('psbt_nostr') : null
|
||||||
function onCosignerReceivedPsbt(pubkey, event, tx, label) {
|
function onCosignerReceivedPsbt(pubkey, event, tx, label) {
|
||||||
var dialog = app.messageDialog.createObject(app, {
|
var dialog = psbtReceiveDialog.createObject(app, {
|
||||||
text: [
|
tx_label: label
|
||||||
label
|
|
||||||
? qsTr('A transaction was received from your cosigner with label: <br/><br/><b>%1</b>').arg(label)
|
|
||||||
: qsTr('A transaction was received from your cosigner.'),
|
|
||||||
qsTr('Do you want to open it now?')
|
|
||||||
].join('<br/><br/>'),
|
|
||||||
yesno: true,
|
|
||||||
richText: true
|
|
||||||
})
|
})
|
||||||
dialog.accepted.connect(function () {
|
dialog.accepted.connect(function () {
|
||||||
var page = app.stack.push(Qt.resolvedUrl('../../../gui/qml/components/TxDetails.qml'), {
|
if (dialog.choice == PsbtReceiveDialog.Choice.Open) {
|
||||||
rawtx: tx
|
console.log('label:' + label)
|
||||||
})
|
console.log('tx:' + tx)
|
||||||
page.closed.connect(function () {
|
target.saveTxLabel(Daemon.currentWallet, tx, label)
|
||||||
target.acceptPsbt(Daemon.currentWallet, event)
|
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 () {
|
dialog.rejected.connect(function () {
|
||||||
target.rejectPsbt(Daemon.currentWallet, event)
|
target.rejectPsbt(Daemon.currentWallet, event)
|
||||||
@@ -33,6 +35,13 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: psbtReceiveDialog
|
||||||
|
PsbtReceiveDialog {
|
||||||
|
onClosed: destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property variant export_tx_button: Component {
|
property variant export_tx_button: Component {
|
||||||
FlatButton {
|
FlatButton {
|
||||||
id: psbt_nostr_send_button
|
id: psbt_nostr_send_button
|
||||||
|
|||||||
Reference in New Issue
Block a user