Browse Source

Merge JoinMarket-Org/joinmarket-clientserver#1016: Improve the UX of Open Wallet dialog

c706c6e1e9 Improve the UX of open wallet dialog. (Wukong)

Pull request description:

  This PR addresses the first two items in the "Next step improvements" of #932:

  1. Show all the error messages, like "Wrong Password", "File not exist", "Invalid wallet file" etc., within the same dialog, and allow the user to make changes to their decisions in the same dialog when these errors occur.

  ![image](https://user-images.githubusercontent.com/87334822/132820190-1cbbf5fd-4d14-4317-a287-3aec378c4a41.png)

  ![image](https://user-images.githubusercontent.com/87334822/132820240-0a98e50a-43fe-4449-89e6-093af1f3533c.png)

  2. Update the UX of menu action "Wallet -> Load" to also use this new Open Wallet dialog.
  In this update, I also renamed the current menu item "Load" to "Open", and added a shortcut "Ctrl+O" for this menu item, which I believe is more consistent with the expectation of the UI from most users.

ACKs for top commit:
  kristapsk:
    re-ACK c706c6e1e9

Tree-SHA512: 3d953234034859d82f06ac018eb484024272eba58397598a014cbad1faf099ffe4ac28d661e3649c17e77bb26ba9cb7af9433a5bdd856023f61192aba5d1f2e6
master
Kristaps Kaupe 4 years ago
parent
commit
1423fe389e
No known key found for this signature in database
GPG Key ID: 33E472FE870C7E5D
  1. 31
      jmqtui/jmqtui/open_wallet_dialog.py
  2. 63
      jmqtui/jmqtui/open_wallet_dialog.ui
  3. 68
      scripts/joinmarket-qt.py

31
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

63
jmqtui/jmqtui/open_wallet_dialog.ui

@ -25,7 +25,7 @@
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1,0">
<property name="spacing">
<number>10</number>
</property>
@ -145,6 +145,63 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="errorMessageLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>239</red>
<green>41</green>
<blue>41</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>239</red>
<green>41</green>
<blue>41</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>190</red>
<green>190</green>
<blue>190</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@ -194,9 +251,9 @@
</layout>
</widget>
<tabstops>
<tabstop>passphraseEdit</tabstop>
<tabstop>chooseWalletButton</tabstop>
<tabstop>walletFileEdit</tabstop>
<tabstop>chooseWalletButton</tabstop>
<tabstop>passphraseEdit</tabstop>
</tabstops>
<resources/>
<connections>

68
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_())

Loading…
Cancel
Save