mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
Fix issue #6201:
- Pass a proper callback to WalletDialog (we used to call load_wallet_by_name recursively) - Do not cache PasswordDialog instances
This commit is contained in:
parent
dc6dbe5bfb
commit
88bb5309c4
4 changed files with 125 additions and 87 deletions
|
@ -34,7 +34,7 @@ from kivy.clock import Clock
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from kivy.metrics import inch
|
from kivy.metrics import inch
|
||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
from .uix.dialogs.password_dialog import PasswordDialog, PincodeDialog
|
from .uix.dialogs.password_dialog import OpenWalletDialog, ChangePasswordDialog, PincodeDialog
|
||||||
|
|
||||||
## lazy imports for factory so that widgets can be used in kv
|
## lazy imports for factory so that widgets can be used in kv
|
||||||
#Factory.register('InstallWizard', module='electrum.gui.kivy.uix.dialogs.installwizard')
|
#Factory.register('InstallWizard', module='electrum.gui.kivy.uix.dialogs.installwizard')
|
||||||
|
@ -379,8 +379,6 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
# cached dialogs
|
# cached dialogs
|
||||||
self._settings_dialog = None
|
self._settings_dialog = None
|
||||||
self._pincode_dialog = None
|
|
||||||
self._password_dialog = None
|
|
||||||
self._channels_dialog = None
|
self._channels_dialog = None
|
||||||
self._addresses_dialog = None
|
self._addresses_dialog = None
|
||||||
self.fee_status = self.electrum_config.get_fee_status()
|
self.fee_status = self.electrum_config.get_fee_status()
|
||||||
|
@ -635,43 +633,10 @@ class ElectrumWindow(App):
|
||||||
return
|
return
|
||||||
if self.wallet and self.wallet.storage.path == path:
|
if self.wallet and self.wallet.storage.path == path:
|
||||||
return
|
return
|
||||||
wallet = self.daemon.load_wallet(path, None)
|
|
||||||
if wallet:
|
|
||||||
if wallet.has_password():
|
|
||||||
def on_success(x):
|
|
||||||
# save password in memory
|
|
||||||
self.password = x
|
|
||||||
self.load_wallet(wallet)
|
|
||||||
self.password_dialog(
|
|
||||||
basename = wallet.basename(),
|
|
||||||
check_password=wallet.check_password,
|
|
||||||
on_success=on_success,
|
|
||||||
on_failure=self.stop)
|
|
||||||
else:
|
|
||||||
self.load_wallet(wallet)
|
|
||||||
else:
|
else:
|
||||||
def launch_wizard():
|
def launch_wizard():
|
||||||
storage = WalletStorage(path)
|
d = OpenWalletDialog(self, path, self.on_open_wallet)
|
||||||
if not storage.file_exists():
|
d.open()
|
||||||
wizard = Factory.InstallWizard(self.electrum_config, self.plugins)
|
|
||||||
wizard.path = path
|
|
||||||
wizard.bind(on_wizard_complete=self.on_wizard_complete)
|
|
||||||
wizard.run('new')
|
|
||||||
else:
|
|
||||||
if storage.is_encrypted():
|
|
||||||
if not storage.is_encrypted_with_user_pw():
|
|
||||||
raise Exception("Kivy GUI does not support this type of encrypted wallet files.")
|
|
||||||
def on_password(pw):
|
|
||||||
self.password = pw
|
|
||||||
storage.decrypt(pw)
|
|
||||||
self._on_decrypted_storage(storage)
|
|
||||||
self.password_dialog(
|
|
||||||
basename = storage.basename(),
|
|
||||||
check_password=storage.check_password,
|
|
||||||
on_success=on_password,
|
|
||||||
on_failure=self.stop)
|
|
||||||
return
|
|
||||||
self._on_decrypted_storage(storage)
|
|
||||||
if not ask_if_wizard:
|
if not ask_if_wizard:
|
||||||
launch_wizard()
|
launch_wizard()
|
||||||
else:
|
else:
|
||||||
|
@ -685,6 +650,21 @@ class ElectrumWindow(App):
|
||||||
d = Question(_('Do you want to launch the wizard again?'), handle_answer)
|
d = Question(_('Do you want to launch the wizard again?'), handle_answer)
|
||||||
d.open()
|
d.open()
|
||||||
|
|
||||||
|
def on_open_wallet(self, pw, storage):
|
||||||
|
if not storage.file_exists():
|
||||||
|
wizard = Factory.InstallWizard(self.electrum_config, self.plugins)
|
||||||
|
wizard.path = storage.path
|
||||||
|
wizard.bind(on_wizard_complete=self.on_wizard_complete)
|
||||||
|
wizard.run('new')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
storage.decrypt(pw)
|
||||||
|
except StorageReadWriteError:
|
||||||
|
app.show_error(_("R/W error accessing path"))
|
||||||
|
return
|
||||||
|
self.password = pw
|
||||||
|
self._on_decrypted_storage(storage)
|
||||||
|
|
||||||
def on_stop(self):
|
def on_stop(self):
|
||||||
Logger.info('on_stop')
|
Logger.info('on_stop')
|
||||||
self.stop_wallet()
|
self.stop_wallet()
|
||||||
|
@ -749,8 +729,8 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
def wallets_dialog(self):
|
def wallets_dialog(self):
|
||||||
from .uix.dialogs.wallets import WalletDialog
|
from .uix.dialogs.wallets import WalletDialog
|
||||||
d = WalletDialog()
|
dirname = os.path.dirname(self.electrum_config.get_wallet_path())
|
||||||
d.path = os.path.dirname(self.electrum_config.get_wallet_path())
|
d = WalletDialog(dirname, self.load_wallet_by_name)
|
||||||
d.open()
|
d.open()
|
||||||
|
|
||||||
def popup_dialog(self, name):
|
def popup_dialog(self, name):
|
||||||
|
@ -969,7 +949,8 @@ class ElectrumWindow(App):
|
||||||
def on_resume(self):
|
def on_resume(self):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if self.wallet and self.wallet.has_password() and now - self.pause_time > 5*60:
|
if self.wallet and self.wallet.has_password() and now - self.pause_time > 5*60:
|
||||||
self.pincode_dialog(check_password=self.check_pin_code, on_success=None, on_failure=self.stop)
|
d = PincodeDialog(check_password=self.check_pin_code, on_success=None, on_failure=self.stop)
|
||||||
|
d.open()
|
||||||
if self.nfcscanner:
|
if self.nfcscanner:
|
||||||
self.nfcscanner.nfc_enable()
|
self.nfcscanner.nfc_enable()
|
||||||
|
|
||||||
|
@ -1150,11 +1131,12 @@ class ElectrumWindow(App):
|
||||||
if self.electrum_config.get('pin_code'):
|
if self.electrum_config.get('pin_code'):
|
||||||
msg += "\n" + _("Enter your PIN code to proceed")
|
msg += "\n" + _("Enter your PIN code to proceed")
|
||||||
on_success = lambda pw: f(*args, self.password)
|
on_success = lambda pw: f(*args, self.password)
|
||||||
self.pincode_dialog(
|
d = PincodeDialog(
|
||||||
message = msg,
|
message = msg,
|
||||||
check_password=self.check_pin_code,
|
check_password=self.check_pin_code,
|
||||||
on_success=on_success,
|
on_success=on_success,
|
||||||
on_failure=lambda: None)
|
on_failure=lambda: None)
|
||||||
|
d.open()
|
||||||
else:
|
else:
|
||||||
d = Question(
|
d = Question(
|
||||||
msg,
|
msg,
|
||||||
|
@ -1242,45 +1224,28 @@ class ElectrumWindow(App):
|
||||||
if pin != self.electrum_config.get('pin_code'):
|
if pin != self.electrum_config.get('pin_code'):
|
||||||
raise InvalidPassword
|
raise InvalidPassword
|
||||||
|
|
||||||
def password_dialog(self, **kwargs):
|
|
||||||
if self._password_dialog is None:
|
|
||||||
self._password_dialog = PasswordDialog()
|
|
||||||
self._password_dialog.init(self, **kwargs)
|
|
||||||
self._password_dialog.open()
|
|
||||||
|
|
||||||
def pincode_dialog(self, **kwargs):
|
|
||||||
if self._pincode_dialog is None:
|
|
||||||
self._pincode_dialog = PincodeDialog()
|
|
||||||
self._pincode_dialog.init(self, **kwargs)
|
|
||||||
self._pincode_dialog.open()
|
|
||||||
|
|
||||||
def change_password(self, cb):
|
def change_password(self, cb):
|
||||||
def on_success(old_password, new_password):
|
def on_success(old_password, new_password):
|
||||||
self.wallet.update_password(old_password, new_password)
|
self.wallet.update_password(old_password, new_password)
|
||||||
self.password = new_password
|
self.password = new_password
|
||||||
self.show_info(_("Your password was updated"))
|
self.show_info(_("Your password was updated"))
|
||||||
on_failure = lambda: self.show_error(_("Password not updated"))
|
on_failure = lambda: self.show_error(_("Password not updated"))
|
||||||
self.password_dialog(
|
d = ChangePasswordDialog(self, self.wallet, on_success, on_failure)
|
||||||
basename = self.wallet.basename(),
|
d.open()
|
||||||
check_password = self.wallet.check_password,
|
|
||||||
on_success=on_success, on_failure=on_failure,
|
|
||||||
is_change=True,
|
|
||||||
has_password=self.wallet.has_password())
|
|
||||||
|
|
||||||
def change_pin_code(self, cb):
|
def change_pin_code(self, cb):
|
||||||
if self._pincode_dialog is None:
|
|
||||||
self._pincode_dialog = PincodeDialog()
|
|
||||||
def on_success(old_password, new_password):
|
def on_success(old_password, new_password):
|
||||||
self.electrum_config.set_key('pin_code', new_password)
|
self.electrum_config.set_key('pin_code', new_password)
|
||||||
cb()
|
cb()
|
||||||
self.show_info(_("PIN updated") if new_password else _('PIN disabled'))
|
self.show_info(_("PIN updated") if new_password else _('PIN disabled'))
|
||||||
on_failure = lambda: self.show_error(_("PIN not updated"))
|
on_failure = lambda: self.show_error(_("PIN not updated"))
|
||||||
self._pincode_dialog.init(
|
|
||||||
|
d = PincodeDialog(
|
||||||
self, check_password=self.check_pin_code,
|
self, check_password=self.check_pin_code,
|
||||||
on_success=on_success, on_failure=on_failure,
|
on_success=on_success, on_failure=on_failure,
|
||||||
is_change=True,
|
is_change=True,
|
||||||
has_password = self.has_pin_code())
|
has_password = self.has_pin_code())
|
||||||
self._pincode_dialog.open()
|
d.open()
|
||||||
|
|
||||||
def save_backup(self):
|
def save_backup(self):
|
||||||
if platform != 'android':
|
if platform != 'android':
|
||||||
|
|
|
@ -1168,9 +1168,8 @@ class InstallWizard(BaseWizard, Widget):
|
||||||
def on_failure():
|
def on_failure():
|
||||||
self.show_error(_('Password mismatch'))
|
self.show_error(_('Password mismatch'))
|
||||||
self.run('request_password', run_next)
|
self.run('request_password', run_next)
|
||||||
popup = PasswordDialog()
|
|
||||||
app = App.get_running_app()
|
app = App.get_running_app()
|
||||||
popup.init(
|
popup = PasswordDialog(
|
||||||
app,
|
app,
|
||||||
check_password=lambda x:True,
|
check_password=lambda x:True,
|
||||||
on_success=on_success,
|
on_success=on_success,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Callable, TYPE_CHECKING, Optional, Union
|
from typing import Callable, TYPE_CHECKING, Optional, Union
|
||||||
|
import os
|
||||||
|
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
|
@ -8,8 +9,11 @@ from decimal import Decimal
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
|
||||||
from electrum.util import InvalidPassword
|
from electrum.util import InvalidPassword
|
||||||
|
from electrum.wallet import WalletStorage
|
||||||
from electrum.gui.kivy.i18n import _
|
from electrum.gui.kivy.i18n import _
|
||||||
|
|
||||||
|
from .wallets import WalletDialog
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ...main_window import ElectrumWindow
|
from ...main_window import ElectrumWindow
|
||||||
from electrum.wallet import Abstract_Wallet
|
from electrum.wallet import Abstract_Wallet
|
||||||
|
@ -23,6 +27,7 @@ Builder.load_string('''
|
||||||
message: ''
|
message: ''
|
||||||
basename:''
|
basename:''
|
||||||
is_change: False
|
is_change: False
|
||||||
|
require_password: True
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1, 1
|
size_hint: 1, 1
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
|
@ -57,6 +62,8 @@ Builder.load_string('''
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
orientation: 'horizontal'
|
orientation: 'horizontal'
|
||||||
id: box_generic_password
|
id: box_generic_password
|
||||||
|
disabled: not root.require_password
|
||||||
|
opacity: int(root.require_password)
|
||||||
size_hint_y: 0.05
|
size_hint_y: 0.05
|
||||||
height: '40dp'
|
height: '40dp'
|
||||||
TextInput:
|
TextInput:
|
||||||
|
@ -79,6 +86,20 @@ Builder.load_string('''
|
||||||
textinput_generic_password.password = False if textinput_generic_password.password else True
|
textinput_generic_password.password = False if textinput_generic_password.password else True
|
||||||
Widget:
|
Widget:
|
||||||
size_hint: 1, 1
|
size_hint: 1, 1
|
||||||
|
BoxLayout:
|
||||||
|
orientation: 'horizontal'
|
||||||
|
size_hint: 1, 0.5
|
||||||
|
Button:
|
||||||
|
text: 'Cancel'
|
||||||
|
size_hint: 0.5, None
|
||||||
|
height: '48dp'
|
||||||
|
on_release: popup.dismiss()
|
||||||
|
Button:
|
||||||
|
text: 'Next'
|
||||||
|
size_hint: 0.5, None
|
||||||
|
height: '48dp'
|
||||||
|
on_release:
|
||||||
|
popup.on_password(textinput_generic_password.text)
|
||||||
|
|
||||||
|
|
||||||
<PincodeDialog@Popup>
|
<PincodeDialog@Popup>
|
||||||
|
@ -142,9 +163,9 @@ Builder.load_string('''
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
class AbstractPasswordDialog:
|
class AbstractPasswordDialog(Factory.Popup):
|
||||||
|
|
||||||
def init(self, app: 'ElectrumWindow', *,
|
def __init__(self, app: 'ElectrumWindow', *,
|
||||||
check_password = None,
|
check_password = None,
|
||||||
on_success: Callable = None, on_failure: Callable = None,
|
on_success: Callable = None, on_failure: Callable = None,
|
||||||
is_change: bool = False,
|
is_change: bool = False,
|
||||||
|
@ -152,6 +173,7 @@ class AbstractPasswordDialog:
|
||||||
has_password: bool = False,
|
has_password: bool = False,
|
||||||
message: str = '',
|
message: str = '',
|
||||||
basename:str=''):
|
basename:str=''):
|
||||||
|
Factory.Popup.__init__(self)
|
||||||
self.app = app
|
self.app = app
|
||||||
self.pw_check = check_password
|
self.pw_check = check_password
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -234,17 +256,26 @@ class AbstractPasswordDialog:
|
||||||
self.clear_password()
|
self.clear_password()
|
||||||
|
|
||||||
|
|
||||||
class PasswordDialog(AbstractPasswordDialog, Factory.Popup):
|
class PasswordDialog(AbstractPasswordDialog):
|
||||||
enter_pw_message = _('Enter your password')
|
enter_pw_message = _('Enter your password')
|
||||||
enter_new_pw_message = _('Enter new password')
|
enter_new_pw_message = _('Enter new password')
|
||||||
confirm_new_pw_message = _('Confirm new password')
|
confirm_new_pw_message = _('Confirm new password')
|
||||||
wrong_password_message = _('Wrong password')
|
wrong_password_message = _('Wrong password')
|
||||||
allow_disable = False
|
allow_disable = False
|
||||||
|
|
||||||
|
def __init__(self, app, **kwargs):
|
||||||
|
AbstractPasswordDialog.__init__(self, app, **kwargs)
|
||||||
|
|
||||||
def clear_password(self):
|
def clear_password(self):
|
||||||
self.ids.textinput_generic_password.text = ''
|
self.ids.textinput_generic_password.text = ''
|
||||||
|
|
||||||
def on_password(self, pw: str):
|
def on_password(self, pw: str):
|
||||||
|
#
|
||||||
|
if not self.require_password:
|
||||||
|
self.success = True
|
||||||
|
self.message = _('Please wait...')
|
||||||
|
self.dismiss()
|
||||||
|
return
|
||||||
# if setting new generic password, enforce min length
|
# if setting new generic password, enforce min length
|
||||||
if self.level > 0:
|
if self.level > 0:
|
||||||
if len(pw) < 6:
|
if len(pw) < 6:
|
||||||
|
@ -253,17 +284,18 @@ class PasswordDialog(AbstractPasswordDialog, Factory.Popup):
|
||||||
# don't enforce minimum length on existing
|
# don't enforce minimum length on existing
|
||||||
self.do_check(pw)
|
self.do_check(pw)
|
||||||
|
|
||||||
def select_file(self):
|
|
||||||
self.app.wallets_dialog()
|
|
||||||
|
|
||||||
|
|
||||||
class PincodeDialog(AbstractPasswordDialog, Factory.Popup):
|
class PincodeDialog(AbstractPasswordDialog):
|
||||||
enter_pw_message = _('Enter your PIN')
|
enter_pw_message = _('Enter your PIN')
|
||||||
enter_new_pw_message = _('Enter new PIN')
|
enter_new_pw_message = _('Enter new PIN')
|
||||||
confirm_new_pw_message = _('Confirm new PIN')
|
confirm_new_pw_message = _('Confirm new PIN')
|
||||||
wrong_password_message = _('Wrong PIN')
|
wrong_password_message = _('Wrong PIN')
|
||||||
allow_disable = True
|
allow_disable = True
|
||||||
|
|
||||||
|
def __init__(self, app, **kwargs):
|
||||||
|
AbstractPasswordDialog.__init__(self, app, **kwargs)
|
||||||
|
|
||||||
def clear_password(self):
|
def clear_password(self):
|
||||||
self.ids.kb.password = ''
|
self.ids.kb.password = ''
|
||||||
|
|
||||||
|
@ -271,3 +303,51 @@ class PincodeDialog(AbstractPasswordDialog, Factory.Popup):
|
||||||
# PIN codes are exactly 6 chars
|
# PIN codes are exactly 6 chars
|
||||||
if len(pw) >= 6:
|
if len(pw) >= 6:
|
||||||
self.do_check(pw)
|
self.do_check(pw)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangePasswordDialog(PasswordDialog):
|
||||||
|
|
||||||
|
def __init__(self, app, wallet, on_success, on_failure):
|
||||||
|
PasswordDialog.__init__(self, app,
|
||||||
|
basename = wallet.basename(),
|
||||||
|
check_password = wallet.check_password,
|
||||||
|
on_success=on_success,
|
||||||
|
on_failure=on_failure,
|
||||||
|
is_change=True,
|
||||||
|
has_password=wallet.has_password())
|
||||||
|
|
||||||
|
|
||||||
|
class OpenWalletDialog(PasswordDialog):
|
||||||
|
|
||||||
|
def __init__(self, app, path, callback):
|
||||||
|
self.app = app
|
||||||
|
self.callback = callback
|
||||||
|
PasswordDialog.__init__(self, app,
|
||||||
|
on_success=lambda pw: self.callback(pw, self.storage),
|
||||||
|
on_failure=self.app.stop)
|
||||||
|
self.init_storage_from_path(path)
|
||||||
|
|
||||||
|
def select_file(self):
|
||||||
|
dirname = os.path.dirname(self.app.electrum_config.get_wallet_path())
|
||||||
|
d = WalletDialog(dirname, self.init_storage_from_path)
|
||||||
|
d.open()
|
||||||
|
|
||||||
|
def init_storage_from_path(self, path):
|
||||||
|
self.storage = WalletStorage(path)
|
||||||
|
self.basename = self.storage.basename()
|
||||||
|
if not self.storage.file_exists():
|
||||||
|
self.require_password = False
|
||||||
|
self.message = _('Press Next to create')
|
||||||
|
elif self.storage.is_encrypted():
|
||||||
|
if not self.storage.is_encrypted_with_user_pw():
|
||||||
|
raise Exception("Kivy GUI does not support this type of encrypted wallet files.")
|
||||||
|
self.require_password = True
|
||||||
|
self.pw_check = self.storage.check_password
|
||||||
|
self.message = self.enter_pw_message
|
||||||
|
else:
|
||||||
|
# it is a bit wasteful load the wallet here and load it again in main_window,
|
||||||
|
# but that is fine, because we are progressively enforcing storage encryption.
|
||||||
|
wallet = self.app.daemon.load_wallet(path, None)
|
||||||
|
self.require_password = wallet.has_password()
|
||||||
|
self.pw_check = wallet.check_password
|
||||||
|
self.message = self.enter_pw_message if self.require_password else _('Wallet not encrypted')
|
||||||
|
|
|
@ -12,7 +12,6 @@ from ...i18n import _
|
||||||
from .label_dialog import LabelDialog
|
from .label_dialog import LabelDialog
|
||||||
|
|
||||||
Builder.load_string('''
|
Builder.load_string('''
|
||||||
#:import os os
|
|
||||||
<WalletDialog@Popup>:
|
<WalletDialog@Popup>:
|
||||||
title: _('Wallets')
|
title: _('Wallets')
|
||||||
id: popup
|
id: popup
|
||||||
|
@ -40,7 +39,7 @@ Builder.load_string('''
|
||||||
text: _('New')
|
text: _('New')
|
||||||
on_release:
|
on_release:
|
||||||
popup.dismiss()
|
popup.dismiss()
|
||||||
root.new_wallet(app, wallet_selector.path)
|
root.new_wallet(wallet_selector.path)
|
||||||
Button:
|
Button:
|
||||||
id: open_button
|
id: open_button
|
||||||
size_hint: 0.1, None
|
size_hint: 0.1, None
|
||||||
|
@ -49,26 +48,21 @@ Builder.load_string('''
|
||||||
disabled: not wallet_selector.selection
|
disabled: not wallet_selector.selection
|
||||||
on_release:
|
on_release:
|
||||||
popup.dismiss()
|
popup.dismiss()
|
||||||
root.open_wallet(app)
|
root.callback(wallet_selector.selection[0])
|
||||||
''')
|
''')
|
||||||
|
|
||||||
class WalletDialog(Factory.Popup):
|
class WalletDialog(Factory.Popup):
|
||||||
|
|
||||||
def new_wallet(self, app, dirname):
|
def __init__(self, path, callback):
|
||||||
|
Factory.Popup.__init__(self)
|
||||||
|
self.path = path
|
||||||
|
self.callback = callback
|
||||||
|
|
||||||
|
def new_wallet(self, dirname):
|
||||||
def cb(filename):
|
def cb(filename):
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
return
|
||||||
# FIXME? "filename" might contain ".." (etc) and hence sketchy path traversals are possible
|
# FIXME? "filename" might contain ".." (etc) and hence sketchy path traversals are possible
|
||||||
try:
|
self.callback(os.path.join(dirname, filename))
|
||||||
app.load_wallet_by_name(os.path.join(dirname, filename))
|
|
||||||
except StorageReadWriteError:
|
|
||||||
app.show_error(_("R/W error accessing path"))
|
|
||||||
d = LabelDialog(_('Enter wallet name'), '', cb)
|
d = LabelDialog(_('Enter wallet name'), '', cb)
|
||||||
d.open()
|
d.open()
|
||||||
|
|
||||||
def open_wallet(self, app):
|
|
||||||
try:
|
|
||||||
app.load_wallet_by_name(self.ids.wallet_selector.selection[0])
|
|
||||||
except StorageReadWriteError:
|
|
||||||
app.show_error(_("R/W error accessing path"))
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue