URI: 
       tkivy wizard: do not scan seed as qr code. separate screen for watching only wallets. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4e7f9c061bb2d35706fea1b66f2647157cbea8c1
   DIR parent 8c365fd6811016977f365d0b6bfcd2efb712528c
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Fri, 26 Feb 2016 10:17:38 +0100
       
       kivy wizard: do not scan seed as qr code. separate screen for watching only wallets.
       
       Diffstat:
         M gui/kivy/uix/dialogs/create_restor… |     110 +++++++++++++++++++++++++------
         M gui/kivy/uix/dialogs/installwizard… |      42 ++++++++++++++++---------------
       
       2 files changed, 113 insertions(+), 39 deletions(-)
       ---
   DIR diff --git a/gui/kivy/uix/dialogs/create_restore.py b/gui/kivy/uix/dialogs/create_restore.py
       t@@ -99,8 +99,8 @@ Builder.load_string('''
                text_size: self.width, None
                height: self.texture_size[1]
                text:
       -            _("Wallet file not found")+"\\n\\n" +\
       -            _("Do you want to create a new wallet ")+\
       +            _("Creating a new wallet.")+" " +\
       +            _("Do you want to create a wallet with a new seed")+\
                    _("or restore an existing one?")
            Widget
                size_hint: 1, 1
       t@@ -116,9 +116,13 @@ Builder.load_string('''
                    text: _('Create a new seed')
                    root: root
                WizardButton:
       -            id: restore
       +            id: restore_seed
                    text: _('I already have a seed')
                    root: root
       +        WizardButton:
       +            id: restore_xpub
       +            text: _('Watching-only wallet')
       +            root: root
        
        
        <MButton@Button>:
       t@@ -277,10 +281,65 @@ Builder.load_string('''
                    id: back
                    text: _('Back')
                    root: root
       +        WizardButton:
       +            id: next
       +            text: _('Next')
       +            root: root
       +            disabled: True
       +
       +
       +<RestoreXpubDialog>
       +    word: ''
       +    Label:
       +        color: root.text_color
       +        size_hint: 1, None
       +        text_size: self.width, None
       +        height: self.texture_size[1]
       +        text: "[b]MASTER PUBLIC KEY[/b]"
       +    GridLayout
       +        cols: 1
       +        padding: 0, '12dp'
       +        orientation: 'vertical'
       +        spacing: '12dp'
       +        size_hint: 1, None
       +        height: self.minimum_height
       +        SeedButton:
       +            id: text_input_seed
       +            text: ''
       +            on_text: Clock.schedule_once(root.on_text)
       +        SeedLabel:
       +            text: root.message
       +
       +    GridLayout:
       +        rows: 1
       +        spacing: '12dp'
       +        size_hint: 1, None
       +        height: self.minimum_height
                IconButton:
                    id: scan
       +            height: '48sp'
                    on_release: root.scan_seed()
                    icon: 'atlas://gui/kivy/theming/light/camera'
       +            size_hint: 1, None
       +        WizardButton:
       +            text: _('Paste')
       +            on_release: root.do_paste()
       +        WizardButton:
       +            text: _('Clear')
       +            on_release: root.do_clear()
       +
       +    Widget:
       +        size_hint: 1, 1
       +
       +    GridLayout:
       +        rows: 1
       +        spacing: '12dp'
       +        size_hint: 1, None
       +        height: self.minimum_height
       +        WizardButton:
       +            id: back
       +            text: _('Back')
       +            root: root
                WizardButton:
                    id: next
                    text: _('Next')
       t@@ -397,7 +456,7 @@ class RestoreSeedDialog(WizardDialog):
                self.mnemonic = Mnemonic('en')
        
            def on_text(self, dt):
       -        self.ids.next.disabled = not bool(self._test(self.get_seed_text()))
       +        self.ids.next.disabled = not bool(self._test(self.get_text()))
        
                text = self.ids.text_input_seed.text
                if not text:
       t@@ -432,14 +491,14 @@ class RestoreSeedDialog(WizardDialog):
                                c.disabled = not enable_space
        
            def on_word(self, w):
       -        text = self.get_seed_text()
       +        text = self.get_text()
                words = text.split(' ')
                words[-1] = w
                text = ' '.join(words)
                self.ids.text_input_seed.text = text + ' '
                self.ids.suggestions.clear_widgets()
        
       -    def get_seed_text(self):
       +    def get_text(self):
                ti = self.ids.text_input_seed
                text = unicode(ti.text).strip()
                text = ' '.join(text.split())
       t@@ -454,12 +513,6 @@ class RestoreSeedDialog(WizardDialog):
                    text += c
                self.ids.text_input_seed.text = text
        
       -    def scan_seed(self):
       -        def on_complete(text):
       -            self.ids.text_input_seed.text = text
       -        app = App.get_running_app()
       -        app.scan_qr(on_complete)
       -
            def on_parent(self, instance, value):
                if value:
                    tis = self.ids.text_input_seed
       t@@ -487,10 +540,29 @@ class RestoreSeedDialog(WizardDialog):
                    tis._keyboard.unbind(on_key_down=self.on_key_down)
                    tis.focus = False
        
       -    def close(self):
       -        #self._remove_keyboard()
       -        app = App.get_running_app()
       -        #if self._back in app.navigation_higherarchy:
       -        #    app.navigation_higherarchy.pop()
       -        #    self._back = None
       -        super(RestoreSeedDialog, self).close()
       +class RestoreXpubDialog(WizardDialog):
       +
       +    message = StringProperty('')
       +
       +    def __init__(self, **kwargs):
       +        super(RestoreXpubDialog, self).__init__(**kwargs)
       +        self._test = kwargs['test']
       +        self.app = App.get_running_app()
       +
       +    def get_text(self):
       +        ti = self.ids.text_input_seed
       +        return unicode(ti.text).strip()
       +
       +    def on_text(self, dt):
       +        self.ids.next.disabled = not bool(self._test(self.get_text()))
       +
       +    def scan_seed(self):
       +        def on_complete(text):
       +            self.ids.text_input_seed.text = text
       +        self.app.scan_qr(on_complete)
       +
       +    def do_paste(self):
       +        self.ids.text_input_seed.text = unicode(self.app._clipboard.paste())
       +
       +    def do_clear(self):
       +        self.ids.text_input_seed.text = ''
   DIR diff --git a/gui/kivy/uix/dialogs/installwizard.py b/gui/kivy/uix/dialogs/installwizard.py
       t@@ -12,7 +12,7 @@ import threading
        from functools import partial
        import weakref
        
       -from create_restore import CreateRestoreDialog, ShowSeedDialog, RestoreSeedDialog
       +from create_restore import CreateRestoreDialog, ShowSeedDialog, RestoreSeedDialog, RestoreXpubDialog
        from password_dialog import PasswordDialog
        
        
       t@@ -37,7 +37,6 @@ class InstallWizard(Widget):
                self.network = network
                self.storage = storage
                self.wallet = Wallet(self.storage)
       -        self.is_restore = False
        
            def waiting_dialog(self, task, msg, on_complete=None):
                '''Perform a blocking task in the background by running the passed
       t@@ -79,27 +78,36 @@ class InstallWizard(Widget):
                    action = dialog.action
                    if button == dialog.ids.create:
                        self.run('create')
       -            elif button == dialog.ids.restore:
       -                self.run('restore')
       +            elif button == dialog.ids.restore_seed:
       +                self.run('restore_seed')
       +            elif button == dialog.ids.restore_xpub:
       +                self.run('restore_xpub')
                    else:
                        self.dispatch('on_wizard_complete', None)
                CreateRestoreDialog(on_release=on_release).open()
        
       -    def restore(self):
       -        self.is_restore = True
       +    def restore_seed(self):
                def on_seed(_dlg, btn):
                    _dlg.close()
                    if btn is _dlg.ids.back:
                        self.run('new')
                        return
       -            text = _dlg.get_seed_text()
       -            if Wallet.should_encrypt(text):
       -                self.run('enter_pin', (text,))
       -            else:
       -                self.run('add_seed', (text, None))
       -                # fixme: sync
       -        msg = _('You may use the camera to scan your seed. To create a watching-only wallet, scan your master public key.')
       -        RestoreSeedDialog(test=Wallet.is_any, message=msg, on_release=on_seed).open()
       +            text = _dlg.get_text()
       +            self.run('enter_pin', (text,))
       +        msg = _('Please type your seed phrase using the virtual keyboard.')
       +        RestoreSeedDialog(test=Wallet.is_seed, message=msg, on_release=on_seed).open()
       +
       +    def restore_xpub(self):
       +        def on_xpub(_dlg, btn):
       +            _dlg.close()
       +            if btn is _dlg.ids.back:
       +                self.run('new')
       +                return
       +            text = _dlg.get_text()
       +            self.run('add_seed', (text, None))
       +
       +        msg = _('To create a watching-only wallet, paste your master public key, or scan it using the camera button.')
       +        RestoreXpubDialog(test=Wallet.is_xpub, message=msg, on_release=on_xpub).open()
        
            def add_seed(self, text, password):
                def task():
       t@@ -114,7 +122,6 @@ class InstallWizard(Widget):
                self.waiting_dialog(task, msg, self.terminate)
        
            def create(self):
       -        self.is_restore = False
                seed = self.wallet.make_seed()
                msg = _("If you forget your PIN or lose your device, your seed phrase will be the "
                        "only way to recover your funds.")
       t@@ -156,11 +163,6 @@ class InstallWizard(Widget):
        
            def terminate(self):
                self.wallet.start_threads(self.network)
       -        #if self.is_restore:
       -        #    if self.wallet.is_found():
       -        #        app.show_info(_("Recovery successful"), duration=.5)
       -        #    else:
       -        #        app.show_info(_("No transactions found for this seed"), duration=.5)
                self.dispatch('on_wizard_complete', self.wallet)
        
            def on_wizard_complete(self, wallet):