Merge pull request #9245 from accumulator/qt_refactor_layouts_to_widgets
qt: refactor SeedLayout/KeysLayout to SeedWidget/KeysWidget, remove t…
This commit is contained in:
@@ -69,66 +69,10 @@ def seed_warning_msg(seed):
|
|||||||
]).format(len(seed.split()))
|
]).format(len(seed.split()))
|
||||||
|
|
||||||
|
|
||||||
class SeedLayout(QVBoxLayout):
|
class SeedWidget(QWidget):
|
||||||
|
|
||||||
updated = pyqtSignal()
|
updated = pyqtSignal()
|
||||||
|
validChanged = pyqtSignal([bool], arguments=['valid'])
|
||||||
def seed_options(self):
|
|
||||||
dialog = QDialog()
|
|
||||||
dialog.setWindowTitle(_("Seed Options"))
|
|
||||||
vbox = QVBoxLayout(dialog)
|
|
||||||
|
|
||||||
seed_types = [
|
|
||||||
(value, title) for value, title in (
|
|
||||||
('electrum', _('Electrum')),
|
|
||||||
('bip39', _('BIP39 seed')),
|
|
||||||
('slip39', _('SLIP39 seed')),
|
|
||||||
)
|
|
||||||
if value in self.options or value == 'electrum'
|
|
||||||
]
|
|
||||||
|
|
||||||
if 'ext' in self.options:
|
|
||||||
cb_ext = QCheckBox(_('Extend this seed with custom words'))
|
|
||||||
cb_ext.setChecked(self.is_ext)
|
|
||||||
vbox.addWidget(cb_ext)
|
|
||||||
|
|
||||||
if len(seed_types) >= 2:
|
|
||||||
def on_selected(idx):
|
|
||||||
self.seed_type = seed_type_choice.selected_key
|
|
||||||
self.is_seed = (lambda x: bool(x)) if self.seed_type != 'electrum' else self.saved_is_seed
|
|
||||||
self.slip39_current_mnemonic_invalid = None
|
|
||||||
self.seed_status.setText('')
|
|
||||||
self.on_edit()
|
|
||||||
if self.seed_type == 'bip39':
|
|
||||||
msg = ' '.join([
|
|
||||||
'<b>' + _('Warning') + ':</b> ',
|
|
||||||
_('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
|
|
||||||
_('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'),
|
|
||||||
_('BIP39 seeds do not include a version number, which compromises compatibility with future software.'),
|
|
||||||
_('We do not guarantee that BIP39 imports will always be supported in Electrum.'),
|
|
||||||
])
|
|
||||||
elif self.seed_type == 'slip39':
|
|
||||||
msg = ' '.join([
|
|
||||||
'<b>' + _('Warning') + ':</b> ',
|
|
||||||
_('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
|
|
||||||
_('However, we do not generate SLIP39 seeds.'),
|
|
||||||
])
|
|
||||||
else:
|
|
||||||
msg = ''
|
|
||||||
self.update_share_buttons()
|
|
||||||
self.initialize_completer()
|
|
||||||
self.seed_warning.setText(msg)
|
|
||||||
|
|
||||||
seed_type_choice = ChoiceWidget(message=_('Seed type'), choices=seed_types, selected=self.seed_type)
|
|
||||||
seed_type_choice.itemSelected.connect(on_selected)
|
|
||||||
vbox.addWidget(seed_type_choice)
|
|
||||||
|
|
||||||
vbox.addLayout(Buttons(OkButton(dialog)))
|
|
||||||
if not dialog.exec():
|
|
||||||
return None
|
|
||||||
self.is_ext = cb_ext.isChecked() if 'ext' in self.options else False
|
|
||||||
self.seed_type = seed_type_choice.selected_key if len(seed_types) >= 2 else 'electrum'
|
|
||||||
self.updated.emit()
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -137,20 +81,38 @@ class SeedLayout(QVBoxLayout):
|
|||||||
icon=True,
|
icon=True,
|
||||||
msg=None,
|
msg=None,
|
||||||
options=None,
|
options=None,
|
||||||
is_seed=None,
|
is_seed=None, # only used for electrum seeds
|
||||||
passphrase=None,
|
passphrase=None,
|
||||||
parent=None,
|
parent=None,
|
||||||
for_seed_words=True,
|
for_seed_words=True,
|
||||||
*,
|
*,
|
||||||
config: 'SimpleConfig',
|
config: 'SimpleConfig',
|
||||||
):
|
):
|
||||||
QVBoxLayout.__init__(self)
|
QWidget.__init__(self, parent)
|
||||||
self.parent = parent
|
vbox = QVBoxLayout()
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
self.options = options
|
self.options = options
|
||||||
self.config = config
|
self.config = config
|
||||||
self.seed_type = 'electrum'
|
|
||||||
|
if options:
|
||||||
|
self.seed_types = [
|
||||||
|
(value, title) for value, title in (
|
||||||
|
('electrum', _('Electrum')),
|
||||||
|
('bip39', _('BIP39 seed')),
|
||||||
|
('slip39', _('SLIP39 seed')),
|
||||||
|
)
|
||||||
|
if value in self.options
|
||||||
|
]
|
||||||
|
assert len(self.seed_types)
|
||||||
|
self.seed_type = self.seed_types[0][0]
|
||||||
|
else:
|
||||||
|
self.seed_type = 'electrum'
|
||||||
|
|
||||||
|
self.is_seed = is_seed
|
||||||
|
|
||||||
if title:
|
if title:
|
||||||
self.addWidget(WWLabel(title))
|
vbox.addWidget(WWLabel(title))
|
||||||
if seed: # "read only", we already have the text
|
if seed: # "read only", we already have the text
|
||||||
if for_seed_words:
|
if for_seed_words:
|
||||||
self.seed_e = ButtonsTextEdit()
|
self.seed_e = ButtonsTextEdit()
|
||||||
@@ -162,8 +124,6 @@ class SeedLayout(QVBoxLayout):
|
|||||||
assert for_seed_words
|
assert for_seed_words
|
||||||
self.seed_e = CompletionTextEdit()
|
self.seed_e = CompletionTextEdit()
|
||||||
self.seed_e.setTabChangesFocus(False) # so that tab auto-completes
|
self.seed_e.setTabChangesFocus(False) # so that tab auto-completes
|
||||||
self.is_seed = is_seed
|
|
||||||
self.saved_is_seed = self.is_seed
|
|
||||||
self.seed_e.textChanged.connect(self.on_edit)
|
self.seed_e.textChanged.connect(self.on_edit)
|
||||||
self.initialize_completer()
|
self.initialize_completer()
|
||||||
|
|
||||||
@@ -176,7 +136,7 @@ class SeedLayout(QVBoxLayout):
|
|||||||
logo.setMaximumWidth(60)
|
logo.setMaximumWidth(60)
|
||||||
hbox.addWidget(logo)
|
hbox.addWidget(logo)
|
||||||
hbox.addWidget(self.seed_e)
|
hbox.addWidget(self.seed_e)
|
||||||
self.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
hbox = QHBoxLayout()
|
hbox = QHBoxLayout()
|
||||||
hbox.addStretch(1)
|
hbox.addStretch(1)
|
||||||
self.seed_type_label = QLabel('')
|
self.seed_type_label = QLabel('')
|
||||||
@@ -187,7 +147,7 @@ class SeedLayout(QVBoxLayout):
|
|||||||
if options:
|
if options:
|
||||||
opt_button = EnterButton(_('Options'), self.seed_options)
|
opt_button = EnterButton(_('Options'), self.seed_options)
|
||||||
hbox.addWidget(opt_button)
|
hbox.addWidget(opt_button)
|
||||||
self.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
if passphrase:
|
if passphrase:
|
||||||
hbox = QHBoxLayout()
|
hbox = QHBoxLayout()
|
||||||
passphrase_e = QLineEdit()
|
passphrase_e = QLineEdit()
|
||||||
@@ -195,7 +155,7 @@ class SeedLayout(QVBoxLayout):
|
|||||||
passphrase_e.setReadOnly(True)
|
passphrase_e.setReadOnly(True)
|
||||||
hbox.addWidget(QLabel(_("Your seed extension is") + ':'))
|
hbox.addWidget(QLabel(_("Your seed extension is") + ':'))
|
||||||
hbox.addWidget(passphrase_e)
|
hbox.addWidget(passphrase_e)
|
||||||
self.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
|
|
||||||
# slip39 shares
|
# slip39 shares
|
||||||
self.slip39_mnemonic_index = 0
|
self.slip39_mnemonic_index = 0
|
||||||
@@ -211,15 +171,75 @@ class SeedLayout(QVBoxLayout):
|
|||||||
self.next_share_btn.clicked.connect(self.on_next_share)
|
self.next_share_btn.clicked.connect(self.on_next_share)
|
||||||
hbox.addWidget(self.next_share_btn)
|
hbox.addWidget(self.next_share_btn)
|
||||||
self.update_share_buttons()
|
self.update_share_buttons()
|
||||||
self.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
|
|
||||||
self.addStretch(1)
|
vbox.addStretch(1)
|
||||||
self.seed_status = WWLabel('')
|
self.seed_status = WWLabel('')
|
||||||
self.addWidget(self.seed_status)
|
vbox.addWidget(self.seed_status)
|
||||||
self.seed_warning = WWLabel('')
|
self.seed_warning = WWLabel('')
|
||||||
if msg:
|
if msg:
|
||||||
self.seed_warning.setText(seed_warning_msg(seed))
|
self.seed_warning.setText(seed_warning_msg(seed))
|
||||||
self.addWidget(self.seed_warning)
|
else:
|
||||||
|
self.update_seed_warning()
|
||||||
|
|
||||||
|
vbox.addWidget(self.seed_warning)
|
||||||
|
|
||||||
|
def seed_options(self):
|
||||||
|
dialog = QDialog()
|
||||||
|
dialog.setWindowTitle(_("Seed Options"))
|
||||||
|
vbox = QVBoxLayout(dialog)
|
||||||
|
|
||||||
|
if 'ext' in self.options:
|
||||||
|
cb_ext = QCheckBox(_('Extend this seed with custom words'))
|
||||||
|
cb_ext.setChecked(self.is_ext)
|
||||||
|
vbox.addWidget(cb_ext)
|
||||||
|
|
||||||
|
def on_selected(idx):
|
||||||
|
self.seed_type = seed_type_choice.selected_key
|
||||||
|
self.slip39_current_mnemonic_invalid = None
|
||||||
|
self.seed_status.setText('')
|
||||||
|
self.update_seed_warning()
|
||||||
|
self.on_edit()
|
||||||
|
self.update_share_buttons()
|
||||||
|
self.initialize_completer()
|
||||||
|
|
||||||
|
if len(self.seed_types) > 1:
|
||||||
|
seed_type_choice = ChoiceWidget(message=_('Seed type'), choices=self.seed_types, selected=self.seed_type)
|
||||||
|
seed_type_choice.itemSelected.connect(on_selected)
|
||||||
|
vbox.addWidget(seed_type_choice)
|
||||||
|
|
||||||
|
vbox.addLayout(Buttons(OkButton(dialog)))
|
||||||
|
|
||||||
|
if not dialog.exec():
|
||||||
|
return None
|
||||||
|
|
||||||
|
if 'ext' in self.options:
|
||||||
|
self.is_ext = cb_ext.isChecked()
|
||||||
|
if len(self.seed_types) > 1:
|
||||||
|
self.seed_type = seed_type_choice.selected_key
|
||||||
|
|
||||||
|
self.update_seed_warning()
|
||||||
|
self.updated.emit()
|
||||||
|
|
||||||
|
def update_seed_warning(self):
|
||||||
|
if self.seed_type == 'bip39':
|
||||||
|
msg = ' '.join([
|
||||||
|
'<b>' + _('Warning') + ':</b> ',
|
||||||
|
_('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
|
||||||
|
_('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'),
|
||||||
|
_('BIP39 seeds do not include a version number, which compromises compatibility with future software.'),
|
||||||
|
_('We do not guarantee that BIP39 imports will always be supported in Electrum.'),
|
||||||
|
])
|
||||||
|
elif self.seed_type == 'slip39':
|
||||||
|
msg = ' '.join([
|
||||||
|
'<b>' + _('Warning') + ':</b> ',
|
||||||
|
_('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'),
|
||||||
|
_('However, we do not generate SLIP39 seeds.'),
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
msg = ''
|
||||||
|
|
||||||
|
self.seed_warning.setText(msg)
|
||||||
|
|
||||||
def initialize_completer(self):
|
def initialize_completer(self):
|
||||||
if self.seed_type != 'slip39':
|
if self.seed_type != 'slip39':
|
||||||
@@ -261,12 +281,12 @@ class SeedLayout(QVBoxLayout):
|
|||||||
|
|
||||||
def on_edit(self):
|
def on_edit(self):
|
||||||
s = ' '.join(self.get_seed_words())
|
s = ' '.join(self.get_seed_words())
|
||||||
b = self.is_seed(s)
|
|
||||||
if self.seed_type == 'bip39':
|
if self.seed_type == 'bip39':
|
||||||
from electrum.keystore import bip39_is_checksum_valid
|
from electrum.keystore import bip39_is_checksum_valid
|
||||||
is_checksum, is_wordlist = bip39_is_checksum_valid(s)
|
is_checksum, is_wordlist = bip39_is_checksum_valid(s)
|
||||||
label = ''
|
label = ''
|
||||||
if bool(s):
|
valid = bool(s)
|
||||||
|
if valid:
|
||||||
label = ('' if is_checksum else _('BIP39 checksum failed')) if is_wordlist else _('Unknown BIP39 wordlist')
|
label = ('' if is_checksum else _('BIP39 checksum failed')) if is_wordlist else _('Unknown BIP39 wordlist')
|
||||||
elif self.seed_type == 'slip39':
|
elif self.seed_type == 'slip39':
|
||||||
self.slip39_mnemonics[self.slip39_mnemonic_index] = s
|
self.slip39_mnemonics[self.slip39_mnemonic_index] = s
|
||||||
@@ -287,15 +307,13 @@ class SeedLayout(QVBoxLayout):
|
|||||||
self.seed_status.setText(seed_status)
|
self.seed_status.setText(seed_status)
|
||||||
self.slip39_current_mnemonic_invalid = current_mnemonic_invalid
|
self.slip39_current_mnemonic_invalid = current_mnemonic_invalid
|
||||||
|
|
||||||
b = self.slip39_seed is not None
|
valid = self.slip39_seed is not None
|
||||||
self.update_share_buttons()
|
self.update_share_buttons()
|
||||||
else:
|
else:
|
||||||
|
valid = self.is_seed(s)
|
||||||
t = calc_seed_type(s)
|
t = calc_seed_type(s)
|
||||||
label = _('Seed Type') + ': ' + t if t else ''
|
label = _('Seed Type') + ': ' + t if t else ''
|
||||||
if t and not b: # electrum seed, but does not conform to dialog rules
|
if t and not valid: # electrum seed, but does not conform to dialog rules
|
||||||
# FIXME we should just accept any electrum seed and "redirect" the wizard automatically.
|
|
||||||
# i.e. if user selected wallet_type=="standard" but entered a 2fa seed, accept and redirect
|
|
||||||
# if user selected wallet_type=="2fa" but entered a std electrum seed, accept and redirect
|
|
||||||
wiztype_fullname = _('Wallet with two-factor authentication') if is_any_2fa_seed_type(t) else _("Standard wallet")
|
wiztype_fullname = _('Wallet with two-factor authentication') if is_any_2fa_seed_type(t) else _("Standard wallet")
|
||||||
msg = ' '.join([
|
msg = ' '.join([
|
||||||
'<b>' + _('Warning') + ':</b> ',
|
'<b>' + _('Warning') + ':</b> ',
|
||||||
@@ -307,7 +325,7 @@ class SeedLayout(QVBoxLayout):
|
|||||||
self.seed_warning.setText("")
|
self.seed_warning.setText("")
|
||||||
|
|
||||||
self.seed_type_label.setText(label)
|
self.seed_type_label.setText(label)
|
||||||
self.parent.next_button.setEnabled(b)
|
self.validChanged.emit(valid)
|
||||||
|
|
||||||
# disable suggestions if user already typed an unknown word
|
# disable suggestions if user already typed an unknown word
|
||||||
for word in self.get_seed_words()[:-1]:
|
for word in self.get_seed_words()[:-1]:
|
||||||
@@ -354,7 +372,10 @@ class SeedLayout(QVBoxLayout):
|
|||||||
self.slip39_current_mnemonic_invalid = None
|
self.slip39_current_mnemonic_invalid = None
|
||||||
|
|
||||||
|
|
||||||
class KeysLayout(QVBoxLayout):
|
class KeysWidget(QWidget):
|
||||||
|
|
||||||
|
validChanged = pyqtSignal([bool], arguments=['valid'])
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent=None,
|
parent=None,
|
||||||
@@ -364,29 +385,28 @@ class KeysLayout(QVBoxLayout):
|
|||||||
*,
|
*,
|
||||||
config: 'SimpleConfig',
|
config: 'SimpleConfig',
|
||||||
):
|
):
|
||||||
QVBoxLayout.__init__(self)
|
QWidget.__init__(self, parent)
|
||||||
self.parent = parent
|
vbox = QVBoxLayout()
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
self.is_valid = is_valid
|
self.is_valid = is_valid
|
||||||
self.text_e = ScanQRTextEdit(allow_multi=allow_multi, config=config)
|
self.text_e = ScanQRTextEdit(allow_multi=allow_multi, config=config)
|
||||||
self.text_e.textChanged.connect(self.on_edit)
|
self.text_e.textChanged.connect(self.on_edit)
|
||||||
if isinstance(header_layout, str):
|
if isinstance(header_layout, str):
|
||||||
self.addWidget(WWLabel(header_layout))
|
vbox.addWidget(WWLabel(header_layout))
|
||||||
else:
|
else:
|
||||||
self.addLayout(header_layout)
|
vbox.addLayout(header_layout)
|
||||||
self.addWidget(self.text_e)
|
vbox.addWidget(self.text_e)
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
return self.text_e.text()
|
return self.text_e.text()
|
||||||
|
|
||||||
def on_edit(self):
|
def on_edit(self):
|
||||||
valid = False
|
|
||||||
try:
|
try:
|
||||||
valid = self.is_valid(self.get_text())
|
valid = self.is_valid(self.get_text())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.parent.next_button.setToolTip(f'{_("Error")}: {str(e)}')
|
valid = False
|
||||||
else:
|
self.validChanged.emit(valid)
|
||||||
self.parent.next_button.setToolTip('')
|
|
||||||
self.parent.next_button.setEnabled(valid)
|
|
||||||
|
|
||||||
|
|
||||||
class SeedDialog(WindowModalDialog):
|
class SeedDialog(WindowModalDialog):
|
||||||
@@ -395,13 +415,7 @@ class SeedDialog(WindowModalDialog):
|
|||||||
WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed')))
|
WindowModalDialog.__init__(self, parent, ('Electrum - ' + _('Seed')))
|
||||||
self.setMinimumWidth(400)
|
self.setMinimumWidth(400)
|
||||||
vbox = QVBoxLayout(self)
|
vbox = QVBoxLayout(self)
|
||||||
title = _("Your wallet generation seed is:")
|
title = _("Your wallet generation seed is:")
|
||||||
slayout = SeedLayout(
|
seed_widget = SeedWidget(title=title, seed=seed, msg=True, passphrase=passphrase, config=config)
|
||||||
title=title,
|
vbox.addWidget(seed_widget)
|
||||||
seed=seed,
|
|
||||||
msg=True,
|
|
||||||
passphrase=passphrase,
|
|
||||||
config=config,
|
|
||||||
)
|
|
||||||
vbox.addLayout(slayout)
|
|
||||||
vbox.addLayout(Buttons(CloseButton(self)))
|
vbox.addLayout(Buttons(CloseButton(self)))
|
||||||
|
|||||||
@@ -27,10 +27,9 @@ from electrum.wizard import NewWalletWizard
|
|||||||
|
|
||||||
from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog
|
from electrum.gui.qt.bip39_recovery_dialog import Bip39RecoveryDialog
|
||||||
from electrum.gui.qt.password_dialog import PasswordLayout, PW_NEW, MSG_ENTER_PASSWORD, PasswordLayoutForHW
|
from electrum.gui.qt.password_dialog import PasswordLayout, PW_NEW, MSG_ENTER_PASSWORD, PasswordLayoutForHW
|
||||||
from electrum.gui.qt.seed_dialog import SeedLayout, MSG_PASSPHRASE_WARN_ISSUE4566, KeysLayout
|
from electrum.gui.qt.seed_dialog import SeedWidget, MSG_PASSPHRASE_WARN_ISSUE4566, KeysWidget
|
||||||
from electrum.gui.qt.util import (PasswordLineEdit, char_width_in_lineedit, WWLabel, InfoButton, font_height,
|
from electrum.gui.qt.util import (PasswordLineEdit, char_width_in_lineedit, WWLabel, InfoButton, font_height,
|
||||||
ChoiceWidget, MessageBoxMixin, WindowModalDialog, CancelButton,
|
ChoiceWidget, MessageBoxMixin, icon_path)
|
||||||
Buttons, OkButton, icon_path)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from electrum.simple_config import SimpleConfig
|
from electrum.simple_config import SimpleConfig
|
||||||
@@ -437,7 +436,7 @@ class WCCreateSeed(WalletWizardComponent):
|
|||||||
WalletWizardComponent.__init__(self, parent, wizard, title=_('Wallet Seed'))
|
WalletWizardComponent.__init__(self, parent, wizard, title=_('Wallet Seed'))
|
||||||
self._busy = True
|
self._busy = True
|
||||||
self.seed_type = 'standard' if self.wizard.config.WIZARD_DONT_CREATE_SEGWIT else 'segwit'
|
self.seed_type = 'standard' if self.wizard.config.WIZARD_DONT_CREATE_SEGWIT else 'segwit'
|
||||||
self.slayout = None
|
self.seed_widget = None
|
||||||
self.seed = None
|
self.seed = None
|
||||||
|
|
||||||
def on_ready(self):
|
def on_ready(self):
|
||||||
@@ -446,10 +445,10 @@ class WCCreateSeed(WalletWizardComponent):
|
|||||||
QTimer.singleShot(1, self.create_seed)
|
QTimer.singleShot(1, self.create_seed)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
if self.slayout:
|
if self.seed_widget:
|
||||||
self.wizard_data['seed'] = self.seed
|
self.wizard_data['seed'] = self.seed
|
||||||
self.wizard_data['seed_type'] = self.seed_type
|
self.wizard_data['seed_type'] = self.seed_type
|
||||||
self.wizard_data['seed_extend'] = self.slayout.is_ext
|
self.wizard_data['seed_extend'] = self.seed_widget.is_ext
|
||||||
self.wizard_data['seed_variant'] = 'electrum'
|
self.wizard_data['seed_variant'] = 'electrum'
|
||||||
self.wizard_data['seed_extra_words'] = '' # empty default
|
self.wizard_data['seed_extra_words'] = '' # empty default
|
||||||
|
|
||||||
@@ -457,15 +456,15 @@ class WCCreateSeed(WalletWizardComponent):
|
|||||||
self.busy = True
|
self.busy = True
|
||||||
self.seed = mnemonic.Mnemonic('en').make_seed(seed_type=self.seed_type)
|
self.seed = mnemonic.Mnemonic('en').make_seed(seed_type=self.seed_type)
|
||||||
|
|
||||||
self.slayout = SeedLayout(
|
self.seed_widget = SeedWidget(
|
||||||
title=_('Your wallet generation seed is:'),
|
title=_('Your wallet generation seed is:'),
|
||||||
seed=self.seed,
|
seed=self.seed,
|
||||||
options=['ext'],
|
options=['ext', 'electrum'],
|
||||||
msg=True,
|
msg=True,
|
||||||
parent=self,
|
parent=self,
|
||||||
config=self.wizard.config,
|
config=self.wizard.config,
|
||||||
)
|
)
|
||||||
self.layout().addLayout(self.slayout)
|
self.layout().addWidget(self.seed_widget)
|
||||||
self.layout().addStretch(1)
|
self.layout().addStretch(1)
|
||||||
self.busy = False
|
self.busy = False
|
||||||
self.valid = True
|
self.valid = True
|
||||||
@@ -482,19 +481,16 @@ class WCConfirmSeed(WalletWizardComponent):
|
|||||||
|
|
||||||
self.layout().addWidget(WWLabel(message))
|
self.layout().addWidget(WWLabel(message))
|
||||||
|
|
||||||
# TODO: SeedLayout assumes too much in parent, refactor SeedLayout
|
self.seed_widget = SeedWidget(
|
||||||
# for now, fake parent.next_button.setEnabled
|
|
||||||
class Hack:
|
|
||||||
def setEnabled(self2, b):
|
|
||||||
self.valid = b
|
|
||||||
self.next_button = Hack()
|
|
||||||
|
|
||||||
self.slayout = SeedLayout(
|
|
||||||
is_seed=lambda x: x == self.wizard_data['seed'],
|
is_seed=lambda x: x == self.wizard_data['seed'],
|
||||||
parent=self,
|
|
||||||
config=self.wizard.config,
|
config=self.wizard.config,
|
||||||
)
|
)
|
||||||
self.layout().addLayout(self.slayout)
|
|
||||||
|
def seed_valid_changed(valid):
|
||||||
|
self.valid = valid
|
||||||
|
|
||||||
|
self.seed_widget.validChanged.connect(seed_valid_changed)
|
||||||
|
self.layout().addWidget(self.seed_widget)
|
||||||
|
|
||||||
wizard.app.clipboard().clear()
|
wizard.app.clipboard().clear()
|
||||||
|
|
||||||
@@ -583,37 +579,39 @@ class WCHaveSeed(WalletWizardComponent, Logger):
|
|||||||
WalletWizardComponent.__init__(self, parent, wizard, title=_('Enter Seed'))
|
WalletWizardComponent.__init__(self, parent, wizard, title=_('Enter Seed'))
|
||||||
Logger.__init__(self)
|
Logger.__init__(self)
|
||||||
|
|
||||||
self.slayout = None
|
|
||||||
|
|
||||||
self.layout().addWidget(WWLabel(_('Please enter your seed phrase in order to restore your wallet.')))
|
self.layout().addWidget(WWLabel(_('Please enter your seed phrase in order to restore your wallet.')))
|
||||||
|
|
||||||
# TODO: SeedLayout assumes too much in parent, refactor SeedLayout
|
self.seed_widget = None
|
||||||
# for now, fake parent.next_button.setEnabled
|
|
||||||
class Hack:
|
|
||||||
def setEnabled(self2, b):
|
|
||||||
if not b:
|
|
||||||
self.valid = b
|
|
||||||
else:
|
|
||||||
self.validate()
|
|
||||||
|
|
||||||
self.next_button = Hack()
|
|
||||||
|
|
||||||
self.can_passphrase = True
|
self.can_passphrase = True
|
||||||
|
|
||||||
def on_ready(self):
|
def on_ready(self):
|
||||||
options = ['ext'] if self.wizard_data['wallet_type'] == '2fa' else ['ext', 'bip39', 'slip39']
|
options = ['ext', 'electrum', 'bip39', 'slip39']
|
||||||
self.slayout = SeedLayout(
|
if self.wizard_data['wallet_type'] == '2fa':
|
||||||
|
options = ['ext', 'electrum']
|
||||||
|
else:
|
||||||
|
if self.params and 'seed_options' in self.params:
|
||||||
|
options = self.params['seed_options']
|
||||||
|
|
||||||
|
self.seed_widget = SeedWidget(
|
||||||
is_seed=self.is_seed,
|
is_seed=self.is_seed,
|
||||||
options=options,
|
options=options,
|
||||||
parent=self,
|
|
||||||
config=self.wizard.config,
|
config=self.wizard.config,
|
||||||
)
|
)
|
||||||
self.slayout.updated.connect(self.validate)
|
|
||||||
|
|
||||||
self.layout().addLayout(self.slayout)
|
def seed_valid_changed(valid):
|
||||||
|
if not valid:
|
||||||
|
self.valid = valid
|
||||||
|
else:
|
||||||
|
self.validate()
|
||||||
|
|
||||||
|
self.seed_widget.validChanged.connect(seed_valid_changed)
|
||||||
|
self.seed_widget.updated.connect(self.validate)
|
||||||
|
|
||||||
|
self.layout().addWidget(self.seed_widget)
|
||||||
self.layout().addStretch(1)
|
self.layout().addStretch(1)
|
||||||
|
|
||||||
def is_seed(self, x):
|
def is_seed(self, x):
|
||||||
|
# really only used for electrum seeds. bip39 and slip39 are validated in SeedWidget
|
||||||
t = mnemonic.calc_seed_type(x)
|
t = mnemonic.calc_seed_type(x)
|
||||||
if self.wizard_data['wallet_type'] == 'standard':
|
if self.wizard_data['wallet_type'] == 'standard':
|
||||||
return mnemonic.is_seed(x) and not mnemonic.is_any_2fa_seed_type(t)
|
return mnemonic.is_seed(x) and not mnemonic.is_any_2fa_seed_type(t)
|
||||||
@@ -624,9 +622,9 @@ class WCHaveSeed(WalletWizardComponent, Logger):
|
|||||||
return t in ['standard', 'segwit']
|
return t in ['standard', 'segwit']
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
# precond: only call when SeedLayout deems seed a valid seed
|
# precond: only call when SeedWidget deems seed a valid seed
|
||||||
seed = self.slayout.get_seed()
|
seed = self.seed_widget.get_seed()
|
||||||
seed_variant = self.slayout.seed_type
|
seed_variant = self.seed_widget.seed_type
|
||||||
wallet_type = self.wizard_data['wallet_type']
|
wallet_type = self.wizard_data['wallet_type']
|
||||||
seed_valid, seed_type, validation_message, self.can_passphrase = self.wizard.validate_seed(seed, seed_variant, wallet_type)
|
seed_valid, seed_type, validation_message, self.can_passphrase = self.wizard.validate_seed(seed, seed_variant, wallet_type)
|
||||||
|
|
||||||
@@ -646,13 +644,13 @@ class WCHaveSeed(WalletWizardComponent, Logger):
|
|||||||
def apply(self):
|
def apply(self):
|
||||||
cosigner_data = self.wizard.current_cosigner(self.wizard_data)
|
cosigner_data = self.wizard.current_cosigner(self.wizard_data)
|
||||||
|
|
||||||
cosigner_data['seed'] = self.slayout.get_seed()
|
cosigner_data['seed'] = self.seed_widget.get_seed()
|
||||||
cosigner_data['seed_variant'] = self.slayout.seed_type
|
cosigner_data['seed_variant'] = self.seed_widget.seed_type
|
||||||
if self.slayout.seed_type == 'electrum':
|
if self.seed_widget.seed_type == 'electrum':
|
||||||
cosigner_data['seed_type'] = mnemonic.calc_seed_type(self.slayout.get_seed())
|
cosigner_data['seed_type'] = mnemonic.calc_seed_type(self.seed_widget.get_seed())
|
||||||
else:
|
else:
|
||||||
cosigner_data['seed_type'] = self.slayout.seed_type
|
cosigner_data['seed_type'] = self.seed_widget.seed_type
|
||||||
cosigner_data['seed_extend'] = self.slayout.is_ext if self.can_passphrase else False
|
cosigner_data['seed_extend'] = self.seed_widget.is_ext if self.can_passphrase else False
|
||||||
cosigner_data['seed_extra_words'] = '' # empty default
|
cosigner_data['seed_extra_words'] = '' # empty default
|
||||||
|
|
||||||
|
|
||||||
@@ -790,13 +788,13 @@ class WCCosignerKeystore(WalletWizardComponent):
|
|||||||
# different from old wizard: master public key for sharing is now shown on this page
|
# different from old wizard: master public key for sharing is now shown on this page
|
||||||
self.layout().addSpacing(20)
|
self.layout().addSpacing(20)
|
||||||
self.layout().addWidget(WWLabel(_('Below is your master public key. Please share it with your cosigners')))
|
self.layout().addWidget(WWLabel(_('Below is your master public key. Please share it with your cosigners')))
|
||||||
slayout = SeedLayout(
|
seed_widget = SeedWidget(
|
||||||
self.wizard_data['multisig_master_pubkey'],
|
self.wizard_data['multisig_master_pubkey'],
|
||||||
icon=False,
|
icon=False,
|
||||||
for_seed_words=False,
|
for_seed_words=False,
|
||||||
config=self.wizard.config,
|
config=self.wizard.config,
|
||||||
)
|
)
|
||||||
self.layout().addLayout(slayout)
|
self.layout().addWidget(seed_widget)
|
||||||
self.layout().addStretch(1)
|
self.layout().addStretch(1)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
@@ -811,7 +809,7 @@ class WCHaveMasterKey(WalletWizardComponent):
|
|||||||
def __init__(self, parent, wizard):
|
def __init__(self, parent, wizard):
|
||||||
WalletWizardComponent.__init__(self, parent, wizard, title=_('Create keystore from a master key'))
|
WalletWizardComponent.__init__(self, parent, wizard, title=_('Create keystore from a master key'))
|
||||||
|
|
||||||
self.slayout = None
|
self.keys_widget = None
|
||||||
|
|
||||||
self.message_create = ' '.join([
|
self.message_create = ' '.join([
|
||||||
_("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."),
|
_("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."),
|
||||||
@@ -827,16 +825,6 @@ class WCHaveMasterKey(WalletWizardComponent):
|
|||||||
self.label.setMinimumWidth(400)
|
self.label.setMinimumWidth(400)
|
||||||
self.header_layout.addWidget(self.label)
|
self.header_layout.addWidget(self.label)
|
||||||
|
|
||||||
# TODO: KeysLayout assumes too much in parent, refactor KeysLayout
|
|
||||||
# for now, fake parent.next_button.setEnabled
|
|
||||||
class Hack:
|
|
||||||
def setEnabled(self2, b):
|
|
||||||
self.valid = b
|
|
||||||
|
|
||||||
def setToolTip(self2, b):
|
|
||||||
pass
|
|
||||||
self.next_button = Hack()
|
|
||||||
|
|
||||||
def on_ready(self):
|
def on_ready(self):
|
||||||
if self.wizard_data['wallet_type'] == 'standard':
|
if self.wizard_data['wallet_type'] == 'standard':
|
||||||
self.label.setText(self.message_create)
|
self.label.setText(self.message_create)
|
||||||
@@ -860,12 +848,19 @@ class WCHaveMasterKey(WalletWizardComponent):
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception(f"unexpected wallet type: {self.wizard_data['wallet_type']}")
|
raise Exception(f"unexpected wallet type: {self.wizard_data['wallet_type']}")
|
||||||
self.slayout = KeysLayout(parent=self, header_layout=self.header_layout, is_valid=is_valid,
|
|
||||||
allow_multi=False, config=self.wizard.config)
|
self.keys_widget = KeysWidget(parent=self, header_layout=self.header_layout, is_valid=is_valid,
|
||||||
self.layout().addLayout(self.slayout)
|
allow_multi=False, config=self.wizard.config)
|
||||||
|
|
||||||
|
def key_valid_changed(valid):
|
||||||
|
self.valid = valid
|
||||||
|
|
||||||
|
self.keys_widget.validChanged.connect(key_valid_changed)
|
||||||
|
|
||||||
|
self.layout().addWidget(self.keys_widget)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
text = self.slayout.get_text()
|
text = self.keys_widget.get_text()
|
||||||
cosigner_data = self.wizard.current_cosigner(self.wizard_data)
|
cosigner_data = self.wizard.current_cosigner(self.wizard_data)
|
||||||
cosigner_data['master_key'] = text
|
cosigner_data['master_key'] = text
|
||||||
|
|
||||||
@@ -942,25 +937,20 @@ class WCImport(WalletWizardComponent):
|
|||||||
header_layout.addWidget(label)
|
header_layout.addWidget(label)
|
||||||
header_layout.addWidget(InfoButton(WIF_HELP_TEXT), alignment=Qt.AlignmentFlag.AlignRight)
|
header_layout.addWidget(InfoButton(WIF_HELP_TEXT), alignment=Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
# TODO: KeysLayout assumes too much in parent, refactor KeysLayout
|
|
||||||
# for now, fake parent.next_button.setEnabled
|
|
||||||
class Hack:
|
|
||||||
def setEnabled(self2, b):
|
|
||||||
self.valid = b
|
|
||||||
|
|
||||||
def setToolTip(self2, b):
|
|
||||||
pass
|
|
||||||
self.next_button = Hack()
|
|
||||||
|
|
||||||
def is_valid(x) -> bool:
|
def is_valid(x) -> bool:
|
||||||
return keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True)
|
return keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True)
|
||||||
|
|
||||||
self.slayout = KeysLayout(parent=self, header_layout=header_layout, is_valid=is_valid,
|
self.keys_widget = KeysWidget(header_layout=header_layout, is_valid=is_valid,
|
||||||
allow_multi=True, config=self.wizard.config)
|
allow_multi=True, config=self.wizard.config)
|
||||||
self.layout().addLayout(self.slayout)
|
|
||||||
|
def key_valid_changed(valid):
|
||||||
|
self.valid = valid
|
||||||
|
|
||||||
|
self.keys_widget.validChanged.connect(key_valid_changed)
|
||||||
|
self.layout().addWidget(self.keys_widget)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
text = self.slayout.get_text()
|
text = self.keys_widget.get_text()
|
||||||
if keystore.is_address_list(text):
|
if keystore.is_address_list(text):
|
||||||
self.wizard_data['address_list'] = text
|
self.wizard_data['address_list'] = text
|
||||||
elif keystore.is_private_key_list(text):
|
elif keystore.is_private_key_list(text):
|
||||||
|
|||||||
Reference in New Issue
Block a user