commit 656069070a9ba8c68c066226bdd4c02883f7c7ae
parent 950f3ae633ae2d774dbbd0f60dd23cd8be06c624
Author: ThomasV <thomasv@electrum.org>
Date: Sat, 13 Feb 2016 15:10:17 +0100
kivy wizard: use own soft keyboard
Diffstat:
3 files changed, 168 insertions(+), 56 deletions(-)
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -230,11 +230,11 @@ class ElectrumWindow(App):
def set_URI(self, url):
try:
- url = electrum.util.parse_URI(url, self.on_pr)
+ d = electrum.util.parse_URI(url, self.on_pr)
except:
self.show_info(_("Not a Bitcoin URI") + ':\n', url)
return
- self.send_screen.set_URI(url)
+ self.send_screen.set_URI(d)
def on_qr(self, data):
if data.startswith('bitcoin:'):
diff --git a/gui/kivy/uix/dialogs/create_restore.py b/gui/kivy/uix/dialogs/create_restore.py
@@ -11,6 +11,7 @@ from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty, OptionProperty
from kivy.core.window import Window
+from kivy.uix.button import Button
from electrum_gui.kivy.uix.dialogs import EventsDialog
from electrum_gui.kivy.i18n import _
@@ -60,62 +61,49 @@ Builder.load_string('''
BoxLayout:
orientation: 'vertical' if self.width < self.height else 'horizontal'
padding:
- min(dp(42), self.width/8), min(dp(60), self.height/9.7),\
- min(dp(42), self.width/8), min(dp(72), self.height/8)
+ min(dp(42), self.width/16), min(dp(60), self.height/16),\
+ min(dp(42), self.width/16), min(dp(72), self.height/16)
spacing: '27dp'
GridLayout:
id: grid_logo
cols: 1
pos_hint: {'center_y': .5}
- size_hint: 1, .42
+ size_hint: 1, None
#height: self.minimum_height
- Image:
- id: logo_img
- mipmap: True
- allow_stretch: True
- size_hint: 1, None
- height: '110dp'
- source: 'atlas://gui/kivy/theming/light/electrum_icon640'
- Widget:
- size_hint: 1, None
- height: 0 if stepper.opacity else dp(15)
Label:
color: root.text_color
- opacity: 0 if stepper.opacity else 1
text: 'ELECTRUM'
size_hint: 1, None
height: self.texture_size[1] if self.opacity else 0
font_size: '33sp'
font_name: 'gui/kivy/data/fonts/tron/Tr2n.ttf'
- Image:
- id: stepper
- allow_stretch: True
- opacity: 0
- source: 'atlas://gui/kivy/theming/light/stepper_left'
- size_hint: 1, None
- height: grid_logo.height/2.5 if self.opacity else 0
- Widget:
- size_hint: None, None
- size: '5dp', '5dp'
GridLayout:
cols: 1
id: crcontent
- spacing: '13dp'
+ spacing: '1dp'
<CreateRestoreDialog>
+ Image:
+ id: logo_img
+ mipmap: True
+ allow_stretch: True
+ size_hint: 1, None
+ height: '110dp'
+ source: 'atlas://gui/kivy/theming/light/electrum_icon640'
+ Widget:
+ size_hint: 1, 1
Label:
color: root.text_color
size_hint: 1, None
text_size: self.width, None
height: self.texture_size[1]
text:
- _("Wallet file not found!!")+"\\n\\n" +\
+ _("Wallet file not found")+"\\n\\n" +\
_("Do you want to create a new wallet ")+\
_("or restore an existing one?")
Widget
- size_hint: 1, None
- height: dp(15)
+ size_hint: 1, 1
GridLayout:
id: grid
orientation: 'vertical'
@@ -133,7 +121,23 @@ Builder.load_string('''
root: root
+<MButton@Button>:
+ size_hint: 1, None
+ height: '33dp'
+ on_release:
+ self.parent.update_amount(self.text)
+
+<WordButton@Button>:
+ size_hint: None, None
+ text_size: None, self.height
+ width: self.texture_size[0]
+ height: '30dp'
+ on_release:
+ self.parent.new_word(self.text)
+
+
<RestoreSeedDialog>
+ word: ''
Label:
color: root.text_color
size_hint: 1, None
@@ -147,13 +151,20 @@ Builder.load_string('''
spacing: '12dp'
size_hint: 1, None
height: self.minimum_height
- WizardTextInput:
+ Button:
+ border: 4, 4, 4, 4
+ halign: 'justify'
+ valign: 'middle'
+ font_size: self.width/15
+ text_size: self.width - dp(24), self.height - dp(12)
+ color: .1, .1, .1, 1
+ background_normal: 'atlas://gui/kivy/theming/light/white_bg_round_top'
+ background_down: self.background_normal
id: text_input_seed
- size_hint: 1, None
- height: '110dp'
- hint_text:
- _('Enter your seedphrase')
- on_text: root._trigger_check_seed()
+ size_hint_y: None
+ height: dp(100)
+ text: ''
+ on_text: Clock.schedule_once(root.on_text)
Label:
font_size: '12sp'
text_size: self.width, None
@@ -165,6 +176,80 @@ Builder.load_string('''
on_ref_press:
import webbrowser
webbrowser.open('https://electrum.org/faq.html#seed')
+
+ BoxLayout:
+ id: suggestions
+ height: '35dp'
+ size_hint: 1, None
+ new_word: root.on_word
+
+ BoxLayout:
+ update_amount: root.update_text
+ size_hint: 1, None
+ height: '30dp'
+ MButton:
+ text: 'Q'
+ MButton:
+ text: 'W'
+ MButton:
+ text: 'E'
+ MButton:
+ text: 'R'
+ MButton:
+ text: 'T'
+ MButton:
+ text: 'Y'
+ MButton:
+ text: 'U'
+ MButton:
+ text: 'I'
+ MButton:
+ text: 'O'
+ MButton:
+ text: 'P'
+ BoxLayout:
+ update_amount: root.update_text
+ size_hint: 1, None
+ height: '30dp'
+ MButton:
+ text: 'A'
+ MButton:
+ text: 'S'
+ MButton:
+ text: 'D'
+ MButton:
+ text: 'F'
+ MButton:
+ text: 'G'
+ MButton:
+ text: 'H'
+ MButton:
+ text: 'J'
+ MButton:
+ text: 'K'
+ MButton:
+ text: 'L'
+ BoxLayout:
+ update_amount: root.update_text
+ size_hint: 1, None
+ height: '30dp'
+ MButton:
+ text: 'Z'
+ MButton:
+ text: 'X'
+ MButton:
+ text: 'C'
+ MButton:
+ text: 'V'
+ MButton:
+ text: 'B'
+ MButton:
+ text: 'N'
+ MButton:
+ text: 'M'
+ MButton:
+ text: '<'
+
GridLayout:
rows: 1
spacing: '12dp'
@@ -182,6 +267,7 @@ Builder.load_string('''
id: next
text: _('Next')
root: root
+ disabled: True
<ShowSeedDialog>
@@ -206,8 +292,6 @@ Builder.load_string('''
valign: 'middle'
font_size: self.width/15
text_size: self.width - dp(24), self.height - dp(12)
- #size_hint: 1, None
- #height: self.texture_size[1] + dp(24)
color: .1, .1, .1, 1
background_normal: 'atlas://gui/kivy/theming/light/white_bg_round_top'
background_down: self.background_normal
@@ -215,7 +299,6 @@ Builder.load_string('''
Label:
rows: 1
size_hint: 1, .7
- id: but_seed
border: 4, 4, 4, 4
halign: 'justify'
valign: 'middle'
@@ -250,7 +333,6 @@ class WizardDialog(EventsDialog):
Window.bind(size=_trigger_size_dialog,
rotation=_trigger_size_dialog)
_trigger_size_dialog()
- Window.softinput_mode = 'pan'
def _size_dialog(self, dt):
app = App.get_running_app()
@@ -273,10 +355,7 @@ class WizardDialog(EventsDialog):
def on_dismiss(self):
app = App.get_running_app()
if app.wallet is None and self._on_release is not None:
- print "on dismiss: stopping app"
app.stop()
- else:
- Window.softinput_mode = 'below_target'
class CreateRestoreDialog(WizardDialog):
@@ -296,12 +375,12 @@ class ShowSeedDialog(WizardDialog):
def on_parent(self, instance, value):
if value:
app = App.get_running_app()
- stepper = self.ids.stepper
- stepper.opacity = 1
- stepper.source = 'atlas://gui/kivy/theming/light/stepper_full'
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
+class WordButton(Button):
+ pass
+
class RestoreSeedDialog(WizardDialog):
message = StringProperty('')
@@ -309,10 +388,34 @@ class RestoreSeedDialog(WizardDialog):
def __init__(self, **kwargs):
super(RestoreSeedDialog, self).__init__(**kwargs)
self._test = kwargs['test']
- self._trigger_check_seed = Clock.create_trigger(self.check_seed)
+ from electrum.mnemonic import Mnemonic
+ self.mnemonic = Mnemonic('en')
+
+ def on_text(self, dt):
+ text = self.get_seed_text()
+ self.ids.next.disabled = not bool(self._test(text))
- def check_seed(self, dt):
- self.ids.next.disabled = not bool(self._test(self.get_seed_text()))
+ if not text:
+ last_word = ''
+ elif text[-1] == ' ':
+ last_word = ''
+ else:
+ last_word = text.split(' ')[-1]
+
+ self.ids.suggestions.clear_widgets()
+ suggestions = [x for x in self.mnemonic.get_suggestions(last_word)]
+ if suggestions and len(suggestions) < 10:
+ for w in suggestions:
+ b = WordButton(text=w)
+ self.ids.suggestions.add_widget(b)
+
+ def on_word(self, w):
+ text = self.get_seed_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):
ti = self.ids.text_input_seed
@@ -320,6 +423,15 @@ class RestoreSeedDialog(WizardDialog):
text = ' '.join(text.split())
return text
+ def update_text(self, c):
+ c = c.lower()
+ text = self.ids.text_input_seed.text
+ if c == '<':
+ text = text[:-1]
+ else:
+ text += c
+ self.ids.text_input_seed.text = text
+
def scan_seed(self):
def on_complete(text):
self.ids.text_input_seed.text = text
@@ -330,15 +442,10 @@ class RestoreSeedDialog(WizardDialog):
if value:
tis = self.ids.text_input_seed
tis.focus = True
- tis._keyboard.bind(on_key_down=self.on_key_down)
- stepper = self.ids.stepper
- stepper.opacity = 1
- stepper.source = ('atlas://gui/kivy/theming'
- '/light/stepper_restore_seed')
+ #tis._keyboard.bind(on_key_down=self.on_key_down)
self._back = _back = partial(self.ids.back.dispatch,
'on_release')
app = App.get_running_app()
- #app.navigation_higherarchy.append(_back)
def on_key_down(self, keyboard, keycode, key, modifiers):
if keycode[0] in (13, 271):
@@ -359,7 +466,7 @@ class RestoreSeedDialog(WizardDialog):
tis.focus = False
def close(self):
- self._remove_keyboard()
+ #self._remove_keyboard()
app = App.get_running_app()
#if self._back in app.navigation_higherarchy:
# app.navigation_higherarchy.pop()
diff --git a/lib/mnemonic.py b/lib/mnemonic.py
@@ -132,6 +132,11 @@ class Mnemonic(object):
words.append(self.wordlist[x])
return ' '.join(words)
+ def get_suggestions(self, prefix):
+ for w in self.wordlist:
+ if w.startswith(prefix) and w!=prefix:
+ yield w
+
def mnemonic_decode(self, seed):
n = len(self.wordlist)
words = seed.split()