handle app start, background wallet interfacing. UX to be merged next.
This commit is contained in:
parent
f33fbefce0
commit
a1681eeeba
|
@ -495,8 +495,8 @@ class RestoreSeedDialog(CreateAccountDialog):
|
||||||
tis._keyboard.bind(on_key_down=self.on_key_down)
|
tis._keyboard.bind(on_key_down=self.on_key_down)
|
||||||
stepper = self.ids.stepper
|
stepper = self.ids.stepper
|
||||||
stepper.opacity = 1
|
stepper.opacity = 1
|
||||||
stepper.source = ('atlas://gui/kivy/theming"
|
stepper.source = ('atlas://gui/kivy/theming'
|
||||||
"/light/stepper_restore_seed')
|
'/light/stepper_restore_seed')
|
||||||
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
||||||
app.navigation_higherarchy.append(_back)
|
app.navigation_higherarchy.append(_back)
|
||||||
|
|
||||||
|
@ -582,7 +582,15 @@ class ChangePasswordDialog(CreateAccountDialog):
|
||||||
if value:
|
if value:
|
||||||
stepper = self.ids.stepper
|
stepper = self.ids.stepper
|
||||||
stepper.opacity = 1
|
stepper.opacity = 1
|
||||||
self.ids.ti_wallet_name.focus = True
|
t_wallet_name = self.ids.ti_wallet_name
|
||||||
|
if self.mode in ('create', 'restore'):
|
||||||
|
t_wallet_name.text = 'Default Wallet'
|
||||||
|
t_wallet_name.readonly = True
|
||||||
|
self.ids.ti_new_password.focus = True
|
||||||
|
else:
|
||||||
|
t_wallet_name.text = ''
|
||||||
|
t_wallet_name.readonly = False
|
||||||
|
t_wallet_name.focus = True
|
||||||
stepper.source = 'atlas://gui/kivy/theming/light/stepper_left'
|
stepper.source = 'atlas://gui/kivy/theming/light/stepper_left'
|
||||||
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
self._back = _back = partial(self.ids.back.dispatch, 'on_release')
|
||||||
app.navigation_higherarchy.append(_back)
|
app.navigation_higherarchy.append(_back)
|
||||||
|
|
|
@ -20,7 +20,7 @@ app = App.get_running_app()
|
||||||
|
|
||||||
|
|
||||||
class InstallWizard(Widget):
|
class InstallWizard(Widget):
|
||||||
'''Instalation Wizzard. Responsible for instantiating the
|
'''Installation Wizard. Responsible for instantiating the
|
||||||
creation/restoration of wallets.
|
creation/restoration of wallets.
|
||||||
|
|
||||||
events::
|
events::
|
||||||
|
@ -232,7 +232,7 @@ class InstallWizard(Widget):
|
||||||
ti_new_password.focus = True
|
ti_new_password.focus = True
|
||||||
else:
|
else:
|
||||||
ti_password.focus = True
|
ti_password.focus = True
|
||||||
return app.show_error(_('Passwords do not match'))
|
return app.show_error(_('Passwords do not match'), duration=.5)
|
||||||
|
|
||||||
if mode == 'restore':
|
if mode == 'restore':
|
||||||
try:
|
try:
|
||||||
|
@ -253,7 +253,7 @@ class InstallWizard(Widget):
|
||||||
try:
|
try:
|
||||||
seed = wallet.decode_seed(password)
|
seed = wallet.decode_seed(password)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
return app.show_error(_('Incorrect Password'))
|
return app.show_error(_('Incorrect Password'), duration=.5)
|
||||||
|
|
||||||
# test carefully
|
# test carefully
|
||||||
try:
|
try:
|
||||||
|
@ -291,6 +291,7 @@ class InstallWizard(Widget):
|
||||||
if mode in ('restore', 'create'):
|
if mode in ('restore', 'create'):
|
||||||
# auto cycle
|
# auto cycle
|
||||||
self.config.set_key('auto_cycle', True, True)
|
self.config.set_key('auto_cycle', True, True)
|
||||||
|
|
||||||
# start wallet threads
|
# start wallet threads
|
||||||
wallet.start_threads(self.network)
|
wallet.start_threads(self.network)
|
||||||
|
|
||||||
|
@ -303,14 +304,16 @@ class InstallWizard(Widget):
|
||||||
|
|
||||||
def on_complete(*l):
|
def on_complete(*l):
|
||||||
if not self.network:
|
if not self.network:
|
||||||
app.show_info(_("This wallet was restored offline."
|
app.show_info(
|
||||||
"It may contain more addresses than displayed."))
|
_("This wallet was restored offline. It may contain more"
|
||||||
|
" addresses than displayed."), duration=.5)
|
||||||
return self.dispatch('on_wizard_complete', wallet)
|
return self.dispatch('on_wizard_complete', wallet)
|
||||||
|
|
||||||
if wallet.is_found():
|
if wallet.is_found():
|
||||||
app.show_info(_("Recovery successful"))
|
app.show_info(_("Recovery successful"), duration=.5)
|
||||||
else:
|
else:
|
||||||
app.show_info(_("No transactions found for this seed"))
|
app.show_info(_("No transactions found for this seed"),
|
||||||
|
duration=.5)
|
||||||
return self.dispatch('on_wizard_complete', wallet)
|
return self.dispatch('on_wizard_complete', wallet)
|
||||||
|
|
||||||
self.waiting_dialog(lambda: wallet.restore(get_text),
|
self.waiting_dialog(lambda: wallet.restore(get_text),
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
size_hint: None, 1
|
size_hint: None, 1
|
||||||
width: (root.width - dp(20)) if root.fs else (0 if not root.icon else '32dp')
|
width: (root.width - dp(20)) if root.fs else (0 if not root.icon else '32dp')
|
||||||
Widget:
|
Widget:
|
||||||
size_hint_y: None
|
size_hint_x: None
|
||||||
width: '5dp'
|
width: '5dp'
|
||||||
Label:
|
Label:
|
||||||
id: lbl
|
id: lbl
|
||||||
|
@ -112,7 +112,8 @@
|
||||||
font_size: '12sp'
|
font_size: '12sp'
|
||||||
text: root.message
|
text: root.message
|
||||||
text_size: self.width, None
|
text_size: self.width, None
|
||||||
size_hint: None, 1
|
valign: 'middle'
|
||||||
|
size_hint: 1, 1
|
||||||
width: 0 if root.fs else (root.width - img.width)
|
width: 0 if root.fs else (root.width - img.width)
|
||||||
|
|
||||||
<-CreateAccountDialog>
|
<-CreateAccountDialog>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import sys
|
import sys
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from electrum import WalletStorage, Wallet
|
from electrum import WalletStorage, Wallet
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _, set_language
|
||||||
|
from electrum.wallet import format_satoshis
|
||||||
|
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
|
@ -10,11 +12,15 @@ from kivy.logger import Logger
|
||||||
from kivy.utils import platform
|
from kivy.utils import platform
|
||||||
from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty,
|
from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty,
|
||||||
StringProperty, ListProperty)
|
StringProperty, ListProperty)
|
||||||
|
from kivy.clock import Clock
|
||||||
|
|
||||||
#inclusions for factory so that widgets can be used in kv
|
#inclusions for factory so that widgets can be used in kv
|
||||||
from gui.kivy.drawer import Drawer
|
from gui.kivy.drawer import Drawer
|
||||||
from gui.kivy.dialog import InfoBubble
|
from gui.kivy.dialog import InfoBubble
|
||||||
|
|
||||||
|
# delayed imports
|
||||||
|
notification = None
|
||||||
|
|
||||||
class ElectrumWindow(App):
|
class ElectrumWindow(App):
|
||||||
|
|
||||||
title = _('Electrum App')
|
title = _('Electrum App')
|
||||||
|
@ -25,10 +31,10 @@ class ElectrumWindow(App):
|
||||||
:attr:`wallet` is a `ObjectProperty` defaults to None.
|
:attr:`wallet` is a `ObjectProperty` defaults to None.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
conf = ObjectProperty(None)
|
electrum_config = ObjectProperty(None)
|
||||||
'''Holds the electrum config
|
'''Holds the electrum config
|
||||||
|
|
||||||
:attr:`conf` is a `ObjectProperty`, defaults to None.
|
:attr:`electrum_config` is a `ObjectProperty`, defaults to None.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
status = StringProperty(_('Uninitialised'))
|
status = StringProperty(_('Uninitialised'))
|
||||||
|
@ -37,10 +43,60 @@ class ElectrumWindow(App):
|
||||||
:attr:`status` is a `StringProperty` defaults to _'uninitialised'
|
:attr:`status` is a `StringProperty` defaults to _'uninitialised'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
base_unit = StringProperty('BTC')
|
def _get_num_zeros(self):
|
||||||
|
try:
|
||||||
|
return self.electrum_config.get('num_zeros', 0)
|
||||||
|
except AttributeError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _set_num_zeros(self):
|
||||||
|
try:
|
||||||
|
self.electrum_config.set_key('num_zeros', value, True)
|
||||||
|
except AttributeError:
|
||||||
|
Logger.error('Electrum: Config not available '
|
||||||
|
'While trying to save value to config')
|
||||||
|
|
||||||
|
num_zeros = AliasProperty(_get_num_zeros , _set_num_zeros)
|
||||||
|
'''Number of zeros used while representing the value in base_unit.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def _get_decimal(self):
|
||||||
|
try:
|
||||||
|
return self.electrum_config.get('decimal_point', 8)
|
||||||
|
except AttributeError:
|
||||||
|
return 8
|
||||||
|
|
||||||
|
def _set_decimal(self, value):
|
||||||
|
try:
|
||||||
|
self.electrum_config.set_key('decimal_point', value, True)
|
||||||
|
except AttributeError:
|
||||||
|
Logger.error('Electrum: Config not set '
|
||||||
|
'While trying to save value to config')
|
||||||
|
|
||||||
|
decimal_point = AliasProperty(_get_decimal, _set_decimal)
|
||||||
|
'''This defines the decimal point to be used determining the
|
||||||
|
:attr:`base_unit`.
|
||||||
|
|
||||||
|
:attr:`decimal_point` is a `AliasProperty` defaults to the value gotten
|
||||||
|
from electrum config.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def _get_bu(self):
|
||||||
|
assert self.decimal_point in (5,8)
|
||||||
|
return "BTC" if self.decimal_point == 8 else "mBTC"
|
||||||
|
|
||||||
|
def _set_bu(self, value):
|
||||||
|
try:
|
||||||
|
self.electrum_config.set_key('base_unit', value, True)
|
||||||
|
except AttributeError:
|
||||||
|
Logger.error('Electrum: Config not set '
|
||||||
|
'While trying to save value to config')
|
||||||
|
|
||||||
|
base_unit = AliasProperty(_get_bu, _set_bu, bind=('decimal_point',))
|
||||||
'''BTC or UBTC or ...
|
'''BTC or UBTC or ...
|
||||||
|
|
||||||
:attr:`base_unit` is a `StringProperty` defaults to 'BTC'
|
:attr:`base_unit` is a `AliasProperty` defaults to the unit set in
|
||||||
|
electrum config.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
_ui_mode = OptionProperty('phone', options=('tablet', 'phone'))
|
_ui_mode = OptionProperty('phone', options=('tablet', 'phone'))
|
||||||
|
@ -84,13 +140,20 @@ class ElectrumWindow(App):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
# initialize variables
|
# initialize variables
|
||||||
self.info_bubble = None
|
self.info_bubble = None
|
||||||
|
self.console = None
|
||||||
|
self.exchanger = None
|
||||||
|
|
||||||
super(ElectrumWindow, self).__init__(**kwargs)
|
super(ElectrumWindow, self).__init__(**kwargs)
|
||||||
self.network = network = kwargs.get('network')
|
self.network = network = kwargs.get('network')
|
||||||
self.electrum_config = config = kwargs.get('config')
|
self.electrum_config = config = kwargs.get('config')
|
||||||
|
|
||||||
def load_wallet(self, wallet):
|
# create triggers so as to minimize updation a max of 5 times a sec
|
||||||
# TODO
|
self._trigger_update_status = Clock.create_trigger(self.update_status,
|
||||||
pass
|
.2)
|
||||||
|
self._trigger_update_console = Clock.create_trigger(self.update_console,
|
||||||
|
.2)
|
||||||
|
self._trigger_notify_transactions = \
|
||||||
|
Clock.create_trigger(self.notify_transactions, .2)
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
|
@ -98,14 +161,20 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
def _pause(self):
|
def _pause(self):
|
||||||
if platform == 'android':
|
if platform == 'android':
|
||||||
|
# move activity to back
|
||||||
from jnius import autoclass
|
from jnius import autoclass
|
||||||
python_act = autoclass('org.renpy.android.PythonActivity')
|
python_act = autoclass('org.renpy.android.PythonActivity')
|
||||||
mActivity = python_act.mActivity
|
mActivity = python_act.mActivity
|
||||||
mActivity.moveTaskToBack(True)
|
mActivity.moveTaskToBack(True)
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
|
''' This is the start point of the kivy ui
|
||||||
|
'''
|
||||||
Window.bind(size=self.on_size,
|
Window.bind(size=self.on_size,
|
||||||
on_keyboard=self.on_keyboard)
|
on_keyboard=self.on_keyboard)
|
||||||
|
Window.bind(on_key_down=self.on_key_down)
|
||||||
|
if platform == 'android':
|
||||||
|
#
|
||||||
Window.bind(keyboard_height=self.on_keyboard_height)
|
Window.bind(keyboard_height=self.on_keyboard_height)
|
||||||
self.on_size(Window, Window.size)
|
self.on_size(Window, Window.size)
|
||||||
config = self.electrum_config
|
config = self.electrum_config
|
||||||
|
@ -127,8 +196,11 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
self.on_resume()
|
self.on_resume()
|
||||||
|
|
||||||
|
def on_stop(self):
|
||||||
|
self.wallet.stop_threads()
|
||||||
|
|
||||||
def on_back(self):
|
def on_back(self):
|
||||||
''' Manage screen higherarchy
|
''' Manage screen hierarchy
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
self.navigation_higherarchy.pop()()
|
self.navigation_higherarchy.pop()()
|
||||||
|
@ -146,9 +218,28 @@ class ElectrumWindow(App):
|
||||||
Window.children[1]
|
Window.children[1]
|
||||||
Animation(y=Window.keyboard_height, d=.1).start(active_widg)
|
Animation(y=Window.keyboard_height, d=.1).start(active_widg)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
def on_keyboard(self, instance, key, keycode, codepoint, modifiers):
|
def on_keyboard(self, instance, key, keycode, codepoint, modifiers):
|
||||||
# override settings button
|
# override settings button
|
||||||
if key in (319, 282):
|
if key in (319, 282): #f1/settings button on android
|
||||||
self.gui.main_gui.toggle_settings(self)
|
self.gui.main_gui.toggle_settings(self)
|
||||||
return True
|
return True
|
||||||
if key == 27:
|
if key == 27:
|
||||||
|
@ -160,14 +251,18 @@ class ElectrumWindow(App):
|
||||||
Logger.debug('Electrum: No Wallet set/found. Exiting...')
|
Logger.debug('Electrum: No Wallet set/found. Exiting...')
|
||||||
app.show_error('Electrum: No Wallet set/found. Exiting...',
|
app.show_error('Electrum: No Wallet set/found. Exiting...',
|
||||||
exit=True)
|
exit=True)
|
||||||
return
|
Logger.info('wizard complete')
|
||||||
|
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
# plugins that need to change the GUI do it here
|
# plugins that need to change the GUI do it here
|
||||||
#run_hook('init')
|
#run_hook('init')
|
||||||
|
|
||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
|
|
||||||
Clock.schedule_once(update_wallet)
|
# check and remove this load_wallet calls update_wallet no
|
||||||
|
# need for this here
|
||||||
|
#Clock.schedule_once(update_wallet)
|
||||||
|
|
||||||
#self.windows.append(w)
|
#self.windows.append(w)
|
||||||
#if url: w.set_url(url)
|
#if url: w.set_url(url)
|
||||||
|
@ -177,7 +272,381 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
#self.app.exec_()
|
#self.app.exec_()
|
||||||
|
|
||||||
wallet.stop_threads()
|
def init_ui(self):
|
||||||
|
''' Initialize The Ux part of electrum. This function performs the basic
|
||||||
|
tasks of setting up the ui.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# unused?
|
||||||
|
#self._close_electrum = False
|
||||||
|
|
||||||
|
#self._tray_icon = 'icons/" + (electrum_dark_icon.png'\
|
||||||
|
# if platform == 'mac' else 'electrum_light_icon.png')
|
||||||
|
|
||||||
|
#setup tray
|
||||||
|
#self.tray = SystemTrayIcon(self.icon, self)
|
||||||
|
#self.tray.setToolTip('Electrum')
|
||||||
|
#self.tray.activated.connect(self.tray_activated)
|
||||||
|
|
||||||
|
set_language(self.electrum_config.get('language'))
|
||||||
|
|
||||||
|
self.funds_error = False
|
||||||
|
self.completions = []
|
||||||
|
|
||||||
|
# setup UX
|
||||||
|
#self.load_dashboard
|
||||||
|
|
||||||
|
self.icon = "icons/electrum.png"
|
||||||
|
|
||||||
|
# load and focus the ui
|
||||||
|
|
||||||
|
# connect callbacks
|
||||||
|
if self.network:
|
||||||
|
self.network.register_callback(
|
||||||
|
'updated', self._trigger_update_status)
|
||||||
|
self.network.register_callback(
|
||||||
|
'banner', self._trigger_update_console)
|
||||||
|
self.network.register_callback(
|
||||||
|
'disconnected', self._trigger_update_status)
|
||||||
|
self.network.register_callback(
|
||||||
|
'disconnecting', self._trigger_update_status)
|
||||||
|
self.network.register_callback('new_transaction',
|
||||||
|
self._trigger_notify_transactions)
|
||||||
|
|
||||||
|
# set initial message
|
||||||
|
self.update_console()
|
||||||
|
|
||||||
|
self.wallet = None
|
||||||
|
|
||||||
|
def create_quote_text(self, btc_balance, mode='normal'):
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
if not self.exchanger:
|
||||||
|
from plugins.exchange_rate import Exchanger
|
||||||
|
self.exchanger = Exchanger(self)
|
||||||
|
self.exchanger.start()
|
||||||
|
quote_currency = self.electrum_config.get("currency", 'EUR')
|
||||||
|
quote_balance = self.exchanger.exchange(btc_balance, quote_currency)
|
||||||
|
|
||||||
|
if mode == 'symbol':
|
||||||
|
if quote_currency:
|
||||||
|
quote_currency = self.exchanger.symbols[quote_currency]
|
||||||
|
|
||||||
|
if quote_balance is None:
|
||||||
|
quote_text = ""
|
||||||
|
else:
|
||||||
|
quote_text = " (%.2f %s)" % (quote_balance, quote_currency)
|
||||||
|
return quote_text
|
||||||
|
|
||||||
|
def set_currencies(self, quote_currencies):
|
||||||
|
self._trigger_update_status
|
||||||
|
#self.currencies = sorted(quote_currencies.keys())
|
||||||
|
|
||||||
|
def update_console(self, *dt):
|
||||||
|
if self.console:
|
||||||
|
self.console.showMessage(self.network.banner)
|
||||||
|
|
||||||
|
def load_wallet(self, wallet):
|
||||||
|
self.wallet = wallet
|
||||||
|
self.accounts_expanded = self.wallet.storage.get('accounts_expanded', {})
|
||||||
|
self.current_account = self.wallet.storage.get('current_account', None)
|
||||||
|
|
||||||
|
title = 'Electrum ' + self.wallet.electrum_version + ' - '\
|
||||||
|
+ self.wallet.storage.path
|
||||||
|
if wallet.is_watching_only():
|
||||||
|
title += ' [{}]'.format(_('watching only'))
|
||||||
|
self.title = title
|
||||||
|
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
|
||||||
|
self.notify_transactions()
|
||||||
|
self.update_account_selector()
|
||||||
|
#TODO
|
||||||
|
#self.new_account.setEnabled(self.wallet.seed_version>4)
|
||||||
|
#self.update_lock_icon()
|
||||||
|
#self.update_buttons_on_seed()
|
||||||
|
|
||||||
|
#run_hook('load_wallet', wallet)
|
||||||
|
|
||||||
|
def update_status(self, *dt):
|
||||||
|
if not self.wallet:
|
||||||
|
return
|
||||||
|
if self.network is None or not self.network.is_running():
|
||||||
|
text = _("Offline")
|
||||||
|
#icon = QIcon(":icons/status_disconnected.png")
|
||||||
|
|
||||||
|
elif self.network.is_connected():
|
||||||
|
unconfirmed = ''
|
||||||
|
quote_text = '.'
|
||||||
|
if not self.wallet.up_to_date:
|
||||||
|
text = _("Synchronizing...")
|
||||||
|
#icon = QIcon(":icons/status_waiting.png")
|
||||||
|
elif self.network.server_lag > 1:
|
||||||
|
text = _("Server is lagging (%d blocks)"%self.network.server_lag)
|
||||||
|
#icon = QIcon(":icons/status_lagging.png")
|
||||||
|
else:
|
||||||
|
c, u = self.wallet.get_account_balance(self.current_account)
|
||||||
|
text = self.format_amount(c)
|
||||||
|
if u:
|
||||||
|
unconfirmed = " [%s unconfirmed]"\
|
||||||
|
%( self.format_amount(u, True).strip())
|
||||||
|
quote_text = self.create_quote_text(Decimal(c+u)/100000000) or '.'
|
||||||
|
|
||||||
|
#r = {}
|
||||||
|
#run_hook('set_quote_text', c+u, r)
|
||||||
|
#quote = r.get(0)
|
||||||
|
#if quote:
|
||||||
|
# text += " (%s)"%quote
|
||||||
|
|
||||||
|
self.notify(_("Balance: ") + text)
|
||||||
|
#icon = QIcon(":icons/status_connected.png")
|
||||||
|
else:
|
||||||
|
text = _("Not connected")
|
||||||
|
#icon = QIcon(":icons/status_disconnected.png")
|
||||||
|
|
||||||
|
#TODO
|
||||||
|
#status_card = self.root.main_screen.ids.tabs.ids.\
|
||||||
|
# screen_dashboard.ids.status_card
|
||||||
|
self.status = text.strip()
|
||||||
|
#status_card.quote_text = quote_text.strip()
|
||||||
|
#status_card.uncomfirmed = unconfirmed.strip()
|
||||||
|
##app.base_unit = self.base_unit().strip()
|
||||||
|
|
||||||
|
def format_amount(self, x, is_diff=False, whitespaces=False):
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
|
||||||
|
|
||||||
|
def update_wallet(self):
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
self.update_status()
|
||||||
|
if (self.wallet.up_to_date or
|
||||||
|
not self.network or not self.network.is_connected()):
|
||||||
|
#TODO
|
||||||
|
#self.update_history_tab()
|
||||||
|
#self.update_receive_tab()
|
||||||
|
#self.update_contacts_tab()
|
||||||
|
self.update_completions()
|
||||||
|
|
||||||
|
def update_account_selector(self):
|
||||||
|
# account selector
|
||||||
|
#TODO
|
||||||
|
return
|
||||||
|
accounts = self.wallet.get_account_names()
|
||||||
|
self.account_selector.clear()
|
||||||
|
if len(accounts) > 1:
|
||||||
|
self.account_selector.addItems([_("All accounts")] + accounts.values())
|
||||||
|
self.account_selector.setCurrentIndex(0)
|
||||||
|
self.account_selector.show()
|
||||||
|
else:
|
||||||
|
self.account_selector.hide()
|
||||||
|
|
||||||
|
def update_history_tab(self, see_all=False):
|
||||||
|
def parse_histories(items):
|
||||||
|
results = []
|
||||||
|
for item in items:
|
||||||
|
tx_hash, conf, is_mine, value, fee, balance, timestamp = item
|
||||||
|
if conf > 0:
|
||||||
|
try:
|
||||||
|
time_str = datetime.datetime.fromtimestamp(
|
||||||
|
timestamp).isoformat(' ')[:-3]
|
||||||
|
except:
|
||||||
|
time_str = _("unknown")
|
||||||
|
|
||||||
|
if conf == -1:
|
||||||
|
time_str = _('unverified')
|
||||||
|
icon = "atlas://gui/kivy/theming/light/close"
|
||||||
|
elif conf == 0:
|
||||||
|
time_str = _('pending')
|
||||||
|
icon = "atlas://gui/kivy/theming/light/unconfirmed"
|
||||||
|
elif conf < 6:
|
||||||
|
time_str = '' # add new to fix error when conf < 0
|
||||||
|
conf = max(1, conf)
|
||||||
|
icon = "atlas://gui/kivy/theming/light/clock{}".format(conf)
|
||||||
|
else:
|
||||||
|
icon = "atlas://gui/kivy/theming/light/confirmed"
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
v_str = self.format_amount(value, True, whitespaces=True)
|
||||||
|
else:
|
||||||
|
v_str = '--'
|
||||||
|
|
||||||
|
balance_str = self.format_amount(balance, whitespaces=True)
|
||||||
|
|
||||||
|
if tx_hash:
|
||||||
|
label, is_default_label = self.wallet.get_label(tx_hash)
|
||||||
|
else:
|
||||||
|
label = _('Pruned transaction outputs')
|
||||||
|
is_default_label = False
|
||||||
|
|
||||||
|
results.append((
|
||||||
|
conf, icon, time_str, label, v_str, balance_str, tx_hash))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
history_card = self.root.main_screen.ids.tabs.ids.\
|
||||||
|
screen_dashboard.ids.recent_activity_card
|
||||||
|
histories = parse_histories(reversed(
|
||||||
|
self.wallet.get_tx_history(self.current_account)))
|
||||||
|
#history_view.content_adapter.data = histories
|
||||||
|
|
||||||
|
# repopulate History Card
|
||||||
|
last_widget = history_card.ids.content.children[-1]
|
||||||
|
history_card.ids.content.clear_widgets()
|
||||||
|
history_add = history_card.ids.content.add_widget
|
||||||
|
history_add(last_widget)
|
||||||
|
RecentActivityItem = Factory.RecentActivityItem
|
||||||
|
|
||||||
|
history_card.ids.btn_see_all.opacity = (0 if see_all or
|
||||||
|
len(histories) < 8 else 1)
|
||||||
|
if not see_all:
|
||||||
|
histories = histories[:8]
|
||||||
|
|
||||||
|
create_quote_text = self.create_quote_text
|
||||||
|
for items in histories:
|
||||||
|
conf, icon, date_time, address, amount, balance, tx = items
|
||||||
|
ri = RecentActivityItem()
|
||||||
|
ri.icon = icon
|
||||||
|
ri.date = date_time
|
||||||
|
ri.address = address
|
||||||
|
ri.amount = amount
|
||||||
|
ri.quote_text = create_quote_text(
|
||||||
|
Decimal(amount)/100000000, mode='symbol')
|
||||||
|
ri.balance = balance
|
||||||
|
ri.confirmations = conf
|
||||||
|
ri.tx_hash = tx
|
||||||
|
history_add(ri)
|
||||||
|
|
||||||
|
def update_receive_tab(self):
|
||||||
|
#TODO move to address managment
|
||||||
|
return
|
||||||
|
data = []
|
||||||
|
|
||||||
|
if self.current_account is None:
|
||||||
|
account_items = self.wallet.accounts.items()
|
||||||
|
elif self.current_account != -1:
|
||||||
|
account_items = [(self.current_account, self.wallet.accounts.get(self.current_account))]
|
||||||
|
else:
|
||||||
|
account_items = []
|
||||||
|
|
||||||
|
for k, account in account_items:
|
||||||
|
name = account.get('name', str(k))
|
||||||
|
c, u = self.wallet.get_account_balance(k)
|
||||||
|
data = [(name, '', self.format_amount(c + u), '')]
|
||||||
|
|
||||||
|
for is_change in ([0, 1] if self.expert_mode else [0]):
|
||||||
|
if self.expert_mode:
|
||||||
|
name = "Receiving" if not is_change else "Change"
|
||||||
|
seq_item = (name, '', '', '')
|
||||||
|
data.append(seq_item)
|
||||||
|
else:
|
||||||
|
seq_item = data
|
||||||
|
is_red = False
|
||||||
|
gap = 0
|
||||||
|
|
||||||
|
for address in account[is_change]:
|
||||||
|
h = self.wallet.history.get(address, [])
|
||||||
|
|
||||||
|
if h == []:
|
||||||
|
gap += 1
|
||||||
|
if gap > self.wallet.gap_limit:
|
||||||
|
is_red = True
|
||||||
|
else:
|
||||||
|
gap = 0
|
||||||
|
|
||||||
|
num_tx = '*' if h == ['*'] else "%d" % len(h)
|
||||||
|
item = (address, self.wallet.labels.get(address, ''), '', num_tx)
|
||||||
|
data.append(item)
|
||||||
|
self.update_receive_item(item)
|
||||||
|
|
||||||
|
if self.wallet.imported_keys and (self.current_account is None
|
||||||
|
or self.current_account == -1):
|
||||||
|
c, u = self.wallet.get_imported_balance()
|
||||||
|
data.append((_('Imported'), '', self.format_amount(c + u), ''))
|
||||||
|
for address in self.wallet.imported_keys.keys():
|
||||||
|
item = (address, self.wallet.labels.get(address, ''), '', '')
|
||||||
|
data.append(item)
|
||||||
|
self.update_receive_item(item)
|
||||||
|
|
||||||
|
receive_list = app.root.main_screen.ids.tabs.ids\
|
||||||
|
.screen_receive.receive_view
|
||||||
|
receive_list.content_adapter.data = data
|
||||||
|
|
||||||
|
def update_contacts_tab(self):
|
||||||
|
data = []
|
||||||
|
for address in self.wallet.addressbook:
|
||||||
|
label = self.wallet.labels.get(address, '')
|
||||||
|
item = (address, label, "%d" % self.wallet.get_num_tx(address))
|
||||||
|
data.append(item)
|
||||||
|
# item.setFont(0, QFont(MONOSPACE_FONT))
|
||||||
|
# # 32 = label can be edited (bool)
|
||||||
|
# item.setData(0,32, True)
|
||||||
|
# # 33 = payto string
|
||||||
|
# item.setData(0,33, address)
|
||||||
|
|
||||||
|
self.run_hook('update_contacts_tab')
|
||||||
|
|
||||||
|
contact_list = app.root.main_screen.ids.tabs.ids.\
|
||||||
|
screen_contacts.ids.contacts_list
|
||||||
|
contact_list.content_adapter.data = data
|
||||||
|
|
||||||
|
def update_completions(self):
|
||||||
|
l = []
|
||||||
|
for addr, label in self.wallet.labels.items():
|
||||||
|
if addr in self.wallet.addressbook:
|
||||||
|
l.append(label + ' <' + addr + '>')
|
||||||
|
|
||||||
|
#self.run_hook('update_completions', l)
|
||||||
|
self.completions = l
|
||||||
|
|
||||||
|
def notify_transactions(self, *dt):
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
if not self.network or not self.network.is_connected():
|
||||||
|
return
|
||||||
|
|
||||||
|
iface = self.network.interface
|
||||||
|
if len(iface.pending_transactions_for_notifications) > 0:
|
||||||
|
# Combine the transactions if there are more then three
|
||||||
|
tx_amount = len(iface.pending_transactions_for_notifications)
|
||||||
|
if(tx_amount >= 3):
|
||||||
|
total_amount = 0
|
||||||
|
for tx in iface.pending_transactions_for_notifications:
|
||||||
|
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):
|
||||||
|
from pudb import set_trace; set_trace()
|
||||||
|
self.notify(
|
||||||
|
_("New transaction received. {amount}s {unit}s").
|
||||||
|
format( amount=self.format_amount(v),
|
||||||
|
unit=self.base_unit()))
|
||||||
|
|
||||||
|
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`')
|
||||||
|
|
||||||
def on_pause(self):
|
def on_pause(self):
|
||||||
'''
|
'''
|
||||||
|
@ -231,7 +700,8 @@ class ElectrumWindow(App):
|
||||||
pos=None,
|
pos=None,
|
||||||
arrow_pos=None,
|
arrow_pos=None,
|
||||||
exit=False,
|
exit=False,
|
||||||
icon='atlas://gui/kivy/theming/light/error',):
|
icon='atlas://gui/kivy/theming/light/error',
|
||||||
|
duration=0):
|
||||||
''' Show a error Message Bubble.
|
''' Show a error Message Bubble.
|
||||||
'''
|
'''
|
||||||
self.show_info_bubble(
|
self.show_info_bubble(
|
||||||
|
@ -240,16 +710,19 @@ class ElectrumWindow(App):
|
||||||
width=width,
|
width=width,
|
||||||
pos=pos or Window.center,
|
pos=pos or Window.center,
|
||||||
arrow_pos=arrow_pos,
|
arrow_pos=arrow_pos,
|
||||||
exit=exit)
|
exit=exit,
|
||||||
|
duration=duration)
|
||||||
|
|
||||||
def show_info(self, error,
|
def show_info(self, error,
|
||||||
width='200dp',
|
width='200dp',
|
||||||
pos=None,
|
pos=None,
|
||||||
arrow_pos=None,
|
arrow_pos=None,
|
||||||
exit=False):
|
exit=False,
|
||||||
|
duration=0):
|
||||||
''' Show a Info Message Bubble.
|
''' Show a Info Message Bubble.
|
||||||
'''
|
'''
|
||||||
self.show_error(error, icon='atlas://gui/kivy/theming/light/error')
|
self.show_error(error, icon='atlas://gui/kivy/theming/light/error',
|
||||||
|
duration=duration)
|
||||||
|
|
||||||
def show_info_bubble(self,
|
def show_info_bubble(self,
|
||||||
text=_('Hello World'),
|
text=_('Hello World'),
|
||||||
|
|
Loading…
Reference in New Issue