|
|
@ -1,7 +1,9 @@ |
|
|
|
import sys |
|
|
|
from decimal import Decimal |
|
|
|
|
|
|
|
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.core.window import Window |
|
|
@ -10,11 +12,15 @@ from kivy.logger import Logger |
|
|
|
from kivy.utils import platform |
|
|
|
from kivy.properties import (OptionProperty, AliasProperty, ObjectProperty, |
|
|
|
StringProperty, ListProperty) |
|
|
|
from kivy.clock import Clock |
|
|
|
|
|
|
|
#inclusions for factory so that widgets can be used in kv |
|
|
|
from gui.kivy.drawer import Drawer |
|
|
|
from gui.kivy.dialog import InfoBubble |
|
|
|
|
|
|
|
# delayed imports |
|
|
|
notification = None |
|
|
|
|
|
|
|
class ElectrumWindow(App): |
|
|
|
|
|
|
|
title = _('Electrum App') |
|
|
@ -25,10 +31,10 @@ class ElectrumWindow(App): |
|
|
|
:attr:`wallet` is a `ObjectProperty` defaults to None. |
|
|
|
''' |
|
|
|
|
|
|
|
conf = ObjectProperty(None) |
|
|
|
electrum_config = ObjectProperty(None) |
|
|
|
'''Holds the electrum config |
|
|
|
|
|
|
|
:attr:`conf` is a `ObjectProperty`, defaults to None. |
|
|
|
:attr:`electrum_config` is a `ObjectProperty`, defaults to None. |
|
|
|
''' |
|
|
|
|
|
|
|
status = StringProperty(_('Uninitialised')) |
|
|
@ -37,10 +43,60 @@ class ElectrumWindow(App): |
|
|
|
: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 ... |
|
|
|
|
|
|
|
: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')) |
|
|
@ -84,13 +140,20 @@ class ElectrumWindow(App): |
|
|
|
def __init__(self, **kwargs): |
|
|
|
# initialize variables |
|
|
|
self.info_bubble = None |
|
|
|
self.console = None |
|
|
|
self.exchanger = None |
|
|
|
|
|
|
|
super(ElectrumWindow, self).__init__(**kwargs) |
|
|
|
self.network = network = kwargs.get('network') |
|
|
|
self.electrum_config = config = kwargs.get('config') |
|
|
|
|
|
|
|
def load_wallet(self, wallet): |
|
|
|
# TODO |
|
|
|
pass |
|
|
|
# create triggers so as to minimize updation a max of 5 times a sec |
|
|
|
self._trigger_update_status = Clock.create_trigger(self.update_status, |
|
|
|
.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): |
|
|
|
from kivy.lang import Builder |
|
|
@ -98,15 +161,21 @@ class ElectrumWindow(App): |
|
|
|
|
|
|
|
def _pause(self): |
|
|
|
if platform == 'android': |
|
|
|
# move activity to back |
|
|
|
from jnius import autoclass |
|
|
|
python_act = autoclass('org.renpy.android.PythonActivity') |
|
|
|
mActivity = python_act.mActivity |
|
|
|
mActivity.moveTaskToBack(True) |
|
|
|
|
|
|
|
def on_start(self): |
|
|
|
''' This is the start point of the kivy ui |
|
|
|
''' |
|
|
|
Window.bind(size=self.on_size, |
|
|
|
on_keyboard=self.on_keyboard) |
|
|
|
Window.bind(keyboard_height=self.on_keyboard_height) |
|
|
|
Window.bind(on_key_down=self.on_key_down) |
|
|
|
if platform == 'android': |
|
|
|
# |
|
|
|
Window.bind(keyboard_height=self.on_keyboard_height) |
|
|
|
self.on_size(Window, Window.size) |
|
|
|
config = self.electrum_config |
|
|
|
storage = WalletStorage(config) |
|
|
@ -127,8 +196,11 @@ class ElectrumWindow(App): |
|
|
|
|
|
|
|
self.on_resume() |
|
|
|
|
|
|
|
def on_stop(self): |
|
|
|
self.wallet.stop_threads() |
|
|
|
|
|
|
|
def on_back(self): |
|
|
|
''' Manage screen higherarchy |
|
|
|
''' Manage screen hierarchy |
|
|
|
''' |
|
|
|
try: |
|
|
|
self.navigation_higherarchy.pop()() |
|
|
@ -146,9 +218,28 @@ class ElectrumWindow(App): |
|
|
|
Window.children[1] |
|
|
|
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): |
|
|
|
# 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) |
|
|
|
return True |
|
|
|
if key == 27: |
|
|
@ -160,14 +251,18 @@ class ElectrumWindow(App): |
|
|
|
Logger.debug('Electrum: No Wallet set/found. Exiting...') |
|
|
|
app.show_error('Electrum: No Wallet set/found. Exiting...', |
|
|
|
exit=True) |
|
|
|
return |
|
|
|
Logger.info('wizard complete') |
|
|
|
|
|
|
|
|
|
|
|
self.init_ui() |
|
|
|
# plugins that need to change the GUI do it here |
|
|
|
#run_hook('init') |
|
|
|
|
|
|
|
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) |
|
|
|
#if url: w.set_url(url) |
|
|
@ -177,7 +272,381 @@ class ElectrumWindow(App): |
|
|
|
|
|
|
|
#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): |
|
|
|
''' |
|
|
@ -231,7 +700,8 @@ class ElectrumWindow(App): |
|
|
|
pos=None, |
|
|
|
arrow_pos=None, |
|
|
|
exit=False, |
|
|
|
icon='atlas://gui/kivy/theming/light/error',): |
|
|
|
icon='atlas://gui/kivy/theming/light/error', |
|
|
|
duration=0): |
|
|
|
''' Show a error Message Bubble. |
|
|
|
''' |
|
|
|
self.show_info_bubble( |
|
|
@ -240,16 +710,19 @@ class ElectrumWindow(App): |
|
|
|
width=width, |
|
|
|
pos=pos or Window.center, |
|
|
|
arrow_pos=arrow_pos, |
|
|
|
exit=exit) |
|
|
|
exit=exit, |
|
|
|
duration=duration) |
|
|
|
|
|
|
|
def show_info(self, error, |
|
|
|
width='200dp', |
|
|
|
pos=None, |
|
|
|
arrow_pos=None, |
|
|
|
exit=False): |
|
|
|
exit=False, |
|
|
|
duration=0): |
|
|
|
''' 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, |
|
|
|
text=_('Hello World'), |
|
|
|