URI: 
       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