kivy: use plugins

This commit is contained in:
ThomasV 2015-10-13 12:12:49 +02:00
parent c803a8ecab
commit a5e94ef0e8
12 changed files with 92 additions and 472 deletions

View File

@ -444,7 +444,7 @@ if __name__ == '__main__':
'verbose': True, 'verbose': True,
'cmd': 'gui', 'cmd': 'gui',
'gui': 'kivy' if is_kivy else 'android', 'gui': 'kivy' if is_kivy else 'android',
'auto_connect': True, #'auto_connect': True,
} }
else: else:
config_options = args.__dict__ config_options = args.__dict__
@ -474,8 +474,6 @@ if __name__ == '__main__':
cmd_name = config.get('cmd') cmd_name = config.get('cmd')
# initialize plugins. # initialize plugins.
plugins = None
if not is_android:
gui_name = config.get('gui', 'qt') if cmd_name == 'gui' else 'cmdline' gui_name = config.get('gui', 'qt') if cmd_name == 'gui' else 'cmdline'
plugins = Plugins(config, is_bundle or is_local or is_android, gui_name) plugins = Plugins(config, is_bundle or is_local or is_android, gui_name)

View File

@ -61,10 +61,11 @@ from main_window import ElectrumWindow
class ElectrumGui: class ElectrumGui:
def __init__(self, config, network, app=None): def __init__(self, config, network, plugins, app=None):
Logger.debug('ElectrumGUI: initialising') Logger.debug('ElectrumGUI: initialising')
self.network = network self.network = network
self.config = config self.config = config
self.plugins = plugins
#:TODO #:TODO
# implement kivy plugin mechanism that needs to be more extensible # implement kivy plugin mechanism that needs to be more extensible
@ -85,5 +86,6 @@ class ElectrumGui:
self.main_window = w = ElectrumWindow(config=self.config, self.main_window = w = ElectrumWindow(config=self.config,
network=self.network, network=self.network,
plugins = self.plugins,
gui_object=self) gui_object=self)
w.run() w.run()

View File

@ -451,13 +451,17 @@ BoxLayout:
on_press: ao._dropdown.dismiss() on_press: ao._dropdown.dismiss()
on_release: app.popup_dialog('network') on_release: app.popup_dialog('network')
ActionButton: ActionButton:
text: _('Wallet') text: _('Settings')
on_press: ao._dropdown.dismiss()
on_release: app.popup_dialog('settings')
ActionButton:
text: _('Wallets')
on_press: ao._dropdown.dismiss() on_press: ao._dropdown.dismiss()
on_release: app.popup_dialog('wallet') on_release: app.popup_dialog('wallet')
ActionButton: ActionButton:
text: _('Preferences') text: _('Plugins')
on_press: ao._dropdown.dismiss() on_press: ao._dropdown.dismiss()
on_release: app.popup_dialog('settings') on_release: app.popup_dialog('plugins')
ScreenManager: ScreenManager:
id: manager id: manager

View File

@ -1,12 +1,15 @@
import re
import sys import sys
import time import time
import datetime import datetime
import traceback import traceback
from decimal import Decimal
from electrum import WalletStorage, Wallet from electrum import WalletStorage, Wallet
from electrum.i18n import _, set_language from electrum.i18n import _, set_language
from electrum.contacts import Contacts from electrum.contacts import Contacts
from electrum.util import profiler from electrum.util import profiler
from electrum.plugins import run_hook
from kivy.app import App from kivy.app import App
from kivy.core.window import Window from kivy.core.window import Window
@ -18,6 +21,7 @@ from kivy.cache import Cache
from kivy.clock import Clock from kivy.clock import Clock
from kivy.factory import Factory from kivy.factory import Factory
from kivy.metrics import inch, metrics from kivy.metrics import inch, metrics
from kivy.lang import Builder
# lazy imports for factory so that widgets can be used in kv # lazy imports for factory so that widgets can be used in kv
Factory.register('InstallWizard', Factory.register('InstallWizard',
@ -27,11 +31,9 @@ Factory.register('ELTextInput', module='electrum_gui.kivy.uix.screens')
# delayed imports: for startup speed on android # delayed imports: for startup speed on android
notification = app = ref = format_satoshis = Builder = None notification = app = ref = format_satoshis = None
util = False util = False
from decimal import Decimal
import re
# register widget cache for keeping memory down timeout to forever to cache # register widget cache for keeping memory down timeout to forever to cache
# the data # the data
@ -39,7 +41,8 @@ Cache.register('electrum_widgets', timeout=0)
from kivy.uix.screenmanager import Screen from kivy.uix.screenmanager import Screen
from kivy.uix.tabbedpanel import TabbedPanel from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox
Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens') Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens')
@ -176,7 +179,6 @@ class ElectrumWindow(App):
def __init__(self, **kwargs): def __init__(self, **kwargs):
# initialize variables # initialize variables
self._clipboard = None self._clipboard = None
self.exchanger = None
self.info_bubble = None self.info_bubble = None
self.qrscanner = None self.qrscanner = None
self.nfcscanner = None self.nfcscanner = None
@ -185,8 +187,10 @@ class ElectrumWindow(App):
super(ElectrumWindow, self).__init__(**kwargs) super(ElectrumWindow, self).__init__(**kwargs)
title = _('Electrum App') title = _('Electrum App')
self.network = network = kwargs.get('network', None)
self.electrum_config = config = kwargs.get('config', None) self.electrum_config = config = kwargs.get('config', None)
self.network = network = kwargs.get('network', None)
self.plugins = kwargs.get('plugins', [])
self.gui_object = kwargs.get('gui_object', None) self.gui_object = kwargs.get('gui_object', None)
#self.config = self.gui_object.config #self.config = self.gui_object.config
@ -206,6 +210,8 @@ class ElectrumWindow(App):
self._trigger_notify_transactions = \ self._trigger_notify_transactions = \
Clock.create_trigger(self.notify_transactions, 5) Clock.create_trigger(self.notify_transactions, 5)
def set_url(self, instance, url): def set_url(self, instance, url):
self.gui_object.set_url(url) self.gui_object.set_url(url)
@ -226,12 +232,23 @@ class ElectrumWindow(App):
activity.bind(on_activity_result=on_qr_result) activity.bind(on_activity_result=on_qr_result)
PythonActivity.mActivity.startActivityForResult(intent, 0) PythonActivity.mActivity.startActivityForResult(intent, 0)
def show_plugins(self, plugins_list):
def on_checkbox_active(cb, value):
self.plugins.toggle_enabled(self.electrum_config, cb.name)
for item in self.plugins.descriptions:
if 'kivy' not in item.get('available_for', []):
continue
name = item.get('name')
label = Label(text=item.get('fullname'))
plugins_list.add_widget(label)
cb = CheckBox()
cb.name = name
p = self.plugins.get(name)
cb.active = (p is not None) and p.is_enabled()
cb.bind(active=on_checkbox_active)
plugins_list.add_widget(cb)
def build(self): def build(self):
global Builder
if not Builder:
from kivy.lang import Builder
return Builder.load_file('gui/kivy/main.kv') return Builder.load_file('gui/kivy/main.kv')
def _pause(self): def _pause(self):
@ -403,52 +420,11 @@ class ElectrumWindow(App):
self.wallet = None self.wallet = None
def create_quote_text(self, btc_balance, mode='normal'):
'''
'''
if not self.exchanger:
return
quote_currency = self.exchanger.currency
quote_balance = self.exchanger.exchange(btc_balance, quote_currency)
if quote_currency and mode == 'symbol':
quote_currency = self.exchanger.symbols.get(quote_currency,
quote_currency)
if quote_balance is None:
quote_text = u"..."
else:
quote_text = u"%s%.2f" % (quote_currency,
quote_balance)
return quote_text
def set_currencies(self, quote_currencies): def set_currencies(self, quote_currencies):
self.currencies = sorted(quote_currencies.keys()) self.currencies = sorted(quote_currencies.keys())
self._trigger_update_status() self._trigger_update_status()
def get_history_rate(self, item, btc_balance, mintime):
'''Historical rates: currently only using coindesk by default.
'''
maxtime = datetime.datetime.now().strftime('%Y-%m-%d')
rate = self.exchanger.get_history_rate(item, btc_balance, mintime,
maxtime)
return self.set_history_rate(item, rate)
def set_history_rate(self, item, rate):
'''
'''
#TODO: fix me allow other currencies to be used for history rates
quote_currency = self.exchanger.symbols.get('USD', 'USD')
if rate is None:
quote_text = "..."
else:
quote_text = "{0}{1:.3}".format(quote_currency, rate)
item = item()
if item:
item.quote_text = quote_text
return quote_text
@profiler @profiler
@ -485,7 +461,7 @@ class ElectrumWindow(App):
unconfirmed = " [%s unconfirmed]" %( self.format_amount(u, True).strip()) unconfirmed = " [%s unconfirmed]" %( self.format_amount(u, True).strip())
if x: if x:
unmatured = " [%s unmatured]"%(self.format_amount(x, True).strip()) unmatured = " [%s unmatured]"%(self.format_amount(x, True).strip())
quote_text = self.create_quote_text(Decimal(c+u+x)/100000000, mode='symbol') or '' #quote_text = self.create_quote_text(Decimal(c+u+x)/100000000, mode='symbol') or ''
self.status = text.strip() + ' ' + self.base_unit self.status = text.strip() + ' ' + self.base_unit
else: else:
self.status = _("Not connected") self.status = _("Not connected")
@ -510,13 +486,6 @@ class ElectrumWindow(App):
@profiler @profiler
def update_wallet(self, *dt): def update_wallet(self, *dt):
'''
'''
if not self.exchanger:
from electrum_gui.kivy.plugins.exchange_rate import Exchanger
self.exchanger = Exchanger(self)
self.exchanger.start()
return
self._trigger_update_status() self._trigger_update_status()
if self.wallet.up_to_date or not self.network or not self.network.is_connected(): if self.wallet.up_to_date or not self.network or not self.network.is_connected():
self.update_history_tab() self.update_history_tab()

View File

@ -1 +0,0 @@

View File

@ -1,376 +0,0 @@
# -*- encoding: utf8 -*-
'''Module exchange_rate:
This module is responsible for getting the conversion rates from different
bitcoin exchanges.
'''
import decimal
import json
from kivy.network.urlrequest import UrlRequest
from kivy.event import EventDispatcher
from kivy.properties import (OptionProperty, StringProperty, AliasProperty,
ListProperty)
from kivy.clock import Clock
from kivy.cache import Cache
# Register local cache
Cache.register('history_rate', timeout=220)
EXCHANGES = ["BitcoinAverage",
"BitcoinVenezuela",
"BitPay",
"Blockchain",
"BTCChina",
"CaVirtEx",
"Coinbase",
"CoinDesk",
"LocalBitcoins",
"Winkdex"]
HISTORY_EXCHNAGES = ['Coindesk',
'Winkdex',
'BitcoinVenezuela']
class Exchanger(EventDispatcher):
''' Provide exchanges rate between crypto and different national
currencies. See Module Documentation for details.
'''
symbols = {'ALL': u'Lek', 'AED': u'د.إ', 'AFN':u'؋', 'ARS': u'$',
'AMD': u'֏', 'AWG': u'ƒ', 'ANG': u'ƒ', 'AOA': u'Kz', 'BDT': u'',
'BHD': u'BD', 'BIF': u'FBu', 'BTC': u'BTC', 'BTN': u'Nu', 'CDF': u'FC',
'CHF': u'CHF', 'CLF': u'UF', 'CLP':u'$', 'CVE': u'$', 'DJF':u'Fdj',
'DZD': u'دج', 'AUD': u'$', 'AZN': u'ман', 'BSD': u'$', 'BBD': u'$',
'BYR': u'p', 'CRC': u'', 'BZD': u'BZ$', 'BMD': u'$', 'BOB': u'$b',
'BAM': u'KM', 'BWP': u'P', 'BGN': 'uлв', 'BRL': u'R$', 'BND': u'$',
'KHR': u'', 'CAD': u'$', 'ERN': u'Nfk', 'ETB': u'Br', 'KYD': u'$',
'USD': u'$', 'CLP': u'$', 'HRK': u'kn', 'CUP': u'', 'CZK': u'',
'DKK': u'kr', 'DOP': u'RD$', 'XCD': u'$', 'EGP': u'£', 'SVC': u'$' ,
'EEK': u'kr', 'EUR': u'', u'FKP': u'£', 'FJD': u'$', 'GHC': u'¢',
'GIP': u'£', 'GTQ': u'Q', 'GBP': u'£', 'GYD': u'$', 'HNL': u'L',
'HKD': u'$', 'HUF': u'Ft', 'ISK': u'kr', 'INR': u'', 'IDR': u'Rp',
'IRR': u'', 'IMP': '£', 'ILS': '', 'COP': '$', 'JMD': u'J$',
'JPY': u'¥', 'JEP': u'£', 'KZT': u'лв', 'KPW': u'', 'KRW': u'',
'KGS': u'лв', 'LAK': u'', 'LVL': u'Ls', 'CNY': u'¥'}
_use_exchange = OptionProperty('Blockchain', options=EXCHANGES)
'''This is the exchange to be used for getting the currency exchange rates
'''
_currency = StringProperty('EUR')
'''internal use only
'''
def _set_currency(self, value):
value = str(value)
if self.use_exchange == 'CoinDesk':
self._update_cd_currency(self.currency)
return
self._currency = value
self.parent.electrum_config.set_key('currency', value, True)
def _get_currency(self):
self._currency = self.parent.electrum_config.get('currency', 'EUR')
return self._currency
currency = AliasProperty(_get_currency, _set_currency, bind=('_currency',))
currencies = ListProperty(['EUR', 'GBP', 'USD'])
'''List of currencies supported by the current exchanger plugin.
:attr:`currencies` is a `ListProperty` default to ['Eur', 'GBP'. 'USD'].
'''
def _get_useex(self):
if not self.parent:
return self._use_exchange
self._use_exchange = self.parent.electrum_config.get('use_exchange',
'Blockchain')
return self._use_exchange
def _set_useex(self, value):
if not self.parent:
return self._use_exchange
self.parent.electrum_config.set_key('use_exchange', value, True)
self._use_exchange = value
use_exchange = AliasProperty(_get_useex, _set_useex,
bind=('_use_exchange', ))
def __init__(self, parent):
super(Exchanger, self).__init__()
self.parent = parent
self.quote_currencies = None
self.exchanges = EXCHANGES
self.history_exchanges = HISTORY_EXCHNAGES
def exchange(self, btc_amount, quote_currency):
if self.quote_currencies is None:
return None
quote_currencies = self.quote_currencies.copy()
if quote_currency not in quote_currencies:
return None
return btc_amount * decimal.Decimal(quote_currencies[quote_currency])
def get_history_rate(self, item, btc_amt, mintime, maxtime):
def on_success(request, response):
response = json.loads(response)
try:
hrate = response['bpi'][mintime]
hrate = abs(btc_amt) * decimal.Decimal(hrate)
Cache.append('history_rate', uid, hrate)
except KeyError:
hrate = 'not found'
self.parent.set_history_rate(item, hrate)
# Check local cache before getting data from remote
exchange = 'coindesk'
uid = '{}:{}'.format(exchange, mintime)
hrate = Cache.get('history_rate', uid)
if hrate:
return hrate
req = UrlRequest(url='https://api.coindesk.com/v1/bpi/historical'
'/close.json?start={}&end={}'
.format(mintime, maxtime)
,on_success=on_success, timeout=15)
return None
def update_rate(self, dt):
''' This is called from :method:`start` every X seconds; to update the
rates for currencies for the currently selected exchange.
'''
if not self.parent.network or not self.parent.network.is_connected():
return
# temporarily disabled
return
update_rates = {
"BitcoinAverage": self.update_ba,
"BitcoinVenezuela": self.update_bv,
"BitPay": self.update_bp,
"Blockchain": self.update_bc,
"BTCChina": self.update_CNY,
"CaVirtEx": self.update_cv,
"CoinDesk": self.update_cd,
"Coinbase": self.update_cb,
"LocalBitcoins": self.update_lb,
"Winkdex": self.update_wd,
}
try:
update_rates[self.use_exchange]()
except KeyError:
return
def update_wd(self):
def on_success(request, response):
response = json.loads(response)
quote_currencies = {'USD': 0.0}
lenprices = len(response["prices"])
usdprice = response['prices'][lenprices-1]['y']
try:
quote_currencies["USD"] = decimal.Decimal(usdprice)
except KeyError:
pass
self.quote_currencies = quote_currencies
self.parent.set_currencies(quote_currencies)
req = UrlRequest(
url='https://winkdex.com/static/data/0_600_288.json',
on_success=on_success,
timeout=5)
def update_cd_currency(self, currency):
def on_success(request, response):
response = json.loads(response)
quote_currencies = self.quote_currencies
quote_currencies[currency] =\
str(response['bpi'][str(currency)]['rate_float'])
self.parent.set_currencies(quote_currencies)
req = UrlRequest(
url='https://api.coindesk.com/v1/bpi/currentprice/'\
+ str(currency) + '.json',on_success=on_success, timeout=5)
def update_cd(self):
def on_success(request, response):
quote_currencies = {}
response = json.loads(response)
for cur in response:
quote_currencies[str(cur["currency"])] = 0.0
self.quote_currencies = quote_currencies
self.update_cd_currency(self.currency)
req = UrlRequest(
url='https://api.coindesk.com/v1/bpi/supported-currencies.json',
on_success=on_success,
timeout=5)
def update_cv(self):
def on_success(request, response):
response = json.loads(response)
quote_currencies = {"CAD": 0.0}
cadprice = response["last"]
try:
quote_currencies["CAD"] = decimal.Decimal(cadprice)
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://www.cavirtex.com/api/CAD/ticker.json',
on_success=on_success,
timeout=5)
def update_CNY(self):
def on_success(request, response):
quote_currencies = {"CNY": 0.0}
cnyprice = response["ticker"]["last"]
try:
quote_currencies["CNY"] = decimal.Decimal(cnyprice)
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://data.btcchina.com/data/ticker',
on_success=on_success,
timeout=5)
def update_bp(self):
def on_success(request, response):
quote_currencies = {}
try:
for r in response:
quote_currencies[str(r['code'])] = decimal.Decimal(r['rate'])
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://bitpay.com/api/rates',
on_success=on_success,
timeout=5)
def update_cb(self):
def _lookup_rate(response, quote_id):
return decimal.Decimal(str(response[str(quote_id)]))
def on_success(request, response):
quote_currencies = {}
try:
for r in response:
if r[:7] == "btc_to_":
quote_currencies[r[7:].upper()] =\
_lookup_rate(response, r)
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(
url='https://coinbase.com/api/v1/currencies/exchange_rates',
on_success=on_success,
timeout=5)
def update_bc(self):
def _lookup_rate(response, quote_id):
return decimal.Decimal(str(response[str(quote_id)]["15m"]))
def on_success(request, response):
quote_currencies = {}
try:
for r in response:
quote_currencies[r] = _lookup_rate(response, r)
self.quote_currencies = quote_currencies
except KeyError, TypeError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://blockchain.info/ticker',
on_success=on_success,
timeout=5)
def update_lb(self):
def _lookup_rate(response, quote_id):
return decimal.Decimal(response[str(quote_id)]["rates"]["last"])
def on_success(request, response):
quote_currencies = {}
try:
for r in response:
quote_currencies[r] = _lookup_rate(response, r)
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(
url='https://localbitcoins.com/bitcoinaverage/ticker-all-currencies/',
on_success=on_success,
timeout=5)
def update_ba(self):
def on_success(request, response):
quote_currencies = {}
try:
for r in response:
quote_currencies[r] = decimal.Decimal(response[r][u'last'])
self.quote_currencies = quote_currencies
except TypeError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://api.bitcoinaverage.com/ticker/global/all',
on_success=on_success,
timeout=5)
def update_bv(self):
def on_success(request, response):
quote_currencies = {}
try:
for r in response["BTC"]:
quote_currencies[r] = decimal.Decimal(response['BTC'][r])
self.quote_currencies = quote_currencies
except KeyError:
pass
self.parent.set_currencies(quote_currencies)
req = UrlRequest(url='https://api.bitcoinvenezuela.com/',
on_success=on_success,
timeout=5)
def start(self):
self.update_rate(0)
# check every 20 seconds
Clock.unschedule(self.update_rate)
Clock.schedule_interval(self.update_rate, 20)
def stop(self):
Clock.unschedule(self.update_rate)

View File

@ -15,6 +15,8 @@ from kivy.factory import Factory
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import profiler from electrum.util import profiler
from electrum import bitcoin from electrum import bitcoin
from electrum.util import timestamp_to_datetime
from electrum.plugins import run_hook
class CScreen(Factory.Screen): class CScreen(Factory.Screen):
@ -84,6 +86,10 @@ class HistoryScreen(CScreen):
ra_dialog.item = item ra_dialog.item = item
ra_dialog.open() ra_dialog.open()
def get_history_rate(self, btc_balance, timestamp):
date = timestamp_to_datetime(timestamp)
return run_hook('historical_value_str', btc_balance, date)
def parse_history(self, items): def parse_history(self, items):
for item in items: for item in items:
tx_hash, conf, value, timestamp, balance = item tx_hash, conf, value, timestamp, balance = item
@ -121,7 +127,11 @@ class HistoryScreen(CScreen):
label = _('Pruned transaction outputs') label = _('Pruned transaction outputs')
is_default_label = False is_default_label = False
yield (conf, icon, time_str, label, v_str, balance_str, tx_hash) quote_currency = 'USD'
rate = self.get_history_rate(value, timestamp)
quote_text = "..." if rate is None else "{0:.3} {1}".format(rate, quote_currency)
yield (conf, icon, time_str, label, v_str, balance_str, tx_hash, quote_text)
def update(self, see_all=False): def update(self, see_all=False):
@ -134,20 +144,17 @@ class HistoryScreen(CScreen):
history_add = history_card.ids.content.add_widget history_add = history_card.ids.content.add_widget
history_add(last_widget) history_add(last_widget)
RecentActivityItem = Factory.RecentActivityItem RecentActivityItem = Factory.RecentActivityItem
get_history_rate = self.app.get_history_rate
count = 0 count = 0
for item in history: for item in history:
count += 1 count += 1
conf, icon, date_time, address, amount, balance, tx = item conf, icon, date_time, address, amount, balance, tx, quote_text = item
ri = RecentActivityItem() ri = RecentActivityItem()
ri.icon = icon ri.icon = icon
ri.date = date_time ri.date = date_time
mintimestr = date_time.split()[0] mintimestr = date_time.split()[0]
ri.address = address ri.address = address
ri.amount = amount ri.amount = amount
ri.quote_text = get_history_rate(ref(ri), ri.quote_text = quote_text
Decimal(amount),
mintimestr)
ri.balance = balance ri.balance = balance
ri.confirmations = conf ri.confirmations = conf
ri.tx_hash = tx ri.tx_hash = tx

View File

@ -9,6 +9,7 @@ Popup:
app.network.set_parameters(host.text, nd.port, nd.protocol, nd.proxy, auto_connect.active) app.network.set_parameters(host.text, nd.port, nd.protocol, nd.proxy, auto_connect.active)
BoxLayout: BoxLayout:
orientation: 'vertical' orientation: 'vertical'
GridLayout: GridLayout:

View File

@ -0,0 +1,16 @@
Popup:
title: _('Plugins')
id: popup
BoxLayout:
orientation: 'vertical'
GridLayout:
size_hint_y: None
cols: 2
id: plugins_list
on_parent:
app.show_plugins(plugins_list)
Button:
size_hint_y: None
height: '48dp'
text: _('Close')
on_release: popup.dismiss()

View File

@ -1,27 +1,26 @@
Popup: Popup:
id: settings id: settings
title: _('Settings') title: _('Settings')
BoxLayout: BoxLayout:
Button: orientation: 'vertical'
size_hint_y: None size_hint_y: None
GridLayout:
cols: 2
Label:
text: _('Base unit')
height: '48dp'
Spinner:
text: 'BTC'
values: ('BTC', 'mBTC')
height: '48dp' height: '48dp'
text: 'Button normal'
Button: Button:
size_hint_y: None #size_hint_y: None
height: '48dp' height: '48dp'
text: 'Button down' text: _('Close')
state: 'down'
Button:
size_hint_y: None
height: '48dp'
text: 'Button disabled'
disabled: True
Button:
size_hint_y: None
height: '48dp'
text: 'close'
on_release: settings.dismiss() on_release: settings.dismiss()
#Widget:
# size_hint_y: None

View File

@ -57,7 +57,7 @@ descriptions = [
'name': 'exchange_rate', 'name': 'exchange_rate',
'fullname': _("Exchange rates"), 'fullname': _("Exchange rates"),
'description': _("Exchange rates and currency conversion tools."), 'description': _("Exchange rates and currency conversion tools."),
'available_for': ['qt'], 'available_for': ['qt','kivy'],
}, },
{ {
'name': 'greenaddress_instant', 'name': 'greenaddress_instant',
@ -78,10 +78,10 @@ descriptions = [
'name': 'labels', 'name': 'labels',
'fullname': _('LabelSync'), 'fullname': _('LabelSync'),
'description': '\n'.join([ 'description': '\n'.join([
_("The new and improved LabelSync plugin. This can sync your labels across multiple Electrum installs by using a remote database to save your data. Labels, transactions ids and addresses are encrypted before they are sent to the remote server."), _("Synchronize your labels across multiple Electrum installs by using a remote database to save your data. Labels, transactions ids and addresses are encrypted before they are sent to the remote server."),
_("The label sync's server software is open-source as well and can be found on github.com/maran/electrum-sync-server") _("The label sync's server software is open-source as well and can be found on github.com/maran/electrum-sync-server")
]), ]),
'available_for': ['qt'] 'available_for': ['qt','kivy']
}, },
{ {
'name': 'plot', 'name': 'plot',

View File

@ -423,6 +423,7 @@ class Plugin(BasePlugin, ThreadJob):
return "%s" % (self.ccy_amount_str(value, True)) return "%s" % (self.ccy_amount_str(value, True))
return _("No data") return _("No data")
@hook
def historical_value_str(self, satoshis, d_t): def historical_value_str(self, satoshis, d_t):
rate = self.exchange.historical_rate(self.ccy, d_t) rate = self.exchange.historical_rate(self.ccy, d_t)
# Frequently there is no rate for today, until tomorrow :) # Frequently there is no rate for today, until tomorrow :)