From c706c6e1e9cbe7a89b04a7d01ab0907cd0ab880a Mon Sep 17 00:00:00 2001 From: Wukong Date: Fri, 10 Sep 2021 00:13:54 -0700 Subject: [PATCH] Improve the UX of open wallet dialog. When open wallet from menu, also use the JMOpenWalletDialog to handle the workflow Create a new "errorMessageLabel" in the OpenWalletDialog, and show the error message in this new label instead of in a separate message box popup. Auto focus on passphraseEdit when OpenWalletDialog is launched, and when a wallet file has been chosen --- jmqtui/jmqtui/open_wallet_dialog.py | 31 +++++++++++-- jmqtui/jmqtui/open_wallet_dialog.ui | 63 ++++++++++++++++++++++++-- scripts/joinmarket-qt.py | 68 +++++++++++++++++------------ 3 files changed, 129 insertions(+), 33 deletions(-) diff --git a/jmqtui/jmqtui/open_wallet_dialog.py b/jmqtui/jmqtui/open_wallet_dialog.py index ebdbb8e..bfaafce 100644 --- a/jmqtui/jmqtui/open_wallet_dialog.py +++ b/jmqtui/jmqtui/open_wallet_dialog.py @@ -92,6 +92,30 @@ class Ui_OpenWalletDialog(object): self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout_4 = QHBoxLayout() + self.horizontalLayout_4.setSpacing(10) + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.errorMessageLabel = QLabel(OpenWalletDialog) + self.errorMessageLabel.setObjectName(u"errorMessageLabel") + palette = QPalette() + brush = QBrush(QColor(239, 41, 41, 255)) + brush.setStyle(Qt.SolidPattern) + palette.setBrush(QPalette.Active, QPalette.WindowText, brush) + palette.setBrush(QPalette.Inactive, QPalette.WindowText, brush) + brush1 = QBrush(QColor(190, 190, 190, 255)) + brush1.setStyle(Qt.SolidPattern) + palette.setBrush(QPalette.Disabled, QPalette.WindowText, brush1) + self.errorMessageLabel.setPalette(palette) + font = QFont() + font.setBold(True) + font.setWeight(75) + self.errorMessageLabel.setFont(font) + + self.horizontalLayout_4.addWidget(self.errorMessageLabel) + + + self.verticalLayout.addLayout(self.horizontalLayout_4) + self.verticalSpacer = QSpacerItem(20, 150, QSizePolicy.Minimum, QSizePolicy.Minimum) self.verticalLayout.addItem(self.verticalSpacer) @@ -114,9 +138,9 @@ class Ui_OpenWalletDialog(object): self.verticalLayout.addLayout(self.horizontalLayout_3) - self.verticalLayout.setStretch(2, 1) - QWidget.setTabOrder(self.passphraseEdit, self.chooseWalletButton) - QWidget.setTabOrder(self.chooseWalletButton, self.walletFileEdit) + self.verticalLayout.setStretch(3, 1) + QWidget.setTabOrder(self.walletFileEdit, self.chooseWalletButton) + QWidget.setTabOrder(self.chooseWalletButton, self.passphraseEdit) self.retranslateUi(OpenWalletDialog) self.buttonBox.accepted.connect(OpenWalletDialog.accept) @@ -132,5 +156,6 @@ class Ui_OpenWalletDialog(object): self.walletFileEdit.setPlaceholderText("") self.chooseWalletButton.setText(QCoreApplication.translate("OpenWalletDialog", u"Choose...", None)) self.label_2.setText(QCoreApplication.translate("OpenWalletDialog", u"Passphrase:", None)) + self.errorMessageLabel.setText("") # retranslateUi diff --git a/jmqtui/jmqtui/open_wallet_dialog.ui b/jmqtui/jmqtui/open_wallet_dialog.ui index 06335af..65b3b2c 100644 --- a/jmqtui/jmqtui/open_wallet_dialog.ui +++ b/jmqtui/jmqtui/open_wallet_dialog.ui @@ -25,7 +25,7 @@ true - + 10 @@ -145,6 +145,63 @@ + + + + 10 + + + + + + + + + + 239 + 41 + 41 + + + + + + + + + 239 + 41 + 41 + + + + + + + + + 190 + 190 + 190 + + + + + + + + + 75 + true + + + + + + + + + @@ -194,9 +251,9 @@ - passphraseEdit - chooseWalletButton walletFileEdit + chooseWalletButton + passphraseEdit diff --git a/scripts/joinmarket-qt.py b/scripts/joinmarket-qt.py index 3fa6d4c..61e04dd 100755 --- a/scripts/joinmarket-qt.py +++ b/scripts/joinmarket-qt.py @@ -114,6 +114,7 @@ class JMOpenWalletDialog(QDialog, Ui_OpenWalletDialog): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) + self.passphraseEdit.setFocus() self.chooseWalletButton.clicked.connect(self.chooseWalletFile) @@ -125,6 +126,7 @@ class JMOpenWalletDialog(QDialog, Ui_OpenWalletDialog): options=QFileDialog.DontUseNativeDialog) if filename: self.walletFileEdit.setText(filename) + self.passphraseEdit.setFocus() class HelpLabel(QLabel): @@ -1635,9 +1637,10 @@ class JMMainWindow(QMainWindow): def initUI(self): self.statusBar().showMessage("Ready") self.setGeometry(300, 300, 250, 150) - loadAction = QAction('&Load...', self) - loadAction.setStatusTip('Load wallet from file') - loadAction.triggered.connect(self.selectWallet) + openWalletAction = QAction('&Open...', self) + openWalletAction.setStatusTip('Open JoinMarket wallet file') + openWalletAction.setShortcut(QKeySequence.Open) + openWalletAction.triggered.connect(self.openWallet) generateAction = QAction('&Generate...', self) generateAction.setStatusTip('Generate new wallet') generateAction.triggered.connect(self.generateWallet) @@ -1657,7 +1660,7 @@ class JMMainWindow(QMainWindow): receivePayjoinAction.setStatusTip('Receive BIP78 style payment') receivePayjoinAction.triggered.connect(self.receiver_bip78_init) quitAction = QAction(QIcon('exit.png'), '&Quit', self) - quitAction.setShortcut('Ctrl+Q') + quitAction.setShortcut(QKeySequence.Quit) quitAction.setStatusTip('Quit application') quitAction.triggered.connect(qApp.quit) @@ -1666,7 +1669,7 @@ class JMMainWindow(QMainWindow): menubar = self.menuBar() walletMenu = menubar.addMenu('&Wallet') - walletMenu.addAction(loadAction) + walletMenu.addAction(openWalletAction) walletMenu.addAction(generateAction) walletMenu.addAction(recoverAction) walletMenu.addAction(showSeedAction) @@ -1960,6 +1963,28 @@ class JMMainWindow(QMainWindow): title="Wallet created") self.initWallet(seed=self.walletname) + def openWallet(self): + wallet_loaded = False + wallet_file_text = "wallet.jmdat" + error_text = "" + + while not wallet_loaded: + openWalletDialog = JMOpenWalletDialog() + openWalletDialog.walletFileEdit.setText(wallet_file_text) + openWalletDialog.errorMessageLabel.setText(error_text) + if openWalletDialog.exec_() == QDialog.Accepted: + wallet_file_text = openWalletDialog.walletFileEdit.text() + wallet_path = wallet_file_text + if not os.path.isabs(wallet_path): + wallet_path = os.path.join(jm_single().datadir, 'wallets', wallet_path) + + try: + wallet_loaded = mainWindow.loadWalletFromBlockchain(wallet_path, openWalletDialog.passphraseEdit.text(), rethrow=True) + except Exception as e: + error_text = str(e) + else: + break + def selectWallet(self, testnet_seed=None): if jm_single().config.get("BLOCKCHAIN", "blockchain_source") != "regtest": # guaranteed to exist as load_program_config was called on startup: @@ -2006,7 +2031,7 @@ class JMMainWindow(QMainWindow): #ignore return value as there is no decryption failure possible self.loadWalletFromBlockchain(firstarg, pwd) - def loadWalletFromBlockchain(self, firstarg=None, pwd=None): + def loadWalletFromBlockchain(self, firstarg=None, pwd=None, rethrow=False): if firstarg: wallet_path = get_wallet_path(str(firstarg), None) try: @@ -2014,11 +2039,14 @@ class JMMainWindow(QMainWindow): None, ask_for_password=False, password=pwd.encode('utf-8') if pwd else None, gap_limit=jm_single().config.getint("GUI", "gaplimit")) except RetryableStorageError as e: - JMQtMessageBox(self, - str(e), - mbtype='warn', - title="Error") - return False + if rethrow: + raise e + else: + JMQtMessageBox(self, + str(e), + mbtype='warn', + title="Error") + return False # only used for GUI display on regtest: self.testwalletname = wallet.seed = str(firstarg) if 'listunspent_args' not in jm_single().config.options('POLICY'): @@ -2385,21 +2413,7 @@ tabWidget.currentChanged.connect(onTabChange) mainWindow.show() reactor.runReturn() -# Upon launching the app, allow the user to choose a wallet to open -openWalletDialog = JMOpenWalletDialog() -openWalletDialog.show() - -if openWalletDialog.exec_() == QDialog.Accepted: - wallet_path = openWalletDialog.walletFileEdit.text() - if not os.path.isabs(wallet_path): - wallet_path = os.path.join(jm_single().datadir, 'wallets', wallet_path) - - try: - mainWindow.loadWalletFromBlockchain(wallet_path, openWalletDialog.passphraseEdit.text()) - except Exception as e: - JMQtMessageBox(None, - str(e), - mbtype='warn', - title="Error") +# Upon launching the app, ask the user to choose a wallet to open +mainWindow.openWallet() sys.exit(app.exec_())