2015-10-13 03:12:49 -07:00
|
|
|
import re
|
2015-09-08 07:19:02 -07:00
|
|
|
import sys
|
2015-09-30 06:39:02 -07:00
|
|
|
import time
|
2014-06-04 17:42:29 -07:00
|
|
|
import datetime
|
2015-09-09 03:09:16 -07:00
|
|
|
import traceback
|
2015-10-13 03:12:49 -07:00
|
|
|
from decimal import Decimal
|
2015-09-08 07:19:02 -07:00
|
|
|
|
2015-10-16 02:18:24 -07:00
|
|
|
import electrum
|
2014-02-17 23:12:57 -08:00
|
|
|
from electrum import WalletStorage, Wallet
|
2014-03-01 11:11:58 -08:00
|
|
|
from electrum.i18n import _, set_language
|
2015-09-03 07:53:11 -07:00
|
|
|
from electrum.contacts import Contacts
|
2015-10-06 05:30:44 -07:00
|
|
|
from electrum.util import profiler
|
2015-10-13 03:12:49 -07:00
|
|
|
from electrum.plugins import run_hook
|
2015-12-03 13:43:43 -08:00
|
|
|
from electrum.util import format_satoshis, format_satoshis_plain
|
2014-02-17 23:12:57 -08:00
|
|
|
|
|
|
|
from kivy.app import App
|
|
|
|
from kivy.core.window import Window
|
|
|
|
from kivy.logger import Logger
|
|
|
|
from kivy.utils import platform
|
|
|
|
from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty,
|
2014-06-04 17:42:29 -07:00
|
|
|
StringProperty, ListProperty, BooleanProperty)
|
|
|
|
from kivy.cache import Cache
|
2014-03-01 11:11:58 -08:00
|
|
|
from kivy.clock import Clock
|
2014-06-04 17:42:29 -07:00
|
|
|
from kivy.factory import Factory
|
2015-10-06 00:59:29 -07:00
|
|
|
from kivy.metrics import inch, metrics
|
2015-10-13 03:12:49 -07:00
|
|
|
from kivy.lang import Builder
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
# lazy imports for factory so that widgets can be used in kv
|
|
|
|
Factory.register('InstallWizard',
|
|
|
|
module='electrum_gui.kivy.uix.dialogs.installwizard')
|
|
|
|
Factory.register('InfoBubble', module='electrum_gui.kivy.uix.dialogs')
|
|
|
|
Factory.register('ELTextInput', module='electrum_gui.kivy.uix.screens')
|
2014-06-21 10:09:31 -07:00
|
|
|
|
2015-12-01 07:51:14 -08:00
|
|
|
#from kivy.core.window import Window
|
|
|
|
#Window.softinput_mode = 'below_target'
|
2015-11-01 01:32:40 -07:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
# delayed imports: for startup speed on android
|
2015-12-03 13:43:43 -08:00
|
|
|
notification = app = ref = None
|
2014-06-04 17:42:29 -07:00
|
|
|
util = False
|
2015-10-06 00:59:29 -07:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
|
2014-08-01 09:09:34 -07:00
|
|
|
# register widget cache for keeping memory down timeout to forever to cache
|
2014-06-04 17:42:29 -07:00
|
|
|
# the data
|
2014-08-01 09:09:34 -07:00
|
|
|
Cache.register('electrum_widgets', timeout=0)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2015-10-06 00:59:29 -07:00
|
|
|
from kivy.uix.screenmanager import Screen
|
|
|
|
from kivy.uix.tabbedpanel import TabbedPanel
|
2015-10-13 03:12:49 -07:00
|
|
|
from kivy.uix.label import Label
|
|
|
|
from kivy.uix.checkbox import CheckBox
|
2015-12-06 01:41:32 -08:00
|
|
|
from kivy.uix.switch import Switch
|
2015-12-04 02:47:46 -08:00
|
|
|
from kivy.core.clipboard import Clipboard
|
2015-10-06 00:59:29 -07:00
|
|
|
|
|
|
|
Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens')
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-10-15 02:18:10 -07:00
|
|
|
base_units = {'BTC':8, 'mBTC':5, 'uBTC':2}
|
|
|
|
|
2014-02-17 23:12:57 -08:00
|
|
|
class ElectrumWindow(App):
|
|
|
|
|
2015-10-15 02:35:32 -07:00
|
|
|
electrum_config = ObjectProperty(None)
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
def _get_bu(self):
|
2015-10-15 02:18:10 -07:00
|
|
|
return self.electrum_config.get('base_unit', 'mBTC')
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
def _set_bu(self, value):
|
2015-10-15 02:18:10 -07:00
|
|
|
assert value in base_units.keys()
|
|
|
|
self.electrum_config.set_key('base_unit', value, True)
|
|
|
|
self.update_status()
|
|
|
|
if self.history_screen:
|
|
|
|
self.history_screen.update()
|
2014-06-04 17:42:29 -07:00
|
|
|
|
2015-10-15 02:18:10 -07:00
|
|
|
base_unit = AliasProperty(_get_bu, _set_bu)
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2015-10-15 02:35:32 -07:00
|
|
|
def _rotate_bu(self):
|
|
|
|
keys = sorted(base_units.keys())
|
|
|
|
self.base_unit = keys[ (keys.index(self.base_unit) + 1) % len(keys)]
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2015-12-06 01:25:02 -08:00
|
|
|
context = StringProperty('')
|
2015-12-06 01:45:57 -08:00
|
|
|
context_action = lambda x: None
|
2015-10-06 00:59:29 -07:00
|
|
|
status = StringProperty(_('Not Connected'))
|
2015-12-03 13:43:43 -08:00
|
|
|
fiat_unit = StringProperty('')
|
|
|
|
|
2015-10-15 02:18:10 -07:00
|
|
|
def decimal_point(self):
|
|
|
|
return base_units[self.base_unit]
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2015-12-03 13:43:43 -08:00
|
|
|
def btc_to_fiat(self, amount_str):
|
|
|
|
if not amount_str:
|
|
|
|
return ''
|
2015-12-05 09:14:17 -08:00
|
|
|
rate = run_hook('exchange_rate')
|
|
|
|
if not rate:
|
|
|
|
return ''
|
|
|
|
fiat_amount = self.get_amount(amount_str + ' ' + self.base_unit) * rate / pow(10, 8)
|
2015-12-07 01:40:10 -08:00
|
|
|
return "{:.2f}".format(fiat_amount).rstrip('0').rstrip('.')
|
2015-12-03 13:43:43 -08:00
|
|
|
|
|
|
|
def fiat_to_btc(self, fiat_amount):
|
|
|
|
if not fiat_amount:
|
|
|
|
return ''
|
2015-12-05 09:14:17 -08:00
|
|
|
rate = run_hook('exchange_rate')
|
|
|
|
if not rate:
|
|
|
|
return ''
|
|
|
|
satoshis = int(pow(10,8) * Decimal(fiat_amount) / Decimal(rate))
|
2015-12-07 01:40:10 -08:00
|
|
|
return format_satoshis_plain(satoshis, self.decimal_point())
|
2015-12-02 03:11:28 -08:00
|
|
|
|
2015-09-09 03:09:16 -07:00
|
|
|
def get_amount(self, amount_str):
|
2015-10-16 02:18:24 -07:00
|
|
|
a, u = amount_str.split()
|
|
|
|
assert u == self.base_unit
|
2015-09-09 03:09:16 -07:00
|
|
|
try:
|
2015-10-16 02:18:24 -07:00
|
|
|
x = Decimal(a)
|
2015-09-09 03:09:16 -07:00
|
|
|
except:
|
|
|
|
return None
|
2015-10-15 02:18:10 -07:00
|
|
|
p = pow(10, self.decimal_point())
|
2015-09-09 03:09:16 -07:00
|
|
|
return int(p * x)
|
|
|
|
|
|
|
|
|
2015-10-06 00:59:29 -07:00
|
|
|
hierarchy = ListProperty([])
|
|
|
|
'''used to navigate with the back button.
|
2014-03-01 11:11:58 -08:00
|
|
|
'''
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
_orientation = OptionProperty('landscape',
|
|
|
|
options=('landscape', 'portrait'))
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
def _get_orientation(self):
|
|
|
|
return self._orientation
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
orientation = AliasProperty(_get_orientation,
|
|
|
|
None,
|
|
|
|
bind=('_orientation',))
|
|
|
|
'''Tries to ascertain the kind of device the app is running on.
|
|
|
|
Cane be one of `tablet` or `phone`.
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
:data:`orientation` is a read only `AliasProperty` Defaults to 'landscape'
|
2014-02-17 23:12:57 -08:00
|
|
|
'''
|
|
|
|
|
|
|
|
_ui_mode = OptionProperty('phone', options=('tablet', 'phone'))
|
|
|
|
|
|
|
|
def _get_ui_mode(self):
|
|
|
|
return self._ui_mode
|
|
|
|
|
|
|
|
ui_mode = AliasProperty(_get_ui_mode,
|
|
|
|
None,
|
|
|
|
bind=('_ui_mode',))
|
|
|
|
'''Defines tries to ascertain the kind of device the app is running on.
|
|
|
|
Cane be one of `tablet` or `phone`.
|
|
|
|
|
|
|
|
:data:`ui_mode` is a read only `AliasProperty` Defaults to 'phone'
|
|
|
|
'''
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
url = StringProperty('', allownone=True)
|
|
|
|
'''
|
2014-02-17 23:12:57 -08:00
|
|
|
'''
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
wallet = ObjectProperty(None)
|
|
|
|
'''Holds the electrum wallet
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
:attr:`wallet` is a `ObjectProperty` defaults to None.
|
2014-02-17 23:12:57 -08:00
|
|
|
'''
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
# initialize variables
|
2015-12-04 02:47:46 -08:00
|
|
|
self._clipboard = Clipboard
|
2014-06-04 17:42:29 -07:00
|
|
|
self.info_bubble = None
|
|
|
|
self.qrscanner = None
|
|
|
|
self.nfcscanner = None
|
|
|
|
self.tabs = None
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2014-02-17 23:12:57 -08:00
|
|
|
super(ElectrumWindow, self).__init__(**kwargs)
|
2014-03-04 10:02:03 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
title = _('Electrum App')
|
|
|
|
self.electrum_config = config = kwargs.get('config', None)
|
2015-10-13 03:12:49 -07:00
|
|
|
self.network = network = kwargs.get('network', None)
|
|
|
|
self.plugins = kwargs.get('plugins', [])
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
self.gui_object = kwargs.get('gui_object', None)
|
|
|
|
|
2015-09-09 03:09:16 -07:00
|
|
|
#self.config = self.gui_object.config
|
|
|
|
self.contacts = Contacts(self.electrum_config)
|
2015-09-03 07:53:11 -07:00
|
|
|
|
2015-12-02 06:27:23 -08:00
|
|
|
self.bind(url=self.set_URI)
|
2014-06-04 17:42:29 -07:00
|
|
|
# were we sent a url?
|
2015-10-16 02:18:24 -07:00
|
|
|
url = self.electrum_config.get('url', None)
|
2014-06-04 17:42:29 -07:00
|
|
|
if url:
|
2015-12-02 06:27:23 -08:00
|
|
|
self.set_URI(url)
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-03-10 11:48:12 -07:00
|
|
|
# create triggers so as to minimize updation a max of 2 times a sec
|
2014-06-04 17:42:29 -07:00
|
|
|
self._trigger_update_wallet =\
|
|
|
|
Clock.create_trigger(self.update_wallet, .5)
|
2014-03-04 10:02:03 -08:00
|
|
|
self._trigger_update_status =\
|
2014-03-10 11:48:12 -07:00
|
|
|
Clock.create_trigger(self.update_status, .5)
|
2014-03-01 11:11:58 -08:00
|
|
|
self._trigger_notify_transactions = \
|
2014-06-04 17:42:29 -07:00
|
|
|
Clock.create_trigger(self.notify_transactions, 5)
|
|
|
|
|
2015-12-02 06:27:23 -08:00
|
|
|
def set_URI(self, url):
|
|
|
|
try:
|
|
|
|
url = electrum.util.parse_URI(url)
|
|
|
|
except:
|
|
|
|
self.show_info("Invalid URI", url)
|
|
|
|
return
|
|
|
|
self.send_screen.set_URI(url)
|
|
|
|
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2015-09-08 07:19:02 -07:00
|
|
|
def scan_qr(self, on_complete):
|
|
|
|
from jnius import autoclass
|
2015-09-09 03:09:16 -07:00
|
|
|
from android import activity
|
2015-09-08 07:19:02 -07:00
|
|
|
PythonActivity = autoclass('org.renpy.android.PythonActivity')
|
|
|
|
Intent = autoclass('android.content.Intent')
|
|
|
|
intent = Intent("com.google.zxing.client.android.SCAN")
|
|
|
|
intent.putExtra("SCAN_MODE", "QR_CODE_MODE")
|
|
|
|
def on_qr_result(requestCode, resultCode, intent):
|
|
|
|
if requestCode == 0:
|
|
|
|
if resultCode == -1: # RESULT_OK:
|
|
|
|
contents = intent.getStringExtra("SCAN_RESULT")
|
|
|
|
if intent.getStringExtra("SCAN_RESULT_FORMAT") == 'QR_CODE':
|
2015-12-02 06:27:23 -08:00
|
|
|
try:
|
|
|
|
uri = electrum.util.parse_URI(contents)
|
|
|
|
except:
|
|
|
|
self.show_info("Invalid URI", url)
|
|
|
|
return
|
2015-09-08 07:19:02 -07:00
|
|
|
on_complete(uri)
|
|
|
|
activity.bind(on_activity_result=on_qr_result)
|
|
|
|
PythonActivity.mActivity.startActivityForResult(intent, 0)
|
|
|
|
|
2015-10-13 03:12:49 -07:00
|
|
|
def show_plugins(self, plugins_list):
|
2015-12-06 01:41:32 -08:00
|
|
|
def on_active(sw, value):
|
|
|
|
self.plugins.toggle_enabled(self.electrum_config, sw.name)
|
2015-10-13 03:12:49 -07:00
|
|
|
for item in self.plugins.descriptions:
|
|
|
|
if 'kivy' not in item.get('available_for', []):
|
|
|
|
continue
|
2015-12-01 07:51:14 -08:00
|
|
|
name = item.get('__name__')
|
|
|
|
label = Label(text=item.get('fullname'), height='48db', size_hint=(1, None))
|
2015-10-13 03:12:49 -07:00
|
|
|
plugins_list.add_widget(label)
|
2015-12-06 01:41:32 -08:00
|
|
|
sw = Switch()
|
|
|
|
sw.name = name
|
2015-10-13 03:12:49 -07:00
|
|
|
p = self.plugins.get(name)
|
2015-12-06 01:41:32 -08:00
|
|
|
sw.active = (p is not None) and p.is_enabled()
|
|
|
|
sw.bind(active=on_active)
|
|
|
|
plugins_list.add_widget(sw)
|
2015-10-06 00:59:29 -07:00
|
|
|
|
2015-10-13 03:12:49 -07:00
|
|
|
def build(self):
|
2014-02-17 23:12:57 -08:00
|
|
|
return Builder.load_file('gui/kivy/main.kv')
|
|
|
|
|
|
|
|
def _pause(self):
|
|
|
|
if platform == 'android':
|
2014-03-01 11:11:58 -08:00
|
|
|
# move activity to back
|
2014-02-17 23:12:57 -08:00
|
|
|
from jnius import autoclass
|
|
|
|
python_act = autoclass('org.renpy.android.PythonActivity')
|
|
|
|
mActivity = python_act.mActivity
|
|
|
|
mActivity.moveTaskToBack(True)
|
|
|
|
|
|
|
|
def on_start(self):
|
2014-03-01 11:11:58 -08:00
|
|
|
''' This is the start point of the kivy ui
|
|
|
|
'''
|
2015-10-06 00:59:29 -07:00
|
|
|
Logger.info("dpi: {} {}".format(metrics.dpi, metrics.dpi_rounded))
|
2014-06-04 17:42:29 -07:00
|
|
|
win = Window
|
|
|
|
win.bind(size=self.on_size,
|
2014-02-17 23:12:57 -08:00
|
|
|
on_keyboard=self.on_keyboard)
|
2014-06-04 17:42:29 -07:00
|
|
|
win.bind(on_key_down=self.on_key_down)
|
2014-03-10 11:48:12 -07:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
# Register fonts without this you won't be able to use bold/italic...
|
|
|
|
# inside markup.
|
2014-03-10 11:48:12 -07:00
|
|
|
from kivy.core.text import Label
|
|
|
|
Label.register('Roboto',
|
|
|
|
'data/fonts/Roboto.ttf',
|
|
|
|
'data/fonts/Roboto.ttf',
|
|
|
|
'data/fonts/Roboto-Bold.ttf',
|
|
|
|
'data/fonts/Roboto-Bold.ttf')
|
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
if platform == 'android':
|
2014-06-04 17:42:29 -07:00
|
|
|
# bind to keyboard height so we can get the window contents to
|
|
|
|
# behave the way we want when the keyboard appears.
|
|
|
|
win.bind(keyboard_height=self.on_keyboard_height)
|
|
|
|
|
|
|
|
self.on_size(win, win.size)
|
2014-02-17 23:12:57 -08:00
|
|
|
config = self.electrum_config
|
2015-09-03 06:09:45 -07:00
|
|
|
storage = WalletStorage(config.get_wallet_path())
|
2014-02-17 23:12:57 -08:00
|
|
|
|
|
|
|
Logger.info('Electrum: Check for existing wallet')
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
if storage.file_exists:
|
|
|
|
wallet = Wallet(storage)
|
|
|
|
action = wallet.get_action()
|
|
|
|
else:
|
|
|
|
action = 'new'
|
|
|
|
|
|
|
|
if action is not None:
|
2014-02-17 23:12:57 -08:00
|
|
|
# start installation wizard
|
|
|
|
Logger.debug('Electrum: Wallet not found. Launching install wizard')
|
2014-06-04 17:42:29 -07:00
|
|
|
wizard = Factory.InstallWizard(config, self.network, storage)
|
2014-02-17 23:12:57 -08:00
|
|
|
wizard.bind(on_wizard_complete=self.on_wizard_complete)
|
2014-06-04 17:42:29 -07:00
|
|
|
wizard.run(action)
|
2014-02-17 23:12:57 -08:00
|
|
|
else:
|
|
|
|
wallet.start_threads(self.network)
|
|
|
|
self.on_wizard_complete(None, wallet)
|
|
|
|
|
|
|
|
self.on_resume()
|
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
def on_stop(self):
|
2014-03-04 10:02:03 -08:00
|
|
|
if self.wallet:
|
|
|
|
self.wallet.stop_threads()
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2015-10-06 00:59:29 -07:00
|
|
|
def on_back(self):
|
|
|
|
try:
|
|
|
|
self.hierarchy.pop()()
|
|
|
|
except IndexError:
|
|
|
|
# capture back button and pause app.
|
|
|
|
self._pause()
|
|
|
|
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
def on_keyboard_height(self, window, height):
|
|
|
|
win = window
|
|
|
|
active_widg = win.children[0]
|
|
|
|
if not issubclass(active_widg.__class__, Factory.Popup):
|
|
|
|
try:
|
|
|
|
active_widg = self.root.children[0]
|
|
|
|
except IndexError:
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
fw = self._focused_widget
|
|
|
|
except AttributeError:
|
|
|
|
return
|
|
|
|
if height > 0 and fw.to_window(*fw.pos)[1] > height:
|
|
|
|
return
|
|
|
|
Factory.Animation(y=win.keyboard_height, d=.1).start(active_widg)
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
def on_key_down(self, instance, key, keycode, codepoint, modifiers):
|
|
|
|
if 'ctrl' in modifiers:
|
|
|
|
# q=24 w=25
|
|
|
|
if keycode in (24, 25):
|
|
|
|
self.stop()
|
|
|
|
elif keycode == 27:
|
|
|
|
# r=27
|
|
|
|
# force update wallet
|
|
|
|
self.update_wallet()
|
|
|
|
elif keycode == 112:
|
|
|
|
# pageup
|
|
|
|
#TODO move to next tab
|
|
|
|
pass
|
|
|
|
elif keycode == 117:
|
|
|
|
# pagedown
|
|
|
|
#TODO move to prev tab
|
|
|
|
pass
|
|
|
|
#TODO: alt+tab_number to activate the particular tab
|
|
|
|
|
2014-02-17 23:12:57 -08:00
|
|
|
def on_keyboard(self, instance, key, keycode, codepoint, modifiers):
|
|
|
|
# override settings button
|
2014-03-01 11:11:58 -08:00
|
|
|
if key in (319, 282): #f1/settings button on android
|
2014-02-17 23:12:57 -08:00
|
|
|
self.gui.main_gui.toggle_settings(self)
|
|
|
|
return True
|
|
|
|
|
|
|
|
def on_wizard_complete(self, instance, wallet):
|
|
|
|
if not wallet:
|
|
|
|
Logger.debug('Electrum: No Wallet set/found. Exiting...')
|
2014-06-04 17:42:29 -07:00
|
|
|
app = App.get_running_app()
|
2014-02-21 20:55:26 -08:00
|
|
|
app.show_error('Electrum: No Wallet set/found. Exiting...',
|
|
|
|
exit=True)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
self.init_ui()
|
2014-02-17 23:12:57 -08:00
|
|
|
self.load_wallet(wallet)
|
|
|
|
|
2015-10-06 00:59:29 -07:00
|
|
|
def popup_dialog(self, name):
|
|
|
|
popup = Builder.load_file('gui/kivy/uix/ui_screens/'+name+'.kv')
|
|
|
|
popup.open()
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-09-30 06:39:02 -07:00
|
|
|
@profiler
|
2014-03-01 11:11:58 -08:00
|
|
|
def init_ui(self):
|
|
|
|
''' Initialize The Ux part of electrum. This function performs the basic
|
|
|
|
tasks of setting up the ui.
|
|
|
|
'''
|
2015-10-13 10:09:12 -07:00
|
|
|
from weakref import ref
|
2014-03-01 11:11:58 -08:00
|
|
|
set_language(self.electrum_config.get('language'))
|
|
|
|
|
|
|
|
self.funds_error = False
|
|
|
|
# setup UX
|
2015-10-06 00:59:29 -07:00
|
|
|
self.screens = {}
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
#setup lazy imports for mainscreen
|
|
|
|
Factory.register('AnimatedPopup',
|
|
|
|
module='electrum_gui.kivy.uix.dialogs')
|
|
|
|
Factory.register('QRCodeWidget',
|
|
|
|
module='electrum_gui.kivy.uix.qrcodewidget')
|
2015-09-09 07:02:06 -07:00
|
|
|
|
2014-08-01 09:09:34 -07:00
|
|
|
# preload widgets. Remove this if you want to load the widgets on demand
|
2015-10-07 04:06:28 -07:00
|
|
|
#Cache.append('electrum_widgets', 'AnimatedPopup', Factory.AnimatedPopup())
|
|
|
|
#Cache.append('electrum_widgets', 'QRCodeWidget', Factory.QRCodeWidget())
|
2014-08-01 09:09:34 -07:00
|
|
|
|
|
|
|
# load and focus the ui
|
2015-10-06 00:59:29 -07:00
|
|
|
self.root.manager = self.root.ids['manager']
|
|
|
|
self.recent_activity_card = None
|
|
|
|
self.history_screen = None
|
|
|
|
self.contacts_screen = None
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
self.icon = "icons/electrum.png"
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
# connect callbacks
|
|
|
|
if self.network:
|
2015-12-01 04:50:47 -08:00
|
|
|
interests = ['updated', 'status', 'new_transaction']
|
2015-11-13 05:42:21 -08:00
|
|
|
self.network.register_callback(self.on_network, interests)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
self.wallet = None
|
|
|
|
|
2015-11-13 05:42:21 -08:00
|
|
|
def on_network(self, event, *args):
|
|
|
|
if event == 'updated':
|
|
|
|
self._trigger_update_wallet()
|
|
|
|
elif event == 'status':
|
|
|
|
self._trigger_update_status()
|
|
|
|
elif event == 'new_transaction':
|
|
|
|
self._trigger_notify_transactions(*args)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2015-09-30 06:39:02 -07:00
|
|
|
@profiler
|
2014-03-01 11:11:58 -08:00
|
|
|
def load_wallet(self, wallet):
|
|
|
|
self.wallet = wallet
|
|
|
|
self.current_account = self.wallet.storage.get('current_account', None)
|
|
|
|
self.update_wallet()
|
|
|
|
# Once GUI has been initialized check if we want to announce something
|
|
|
|
# since the callback has been called before the GUI was initialized
|
2014-06-04 17:42:29 -07:00
|
|
|
self.update_history_tab()
|
2014-03-01 11:11:58 -08:00
|
|
|
self.notify_transactions()
|
2015-12-01 08:29:24 -08:00
|
|
|
run_hook('load_wallet', wallet, self)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
def update_status(self, *dt):
|
|
|
|
if not self.wallet:
|
|
|
|
return
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
unconfirmed = ''
|
|
|
|
quote_text = ''
|
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
if self.network is None or not self.network.is_running():
|
|
|
|
text = _("Offline")
|
|
|
|
|
|
|
|
elif self.network.is_connected():
|
2015-09-04 01:23:56 -07:00
|
|
|
server_height = self.network.get_server_height()
|
|
|
|
server_lag = self.network.get_local_height() - server_height
|
|
|
|
if not self.wallet.up_to_date or server_height == 0:
|
2015-10-06 00:59:29 -07:00
|
|
|
self.status = _("Synchronizing...")
|
2015-09-04 01:23:56 -07:00
|
|
|
elif server_lag > 1:
|
2015-10-06 00:59:29 -07:00
|
|
|
self.status = _("Server lagging (%d blocks)"%server_lag)
|
2014-03-01 11:11:58 -08:00
|
|
|
else:
|
2015-09-04 01:23:56 -07:00
|
|
|
c, u, x = self.wallet.get_account_balance(self.current_account)
|
|
|
|
text = self.format_amount(c)
|
2014-03-01 11:11:58 -08:00
|
|
|
if u:
|
2015-09-04 01:23:56 -07:00
|
|
|
unconfirmed = " [%s unconfirmed]" %( self.format_amount(u, True).strip())
|
|
|
|
if x:
|
|
|
|
unmatured = " [%s unmatured]"%(self.format_amount(x, True).strip())
|
2015-10-13 03:12:49 -07:00
|
|
|
#quote_text = self.create_quote_text(Decimal(c+u+x)/100000000, mode='symbol') or ''
|
2015-10-06 05:30:44 -07:00
|
|
|
self.status = text.strip() + ' ' + self.base_unit
|
2014-03-01 11:11:58 -08:00
|
|
|
else:
|
2015-10-06 00:59:29 -07:00
|
|
|
self.status = _("Not connected")
|
2015-10-30 07:11:54 -07:00
|
|
|
|
2015-10-06 00:59:29 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
print self.root.manager.ids
|
|
|
|
|
|
|
|
#try:
|
|
|
|
status_card = self.root.main_screen.ids.tabs.ids.\
|
|
|
|
screen_dashboard.ids.status_card
|
|
|
|
#except AttributeError:
|
|
|
|
# return
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
status_card.quote_text = quote_text.strip()
|
|
|
|
status_card.uncomfirmed = unconfirmed.strip()
|
2014-03-01 11:11:58 -08:00
|
|
|
|
2015-10-16 05:59:26 -07:00
|
|
|
|
2015-10-30 06:10:41 -07:00
|
|
|
def get_max_amount(self):
|
|
|
|
inputs = self.wallet.get_spendable_coins(None)
|
|
|
|
amount, fee = self.wallet.get_max_amount(self.electrum_config, inputs, None)
|
2015-10-31 07:25:22 -07:00
|
|
|
return format_satoshis_plain(amount, self.decimal_point())
|
2015-10-30 06:10:41 -07:00
|
|
|
|
2015-12-07 01:40:10 -08:00
|
|
|
def update_password(self, label, c):
|
|
|
|
text = label.password
|
|
|
|
if c == '<':
|
|
|
|
text = text[:-1]
|
|
|
|
elif c == 'Clear':
|
|
|
|
text = ''
|
|
|
|
else:
|
|
|
|
text += c
|
|
|
|
label.password = text
|
|
|
|
|
|
|
|
def toggle_fiat(self, a):
|
|
|
|
a.is_fiat = not a.is_fiat
|
|
|
|
|
2015-12-03 13:43:43 -08:00
|
|
|
def update_amount(self, label, c):
|
|
|
|
amount = label.fiat_amount if label.is_fiat else label.amount
|
2015-10-16 05:59:26 -07:00
|
|
|
if c == '<':
|
2015-12-03 13:43:43 -08:00
|
|
|
amount = amount[:-1]
|
|
|
|
elif c == '.' and amount == '':
|
|
|
|
amount = '0.'
|
|
|
|
elif c == '0' and amount == '0':
|
|
|
|
amount = '0'
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
Decimal(amount+c)
|
|
|
|
amount += c
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
if label.is_fiat:
|
|
|
|
label.fiat_amount = amount
|
|
|
|
else:
|
|
|
|
label.amount = amount
|
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
def format_amount(self, x, is_diff=False, whitespaces=False):
|
2015-12-03 13:43:43 -08:00
|
|
|
return format_satoshis(x, is_diff, 0, self.decimal_point(), whitespaces)
|
2014-06-04 17:42:29 -07:00
|
|
|
|
2015-09-30 06:39:02 -07:00
|
|
|
@profiler
|
2014-06-04 17:42:29 -07:00
|
|
|
def update_wallet(self, *dt):
|
|
|
|
self._trigger_update_status()
|
2015-09-04 00:48:43 -07:00
|
|
|
if self.wallet.up_to_date or not self.network or not self.network.is_connected():
|
2014-06-04 17:42:29 -07:00
|
|
|
self.update_history_tab()
|
|
|
|
self.update_contacts_tab()
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
|
2015-09-30 06:39:02 -07:00
|
|
|
@profiler
|
2014-06-04 17:42:29 -07:00
|
|
|
def update_history_tab(self, see_all=False):
|
2015-10-06 00:59:29 -07:00
|
|
|
if self.history_screen:
|
|
|
|
self.history_screen.update(see_all)
|
2014-03-01 11:11:58 -08:00
|
|
|
|
|
|
|
def update_contacts_tab(self):
|
2015-10-06 00:59:29 -07:00
|
|
|
if self.contacts_screen:
|
|
|
|
self.contacts_screen.update()
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
|
2015-09-30 06:39:02 -07:00
|
|
|
@profiler
|
2014-03-01 11:11:58 -08:00
|
|
|
def notify_transactions(self, *dt):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
if not self.network or not self.network.is_connected():
|
|
|
|
return
|
2015-09-03 06:09:45 -07:00
|
|
|
# temporarily disabled for merge
|
|
|
|
return
|
2014-06-04 17:42:29 -07:00
|
|
|
iface = self.network
|
|
|
|
ptfn = iface.pending_transactions_for_notifications
|
|
|
|
if len(ptfn) > 0:
|
2014-03-01 11:11:58 -08:00
|
|
|
# Combine the transactions if there are more then three
|
2014-06-04 17:42:29 -07:00
|
|
|
tx_amount = len(ptfn)
|
2014-03-01 11:11:58 -08:00
|
|
|
if(tx_amount >= 3):
|
|
|
|
total_amount = 0
|
2014-06-04 17:42:29 -07:00
|
|
|
for tx in ptfn:
|
2014-03-01 11:11:58 -08:00
|
|
|
is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
|
|
|
|
if(v > 0):
|
|
|
|
total_amount += v
|
|
|
|
self.notify(_("{txs}s new transactions received. Total amount"
|
|
|
|
"received in the new transactions {amount}s"
|
|
|
|
"{unit}s").format(txs=tx_amount,
|
|
|
|
amount=self.format_amount(total_amount),
|
|
|
|
unit=self.base_unit()))
|
|
|
|
|
|
|
|
iface.pending_transactions_for_notifications = []
|
|
|
|
else:
|
|
|
|
for tx in iface.pending_transactions_for_notifications:
|
|
|
|
if tx:
|
|
|
|
iface.pending_transactions_for_notifications.remove(tx)
|
|
|
|
is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
|
|
|
|
if(v > 0):
|
|
|
|
self.notify(
|
2014-06-21 10:09:31 -07:00
|
|
|
_("{txs} new transaction received. {amount} {unit}").
|
|
|
|
format(txs=tx_amount, amount=self.format_amount(v),
|
2014-06-04 17:42:29 -07:00
|
|
|
unit=self.base_unit))
|
|
|
|
|
2014-03-01 11:11:58 -08:00
|
|
|
def notify(self, message):
|
|
|
|
try:
|
|
|
|
global notification, os
|
|
|
|
if not notification:
|
|
|
|
from plyer import notification
|
|
|
|
import os
|
|
|
|
icon = (os.path.dirname(os.path.realpath(__file__))
|
|
|
|
+ '/../../' + self.icon)
|
|
|
|
notification.notify('Electrum', message,
|
|
|
|
app_icon=icon, app_name='Electrum')
|
|
|
|
except ImportError:
|
|
|
|
Logger.Error('Notification: needs plyer; `sudo pip install plyer`')
|
2014-02-17 23:12:57 -08:00
|
|
|
|
|
|
|
def on_pause(self):
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
# pause nfc
|
2014-06-04 17:42:29 -07:00
|
|
|
if self.qrscanner:
|
|
|
|
self.qrscanner.stop()
|
|
|
|
if self.nfcscanner:
|
|
|
|
self.nfcscanner.nfc_disable()
|
2014-02-17 23:12:57 -08:00
|
|
|
return True
|
|
|
|
|
|
|
|
def on_resume(self):
|
|
|
|
'''
|
|
|
|
'''
|
2014-06-04 17:42:29 -07:00
|
|
|
if self.qrscanner and qrscanner.get_parent_window():
|
|
|
|
self.qrscanner.start()
|
|
|
|
if self.nfcscanner:
|
|
|
|
self.nfcscanner.nfc_enable()
|
2014-02-17 23:12:57 -08:00
|
|
|
|
|
|
|
def on_size(self, instance, value):
|
|
|
|
width, height = value
|
|
|
|
self._orientation = 'landscape' if width > height else 'portrait'
|
|
|
|
self._ui_mode = 'tablet' if min(width, height) > inch(3.51) else 'phone'
|
2015-10-06 00:59:29 -07:00
|
|
|
#Logger.info("size: {} {}".format(width, height))
|
|
|
|
#Logger.info('orientation: {}'.format(self._orientation))
|
|
|
|
#Logger.info('ui_mode: {}'.format(self._ui_mode))
|
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
def save_new_contact(self, address, label):
|
|
|
|
address = unicode(address)
|
|
|
|
label = unicode(label)
|
|
|
|
global is_valid
|
|
|
|
if not is_valid:
|
|
|
|
from electrum.bitcoin import is_valid
|
|
|
|
|
|
|
|
if is_valid(address):
|
|
|
|
if label:
|
|
|
|
self.set_label(address, text=label)
|
|
|
|
self.wallet.add_contact(address)
|
|
|
|
self.update_contacts_tab()
|
|
|
|
self.update_history_tab()
|
|
|
|
else:
|
|
|
|
self.show_error(_('Invalid Address'))
|
|
|
|
|
|
|
|
def send_payment(self, address, amount=0, label='', message=''):
|
|
|
|
tabs = self.tabs
|
|
|
|
screen_send = tabs.ids.screen_send
|
|
|
|
|
|
|
|
if label and self.wallet.labels.get(address) != label:
|
|
|
|
#if self.question('Give label "%s" to address %s ?'%(label,address)):
|
|
|
|
if address not in self.wallet.addressbook and not self.wallet. is_mine(address):
|
|
|
|
self.wallet.addressbook.append(address)
|
|
|
|
self.wallet.set_label(address, label)
|
|
|
|
|
|
|
|
# switch_to the send screen
|
|
|
|
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
|
|
|
|
|
|
label = self.wallet.labels.get(address)
|
|
|
|
m_addr = label + ' <'+ address +'>' if label else address
|
|
|
|
|
|
|
|
# populate
|
|
|
|
def set_address(*l):
|
2014-08-01 09:09:34 -07:00
|
|
|
content = screen_send.ids
|
2014-06-04 17:42:29 -07:00
|
|
|
content.payto_e.text = m_addr
|
|
|
|
content.message_e.text = message
|
|
|
|
if amount:
|
|
|
|
content.amount_e.text = amount
|
|
|
|
|
|
|
|
# wait for screen to load
|
|
|
|
Clock.schedule_once(set_address, .5)
|
|
|
|
|
|
|
|
def set_send(self, address, amount, label, message):
|
|
|
|
self.send_payment(address, amount=amount, label=label, message=message)
|
|
|
|
|
|
|
|
def prepare_for_payment_request(self):
|
|
|
|
tabs = self.tabs
|
|
|
|
screen_send = tabs.ids.screen_send
|
|
|
|
|
|
|
|
# switch_to the send screen
|
|
|
|
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
|
|
|
2014-08-01 09:09:34 -07:00
|
|
|
content = screen_send.ids
|
2014-06-04 17:42:29 -07:00
|
|
|
if content:
|
|
|
|
self.set_frozen(content, False)
|
|
|
|
screen_send.screen_label.text = _("please wait...")
|
|
|
|
return True
|
|
|
|
|
|
|
|
def payment_request_ok(self):
|
|
|
|
tabs = self.tabs
|
|
|
|
screen_send = tabs.ids.screen_send
|
|
|
|
|
|
|
|
# switch_to the send screen
|
|
|
|
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
|
|
|
|
|
|
self.set_frozen(content, True)
|
|
|
|
|
2014-08-01 09:09:34 -07:00
|
|
|
screen_send.ids.payto_e.text = self.gui_object.payment_request.domain
|
|
|
|
screen_send.ids.amount_e.text = self.format_amount(self.gui_object.payment_request.get_amount())
|
|
|
|
screen_send.ids.message_e.text = self.gui_object.payment_request.memo
|
2014-06-04 17:42:29 -07:00
|
|
|
|
|
|
|
# wait for screen to load
|
|
|
|
Clock.schedule_once(set_address, .5)
|
|
|
|
|
|
|
|
def set_frozen(self, entry, frozen):
|
|
|
|
if frozen:
|
|
|
|
entry.disabled = True
|
|
|
|
Factory.Animation(opacity=0).start(content)
|
|
|
|
else:
|
|
|
|
entry.disabled = False
|
|
|
|
Factory.Animation(opacity=1).start(content)
|
|
|
|
|
|
|
|
def payment_request_error(self):
|
|
|
|
tabs = self.tabs
|
|
|
|
screen_send = tabs.ids.screen_send
|
|
|
|
|
|
|
|
# switch_to the send screen
|
|
|
|
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
|
|
|
|
|
|
self.do_clear()
|
|
|
|
self.show_info(self.gui_object.payment_request.error)
|
|
|
|
|
|
|
|
def show_error(self, error, width='200dp', pos=None, arrow_pos=None,
|
|
|
|
exit=False, icon='atlas://gui/kivy/theming/light/error', duration=0,
|
|
|
|
modal=False):
|
2014-02-17 23:12:57 -08:00
|
|
|
''' Show a error Message Bubble.
|
|
|
|
'''
|
2014-06-04 17:42:29 -07:00
|
|
|
self.show_info_bubble( text=error, icon=icon, width=width,
|
|
|
|
pos=pos or Window.center, arrow_pos=arrow_pos, exit=exit,
|
|
|
|
duration=duration, modal=modal)
|
|
|
|
|
|
|
|
def show_info(self, error, width='200dp', pos=None, arrow_pos=None,
|
|
|
|
exit=False, duration=0, modal=False):
|
2014-02-20 23:50:27 -08:00
|
|
|
''' Show a Info Message Bubble.
|
|
|
|
'''
|
2014-03-01 11:11:58 -08:00
|
|
|
self.show_error(error, icon='atlas://gui/kivy/theming/light/error',
|
2014-06-04 17:42:29 -07:00
|
|
|
duration=duration, modal=modal, exit=exit, pos=pos,
|
|
|
|
arrow_pos=arrow_pos)
|
|
|
|
|
|
|
|
def show_info_bubble(self, text=_('Hello World'), pos=None, duration=0,
|
|
|
|
arrow_pos='bottom_mid', width=None, icon='', modal=False, exit=False):
|
2014-02-17 23:12:57 -08:00
|
|
|
'''Method to show a Information Bubble
|
|
|
|
|
|
|
|
.. parameters::
|
|
|
|
text: Message to be displayed
|
|
|
|
pos: position for the bubble
|
|
|
|
duration: duration the bubble remains on screen. 0 = click to hide
|
|
|
|
width: width of the Bubble
|
|
|
|
arrow_pos: arrow position for the bubble
|
|
|
|
'''
|
|
|
|
info_bubble = self.info_bubble
|
|
|
|
if not info_bubble:
|
2014-06-04 17:42:29 -07:00
|
|
|
info_bubble = self.info_bubble = Factory.InfoBubble()
|
2014-02-17 23:12:57 -08:00
|
|
|
|
2014-06-04 17:42:29 -07:00
|
|
|
win = Window
|
2014-02-17 23:12:57 -08:00
|
|
|
if info_bubble.parent:
|
2014-06-04 17:42:29 -07:00
|
|
|
win.remove_widget(info_bubble
|
2014-02-20 23:50:27 -08:00
|
|
|
if not info_bubble.modal else
|
|
|
|
info_bubble._modal_view)
|
2014-02-17 23:12:57 -08:00
|
|
|
|
|
|
|
if not arrow_pos:
|
|
|
|
info_bubble.show_arrow = False
|
|
|
|
else:
|
|
|
|
info_bubble.show_arrow = True
|
|
|
|
info_bubble.arrow_pos = arrow_pos
|
|
|
|
img = info_bubble.ids.img
|
|
|
|
if text == 'texture':
|
|
|
|
# icon holds a texture not a source image
|
|
|
|
# display the texture in full screen
|
|
|
|
text = ''
|
|
|
|
img.texture = icon
|
|
|
|
info_bubble.fs = True
|
|
|
|
info_bubble.show_arrow = False
|
|
|
|
img.allow_stretch = True
|
|
|
|
info_bubble.dim_background = True
|
|
|
|
info_bubble.background_image = 'atlas://gui/kivy/theming/light/card'
|
|
|
|
else:
|
|
|
|
info_bubble.fs = False
|
|
|
|
info_bubble.icon = icon
|
2015-09-09 07:13:40 -07:00
|
|
|
#if img.texture and img._coreimage:
|
|
|
|
# img.reload()
|
2014-02-17 23:12:57 -08:00
|
|
|
img.allow_stretch = False
|
|
|
|
info_bubble.dim_background = False
|
|
|
|
info_bubble.background_image = 'atlas://data/images/defaulttheme/bubble'
|
|
|
|
info_bubble.message = text
|
2014-06-04 17:42:29 -07:00
|
|
|
if not pos:
|
2015-12-02 03:11:28 -08:00
|
|
|
pos = (win.center[0], win.center[1] - (info_bubble.height/2))
|
2014-08-01 09:09:34 -07:00
|
|
|
info_bubble.show(pos, duration, width, modal=modal, exit=exit)
|
2015-10-13 10:09:12 -07:00
|
|
|
|
2015-10-16 21:11:23 -07:00
|
|
|
def tx_dialog(self, tx_hash):
|
|
|
|
popup = Builder.load_file('gui/kivy/uix/ui_screens/transaction.kv')
|
|
|
|
popup.tx_hash = tx_hash
|
|
|
|
popup.open()
|
2015-10-13 10:09:12 -07:00
|
|
|
|
2015-12-06 01:25:02 -08:00
|
|
|
def tx_selected(self, txid, state):
|
|
|
|
if state == 'down':
|
|
|
|
self.context = 'tx'
|
|
|
|
self.context_action = lambda: self.tx_dialog(txid)
|
|
|
|
else:
|
|
|
|
self.reset_context()
|
|
|
|
|
|
|
|
def reset_context(self):
|
|
|
|
self.context = ''
|
|
|
|
self.context_action = lambda: None
|
|
|
|
|
2015-12-04 02:47:46 -08:00
|
|
|
def amount_dialog(self, screen, show_max):
|
2015-10-14 02:44:01 -07:00
|
|
|
popup = Builder.load_file('gui/kivy/uix/ui_screens/amount.kv')
|
2015-10-30 07:11:54 -07:00
|
|
|
but_max = popup.ids.but_max
|
|
|
|
if not show_max:
|
|
|
|
but_max.disabled = True
|
|
|
|
but_max.opacity = 0
|
|
|
|
else:
|
|
|
|
but_max.disabled = False
|
|
|
|
but_max.opacity = 1
|
|
|
|
|
2015-12-04 02:47:46 -08:00
|
|
|
amount = screen.amount
|
|
|
|
if amount:
|
|
|
|
a, u = str(amount).split()
|
2015-10-16 02:18:24 -07:00
|
|
|
assert u == self.base_unit
|
2015-12-07 01:40:10 -08:00
|
|
|
popup.ids.kb.amount = a
|
2015-12-04 02:47:46 -08:00
|
|
|
|
2015-10-14 02:44:01 -07:00
|
|
|
def cb():
|
2015-12-03 13:43:43 -08:00
|
|
|
o = popup.ids.a.btc_text
|
2015-12-04 02:47:46 -08:00
|
|
|
screen.amount = o
|
|
|
|
|
2015-10-14 02:44:01 -07:00
|
|
|
popup.on_dismiss = cb
|
|
|
|
popup.open()
|
|
|
|
|
2015-12-07 01:40:10 -08:00
|
|
|
def change_password(self):
|
|
|
|
self.password_dialog(self._change_password, ())
|
|
|
|
|
|
|
|
def _change_password(self, password):
|
|
|
|
print "zs", password
|
|
|
|
|
2015-10-13 10:09:12 -07:00
|
|
|
def password_dialog(self, f, args):
|
|
|
|
if self.wallet.use_encryption:
|
|
|
|
popup = Builder.load_file('gui/kivy/uix/ui_screens/password.kv')
|
|
|
|
def callback():
|
2015-12-07 01:40:10 -08:00
|
|
|
pw = popup.ids.kb.password
|
2015-10-13 10:09:12 -07:00
|
|
|
Clock.schedule_once(lambda x: apply(f, args + (pw,)), 0.5)
|
|
|
|
popup.on_dismiss = callback
|
|
|
|
popup.open()
|
|
|
|
else:
|
|
|
|
apply(f, args + (None,))
|