From 9886553865fc9c4380a14d6bf9111d0e3be21f65 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Thu, 24 Sep 2020 17:09:47 +0100 Subject: [PATCH] Adds close button to BIP78 receiver dialog Prior to this commit, the cancel button remained activated when the BIP78 payjoin processing had completed, either successfully or unsuccessfully which could be confusing for the user. After this commit, when the processing is complete, the JMBIP78ReceiverManager object fires the shutdown callback, which Qt uses to signal the dialog, which then updates to disable the Cancel button and show the Close button. Additionally, line breaks were added to make tooltips more readable. --- jmclient/jmclient/payjoin.py | 10 ++++++++-- scripts/joinmarket-qt.py | 1 + scripts/qtsupport.py | 34 ++++++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/jmclient/jmclient/payjoin.py b/jmclient/jmclient/payjoin.py index 551c0b3..d3d0952 100644 --- a/jmclient/jmclient/payjoin.py +++ b/jmclient/jmclient/payjoin.py @@ -1043,7 +1043,8 @@ class JMBIP78ReceiverManager(object): """ A class to encapsulate receiver construction """ def __init__(self, wallet_service, mixdepth, amount, port, - info_callback=None, uri_created_callback = None, + info_callback=None, uri_created_callback=None, + shutdown_callback=None, mode="command-line"): assert isinstance(wallet_service, WalletService) assert isinstance(mixdepth, int) @@ -1068,6 +1069,9 @@ class JMBIP78ReceiverManager(object): self.uri_created_callback = self.info_callback else: self.uri_created_callback = uri_created_callback + # This callback used by GUI as a signal that it can + # signal the user that the dialog is close-able: + self.shutdown_callback = shutdown_callback self.receiving_address = None self.mode = mode @@ -1157,4 +1161,6 @@ class JMBIP78ReceiverManager(object): def shutdown(self): self.tor_connection.protocol.transport.loseConnection() process_shutdown(self.mode) - self.info_callback("Hidden service shutdown complete") \ No newline at end of file + self.info_callback("Hidden service shutdown complete") + if self.shutdown_callback: + self.shutdown_callback() diff --git a/scripts/joinmarket-qt.py b/scripts/joinmarket-qt.py index 94e553c..6bf3d5f 100755 --- a/scripts/joinmarket-qt.py +++ b/scripts/joinmarket-qt.py @@ -1571,6 +1571,7 @@ class JMMainWindow(QMainWindow): self.backend_receiver = JMBIP78ReceiverManager(self.wallet_service, mixdepth, amount, 80, self.receiver_bip78_dialog.info_update, uri_created_callback=self.receiver_bip78_dialog.update_uri, + shutdown_callback=self.receiver_bip78_dialog.process_complete, mode="gui") self.backend_receiver.start_pj_server_and_tor() return True diff --git a/scripts/qtsupport.py b/scripts/qtsupport.py index 3260298..030d0b4 100644 --- a/scripts/qtsupport.py +++ b/scripts/qtsupport.py @@ -948,8 +948,8 @@ class ReceiveBIP78Dialog(QDialog): parameter_names = ['Amount to receive', 'Mixdepth'] parameter_tooltips = [ "How much you should receive (after any fees) in BTC or sats.", - "The mixdepth you source coins from to create inputs for the " - "payjoin. Note your receiving address will be chosen from the " + "The mixdepth you source coins from to create inputs for the\n" + "payjoin. Note your receiving address will be chosen from the\n" "*next* mixdepth after this (or 0 if last)."] parameter_types = ["btc", int] parameter_settings = ["", 0] @@ -1007,6 +1007,16 @@ class ReceiveBIP78Dialog(QDialog): self.cancel_fn() self.close() + def process_complete(self): + """ Called by the owning Qt object + when the BIP78 workflow is complete, + whether successful or not. + """ + # Give user indication that they + # can quit without cancelling: + self.close_btn.setVisible(True) + self.btnbox.button(QDialogButtonBox.Cancel).setDisabled(True) + def start_generate(self): """ Before starting up the hidden service and initiating the payment @@ -1015,9 +1025,9 @@ class ReceiveBIP78Dialog(QDialog): If the 'start generate request' action is aborted, we reset the generate button. """ - self.btnbox.buttons()[1].setDisabled(True) + self.generate_btn.setDisabled(True) if not self.action_fn(): - self.btnbox.buttons()[1].setDisabled(False) + self.generate_btn.setDisabled(False) def get_receive_bip78_dialog(self): """ Displays editable parameters and @@ -1062,12 +1072,20 @@ class ReceiveBIP78Dialog(QDialog): layout.addWidget(self.updates_label, i+2, 0, 1, 2) layout.addWidget(self.bip21_widget, i+3, 0, 1, 2) - # Buttons for start/cancel: + # Buttons for start/cancel/close: self.btnbox = QDialogButtonBox() self.btnbox.setStandardButtons(QDialogButtonBox.Cancel) - btnname = "Generate request" - self.btnbox.addButton(btnname, QDialogButtonBox.ActionRole) + self.generate_btn = self.btnbox.addButton("&Generate request", + QDialogButtonBox.ActionRole) + self.close_btn = self.btnbox.addButton("C&lose", + QDialogButtonBox.AcceptRole) + self.close_btn.setVisible(False) layout.addWidget(self.btnbox, i+4, 0) + # note that we don't use a standard 'Close' button because + # it is also associated with 'rejection' (and we don't use "OK" because + # concept doesn't quite fit here: self.btnbox.rejected.connect(self.shutdown_actions) - self.btnbox.buttons()[1].clicked.connect(self.start_generate) + self.generate_btn.clicked.connect(self.start_generate) + # does not trigger cancel_fn callback: + self.close_btn.clicked.connect(self.close) return layout