kivy: invoices and requests handlers
This commit is contained in:
parent
6bd37723d3
commit
eef62112a8
|
@ -13,6 +13,7 @@ from electrum.paymentrequest import InvoiceStore
|
||||||
from electrum.util import profiler, InvalidPassword
|
from electrum.util import profiler, InvalidPassword
|
||||||
from electrum.plugins import run_hook
|
from electrum.plugins import run_hook
|
||||||
from electrum.util import format_satoshis, format_satoshis_plain
|
from electrum.util import format_satoshis, format_satoshis_plain
|
||||||
|
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
|
||||||
|
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
|
@ -164,6 +165,9 @@ class ElectrumWindow(App):
|
||||||
self.nfcscanner = None
|
self.nfcscanner = None
|
||||||
self.tabs = None
|
self.tabs = None
|
||||||
|
|
||||||
|
self.receive_address = None
|
||||||
|
self.current_invoice = None
|
||||||
|
|
||||||
super(ElectrumWindow, self).__init__(**kwargs)
|
super(ElectrumWindow, self).__init__(**kwargs)
|
||||||
|
|
||||||
title = _('Electrum App')
|
title = _('Electrum App')
|
||||||
|
@ -191,19 +195,31 @@ 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 get_receive_address(self):
|
||||||
|
return self.receive_address if self.receive_address else self.wallet.get_unused_address(None)
|
||||||
|
|
||||||
|
def do_pay(self, obj):
|
||||||
|
pr = self.invoices.get(obj.key)
|
||||||
|
self.on_pr(pr)
|
||||||
|
|
||||||
def on_pr(self, pr):
|
def on_pr(self, pr):
|
||||||
from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
|
|
||||||
if pr.verify(self.contacts):
|
if pr.verify(self.contacts):
|
||||||
key = self.invoices.add(pr)
|
key = self.invoices.add(pr)
|
||||||
status = self.invoices.get_status(key)
|
status = self.invoices.get_status(key)
|
||||||
#self.invoices_screen.update()
|
#self.invoices_screen.update()
|
||||||
if status == PR_PAID:
|
if status == PR_PAID:
|
||||||
self.show_message("invoice already paid")
|
self.show_error("invoice already paid")
|
||||||
self.send_screen.do_clear()
|
self.send_screen.do_clear()
|
||||||
else:
|
else:
|
||||||
self.send_screen.set_request(pr)
|
if pr.has_expired():
|
||||||
|
self.show_error(_('Payment request has expired'))
|
||||||
|
else:
|
||||||
|
self.current_pr = pr
|
||||||
|
self.update_screen('send')
|
||||||
|
send_tab = self.tabs.ids.send_tab
|
||||||
|
self.tabs.ids.panel.switch_to(send_tab)
|
||||||
else:
|
else:
|
||||||
self.show_message("invoice error:" + pr.error)
|
self.show_error("invoice error:" + pr.error)
|
||||||
self.send_screen.do_clear()
|
self.send_screen.do_clear()
|
||||||
|
|
||||||
def set_URI(self, url):
|
def set_URI(self, url):
|
||||||
|
@ -214,6 +230,17 @@ class ElectrumWindow(App):
|
||||||
return
|
return
|
||||||
self.send_screen.set_URI(url)
|
self.send_screen.set_URI(url)
|
||||||
|
|
||||||
|
def update_screen(self, name):
|
||||||
|
s = getattr(self, name + '_screen', None)
|
||||||
|
if s:
|
||||||
|
s.update()
|
||||||
|
|
||||||
|
def show_request(self, addr):
|
||||||
|
self.receive_address = addr
|
||||||
|
self.update_screen('receive')
|
||||||
|
receive_tab = self.tabs.ids.receive_tab
|
||||||
|
self.tabs.ids.panel.switch_to(receive_tab)
|
||||||
|
req = self.wallet.receive_requests.get(addr)
|
||||||
|
|
||||||
def scan_qr(self, on_complete):
|
def scan_qr(self, on_complete):
|
||||||
from jnius import autoclass
|
from jnius import autoclass
|
||||||
|
@ -412,6 +439,7 @@ class ElectrumWindow(App):
|
||||||
self.network.register_callback(self.on_network, interests)
|
self.network.register_callback(self.on_network, interests)
|
||||||
|
|
||||||
self.wallet = None
|
self.wallet = None
|
||||||
|
self.tabs = self.root.ids['tabs']
|
||||||
|
|
||||||
def on_network(self, event, *args):
|
def on_network(self, event, *args):
|
||||||
if event == 'updated':
|
if event == 'updated':
|
||||||
|
@ -603,64 +631,10 @@ class ElectrumWindow(App):
|
||||||
else:
|
else:
|
||||||
self.show_error(_('Invalid Address'))
|
self.show_error(_('Invalid Address'))
|
||||||
|
|
||||||
def send_payment(self, address, amount=0, label='', message=''):
|
|
||||||
tabs = self.tabs
|
|
||||||
screen_send = tabs.ids.screen_send
|
|
||||||
|
|
||||||
if label and self.wallet.labels.get(address) != label:
|
|
||||||
#if self.question('Give label "%s" to address %s ?'%(label,address)):
|
|
||||||
if address not in self.wallet.addressbook and not self.wallet. is_mine(address):
|
|
||||||
self.wallet.addressbook.append(address)
|
|
||||||
self.wallet.set_label(address, label)
|
|
||||||
|
|
||||||
# switch_to the send screen
|
|
||||||
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
||||||
|
|
||||||
label = self.wallet.labels.get(address)
|
|
||||||
m_addr = label + ' <'+ address +'>' if label else address
|
|
||||||
|
|
||||||
# populate
|
|
||||||
def set_address(*l):
|
|
||||||
content = screen_send.ids
|
|
||||||
content.payto_e.text = m_addr
|
|
||||||
content.message_e.text = message
|
|
||||||
if amount:
|
|
||||||
content.amount_e.text = amount
|
|
||||||
|
|
||||||
# wait for screen to load
|
|
||||||
Clock.schedule_once(set_address, .5)
|
|
||||||
|
|
||||||
def set_send(self, address, amount, label, message):
|
def set_send(self, address, amount, label, message):
|
||||||
self.send_payment(address, amount=amount, label=label, message=message)
|
self.send_payment(address, amount=amount, label=label, message=message)
|
||||||
|
|
||||||
def prepare_for_payment_request(self):
|
|
||||||
tabs = self.tabs
|
|
||||||
screen_send = tabs.ids.screen_send
|
|
||||||
|
|
||||||
# switch_to the send screen
|
|
||||||
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
||||||
|
|
||||||
content = screen_send.ids
|
|
||||||
if content:
|
|
||||||
self.set_frozen(content, False)
|
|
||||||
screen_send.screen_label.text = _("please wait...")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def payment_request_ok(self):
|
|
||||||
tabs = self.tabs
|
|
||||||
screen_send = tabs.ids.screen_send
|
|
||||||
|
|
||||||
# switch_to the send screen
|
|
||||||
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
||||||
|
|
||||||
self.set_frozen(content, True)
|
|
||||||
|
|
||||||
screen_send.ids.payto_e.text = self.gui_object.payment_request.domain
|
|
||||||
screen_send.ids.amount_e.text = self.format_amount(self.gui_object.payment_request.get_amount())
|
|
||||||
screen_send.ids.message_e.text = self.gui_object.payment_request.memo
|
|
||||||
|
|
||||||
# wait for screen to load
|
|
||||||
Clock.schedule_once(set_address, .5)
|
|
||||||
|
|
||||||
def set_frozen(self, entry, frozen):
|
def set_frozen(self, entry, frozen):
|
||||||
if frozen:
|
if frozen:
|
||||||
|
@ -670,15 +644,6 @@ class ElectrumWindow(App):
|
||||||
entry.disabled = False
|
entry.disabled = False
|
||||||
Factory.Animation(opacity=1).start(content)
|
Factory.Animation(opacity=1).start(content)
|
||||||
|
|
||||||
def payment_request_error(self):
|
|
||||||
tabs = self.tabs
|
|
||||||
screen_send = tabs.ids.screen_send
|
|
||||||
|
|
||||||
# switch_to the send screen
|
|
||||||
tabs.ids.panel.switch_to(tabs.ids.tab_send)
|
|
||||||
|
|
||||||
self.do_clear()
|
|
||||||
self.show_info(self.gui_object.payment_request.error)
|
|
||||||
|
|
||||||
def show_error(self, error, width='200dp', pos=None, arrow_pos=None,
|
def show_error(self, error, width='200dp', pos=None, arrow_pos=None,
|
||||||
exit=False, icon='atlas://gui/kivy/theming/light/error', duration=0,
|
exit=False, icon='atlas://gui/kivy/theming/light/error', duration=0,
|
||||||
|
|
|
@ -39,5 +39,5 @@ class ContextMenu(Bubble):
|
||||||
for k, v in action_list:
|
for k, v in action_list:
|
||||||
l = MenuItem()
|
l = MenuItem()
|
||||||
l.text = k
|
l.text = k
|
||||||
l.on_release = lambda: v(obj)
|
l.on_release = lambda f=v: f(obj)
|
||||||
self.ids.buttons.add_widget(l)
|
self.ids.buttons.add_widget(l)
|
||||||
|
|
|
@ -208,6 +208,10 @@ class SendScreen(CScreen):
|
||||||
amount_str = str( Decimal(amount) / pow(10, self.app.decimal_point()))
|
amount_str = str( Decimal(amount) / pow(10, self.app.decimal_point()))
|
||||||
self.screen.amount = amount_str + ' ' + self.app.base_unit
|
self.screen.amount = amount_str + ' ' + self.app.base_unit
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
if self.app.current_invoice:
|
||||||
|
self.set_request(self.app.current_invoice)
|
||||||
|
|
||||||
def do_clear(self):
|
def do_clear(self):
|
||||||
self.screen.amount = ''
|
self.screen.amount = ''
|
||||||
self.screen.message = ''
|
self.screen.message = ''
|
||||||
|
@ -215,9 +219,6 @@ class SendScreen(CScreen):
|
||||||
self.payment_request = None
|
self.payment_request = None
|
||||||
|
|
||||||
def set_request(self, pr):
|
def set_request(self, pr):
|
||||||
if pr.has_expired():
|
|
||||||
self.app.show_error(_('Payment request has expired'))
|
|
||||||
return
|
|
||||||
self.payment_request = pr
|
self.payment_request = pr
|
||||||
self.screen.address = pr.get_requestor()
|
self.screen.address = pr.get_requestor()
|
||||||
self.screen.amount = self.app.format_amount(pr.get_amount())
|
self.screen.amount = self.app.format_amount(pr.get_amount())
|
||||||
|
@ -283,7 +284,13 @@ class ReceiveScreen(CScreen):
|
||||||
kvname = 'receive'
|
kvname = 'receive'
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.screen.address = self.app.wallet.get_unused_address(None)
|
addr = self.app.get_receive_address()
|
||||||
|
self.screen.address = addr
|
||||||
|
req = self.app.wallet.receive_requests.get(addr)
|
||||||
|
if req:
|
||||||
|
self.screen.message = req.get('memo')
|
||||||
|
self.screen.amount = self.app.format_amount(req.get('amount')) + ' ' + self.app.base_unit
|
||||||
|
|
||||||
|
|
||||||
def amount_callback(self, popup):
|
def amount_callback(self, popup):
|
||||||
amount_label = self.screen.ids.get('amount')
|
amount_label = self.screen.ids.get('amount')
|
||||||
|
@ -320,8 +327,10 @@ class ReceiveScreen(CScreen):
|
||||||
req = self.app.wallet.make_payment_request(addr, amount, message, None)
|
req = self.app.wallet.make_payment_request(addr, amount, message, None)
|
||||||
self.app.wallet.add_payment_request(req, self.app.electrum_config)
|
self.app.wallet.add_payment_request(req, self.app.electrum_config)
|
||||||
self.app.show_error(_('Request saved'))
|
self.app.show_error(_('Request saved'))
|
||||||
|
self.app.update_screen('requests')
|
||||||
|
|
||||||
def do_clear(self):
|
def do_clear(self):
|
||||||
|
self.app.receive_address = None
|
||||||
self.screen.amount = ''
|
self.screen.amount = ''
|
||||||
self.screen.message = ''
|
self.screen.message = ''
|
||||||
self.update()
|
self.update()
|
||||||
|
@ -376,18 +385,19 @@ class InvoicesScreen(CScreen):
|
||||||
ci.screen = self
|
ci.screen = self
|
||||||
invoices_list.add_widget(ci)
|
invoices_list.add_widget(ci)
|
||||||
|
|
||||||
def do_pay(self, x):
|
def do_pay(self, obj):
|
||||||
pass
|
self.app.do_pay(obj)
|
||||||
|
|
||||||
def do_delete(self, x):
|
def do_delete(self, obj):
|
||||||
pass
|
self.app.invoices.remove(obj.key)
|
||||||
|
self.app.update_screen('invoices')
|
||||||
|
|
||||||
class RequestsScreen(CScreen):
|
class RequestsScreen(CScreen):
|
||||||
kvname = 'requests'
|
kvname = 'requests'
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
|
||||||
self.menu_actions = [(_('View'), self.do_view), (_('Delete'), self.do_delete)]
|
self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.do_delete)]
|
||||||
|
|
||||||
requests_list = self.screen.ids.requests_container
|
requests_list = self.screen.ids.requests_container
|
||||||
requests_list.clear_widgets()
|
requests_list.clear_widgets()
|
||||||
|
@ -408,13 +418,12 @@ class RequestsScreen(CScreen):
|
||||||
ci.screen = self
|
ci.screen = self
|
||||||
requests_list.add_widget(ci)
|
requests_list.add_widget(ci)
|
||||||
|
|
||||||
|
def do_show(self, obj):
|
||||||
|
self.app.show_request(obj.address)
|
||||||
|
|
||||||
def do_view(self, o):
|
def do_delete(self, obj):
|
||||||
print o
|
self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
|
||||||
|
self.update()
|
||||||
def do_delete(self, o):
|
|
||||||
print o
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CSpinner(Factory.Spinner):
|
class CSpinner(Factory.Spinner):
|
||||||
|
|
|
@ -99,4 +99,4 @@ HistoryScreen:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: self.minimum_height
|
height: self.minimum_height
|
||||||
padding: '12dp'
|
padding: '12dp'
|
||||||
spacing: '12dp'
|
spacing: '2dp'
|
||||||
|
|
|
@ -19,9 +19,6 @@
|
||||||
|
|
||||||
InvoicesScreen:
|
InvoicesScreen:
|
||||||
name: 'invoices'
|
name: 'invoices'
|
||||||
on_activate:
|
|
||||||
if not self.action_view:\
|
|
||||||
self.action_view = app.root.main_screen.ids.tabs.ids.screen_dashboard.action_view
|
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
spacing: '1dp'
|
spacing: '1dp'
|
||||||
|
@ -37,5 +34,5 @@ InvoicesScreen:
|
||||||
id: invoices_container
|
id: invoices_container
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: self.minimum_height
|
height: self.minimum_height
|
||||||
spacing: '1dp'
|
spacing: '2dp'
|
||||||
padding: '12dp'
|
padding: '12dp'
|
||||||
|
|
|
@ -89,7 +89,7 @@ ReceiveScreen:
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
on_release: s.parent.do_copy()
|
on_release: s.parent.do_copy()
|
||||||
Button:
|
Button:
|
||||||
text: _('Clear')
|
text: _('New')
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
on_release: s.parent.do_clear()
|
on_release: s.parent.do_clear()
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
|
|
||||||
RequestsScreen:
|
RequestsScreen:
|
||||||
name: 'requests'
|
name: 'requests'
|
||||||
on_activate:
|
|
||||||
if not self.action_view:\
|
|
||||||
self.action_view = app.root.main_screen.ids.tabs.ids.screen_dashboard.action_view
|
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
spacing: '1dp'
|
spacing: '1dp'
|
||||||
|
@ -41,5 +38,5 @@ RequestsScreen:
|
||||||
id: requests_container
|
id: requests_container
|
||||||
size_hint_y: None
|
size_hint_y: None
|
||||||
height: self.minimum_height
|
height: self.minimum_height
|
||||||
spacing: '1dp'
|
spacing: '2dp'
|
||||||
padding: '12dp'
|
padding: '12dp'
|
||||||
|
|
Loading…
Reference in New Issue