electrum-bitcoinprivate/gui/kivy/uix/screens.py

620 lines
21 KiB
Python
Raw Normal View History

2015-10-07 04:06:28 -07:00
from weakref import ref
from decimal import Decimal
import re
import datetime
2015-10-13 10:09:12 -07:00
import traceback, sys
2015-10-07 04:06:28 -07:00
from kivy.app import App
from kivy.cache import Cache
from kivy.clock import Clock
from kivy.compat import string_types
from kivy.properties import (ObjectProperty, DictProperty, NumericProperty,
2015-12-04 02:47:46 -08:00
ListProperty, StringProperty)
2016-01-16 07:47:48 -08:00
from kivy.uix.label import Label
2015-12-04 02:47:46 -08:00
from kivy.lang import Builder
from kivy.factory import Factory
2016-02-06 07:58:31 -08:00
from kivy.utils import platform
2016-02-18 02:24:38 -08:00
from electrum.util import profiler, parse_URI, format_time, InvalidPassword, NotEnoughFunds
2015-10-07 04:06:28 -07:00
from electrum import bitcoin
2015-10-13 03:12:49 -07:00
from electrum.util import timestamp_to_datetime
from electrum.plugins import run_hook
2016-02-04 01:57:09 -08:00
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
2015-12-12 07:54:32 -08:00
from context_menu import ContextMenu
2016-02-04 01:57:09 -08:00
from electrum_gui.kivy.i18n import _
2016-01-19 03:57:18 -08:00
class EmptyLabel(Factory.Label):
pass
2016-01-19 03:57:18 -08:00
class CScreen(Factory.Screen):
__events__ = ('on_activate', 'on_deactivate', 'on_enter', 'on_leave')
action_view = ObjectProperty(None)
loaded = False
kvname = None
2015-12-12 07:54:32 -08:00
context_menu = None
menu_actions = []
app = App.get_running_app()
def _change_action_view(self):
app = App.get_running_app()
action_bar = app.root.manager.current_screen.ids.action_bar
_action_view = self.action_view
if (not _action_view) or _action_view.parent:
return
action_bar.clear_widgets()
action_bar.add_widget(_action_view)
def on_enter(self):
# FIXME: use a proper event don't use animation time of screen
Clock.schedule_once(lambda dt: self.dispatch('on_activate'), .25)
pass
def update(self):
pass
2015-10-06 05:30:44 -07:00
@profiler
def load_screen(self):
self.screen = Builder.load_file('gui/kivy/uix/ui_screens/' + self.kvname + '.kv')
self.add_widget(self.screen)
self.loaded = True
self.update()
setattr(self.app, self.kvname + '_screen', self)
def on_activate(self):
if self.kvname and not self.loaded:
2015-10-06 05:30:44 -07:00
self.load_screen()
#Clock.schedule_once(lambda dt: self._change_action_view())
def on_leave(self):
self.dispatch('on_deactivate')
def on_deactivate(self):
2015-12-12 07:54:32 -08:00
self.hide_menu()
def hide_menu(self):
if self.context_menu is not None:
self.remove_widget(self.context_menu)
2015-12-12 07:54:32 -08:00
self.context_menu = None
def show_menu(self, obj):
self.hide_menu()
self.context_menu = ContextMenu(obj, self.menu_actions)
self.add_widget(self.context_menu)
2015-12-12 07:54:32 -08:00
class HistoryScreen(CScreen):
tab = ObjectProperty(None)
kvname = 'history'
def __init__(self, **kwargs):
self.ra_dialog = None
super(HistoryScreen, self).__init__(**kwargs)
2016-02-12 07:09:16 -08:00
self.menu_actions = [ ('Label', self.label_dialog), ('Details', self.show_tx)]
def show_tx(self, obj):
tx_hash = obj.tx_hash
tx = self.app.wallet.transactions.get(tx_hash)
if not tx:
return
self.app.tx_dialog(tx)
2015-12-14 03:08:11 -08:00
def label_dialog(self, obj):
from dialogs.label_dialog import LabelDialog
key = obj.tx_hash
2015-12-15 03:52:30 -08:00
text = self.app.wallet.get_label(key)
2015-12-14 03:08:11 -08:00
def callback(text):
self.app.wallet.set_label(key, text)
self.update()
d = LabelDialog(_('Enter Transaction Label'), text, callback)
d.open()
2015-10-13 03:12:49 -07:00
2015-10-07 04:06:28 -07:00
def parse_history(self, items):
for item in items:
tx_hash, height, conf, timestamp, value, balance = item
time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3] if timestamp else _("unknown")
if conf == 0:
tx = self.app.wallet.transactions.get(tx_hash)
is_final = tx.is_final()
else:
is_final = True
if not is_final:
time_str = _('Replaceable')
icon = "atlas://gui/kivy/theming/light/close"
elif height < 0:
time_str = _('Unconfirmed inputs')
icon = "atlas://gui/kivy/theming/light/close"
elif height == 0:
2016-02-15 10:50:44 -08:00
time_str = _('Unconfirmed')
icon = "atlas://gui/kivy/theming/light/unconfirmed"
elif conf == 0:
time_str = _('Not Verified')
icon = "atlas://gui/kivy/theming/light/close"
elif conf < 6:
conf = max(1, conf)
icon = "atlas://gui/kivy/theming/light/clock{}".format(conf)
else:
icon = "atlas://gui/kivy/theming/light/confirmed"
2015-12-15 03:52:30 -08:00
label = self.app.wallet.get_label(tx_hash) if tx_hash else _('Pruned transaction outputs')
2015-12-15 03:29:48 -08:00
date = timestamp_to_datetime(timestamp)
2016-02-12 06:21:03 -08:00
quote_text = ''
if self.app.fiat_unit and date:
rate = run_hook('history_rate', date)
if rate:
s = run_hook('value_str', value, rate)
quote_text = '' if s is None else s + ' ' + self.app.fiat_unit
2015-10-15 02:18:10 -07:00
yield (conf, icon, time_str, label, value, tx_hash, quote_text)
def update(self, see_all=False):
2015-10-13 06:58:34 -07:00
if self.app.wallet is None:
return
2015-10-07 04:06:28 -07:00
history = self.parse_history(reversed(
self.app.wallet.get_history(self.app.current_account)))
# repopulate History Card
2016-01-16 07:47:48 -08:00
history_card = self.screen.ids.history_container
2015-12-12 07:54:32 -08:00
history_card.clear_widgets()
count = 0
2015-10-07 04:06:28 -07:00
for item in history:
count += 1
conf, icon, date_time, message, value, tx, quote_text = item
ri = Factory.HistoryItem()
ri.icon = icon
ri.date = date_time
ri.message = message
ri.value = value or 0
2016-04-05 08:24:03 -07:00
ri.value_known = value is not None
2015-10-13 03:12:49 -07:00
ri.quote_text = quote_text
ri.confirmations = conf
ri.tx_hash = tx
2015-12-12 07:54:32 -08:00
ri.screen = self
2016-01-16 07:47:48 -08:00
history_card.add_widget(ri)
if count == 8 and not see_all:
break
2016-01-16 07:47:48 -08:00
if count == 0:
msg = _('This screen shows your list of transactions. It is currently empty.')
history_card.add_widget(EmptyLabel(text=msg))
class SendScreen(CScreen):
2015-12-02 06:27:23 -08:00
kvname = 'send'
2015-12-11 06:21:21 -08:00
payment_request = None
2015-12-02 06:27:23 -08:00
def set_URI(self, text):
import electrum
try:
uri = electrum.util.parse_URI(text, self.app.on_pr)
except:
2016-02-26 01:48:43 -08:00
self.app.show_info(_("Not a Bitcoin URI"))
return
2016-02-18 06:53:52 -08:00
amount = uri.get('amount')
2015-12-04 02:47:46 -08:00
self.screen.address = uri.get('address', '')
self.screen.message = uri.get('message', '')
self.screen.amount = self.app.format_amount_and_units(amount) if amount else ''
2016-02-18 06:53:52 -08:00
self.payment_request = None
self.screen.is_pr = False
2015-12-12 14:23:58 -08:00
def update(self):
2016-02-12 13:20:20 -08:00
pass
2015-12-12 14:23:58 -08:00
2015-10-14 05:18:15 -07:00
def do_clear(self):
2015-12-04 02:47:46 -08:00
self.screen.amount = ''
self.screen.message = ''
self.screen.address = ''
2015-12-11 06:21:21 -08:00
self.payment_request = None
self.screen.is_pr = False
2015-12-11 06:21:21 -08:00
def set_request(self, pr):
self.screen.address = pr.get_requestor()
2015-12-13 08:49:51 -08:00
amount = pr.get_amount()
self.screen.amount = self.app.format_amount_and_units(amount) if amount else ''
2015-12-11 06:21:21 -08:00
self.screen.message = pr.get_memo()
if pr.is_pr():
self.screen.is_pr = True
self.payment_request = pr
2016-02-18 06:45:34 -08:00
else:
self.screen.is_pr = False
self.payment_request = None
2015-10-14 05:18:15 -07:00
2016-02-09 03:48:25 -08:00
def do_save(self):
if not self.screen.address:
return
2016-02-18 06:45:34 -08:00
if self.screen.is_pr:
2016-02-09 03:48:25 -08:00
# it sould be already saved
return
# save address as invoice
from electrum.paymentrequest import make_unsigned_request, PaymentRequest
req = {'address':self.screen.address, 'memo':self.screen.message}
amount = self.app.get_amount(self.screen.amount) if self.screen.amount else 0
req['amount'] = amount
pr = make_unsigned_request(req).SerializeToString()
pr = PaymentRequest(pr)
self.app.invoices.add(pr)
self.app.update_tab('invoices')
self.app.show_info(_("Invoice saved"))
2016-02-19 04:53:01 -08:00
if pr.is_pr():
self.screen.is_pr = True
self.payment_request = pr
else:
self.screen.is_pr = False
self.payment_request = None
2016-02-09 03:48:25 -08:00
2015-12-04 02:47:46 -08:00
def do_paste(self):
contents = unicode(self.app._clipboard.paste())
2016-02-09 03:48:25 -08:00
if not contents:
self.app.show_info(_("Clipboard is empty"))
return
self.set_URI(contents)
2015-10-06 05:30:44 -07:00
2015-12-04 02:47:46 -08:00
def do_send(self):
2016-02-18 06:45:34 -08:00
if self.screen.is_pr:
2015-12-11 06:21:21 -08:00
if self.payment_request.has_expired():
self.app.show_error(_('Payment request has expired'))
return
outputs = self.payment_request.get_outputs()
else:
address = str(self.screen.address)
2016-02-26 01:25:37 -08:00
if not address:
2016-02-26 01:29:16 -08:00
self.app.show_error(_('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request'))
2016-02-26 01:25:37 -08:00
return
2015-12-11 06:21:21 -08:00
if not bitcoin.is_address(address):
self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + address)
return
try:
amount = self.app.get_amount(self.screen.amount)
except:
self.app.show_error(_('Invalid amount') + ':\n' + self.screen.amount)
return
2016-01-14 08:15:50 -08:00
outputs = [(bitcoin.TYPE_ADDRESS, address, amount)]
2015-12-04 03:01:13 -08:00
message = unicode(self.screen.message)
2016-02-13 01:00:20 -08:00
amount = sum(map(lambda x:x[2], outputs))
2015-10-06 05:30:44 -07:00
# make unsigned transaction
coins = self.app.wallet.get_spendable_coins()
2016-02-13 01:00:20 -08:00
config = self.app.electrum_config
2015-10-06 05:30:44 -07:00
try:
2016-02-13 01:00:20 -08:00
tx = self.app.wallet.make_unsigned_transaction(coins, outputs, config, None)
2016-02-18 02:24:38 -08:00
except NotEnoughFunds:
self.app.show_error(_("Not enough funds"))
return
2015-10-06 05:30:44 -07:00
except Exception as e:
traceback.print_exc(file=sys.stdout)
self.app.show_error(str(e))
2015-10-06 05:30:44 -07:00
return
2016-02-13 01:00:20 -08:00
fee = tx.get_fee()
msg = [
_("Amount to be sent") + ": " + self.app.format_amount_and_units(amount),
_("Mining fee") + ": " + self.app.format_amount_and_units(fee),
]
if fee >= config.get('confirm_fee', 100000):
msg.append(_('Warning')+ ': ' + _("The fee for this transaction seems unusually high."))
msg.append(_("Enter your PIN code to proceed"))
2016-02-19 05:25:01 -08:00
self.app.protected('\n'.join(msg), self.send_tx, (tx, message))
2016-02-13 01:00:20 -08:00
2016-02-19 05:25:01 -08:00
def send_tx(self, tx, message, password):
def on_success(tx):
if tx.is_complete():
2016-02-19 04:53:01 -08:00
self.app.broadcast(tx, self.payment_request)
2016-02-19 05:25:01 -08:00
self.app.wallet.set_label(tx.hash(), message)
else:
self.app.tx_dialog(tx)
def on_failure(error):
self.app.show_error(error)
2016-02-13 01:33:49 -08:00
if self.app.wallet.can_sign(tx):
self.app.show_info("Signing...")
self.app.sign_tx(tx, password, on_success, on_failure)
else:
2016-02-12 23:15:06 -08:00
self.app.tx_dialog(tx)
2015-10-06 05:30:44 -07:00
class ReceiveScreen(CScreen):
2015-10-14 02:44:01 -07:00
2015-12-04 02:47:46 -08:00
kvname = 'receive'
2016-02-08 10:01:34 -08:00
2015-10-06 05:30:44 -07:00
def update(self):
2016-02-08 10:01:34 -08:00
if not self.screen.address:
self.get_new_address()
2016-02-14 19:18:58 -08:00
else:
status = self.app.wallet.get_request_status(self.screen.address)
2016-02-15 02:33:48 -08:00
self.screen.status = _('Payment received') if status == PR_PAID else ''
2016-02-08 10:01:34 -08:00
2016-03-05 00:44:28 -08:00
def clear(self):
self.screen.address = ''
self.screen.amount = ''
self.screen.message = ''
2016-02-08 10:01:34 -08:00
def get_new_address(self):
2016-03-10 07:22:19 -08:00
if not self.app.wallet:
return False
2016-02-08 10:01:34 -08:00
addr = self.app.wallet.get_unused_address(None)
if addr is None:
return False
2016-03-05 00:44:28 -08:00
self.clear()
2015-12-12 14:23:58 -08:00
self.screen.address = addr
2016-02-08 10:01:34 -08:00
return True
def on_address(self, addr):
2016-02-14 03:24:31 -08:00
req = self.app.wallet.get_payment_request(addr, self.app.electrum_config)
self.screen.status = ''
2015-12-12 14:23:58 -08:00
if req:
2015-12-13 06:26:08 -08:00
self.screen.message = unicode(req.get('memo', ''))
2015-12-13 08:49:51 -08:00
amount = req.get('amount')
2016-02-14 19:18:58 -08:00
self.screen.amount = self.app.format_amount_and_units(amount) if amount else ''
status = req.get('status', PR_UNKNOWN)
2016-02-15 02:33:48 -08:00
self.screen.status = _('Payment received') if status == PR_PAID else ''
2016-02-08 10:01:34 -08:00
Clock.schedule_once(lambda dt: self.update_qr())
2015-10-14 02:44:01 -07:00
2015-12-04 02:47:46 -08:00
def get_URI(self):
2015-10-14 09:03:02 -07:00
from electrum.util import create_URI
2015-12-04 02:47:46 -08:00
amount = self.screen.amount
if amount:
a, u = self.screen.amount.split()
2015-10-16 02:18:24 -07:00
assert u == self.app.base_unit
amount = Decimal(a) * pow(10, self.app.decimal_point())
2015-12-04 02:47:46 -08:00
return create_URI(self.screen.address, amount, self.screen.message)
@profiler
def update_qr(self):
uri = self.get_URI()
qr = self.screen.ids.qr
2015-10-14 02:44:01 -07:00
qr.set_data(uri)
2016-02-06 07:58:31 -08:00
def do_share(self):
if platform != 'android':
2016-02-06 07:35:21 -08:00
return
2016-02-06 07:58:31 -08:00
uri = self.get_URI()
from jnius import autoclass, cast
JS = autoclass('java.lang.String')
Intent = autoclass('android.content.Intent')
sendIntent = Intent()
sendIntent.setAction(Intent.ACTION_SEND)
sendIntent.setType("text/plain")
sendIntent.putExtra(Intent.EXTRA_TEXT, JS(uri))
PythonActivity = autoclass('org.renpy.android.PythonActivity')
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
it = Intent.createChooser(sendIntent, cast('java.lang.CharSequence', JS("Share Bitcoin Request")))
currentActivity.startActivity(it)
2016-02-06 07:35:21 -08:00
2016-02-06 07:58:31 -08:00
def do_copy(self):
uri = self.get_URI()
self.app._clipboard.copy(uri)
2016-01-29 03:46:28 -08:00
self.app.show_info(_('Request copied to clipboard'))
2015-10-14 09:45:26 -07:00
def save_request(self):
2015-12-11 06:48:56 -08:00
addr = str(self.screen.address)
amount = str(self.screen.amount)
2016-03-13 00:25:48 -08:00
message = unicode(self.screen.message)
2016-02-08 10:01:34 -08:00
amount = self.app.get_amount(amount) if amount else 0
2015-12-11 06:48:56 -08:00
req = self.app.wallet.make_payment_request(addr, amount, message, None)
self.app.wallet.add_payment_request(req, self.app.electrum_config)
2015-12-18 06:03:38 -08:00
self.app.update_tab('requests')
def on_amount_or_message(self):
self.save_request()
2016-02-08 10:01:34 -08:00
Clock.schedule_once(lambda dt: self.update_qr())
2015-12-11 06:48:56 -08:00
2015-12-13 06:26:08 -08:00
def do_new(self):
addr = self.get_new_address()
if not addr:
2016-02-08 10:01:34 -08:00
self.app.show_info(_('Please use the existing requests first.'))
else:
self.save_request()
2016-02-15 02:33:48 -08:00
self.app.show_info(_('New request added to your list.'))
2015-10-06 05:30:44 -07:00
2016-02-15 02:33:48 -08:00
invoice_text = {
PR_UNPAID:_('Pending'),
PR_UNKNOWN:_('Unknown'),
PR_PAID:_('Paid'),
PR_EXPIRED:_('Expired')
}
2016-02-15 02:33:48 -08:00
request_text = {
PR_UNPAID: _('Pending'),
PR_UNKNOWN: _('Unknown'),
PR_PAID: _('Received'),
PR_EXPIRED: _('Expired')
2016-02-14 19:18:58 -08:00
}
pr_icon = {
PR_UNPAID: 'atlas://gui/kivy/theming/light/important',
PR_UNKNOWN: 'atlas://gui/kivy/theming/light/important',
PR_PAID: 'atlas://gui/kivy/theming/light/confirmed',
PR_EXPIRED: 'atlas://gui/kivy/theming/light/close'
}
class InvoicesScreen(CScreen):
kvname = 'invoices'
def update(self):
2016-02-11 02:40:23 -08:00
self.menu_actions = [('Pay', self.do_pay), ('Details', self.do_view), ('Delete', self.do_delete)]
invoices_list = self.screen.ids.invoices_container
invoices_list.clear_widgets()
2016-01-16 07:47:48 -08:00
_list = self.app.invoices.sorted_list()
for pr in _list:
ci = Factory.InvoiceItem()
ci.key = pr.get_id()
ci.requestor = pr.get_requestor()
2016-02-09 03:48:25 -08:00
ci.memo = pr.get_memo()
amount = pr.get_amount()
if amount:
ci.amount = self.app.format_amount_and_units(amount)
status = self.app.invoices.get_status(ci.key)
2016-02-15 02:33:48 -08:00
ci.status = invoice_text[status]
2016-02-09 03:48:25 -08:00
ci.icon = pr_icon[status]
else:
ci.amount = _('No Amount')
ci.status = ''
exp = pr.get_expiration_date()
ci.date = format_time(exp) if exp else _('Never')
2015-12-12 07:54:32 -08:00
ci.screen = self
invoices_list.add_widget(ci)
2016-01-16 07:47:48 -08:00
if not _list:
2016-02-09 04:46:42 -08:00
msg = _('This screen shows the list of payment requests that have been sent to you. You may also use it to store contact addresses.')
2016-01-16 07:47:48 -08:00
invoices_list.add_widget(EmptyLabel(text=msg))
2015-12-12 14:23:58 -08:00
def do_pay(self, obj):
pr = self.app.invoices.get(obj.key)
self.app.on_pr(pr)
2015-12-12 07:54:32 -08:00
2016-02-11 02:40:23 -08:00
def do_view(self, obj):
pr = self.app.invoices.get(obj.key)
pr.verify(self.app.contacts)
self.app.show_pr_details(pr.get_dict(), obj.status, True)
2016-02-11 02:40:23 -08:00
2015-12-12 14:23:58 -08:00
def do_delete(self, obj):
2016-02-08 10:01:34 -08:00
from dialogs.question import Question
def cb():
self.app.invoices.remove(obj.key)
self.app.update_tab('invoices')
d = Question(_('Delete invoice?'), cb)
d.open()
2015-12-12 07:54:32 -08:00
class RequestsScreen(CScreen):
kvname = 'requests'
def update(self):
2016-02-15 04:49:33 -08:00
self.menu_actions = [('Show', self.do_show), ('Details', self.do_view), ('Delete', self.do_delete)]
requests_list = self.screen.ids.requests_container
requests_list.clear_widgets()
2016-03-10 07:22:19 -08:00
_list = self.app.wallet.get_sorted_requests(self.app.electrum_config) if self.app.wallet else []
2016-01-16 07:47:48 -08:00
for req in _list:
address = req['address']
timestamp = req.get('time', 0)
amount = req.get('amount')
expiration = req.get('exp', None)
status = req.get('status')
signature = req.get('sig')
2016-02-09 03:48:25 -08:00
ci = Factory.RequestItem()
2016-02-09 03:48:25 -08:00
ci.address = address
2015-12-15 03:52:30 -08:00
ci.memo = self.app.wallet.get_label(address)
2016-02-08 10:01:34 -08:00
if amount:
status = req.get('status')
2016-02-15 02:33:48 -08:00
ci.status = request_text[status]
2016-02-08 10:01:34 -08:00
else:
received = self.app.wallet.get_addr_received(address)
ci.status = self.app.format_amount_and_units(amount)
ci.icon = pr_icon[status]
2016-02-08 10:01:34 -08:00
ci.amount = self.app.format_amount_and_units(amount) if amount else _('No Amount')
ci.date = format_time(timestamp)
2015-12-12 07:54:32 -08:00
ci.screen = self
requests_list.add_widget(ci)
2016-01-16 07:47:48 -08:00
if not _list:
2016-01-21 03:20:45 -08:00
msg = _('This screen shows the list of payment requests you made.')
2016-01-16 07:47:48 -08:00
requests_list.add_widget(EmptyLabel(text=msg))
2015-12-12 14:23:58 -08:00
def do_show(self, obj):
self.app.show_request(obj.address)
2016-02-15 04:49:33 -08:00
def do_view(self, obj):
req = self.app.wallet.get_payment_request(obj.address, self.app.electrum_config)
status = req.get('status')
amount = req.get('amount')
address = req['address']
if amount:
status = req.get('status')
status = request_text[status]
2016-02-15 04:49:33 -08:00
else:
2016-02-17 21:58:46 -08:00
received_amount = self.app.wallet.get_addr_received(address)
status = self.app.format_amount_and_units(received_amount)
2016-02-15 04:49:33 -08:00
self.app.show_pr_details(req, status, False)
2015-12-12 14:23:58 -08:00
def do_delete(self, obj):
2016-02-08 10:01:34 -08:00
from dialogs.question import Question
def cb():
self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
self.update()
d = Question(_('Delete request?'), cb)
d.open()
2015-12-12 07:54:32 -08:00
class TabbedCarousel(Factory.TabbedPanel):
'''Custom TabbedPanel using a carousel used in the Main Screen
'''
carousel = ObjectProperty(None)
def animate_tab_to_center(self, value):
scrlv = self._tab_strip.parent
if not scrlv:
return
idx = self.tab_list.index(value)
2015-12-10 06:26:38 -08:00
n = len(self.tab_list)
if idx in [0, 1]:
scroll_x = 1
elif idx in [n-1, n-2]:
scroll_x = 0
else:
scroll_x = 1. * (n - idx - 1) / (n - 1)
mation = Factory.Animation(scroll_x=scroll_x, d=.25)
mation.cancel_all(scrlv)
mation.start(scrlv)
def on_current_tab(self, instance, value):
self.animate_tab_to_center(value)
def on_index(self, instance, value):
current_slide = instance.current_slide
if not hasattr(current_slide, 'tab'):
return
tab = current_slide.tab
ct = self.current_tab
try:
if ct.text != tab.text:
carousel = self.carousel
carousel.slides[ct.slide].dispatch('on_leave')
self.switch_to(tab)
carousel.slides[tab.slide].dispatch('on_enter')
except AttributeError:
current_slide.dispatch('on_enter')
def switch_to(self, header):
# we have to replace the functionality of the original switch_to
if not header:
return
if not hasattr(header, 'slide'):
header.content = self.carousel
super(TabbedCarousel, self).switch_to(header)
try:
tab = self.tab_list[-1]
except IndexError:
return
self._current_tab = tab
tab.state = 'down'
return
carousel = self.carousel
self.current_tab.state = "normal"
header.state = 'down'
self._current_tab = header
# set the carousel to load the appropriate slide
# saved in the screen attribute of the tab head
slide = carousel.slides[header.slide]
if carousel.current_slide != slide:
carousel.current_slide.dispatch('on_leave')
carousel.load_slide(slide)
slide.dispatch('on_enter')
def add_widget(self, widget, index=0):
if isinstance(widget, Factory.CScreen):
self.carousel.add_widget(widget)
return
super(TabbedCarousel, self).add_widget(widget, index=index)