kivy: rework send and receive screens
This commit is contained in:
parent
e9ee851bb2
commit
df02269bcf
|
@ -48,6 +48,7 @@ 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.label import Label
|
||||||
from kivy.uix.checkbox import CheckBox
|
from kivy.uix.checkbox import CheckBox
|
||||||
|
from kivy.core.clipboard import Clipboard
|
||||||
|
|
||||||
Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens')
|
Factory.register('TabbedCarousel', module='electrum_gui.kivy.uix.screens')
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ class ElectrumWindow(App):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
# initialize variables
|
# initialize variables
|
||||||
self._clipboard = None
|
self._clipboard = Clipboard
|
||||||
self.info_bubble = None
|
self.info_bubble = None
|
||||||
self.qrscanner = None
|
self.qrscanner = None
|
||||||
self.nfcscanner = None
|
self.nfcscanner = None
|
||||||
|
@ -203,18 +204,6 @@ class ElectrumWindow(App):
|
||||||
return
|
return
|
||||||
self.send_screen.set_URI(url)
|
self.send_screen.set_URI(url)
|
||||||
|
|
||||||
def send_from_clipboard(self, on_complete):
|
|
||||||
if not self._clipboard:
|
|
||||||
from kivy.core.clipboard import Clipboard
|
|
||||||
self._clipboard = Clipboard
|
|
||||||
contents = self._clipboard.get()
|
|
||||||
try:
|
|
||||||
uri = electrum.util.parse_URI(contents)
|
|
||||||
except:
|
|
||||||
self.show_info("Invalid URI", url)
|
|
||||||
return
|
|
||||||
on_complete(uri)
|
|
||||||
|
|
||||||
|
|
||||||
def scan_qr(self, on_complete):
|
def scan_qr(self, on_complete):
|
||||||
from jnius import autoclass
|
from jnius import autoclass
|
||||||
|
@ -564,14 +553,6 @@ class ElectrumWindow(App):
|
||||||
format(txs=tx_amount, amount=self.format_amount(v),
|
format(txs=tx_amount, amount=self.format_amount(v),
|
||||||
unit=self.base_unit))
|
unit=self.base_unit))
|
||||||
|
|
||||||
def copy(self, text):
|
|
||||||
''' Copy provided text to clipboard
|
|
||||||
'''
|
|
||||||
if not self._clipboard:
|
|
||||||
from kivy.core.clipboard import Clipboard
|
|
||||||
self._clipboard = Clipboard
|
|
||||||
self._clipboard.put(text, 'text/plain')
|
|
||||||
|
|
||||||
def notify(self, message):
|
def notify(self, message):
|
||||||
try:
|
try:
|
||||||
global notification, os
|
global notification, os
|
||||||
|
@ -776,7 +757,7 @@ class ElectrumWindow(App):
|
||||||
popup.tx_hash = tx_hash
|
popup.tx_hash = tx_hash
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
def amount_dialog(self, label, callback, show_max):
|
def amount_dialog(self, screen, show_max):
|
||||||
popup = Builder.load_file('gui/kivy/uix/ui_screens/amount.kv')
|
popup = Builder.load_file('gui/kivy/uix/ui_screens/amount.kv')
|
||||||
but_max = popup.ids.but_max
|
but_max = popup.ids.but_max
|
||||||
if not show_max:
|
if not show_max:
|
||||||
|
@ -786,15 +767,16 @@ class ElectrumWindow(App):
|
||||||
but_max.disabled = False
|
but_max.disabled = False
|
||||||
but_max.opacity = 1
|
but_max.opacity = 1
|
||||||
|
|
||||||
if label.text != label.default_text:
|
amount = screen.amount
|
||||||
a, u = label.text.split()
|
if amount:
|
||||||
|
a, u = str(amount).split()
|
||||||
assert u == self.base_unit
|
assert u == self.base_unit
|
||||||
popup.ids.a.amount = a
|
popup.ids.a.amount = a
|
||||||
|
|
||||||
def cb():
|
def cb():
|
||||||
o = popup.ids.a.btc_text
|
o = popup.ids.a.btc_text
|
||||||
label.text = o if o else label.default_text
|
screen.amount = o
|
||||||
if callback:
|
|
||||||
callback()
|
|
||||||
popup.on_dismiss = cb
|
popup.on_dismiss = cb
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,14 @@ from kivy.cache import Cache
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.compat import string_types
|
from kivy.compat import string_types
|
||||||
from kivy.properties import (ObjectProperty, DictProperty, NumericProperty,
|
from kivy.properties import (ObjectProperty, DictProperty, NumericProperty,
|
||||||
ListProperty)
|
ListProperty, StringProperty)
|
||||||
|
|
||||||
|
|
||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import profiler
|
from electrum.util import profiler, parse_URI
|
||||||
from electrum import bitcoin
|
from electrum import bitcoin
|
||||||
from electrum.util import timestamp_to_datetime
|
from electrum.util import timestamp_to_datetime
|
||||||
from electrum.plugins import run_hook
|
from electrum.plugins import run_hook
|
||||||
|
@ -181,42 +183,38 @@ class SendScreen(CScreen):
|
||||||
kvname = 'send'
|
kvname = 'send'
|
||||||
|
|
||||||
def set_URI(self, uri):
|
def set_URI(self, uri):
|
||||||
print "z", uri
|
print "set uri", uri
|
||||||
self.ids.payto_e.text = uri.get('address', '')
|
self.screen.address = uri.get('address', '')
|
||||||
self.ids.message_e.text = uri.get('message', '')
|
self.screen.message = uri.get('message', '')
|
||||||
amount = uri.get('amount')
|
amount = uri.get('amount')
|
||||||
if amount:
|
if amount:
|
||||||
amount_str = str( Decimal(amount) / pow(10, self.app.decimal_point()))
|
amount_str = str( Decimal(amount) / pow(10, self.app.decimal_point()))
|
||||||
self.ids.amount_e.text = amount_str + ' ' + self.app.base_unit
|
self.screen.amount = amount_str + ' ' + self.app.base_unit
|
||||||
|
|
||||||
def do_clear(self):
|
def do_clear(self):
|
||||||
self.ids.payto_e.text = ''
|
self.screen.amount = ''
|
||||||
self.ids.message_e.text = ''
|
self.screen.message = ''
|
||||||
self.ids.amount_e.text = 'Amount'
|
self.screen.address = ''
|
||||||
#self.set_frozen(content, False)
|
|
||||||
#self.update_status()
|
def do_paste(self):
|
||||||
|
contents = unicode(self.app._clipboard.get())
|
||||||
|
try:
|
||||||
|
uri = parse_URI(contents)
|
||||||
|
except:
|
||||||
|
self.app.show_info("Invalid URI", contents)
|
||||||
|
return
|
||||||
|
self.set_URI(uri)
|
||||||
|
|
||||||
def do_send(self):
|
def do_send(self):
|
||||||
scrn = self.ids
|
address = str(self.screen.address)
|
||||||
label = unicode(scrn.message_e.text)
|
amount = self.app.get_amount(self.screen.amount)
|
||||||
r = unicode(scrn.payto_e.text).strip()
|
message = unicode(self.screen.message)
|
||||||
# label or alias, with address in brackets
|
if not bitcoin.is_address(self.address):
|
||||||
m = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
|
self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + address)
|
||||||
to_address = m.group(2) if m else r
|
|
||||||
|
|
||||||
if not bitcoin.is_address(to_address):
|
|
||||||
self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + to_address)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
amount = self.app.get_amount(scrn.amount_e.text)
|
|
||||||
#fee = scrn.fee_e.amt
|
|
||||||
#if not fee:
|
|
||||||
# app.show_error(_('Invalid Fee'))
|
|
||||||
# return
|
|
||||||
fee = None
|
fee = None
|
||||||
message = 'sending {} {} to {}'.format(self.app.base_unit, scrn.amount_e.text, r)
|
outputs = [('address', address, amount)]
|
||||||
outputs = [('address', to_address, amount)]
|
self.app.password_dialog(self.send_tx, (outputs, fee, message))
|
||||||
self.app.password_dialog(self.send_tx, (outputs, fee, label))
|
|
||||||
|
|
||||||
def send_tx(self, *args):
|
def send_tx(self, *args):
|
||||||
self.app.show_info("Sending...")
|
self.app.show_info("Sending...")
|
||||||
|
@ -244,43 +242,41 @@ class SendScreen(CScreen):
|
||||||
|
|
||||||
|
|
||||||
class ReceiveScreen(CScreen):
|
class ReceiveScreen(CScreen):
|
||||||
|
|
||||||
kvname = 'receive'
|
kvname = 'receive'
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
addr = self.app.wallet.get_unused_address(None)
|
self.screen.address = self.app.wallet.get_unused_address(None)
|
||||||
address_label = self.screen.ids.get('address')
|
|
||||||
address_label.text = addr
|
|
||||||
self.update_qr()
|
|
||||||
|
|
||||||
def amount_callback(self, popup):
|
def amount_callback(self, popup):
|
||||||
amount_label = self.screen.ids.get('amount')
|
amount_label = self.screen.ids.get('amount')
|
||||||
amount_label.text = popup.ids.amount_label.text
|
amount_label.text = popup.ids.amount_label.text
|
||||||
self.update_qr()
|
self.update_qr()
|
||||||
|
|
||||||
@profiler
|
def get_URI(self):
|
||||||
def update_qr(self):
|
|
||||||
from electrum.util import create_URI
|
from electrum.util import create_URI
|
||||||
address = self.screen.ids.get('address').text
|
amount = self.screen.amount
|
||||||
amount = self.screen.ids.get('amount').text
|
if amount:
|
||||||
default_text = self.screen.ids.get('amount').default_text
|
a, u = self.screen.amount.split()
|
||||||
if amount == default_text:
|
|
||||||
amount = None
|
|
||||||
else:
|
|
||||||
a, u = amount.split()
|
|
||||||
assert u == self.app.base_unit
|
assert u == self.app.base_unit
|
||||||
amount = Decimal(a) * pow(10, self.app.decimal_point())
|
amount = Decimal(a) * pow(10, self.app.decimal_point())
|
||||||
msg = self.screen.ids.get('message').text
|
return create_URI(self.screen.address, amount, self.screen.message)
|
||||||
uri = create_URI(address, amount, msg)
|
|
||||||
|
@profiler
|
||||||
|
def update_qr(self):
|
||||||
|
uri = self.get_URI()
|
||||||
qr = self.screen.ids.get('qr')
|
qr = self.screen.ids.get('qr')
|
||||||
qr.set_data(uri)
|
qr.set_data(uri)
|
||||||
|
|
||||||
def do_share(self):
|
def do_copy(self):
|
||||||
pass
|
uri = self.get_URI()
|
||||||
|
print "put", uri
|
||||||
|
self.app._clipboard.put(uri, 'text/plain')
|
||||||
|
print "get", self.app._clipboard.get()
|
||||||
|
|
||||||
def do_clear(self):
|
def do_clear(self):
|
||||||
a = self.screen.ids.get('amount')
|
self.screen.amount = ''
|
||||||
a.text = a.default_text
|
self.screen.message = ''
|
||||||
self.screen.ids.get('message').text = ''
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,20 @@
|
||||||
|
|
||||||
|
|
||||||
ReceiveScreen:
|
ReceiveScreen:
|
||||||
id: receive_screen
|
id: s
|
||||||
name: 'receive'
|
name: 'receive'
|
||||||
|
|
||||||
|
address: ''
|
||||||
|
amount: ''
|
||||||
|
message: ''
|
||||||
|
|
||||||
|
on_address:
|
||||||
|
self.parent.update_qr()
|
||||||
|
on_amount:
|
||||||
|
self.parent.update_qr()
|
||||||
|
on_message:
|
||||||
|
self.parent.update_qr()
|
||||||
|
|
||||||
BoxLayout
|
BoxLayout
|
||||||
padding: '12dp', '12dp', '12dp', '12dp'
|
padding: '12dp', '12dp', '12dp', '12dp'
|
||||||
spacing: '12dp'
|
spacing: '12dp'
|
||||||
|
@ -27,10 +38,11 @@ ReceiveScreen:
|
||||||
self.shaded = not self.shaded
|
self.shaded = not self.shaded
|
||||||
self.foreground_color = (0, 0, 0, 0.5) if self.shaded else (0, 0, 0, 0)
|
self.foreground_color = (0, 0, 0, 0.5) if self.shaded else (0, 0, 0, 0)
|
||||||
Label:
|
Label:
|
||||||
id: address
|
id: address_label
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
opacity: 0.5 if qr.shaded else 1
|
opacity: 0.5 if qr.shaded else 1
|
||||||
|
text: s.address
|
||||||
|
|
||||||
SendReceiveBlueBottom:
|
SendReceiveBlueBottom:
|
||||||
id: blue_bottom
|
id: blue_bottom
|
||||||
|
@ -45,8 +57,9 @@ ReceiveScreen:
|
||||||
size: '22dp', '22dp'
|
size: '22dp', '22dp'
|
||||||
pos_hint: {'center_y': .5}
|
pos_hint: {'center_y': .5}
|
||||||
AmountButton:
|
AmountButton:
|
||||||
id: amount
|
id: amount_label
|
||||||
on_release: app.amount_dialog(amount, receive_screen.parent.update_qr, False)
|
text: s.amount if s.amount else 'Amount'
|
||||||
|
on_release: app.amount_dialog(s, False)
|
||||||
CardSeparator:
|
CardSeparator:
|
||||||
opacity: message_selection.opacity
|
opacity: message_selection.opacity
|
||||||
color: blue_bottom.foreground_color
|
color: blue_bottom.foreground_color
|
||||||
|
@ -62,23 +75,23 @@ ReceiveScreen:
|
||||||
size: '22dp', '22dp'
|
size: '22dp', '22dp'
|
||||||
pos_hint: {'center_y': .5}
|
pos_hint: {'center_y': .5}
|
||||||
TextInputBlue:
|
TextInputBlue:
|
||||||
id: message
|
id: message_input
|
||||||
hint_text: 'Description'
|
hint_text: 'Description'
|
||||||
on_text_validate: receive_screen.parent.update_qr()
|
text: s.message
|
||||||
|
on_text_validate: s.message = self.text
|
||||||
|
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
|
Button:
|
||||||
|
text: _('Copy')
|
||||||
|
size_hint: 1, None
|
||||||
|
height: '48dp'
|
||||||
|
on_release: s.parent.do_copy()
|
||||||
Button:
|
Button:
|
||||||
text: _('Clear')
|
text: _('Clear')
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
on_release: receive_screen.parent.do_clear()
|
on_release: s.parent.do_clear()
|
||||||
Button:
|
|
||||||
text: _('Share')
|
|
||||||
size_hint: 1, None
|
|
||||||
height: '48dp'
|
|
||||||
on_release: receive_screen.parent.do_share()
|
|
||||||
|
|
||||||
Widget:
|
Widget:
|
||||||
size_hint: 1, 0.3
|
size_hint: 1, 0.3
|
||||||
|
|
|
@ -7,36 +7,14 @@
|
||||||
#:set font_light 'data/fonts/Roboto-Condensed.ttf'
|
#:set font_light 'data/fonts/Roboto-Condensed.ttf'
|
||||||
|
|
||||||
|
|
||||||
<SendToggle@ToggleButton>
|
|
||||||
source: ''
|
|
||||||
markup: False
|
|
||||||
bold: True
|
|
||||||
border: 4, 4, 4, 4
|
|
||||||
group: 'transfer_type'
|
|
||||||
background_normal: self.background_down
|
|
||||||
color:
|
|
||||||
(.140, .140, .140, 1) if self.state == 'down' else (.796, .796, .796, 1)
|
|
||||||
canvas.after:
|
|
||||||
Color:
|
|
||||||
rgba: 1, 1, 1, 1
|
|
||||||
Image:
|
|
||||||
source: root.source
|
|
||||||
color: root.color
|
|
||||||
size: '30dp', '30dp'
|
|
||||||
center_x: root.center_x - ((root.texture_size[0]/2)+(self.width/1.5))
|
|
||||||
center_y: root.center_y
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SendScreen:
|
SendScreen:
|
||||||
|
|
||||||
id: send_screen
|
id: s
|
||||||
name: 'send'
|
name: 'send'
|
||||||
#action_view: Factory.SendActionView()
|
address: ''
|
||||||
#on_deactivate:
|
amount: ''
|
||||||
# self.ids.amount_e.focus = False
|
message: ''
|
||||||
# self.ids.payto_e.focus = False
|
|
||||||
# self.ids.message_e.focus = False
|
|
||||||
BoxLayout
|
BoxLayout
|
||||||
padding: '12dp', '12dp', '12dp', '12dp'
|
padding: '12dp', '12dp', '12dp', '12dp'
|
||||||
spacing: '12dp'
|
spacing: '12dp'
|
||||||
|
@ -56,6 +34,7 @@ SendScreen:
|
||||||
pos_hint: {'center_y': .5}
|
pos_hint: {'center_y': .5}
|
||||||
TextInputBlue:
|
TextInputBlue:
|
||||||
id: payto_e
|
id: payto_e
|
||||||
|
text: s.address
|
||||||
hint_text: "Recipient"
|
hint_text: "Recipient"
|
||||||
CardSeparator:
|
CardSeparator:
|
||||||
opacity: message_selection.opacity
|
opacity: message_selection.opacity
|
||||||
|
@ -70,8 +49,8 @@ SendScreen:
|
||||||
pos_hint: {'center_y': .5}
|
pos_hint: {'center_y': .5}
|
||||||
AmountButton:
|
AmountButton:
|
||||||
id: amount_e
|
id: amount_e
|
||||||
on_release: app.amount_dialog(self, None, True)
|
text: s.amount if s.amount else 'Amount'
|
||||||
|
on_release: app.amount_dialog(s, True)
|
||||||
|
|
||||||
CardSeparator:
|
CardSeparator:
|
||||||
opacity: message_selection.opacity
|
opacity: message_selection.opacity
|
||||||
|
@ -89,6 +68,7 @@ SendScreen:
|
||||||
pos_hint: {'center_y': .5}
|
pos_hint: {'center_y': .5}
|
||||||
TextInputBlue:
|
TextInputBlue:
|
||||||
id: message_e
|
id: message_e
|
||||||
|
text: s.message
|
||||||
hint_text: 'Description'
|
hint_text: 'Description'
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
|
@ -97,26 +77,28 @@ SendScreen:
|
||||||
id: qr
|
id: qr
|
||||||
text: _('QR Code')
|
text: _('QR Code')
|
||||||
on_release:
|
on_release:
|
||||||
app.scan_qr(on_complete=root.set_URI)
|
app.scan_qr(on_complete=s.parent.set_URI)
|
||||||
Button:
|
Button:
|
||||||
id: paste_button
|
id: paste_button
|
||||||
text: _('Clipboard')
|
text: _('Paste')
|
||||||
on_release:
|
on_release:
|
||||||
app.send_from_clipboard(on_complete=root.set_URI)
|
s.parent.do_paste()
|
||||||
Button:
|
Button:
|
||||||
text: _('Clear')
|
text: _('Clear')
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
on_release: send_screen.do_clear()
|
on_release: s.parent.do_clear()
|
||||||
Widget:
|
|
||||||
size_hint: 1, 1
|
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
|
Widget:
|
||||||
|
size_hint: 1, 1
|
||||||
Button:
|
Button:
|
||||||
text: _('Send')
|
text: _('Send')
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
on_release: send_screen.do_send()
|
on_release: s.parent.do_send()
|
||||||
|
Widget:
|
||||||
|
size_hint: 1, 1
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue