|
|
@ -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 |
|
|
|
#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) |
|
|
|
#height: self.minimum_height |
|
|
|
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() |
|
|
|