tkivy: support bip39 seeds - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit a7b61fcab96ef138b9b8f9c8133081d539ace6a1 DIR parent 95ae42b998f6abbe8667d9032f2084f78ad009bf HTML Author: ThomasV <thomasv@electrum.org> Date: Tue, 13 Aug 2019 15:16:49 +0200 kivy: support bip39 seeds Diffstat: M electrum/base_wizard.py | 2 +- M electrum/gui/kivy/uix/dialogs/inst… | 98 +++++++++++++++++++++++++------ M electrum/gui/kivy/uix/dialogs/seed… | 22 ++++++++++++++++++---- 3 files changed, 100 insertions(+), 22 deletions(-) --- DIR diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py t@@ -377,7 +377,7 @@ class BaseWizard(Logger): def derivation_and_script_type_dialog(self, f): message1 = _('Choose the type of addresses in your wallet.') - message2 = '\n'.join([ + message2 = ' '.join([ _('You can override the suggested derivation path.'), _('If you are not sure what this is, leave this field unchanged.') ]) DIR diff --git a/electrum/gui/kivy/uix/dialogs/installwizard.py b/electrum/gui/kivy/uix/dialogs/installwizard.py t@@ -150,7 +150,7 @@ Builder.load_string(''' value: 2 -<WizardChoiceDialog> +<ChoiceDialog> message : '' Widget: size_hint: 1, 1 t@@ -488,7 +488,6 @@ Builder.load_string(''' text: _('Share') on_release: root.do_share() - <ShowSeedDialog> spacing: '12dp' value: 'next' t@@ -508,9 +507,7 @@ Builder.load_string(''' SeedLabel: text: root.message - <LineDialog> - BigLabel: text: root.title SeedLabel: t@@ -519,10 +516,30 @@ Builder.load_string(''' id: passphrase_input multiline: False size_hint: 1, None - height: '27dp' + height: '48dp' SeedLabel: text: root.warning +<ChoiceLineDialog> + BigLabel: + text: root.title + SeedLabel: + text: root.message1 + GridLayout: + row_default_height: '48dp' + orientation: 'vertical' + id: choices + cols: 1 + spacing: '14dp' + size_hint: 1, None + SeedLabel: + text: root.message2 + TextInput: + id: passphrase_input + multiline: False + size_hint: 1, None + height: '48dp' + ''') t@@ -706,12 +723,17 @@ class WizardConfirmDialog(WizardDialog): def get_params(self, button): return (True,) -class WizardChoiceDialog(WizardDialog): + +class ChoiceDialog(WizardDialog): def __init__(self, wizard, **kwargs): - super(WizardChoiceDialog, self).__init__(wizard, **kwargs) + super(ChoiceDialog, self).__init__(wizard, **kwargs) + self.title = kwargs.get('message', '') self.message = kwargs.get('message', '') choices = kwargs.get('choices', []) + self.init_choices(choices) + + def init_choices(self, choices): layout = self.ids.choices layout.bind(minimum_height=layout.setter('height')) for action, text in choices: t@@ -730,7 +752,6 @@ class WizardChoiceDialog(WizardDialog): return (button.action,) - class LineDialog(WizardDialog): title = StringProperty('') message = StringProperty('') t@@ -738,11 +759,47 @@ class LineDialog(WizardDialog): def __init__(self, wizard, **kwargs): WizardDialog.__init__(self, wizard, **kwargs) + self.title = kwargs.get('title', '') + self.message = kwargs.get('message', '') self.ids.next.disabled = False def get_params(self, b): return (self.ids.passphrase_input.text,) +class CLButton(Button): + def on_release(self): + self.root.script_type = self.script_type + self.root.set_text(self.value) + +class ChoiceLineDialog(ChoiceDialog): + title = StringProperty('') + message1 = StringProperty('') + message2 = StringProperty('') + + def __init__(self, wizard, **kwargs): + WizardDialog.__init__(self, wizard, **kwargs) + self.title = kwargs.get('title', '') + self.message1 = kwargs.get('message1', '') + self.message2 = kwargs.get('message2', '') + self.choices = kwargs.get('choices', []) + self.ids.next.disabled = False + layout = self.ids.choices + layout.bind(minimum_height=layout.setter('height')) + for script_type, title, text in self.choices: + b = CLButton(text=title, height='30dp') + b.script_type = script_type + b.root = self + b.value = text + layout.add_widget(b) + # last one is default + b.on_release() + + def set_text(self, value): + self.ids.passphrase_input.text = value + + def get_params(self, b): + return (self.ids.passphrase_input.text, self.script_type) + class ShowSeedDialog(WizardDialog): seed_text = StringProperty('') message = _("If you forget your PIN or lose your device, your seed phrase will be the only way to recover your funds.") t@@ -759,9 +816,9 @@ class ShowSeedDialog(WizardDialog): def options_dialog(self): from .seed_options import SeedOptionsDialog - def callback(status): - self.ext = status - d = SeedOptionsDialog(self.ext, callback) + def callback(ext, _): + self.ext = ext + d = SeedOptionsDialog(self.ext, None, callback) d.open() def get_params(self, b): t@@ -787,12 +844,15 @@ class RestoreSeedDialog(WizardDialog): self.message = _('Please type your seed phrase using the virtual keyboard.') self.title = _('Enter Seed') self.ext = False + self.bip39 = False def options_dialog(self): from .seed_options import SeedOptionsDialog - def callback(status): - self.ext = status - d = SeedOptionsDialog(self.ext, callback) + def callback(ext, bip39): + self.ext = ext + self.bip39 = bip39 + self.update_next_button() + d = SeedOptionsDialog(self.ext, self.bip39, callback) d.open() def get_suggestions(self, prefix): t@@ -800,8 +860,11 @@ class RestoreSeedDialog(WizardDialog): if w.startswith(prefix): yield w + def update_next_button(self): + self.ids.next.disabled = False if self.bip39 else not bool(self._test(self.get_text())) + def on_text(self, dt): - self.ids.next.disabled = not bool(self._test(self.get_text())) + self.update_next_button() text = self.ids.text_input_seed.text if not text: t@@ -887,7 +950,7 @@ class RestoreSeedDialog(WizardDialog): tis.focus = False def get_params(self, b): - return (self.get_text(), False, self.ext) + return (self.get_text(), self.bip39, self.ext) class ConfirmSeedDialog(RestoreSeedDialog): t@@ -1005,7 +1068,7 @@ class InstallWizard(BaseWizard, Widget): def choice_dialog(self, **kwargs): choices = kwargs['choices'] if len(choices) > 1: - WizardChoiceDialog(self, **kwargs).open() + ChoiceDialog(self, **kwargs).open() else: f = kwargs['run_next'] f(choices[0][0]) t@@ -1013,6 +1076,7 @@ class InstallWizard(BaseWizard, Widget): def multisig_dialog(self, **kwargs): WizardMultisigDialog(self, **kwargs).open() def show_seed_dialog(self, **kwargs): ShowSeedDialog(self, **kwargs).open() def line_dialog(self, **kwargs): LineDialog(self, **kwargs).open() + def choice_and_line_dialog(self, **kwargs): ChoiceLineDialog(self, **kwargs).open() def confirm_seed_dialog(self, **kwargs): kwargs['title'] = _('Confirm Seed') DIR diff --git a/electrum/gui/kivy/uix/dialogs/seed_options.py b/electrum/gui/kivy/uix/dialogs/seed_options.py t@@ -23,7 +23,15 @@ Builder.load_string(''' Label: text: _('Extend Seed') CheckBox: - id:cb + id:ext + BoxLayout: + orientation: 'horizontal' + size_hint: 1, 0.2 + Label: + text: _('BIP39') + id:bip39_label + CheckBox: + id:bip39 Widget: size_hint: 1, 0.1 BoxLayout: t@@ -39,13 +47,19 @@ Builder.load_string(''' size_hint: 0.5, None height: '48dp' on_release: - root.callback(cb.active) + root.callback(ext.active, bip39.active) popup.dismiss() ''') class SeedOptionsDialog(Factory.Popup): - def __init__(self, status, callback): + def __init__(self, is_ext, is_bip39, callback): Factory.Popup.__init__(self) - self.ids.cb.active = status + self.ids.ext.active = is_ext + if is_bip39 is None: + self.ids.bip39.opacity = 0 + self.ids.bip39_label.opacity = 0 + self.ids.bip39.disabled = True + else: + self.ids.bip39.active = is_bip39 self.callback = callback