commit a87f3fe887fce7c7ff00166504a599868591b48c
parent 646044b43122e6523253fabc2702b41101bfc5d7
Author: ThomasV <thomasv@electrum.org>
Date: Tue, 6 Mar 2018 19:38:21 +0100
Merge branch 'kivy_new'
Diffstat:
13 files changed, 605 insertions(+), 455 deletions(-)
diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
@@ -372,9 +372,6 @@
tab_height: '48dp'
tab_width: panel.width/3
strip_border: 0, 0, 0, 0
- InvoicesScreen:
- id: invoices_screen
- tab: invoices_tab
SendScreen:
id: send_screen
tab: send_tab
@@ -384,29 +381,18 @@
ReceiveScreen:
id: receive_screen
tab: receive_tab
- AddressScreen:
- id: address_screen
- tab: address_tab
- CleanHeader:
- id: invoices_tab
- text: _('Invoices')
- slide: 0
CleanHeader:
id: send_tab
text: _('Send')
- slide: 1
+ slide: 0
CleanHeader:
id: history_tab
text: _('Balance')
- slide: 2
+ slide: 1
CleanHeader:
id: receive_tab
text: _('Receive')
- slide: 3
- CleanHeader:
- id: address_tab
- text: _('Addresses')
- slide: 4
+ slide: 2
<ActionOvrButton@ActionButton>
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -824,7 +824,6 @@ class ElectrumWindow(App):
d = LabelDialog(_('Enter description'), text, callback)
d.open()
- @profiler
def amount_dialog(self, screen, show_max):
from .uix.dialogs.amount_dialog import AmountDialog
amount = screen.amount
@@ -836,6 +835,34 @@ class ElectrumWindow(App):
popup = AmountDialog(show_max, amount, cb)
popup.open()
+ def invoices_dialog(self, screen):
+ from .uix.dialogs.invoices import InvoicesDialog
+ if len(self.wallet.invoices.sorted_list()) == 0:
+ self.show_info(' '.join([
+ _('No saved invoices.'),
+ _('Signed invoices are saved automatically when you scan them.'),
+ _('You may also save unsigned requests or contact addresses using the save button.')
+ ]))
+ return
+ popup = InvoicesDialog(self, screen, None)
+ popup.update()
+ popup.open()
+
+ def requests_dialog(self, screen):
+ from .uix.dialogs.requests import RequestsDialog
+ if len(self.wallet.get_sorted_requests(self.electrum_config)) == 0:
+ self.show_info(_('No saved requests.'))
+ return
+ popup = RequestsDialog(self, screen, None)
+ popup.update()
+ popup.open()
+
+ def addresses_dialog(self, screen):
+ from .uix.dialogs.addresses import AddressesDialog
+ popup = AddressesDialog(self, screen, None)
+ popup.update()
+ popup.open()
+
def fee_dialog(self, label, dt):
from .uix.dialogs.fee_dialog import FeeDialog
def cb():
diff --git a/gui/kivy/theming/light/share.png b/gui/kivy/theming/light/share.png
Binary files differ.
diff --git a/gui/kivy/uix/context_menu.py b/gui/kivy/uix/context_menu.py
@@ -47,7 +47,6 @@ class ContextMenu(Bubble):
l = MenuItem()
l.text = _(k)
def func(f=v):
- Clock.schedule_once(lambda dt: self.hide(), 0.1)
Clock.schedule_once(lambda dt: f(obj), 0.15)
l.on_release = func
self.ids.buttons.add_widget(l)
diff --git a/gui/kivy/uix/dialogs/addresses.py b/gui/kivy/uix/dialogs/addresses.py
@@ -0,0 +1,212 @@
+from kivy.app import App
+from kivy.factory import Factory
+from kivy.properties import ObjectProperty
+from kivy.lang import Builder
+from decimal import Decimal
+
+Builder.load_string('''
+<AddressLabel@Label>
+ text_size: self.width, None
+ halign: 'left'
+ valign: 'top'
+
+<AddressItem@CardItem>
+ address: ''
+ memo: ''
+ amount: ''
+ status: ''
+ BoxLayout:
+ spacing: '8dp'
+ height: '32dp'
+ orientation: 'vertical'
+ Widget
+ AddressLabel:
+ text: root.address
+ shorten: True
+ Widget
+ AddressLabel:
+ text: (root.amount if root.status == 'Funded' else root.status) + ' ' + root.memo
+ color: .699, .699, .699, 1
+ font_size: '13sp'
+ shorten: True
+ Widget
+
+<AddressesDialog@Popup>
+ id: popup
+ title: _('Addresses')
+ message: ''
+ pr_status: 'Pending'
+ show_change: 0
+ show_used: 0
+ on_message:
+ self.parent.update()
+ BoxLayout:
+ id:box
+ padding: '12dp', '70dp', '12dp', '12dp'
+ spacing: '12dp'
+ orientation: 'vertical'
+ size_hint: 1, 1.1
+ BoxLayout:
+ spacing: '6dp'
+ size_hint: 1, None
+ orientation: 'horizontal'
+ AddressFilter:
+ opacity: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ spacing: '5dp'
+ AddressButton:
+ id: search
+ text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change]
+ on_release:
+ root.show_change = (root.show_change + 1) % 3
+ Clock.schedule_once(lambda dt: root.update())
+ AddressFilter:
+ opacity: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ spacing: '5dp'
+ AddressButton:
+ id: search
+ text: {0:_('All'), 1:_('Unused'), 2:_('Funded'), 3:_('Used')}[root.show_used]
+ on_release:
+ root.show_used = (root.show_used + 1) % 4
+ Clock.schedule_once(lambda dt: root.update())
+ AddressFilter:
+ opacity: 1
+ size_hint: 1, None
+ height: self.minimum_height
+ spacing: '5dp'
+ canvas.before:
+ Color:
+ rgba: 0.9, 0.9, 0.9, 1
+ AddressButton:
+ id: change
+ text: root.message if root.message else _('Search')
+ on_release: Clock.schedule_once(lambda dt: app.description_dialog(addr_screen))
+ ScrollView:
+ GridLayout:
+ cols: 1
+ id: search_container
+ size_hint_y: None
+ height: self.minimum_height
+''')
+
+
+from electrum_gui.kivy.i18n import _
+from electrum_gui.kivy.uix.context_menu import ContextMenu
+
+
+class AddressesDialog(Factory.Popup):
+
+ def __init__(self, app, screen, callback):
+ Factory.Popup.__init__(self)
+ self.app = app
+ self.screen = screen
+ self.callback = callback
+ self.cards = {}
+ self.context_menu = None
+
+ def get_card(self, addr, balance, is_used, label):
+ ci = self.cards.get(addr)
+ if ci is None:
+ ci = Factory.AddressItem()
+ ci.screen = self
+ ci.address = addr
+ self.cards[addr] = ci
+
+ ci.memo = label
+ ci.amount = self.app.format_amount_and_units(balance)
+ request = self.app.wallet.get_payment_request(addr, self.app.electrum_config)
+ if is_used:
+ ci.status = _('Used')
+ else:
+ ci.status = _('Funded') if balance > 0 else _('Unused')
+ return ci
+
+
+ def update(self):
+ self.menu_actions = [(_('Use'), self.do_show), (_('Details'), self.do_view)]
+ wallet = self.app.wallet
+ if self.show_change == 0:
+ _list = wallet.get_receiving_addresses()
+ elif self.show_change == 1:
+ _list = wallet.get_change_addresses()
+ else:
+ _list = wallet.get_addresses()
+ search = self.screen.message
+ container = self.ids.search_container
+ container.clear_widgets()
+ n = 0
+ for address in _list:
+ label = wallet.labels.get(address, '')
+ balance = sum(wallet.get_addr_balance(address))
+ is_used = wallet.is_used(address)
+ if self.show_used == 1 and (balance or is_used):
+ continue
+ if self.show_used == 2 and balance == 0:
+ continue
+ if self.show_used == 3 and not is_used:
+ continue
+ card = self.get_card(address, balance, is_used, label)
+ if search and not self.ext_search(card, search):
+ continue
+ container.add_widget(card)
+ n += 1
+ if not n:
+ msg = _('No address matching your search')
+ container.add_widget(EmptyLabel(text=msg))
+
+ def do_show(self, obj):
+ self.hide_menu()
+ self.dismiss()
+ self.app.show_request(obj.address)
+
+ def do_view(self, obj):
+ req = self.app.wallet.get_payment_request(obj.address, self.app.electrum_config)
+ if req:
+ c, u, x = self.app.wallet.get_addr_balance(obj.address)
+ balance = c + u + x
+ if balance > 0:
+ req['fund'] = balance
+ status = req.get('status')
+ amount = req.get('amount')
+ address = req['address']
+ if amount:
+ status = req.get('status')
+ status = request_text[status]
+ else:
+ received_amount = self.app.wallet.get_addr_received(address)
+ status = self.app.format_amount_and_units(received_amount)
+ self.app.show_pr_details(req, status, False)
+
+ else:
+ req = { 'address': obj.address, 'status' : obj.status }
+ status = obj.status
+ c, u, x = self.app.wallet.get_addr_balance(obj.address)
+ balance = c + u + x
+ if balance > 0:
+ req['fund'] = balance
+ self.app.show_addr_details(req, status)
+
+ def do_delete(self, obj):
+ from .dialogs.question import Question
+ def cb(result):
+ if result:
+ self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
+ self.update()
+ d = Question(_('Delete request?'), cb)
+ d.open()
+
+ def ext_search(self, card, search):
+ return card.memo.find(search) >= 0 or card.amount.find(search) >= 0
+
+ def show_menu(self, obj):
+ self.hide_menu()
+ self.context_menu = ContextMenu(obj, self.menu_actions)
+ self.ids.box.add_widget(self.context_menu)
+
+ def hide_menu(self):
+ if self.context_menu is not None:
+ self.ids.box.remove_widget(self.context_menu)
+ self.context_menu = None
diff --git a/gui/kivy/uix/dialogs/invoices.py b/gui/kivy/uix/dialogs/invoices.py
@@ -0,0 +1,169 @@
+from kivy.app import App
+from kivy.factory import Factory
+from kivy.properties import ObjectProperty
+from kivy.lang import Builder
+from decimal import Decimal
+
+Builder.load_string('''
+<InvoicesLabel@Label>
+ #color: .305, .309, .309, 1
+ text_size: self.width, None
+ halign: 'left'
+ valign: 'top'
+
+<InvoiceItem@CardItem>
+ requestor: ''
+ memo: ''
+ amount: ''
+ status: ''
+ date: ''
+ icon: 'atlas://gui/kivy/theming/light/important'
+ Image:
+ id: icon
+ source: root.icon
+ size_hint: None, 1
+ width: self.height *.54
+ mipmap: True
+ BoxLayout:
+ spacing: '8dp'
+ height: '32dp'
+ orientation: 'vertical'
+ Widget
+ InvoicesLabel:
+ text: root.requestor
+ shorten: True
+ Widget
+ InvoicesLabel:
+ text: root.memo
+ color: .699, .699, .699, 1
+ font_size: '13sp'
+ shorten: True
+ Widget
+ BoxLayout:
+ spacing: '8dp'
+ height: '32dp'
+ orientation: 'vertical'
+ Widget
+ InvoicesLabel:
+ text: root.amount
+ font_size: '15sp'
+ halign: 'right'
+ width: '110sp'
+ Widget
+ InvoicesLabel:
+ text: root.status
+ font_size: '13sp'
+ halign: 'right'
+ color: .699, .699, .699, 1
+ Widget
+
+
+<InvoicesDialog@Popup>
+ id: popup
+ title: _('Invoices')
+ BoxLayout:
+ id: box
+ orientation: 'vertical'
+ spacing: '1dp'
+ ScrollView:
+ GridLayout:
+ cols: 1
+ id: invoices_container
+ size_hint: 1, None
+ height: self.minimum_height
+ spacing: '2dp'
+ padding: '12dp'
+''')
+
+from kivy.properties import BooleanProperty
+from electrum_gui.kivy.i18n import _
+from electrum.util import format_time
+from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
+from electrum_gui.kivy.uix.context_menu import ContextMenu
+
+invoice_text = {
+ PR_UNPAID:_('Pending'),
+ PR_UNKNOWN:_('Unknown'),
+ PR_PAID:_('Paid'),
+ PR_EXPIRED:_('Expired')
+}
+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 InvoicesDialog(Factory.Popup):
+
+ def __init__(self, app, screen, callback):
+ Factory.Popup.__init__(self)
+ self.app = app
+ self.screen = screen
+ self.callback = callback
+ self.cards = {}
+ self.context_menu = None
+
+ def get_card(self, pr):
+ key = pr.get_id()
+ ci = self.cards.get(key)
+ if ci is None:
+ ci = Factory.InvoiceItem()
+ ci.key = key
+ ci.screen = self
+ self.cards[key] = ci
+ ci.requestor = pr.get_requestor()
+ ci.memo = pr.get_memo()
+ amount = pr.get_amount()
+ if amount:
+ ci.amount = self.app.format_amount_and_units(amount)
+ status = self.app.wallet.invoices.get_status(ci.key)
+ ci.status = invoice_text[status]
+ 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')
+ return ci
+
+ def update(self):
+ self.menu_actions = [('Pay', self.do_pay), ('Details', self.do_view), ('Delete', self.do_delete)]
+ invoices_list = self.ids.invoices_container
+ invoices_list.clear_widgets()
+ _list = self.app.wallet.invoices.sorted_list()
+ for pr in _list:
+ ci = self.get_card(pr)
+ invoices_list.add_widget(ci)
+
+ def do_pay(self, obj):
+ self.hide_menu()
+ self.dismiss()
+ pr = self.app.wallet.invoices.get(obj.key)
+ self.app.on_pr(pr)
+
+ def do_view(self, obj):
+ pr = self.app.wallet.invoices.get(obj.key)
+ pr.verify(self.app.wallet.contacts)
+ self.app.show_pr_details(pr.get_dict(), obj.status, True)
+
+ def do_delete(self, obj):
+ from .question import Question
+ def cb(result):
+ if result:
+ self.app.wallet.invoices.remove(obj.key)
+ self.hide_menu()
+ self.update()
+ d = Question(_('Delete invoice?'), cb)
+ d.open()
+
+ def show_menu(self, obj):
+ self.hide_menu()
+ self.context_menu = ContextMenu(obj, self.menu_actions)
+ self.ids.box.add_widget(self.context_menu)
+
+ def hide_menu(self):
+ if self.context_menu is not None:
+ self.ids.box.remove_widget(self.context_menu)
+ self.context_menu = None
diff --git a/gui/kivy/uix/dialogs/requests.py b/gui/kivy/uix/dialogs/requests.py
@@ -0,0 +1,157 @@
+from kivy.app import App
+from kivy.factory import Factory
+from kivy.properties import ObjectProperty
+from kivy.lang import Builder
+from decimal import Decimal
+
+Builder.load_string('''
+<RequestLabel@Label>
+ #color: .305, .309, .309, 1
+ text_size: self.width, None
+ halign: 'left'
+ valign: 'top'
+
+<RequestItem@CardItem>
+ address: ''
+ memo: ''
+ amount: ''
+ status: ''
+ date: ''
+ icon: 'atlas://gui/kivy/theming/light/important'
+ Image:
+ id: icon
+ source: root.icon
+ size_hint: None, 1
+ width: self.height *.54
+ mipmap: True
+ BoxLayout:
+ spacing: '8dp'
+ height: '32dp'
+ orientation: 'vertical'
+ Widget
+ RequestLabel:
+ text: root.address
+ shorten: True
+ Widget
+ RequestLabel:
+ text: root.memo
+ color: .699, .699, .699, 1
+ font_size: '13sp'
+ shorten: True
+ Widget
+ BoxLayout:
+ spacing: '8dp'
+ height: '32dp'
+ orientation: 'vertical'
+ Widget
+ RequestLabel:
+ text: root.amount
+ halign: 'right'
+ font_size: '15sp'
+ Widget
+ RequestLabel:
+ text: root.status
+ halign: 'right'
+ font_size: '13sp'
+ color: .699, .699, .699, 1
+ Widget
+
+<RequestsDialog@Popup>
+ id: popup
+ title: _('Requests')
+ BoxLayout:
+ id:box
+ orientation: 'vertical'
+ spacing: '1dp'
+ ScrollView:
+ GridLayout:
+ cols: 1
+ id: requests_container
+ size_hint: 1, None
+ height: self.minimum_height
+ spacing: '2dp'
+ padding: '12dp'
+''')
+
+from kivy.properties import BooleanProperty
+from electrum_gui.kivy.i18n import _
+from electrum.util import format_time
+from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
+from electrum_gui.kivy.uix.context_menu import ContextMenu
+
+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'
+}
+request_text = {
+ PR_UNPAID: _('Pending'),
+ PR_UNKNOWN: _('Unknown'),
+ PR_PAID: _('Received'),
+ PR_EXPIRED: _('Expired')
+}
+
+
+class RequestsDialog(Factory.Popup):
+
+ def __init__(self, app, screen, callback):
+ Factory.Popup.__init__(self)
+ self.app = app
+ self.screen = screen
+ self.callback = callback
+ self.cards = {}
+ self.context_menu = None
+
+ def get_card(self, req):
+ address = req['address']
+ ci = self.cards.get(address)
+ if ci is None:
+ ci = Factory.RequestItem()
+ ci.address = address
+ ci.screen = self
+ self.cards[address] = ci
+
+ amount = req.get('amount')
+ ci.amount = self.app.format_amount_and_units(amount) if amount else ''
+ ci.memo = req.get('memo', '')
+ status, conf = self.app.wallet.get_request_status(address)
+ ci.status = request_text[status]
+ ci.icon = pr_icon[status]
+ #exp = pr.get_expiration_date()
+ #ci.date = format_time(exp) if exp else _('Never')
+ return ci
+
+ def update(self):
+ self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.do_delete)]
+ requests_list = self.ids.requests_container
+ requests_list.clear_widgets()
+ _list = self.app.wallet.get_sorted_requests(self.app.electrum_config)
+ for pr in _list:
+ ci = self.get_card(pr)
+ requests_list.add_widget(ci)
+
+ def do_show(self, obj):
+ self.hide_menu()
+ self.dismiss()
+ self.app.show_request(obj.address)
+
+ def do_delete(self, req):
+ from .question import Question
+ def cb(result):
+ if result:
+ self.app.wallet.remove_payment_request(req.address, self.app.electrum_config)
+ self.hide_menu()
+ self.update()
+ d = Question(_('Delete request'), cb)
+ d.open()
+
+ def show_menu(self, obj):
+ self.hide_menu()
+ self.context_menu = ContextMenu(obj, self.menu_actions)
+ self.ids.box.add_widget(self.context_menu)
+
+ def hide_menu(self):
+ if self.context_menu is not None:
+ self.ids.box.remove_widget(self.context_menu)
+ self.context_menu = None
diff --git a/gui/kivy/uix/screens.py b/gui/kivy/uix/screens.py
@@ -27,8 +27,6 @@ from .context_menu import ContextMenu
from electrum_gui.kivy.i18n import _
-class EmptyLabel(Factory.Label):
- pass
class CScreen(Factory.Screen):
__events__ = ('on_activate', 'on_deactivate', 'on_enter', 'on_leave')
@@ -219,7 +217,6 @@ class SendScreen(CScreen):
pr = make_unsigned_request(req).SerializeToString()
pr = PaymentRequest(pr)
self.app.wallet.invoices.add(pr)
- self.app.update_tab('invoices')
self.app.show_info(_("Invoice saved"))
if pr.is_pr():
self.screen.is_pr = True
@@ -390,205 +387,10 @@ class ReceiveScreen(CScreen):
addr = self.get_new_address()
if not addr:
self.app.show_info(_('Please use the existing requests first.'))
- else:
- self.save_request()
- self.app.show_info(_('New request added to your list.'))
-
-
-invoice_text = {
- PR_UNPAID:_('Pending'),
- PR_UNKNOWN:_('Unknown'),
- PR_PAID:_('Paid'),
- PR_EXPIRED:_('Expired')
-}
-request_text = {
- PR_UNPAID: _('Pending'),
- PR_UNKNOWN: _('Unknown'),
- PR_PAID: _('Received'),
- PR_EXPIRED: _('Expired')
-}
-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'
- cards = {}
-
- def get_card(self, pr):
- key = pr.get_id()
- ci = self.cards.get(key)
- if ci is None:
- ci = Factory.InvoiceItem()
- ci.key = key
- ci.screen = self
- self.cards[key] = ci
-
- ci.requestor = pr.get_requestor()
- ci.memo = pr.get_memo()
- amount = pr.get_amount()
- if amount:
- ci.amount = self.app.format_amount_and_units(amount)
- status = self.app.wallet.invoices.get_status(ci.key)
- ci.status = invoice_text[status]
- 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')
- return ci
-
- def update(self):
- 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()
- _list = self.app.wallet.invoices.sorted_list()
- for pr in _list:
- ci = self.get_card(pr)
- invoices_list.add_widget(ci)
- if not _list:
- msg = _('This screen shows the list of payment requests that have been sent to you. You may also use it to store contact addresses.')
- invoices_list.add_widget(EmptyLabel(text=msg))
-
- def do_pay(self, obj):
- pr = self.app.wallet.invoices.get(obj.key)
- self.app.on_pr(pr)
-
- def do_view(self, obj):
- pr = self.app.wallet.invoices.get(obj.key)
- pr.verify(self.app.wallet.contacts)
- self.app.show_pr_details(pr.get_dict(), obj.status, True)
-
- def do_delete(self, obj):
- from .dialogs.question import Question
- def cb(result):
- if result:
- self.app.wallet.invoices.remove(obj.key)
- self.app.update_tab('invoices')
- d = Question(_('Delete invoice?'), cb)
- d.open()
-
-
-address_icon = {
- 'Pending' : 'atlas://gui/kivy/theming/light/important',
- 'Paid' : 'atlas://gui/kivy/theming/light/confirmed'
-}
-
-class AddressScreen(CScreen):
- kvname = 'address'
- cards = {}
-
- def get_card(self, addr, balance, is_used, label):
- ci = self.cards.get(addr)
- if ci is None:
- ci = Factory.AddressItem()
- ci.screen = self
- ci.address = addr
- self.cards[addr] = ci
-
- ci.memo = label
- ci.amount = self.app.format_amount_and_units(balance)
- request = self.app.wallet.get_payment_request(addr, self.app.electrum_config)
- if is_used:
- ci.status = _('Used')
- elif request:
- status, conf = self.app.wallet.get_request_status(addr)
- requested_amount = request.get('amount')
- # make sure that requested amount is > 0
- if status == PR_PAID:
- s = _('Request paid')
- elif status == PR_UNPAID:
- s = _('Request pending')
- elif status == PR_EXPIRED:
- s = _('Request expired')
- else:
- s = ''
- ci.status = s + ': ' + self.app.format_amount_and_units(requested_amount)
- else:
- ci.status = _('Funded') if balance>0 else _('Unused')
- return ci
-
-
- def update(self):
- self.menu_actions = [('Receive', self.do_show), ('Details', self.do_view)]
- wallet = self.app.wallet
- if self.screen.show_change == 0:
- _list = wallet.get_receiving_addresses()
- elif self.screen.show_change == 1:
- _list = wallet.get_change_addresses()
- else:
- _list = wallet.get_addresses()
- search = self.screen.message
- container = self.screen.ids.search_container
- container.clear_widgets()
- n = 0
- for address in _list:
- label = wallet.labels.get(address, '')
- balance = sum(wallet.get_addr_balance(address))
- is_used = wallet.is_used(address)
- if self.screen.show_used == 1 and (balance or is_used):
- continue
- if self.screen.show_used == 2 and balance == 0:
- continue
- if self.screen.show_used == 3 and not is_used:
- continue
- card = self.get_card(address, balance, is_used, label)
- if search and not self.ext_search(card, search):
- continue
- container.add_widget(card)
- n += 1
- if not n:
- msg = _('No address matching your search')
- container.add_widget(EmptyLabel(text=msg))
-
- def do_show(self, obj):
- self.app.show_request(obj.address)
-
- def do_view(self, obj):
- req = self.app.wallet.get_payment_request(obj.address, self.app.electrum_config)
- if req:
- c, u, x = self.app.wallet.get_addr_balance(obj.address)
- balance = c + u + x
- if balance > 0:
- req['fund'] = balance
- status = req.get('status')
- amount = req.get('amount')
- address = req['address']
- if amount:
- status = req.get('status')
- status = request_text[status]
- else:
- received_amount = self.app.wallet.get_addr_received(address)
- status = self.app.format_amount_and_units(received_amount)
- self.app.show_pr_details(req, status, False)
-
- else:
- req = { 'address': obj.address, 'status' : obj.status }
- status = obj.status
- c, u, x = self.app.wallet.get_addr_balance(obj.address)
- balance = c + u + x
- if balance > 0:
- req['fund'] = balance
- self.app.show_addr_details(req, status)
-
- def do_delete(self, obj):
- from .dialogs.question import Question
- def cb(result):
- if result:
- self.app.wallet.remove_payment_request(obj.address, self.app.electrum_config)
- self.update()
- d = Question(_('Delete request?'), cb)
- d.open()
-
- def ext_search(self, card, search):
- return card.memo.find(search) >= 0 or card.amount.find(search) >= 0
-
+ def do_save(self):
+ self.save_request()
+ self.app.show_info(_('Request was saved.'))
class TabbedCarousel(Factory.TabbedPanel):
diff --git a/gui/kivy/uix/ui_screens/address.kv b/gui/kivy/uix/ui_screens/address.kv
@@ -1,90 +0,0 @@
-#:import _ electrum_gui.kivy.i18n._
-#:import Decimal decimal.Decimal
-#:set btc_symbol chr(171)
-#:set mbtc_symbol chr(187)
-#:set font_light 'gui/kivy/data/fonts/Roboto-Condensed.ttf'
-
-<AddressLabel@Label>
- text_size: self.width, None
- halign: 'left'
- valign: 'top'
-
-<AddressItem@CardItem>
- address: ''
- memo: ''
- amount: ''
- status: ''
- BoxLayout:
- spacing: '8dp'
- height: '32dp'
- orientation: 'vertical'
- Widget
- AddressLabel:
- text: root.address
- shorten: True
- Widget
- AddressLabel:
- text: (root.amount if root.status == 'Funded' else root.status) + ' ' + root.memo
- color: .699, .699, .699, 1
- font_size: '13sp'
- shorten: True
- Widget
-
-AddressScreen:
- id: addr_screen
- name: 'address'
- message: ''
- pr_status: 'Pending'
- show_change: 0
- show_used: 0
- on_message:
- self.parent.update()
- BoxLayout
- padding: '12dp', '70dp', '12dp', '12dp'
- spacing: '12dp'
- orientation: 'vertical'
- size_hint: 1, 1.1
- BoxLayout:
- spacing: '6dp'
- size_hint: 1, None
- orientation: 'horizontal'
- AddressFilter:
- opacity: 1
- size_hint: 1, None
- height: self.minimum_height
- spacing: '5dp'
- AddressButton:
- id: search
- text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change]
- on_release:
- root.show_change = (root.show_change + 1) % 3
- Clock.schedule_once(lambda dt: app.address_screen.update())
- AddressFilter:
- opacity: 1
- size_hint: 1, None
- height: self.minimum_height
- spacing: '5dp'
- AddressButton:
- id: search
- text: {0:_('All'), 1:_('Unused'), 2:_('Funded'), 3:_('Used')}[root.show_used]
- on_release:
- root.show_used = (root.show_used + 1) % 4
- Clock.schedule_once(lambda dt: app.address_screen.update())
- AddressFilter:
- opacity: 1
- size_hint: 1, None
- height: self.minimum_height
- spacing: '5dp'
- canvas.before:
- Color:
- rgba: 0.9, 0.9, 0.9, 1
- AddressButton:
- id: change
- text: root.message if root.message else _('Search')
- on_release: Clock.schedule_once(lambda dt: app.description_dialog(addr_screen))
- ScrollView:
- GridLayout:
- cols: 1
- id: search_container
- size_hint_y: None
- height: self.minimum_height
diff --git a/gui/kivy/uix/ui_screens/invoices.kv b/gui/kivy/uix/ui_screens/invoices.kv
@@ -1,66 +0,0 @@
-<InvoicesLabel@Label>
- #color: .305, .309, .309, 1
- text_size: self.width, None
- halign: 'left'
- valign: 'top'
-
-<InvoiceItem@CardItem>
- requestor: ''
- memo: ''
- amount: ''
- status: ''
- date: ''
- icon: 'atlas://gui/kivy/theming/light/important'
- Image:
- id: icon
- source: root.icon
- size_hint: None, 1
- width: self.height *.54
- mipmap: True
- BoxLayout:
- spacing: '8dp'
- height: '32dp'
- orientation: 'vertical'
- Widget
- InvoicesLabel:
- text: root.requestor
- shorten: True
- Widget
- InvoicesLabel:
- text: root.memo
- color: .699, .699, .699, 1
- font_size: '13sp'
- shorten: True
- Widget
- BoxLayout:
- spacing: '8dp'
- height: '32dp'
- orientation: 'vertical'
- Widget
- InvoicesLabel:
- text: root.amount
- font_size: '15sp'
- halign: 'right'
- width: '110sp'
- Widget
- InvoicesLabel:
- text: root.status
- font_size: '13sp'
- halign: 'right'
- color: .699, .699, .699, 1
- Widget
-
-
-InvoicesScreen:
- name: 'invoices'
- BoxLayout:
- orientation: 'vertical'
- spacing: '1dp'
- ScrollView:
- GridLayout:
- cols: 1
- id: invoices_container
- size_hint: 1, None
- height: self.minimum_height
- spacing: '2dp'
- padding: '12dp'
diff --git a/gui/kivy/uix/ui_screens/receive.kv b/gui/kivy/uix/ui_screens/receive.kv
@@ -70,7 +70,7 @@ ReceiveScreen:
id: address_label
text: s.address if s.address else _('Bitcoin Address')
shorten: True
- disabled: True
+ on_release: Clock.schedule_once(lambda dt: app.addresses_dialog(s))
CardSeparator:
opacity: message_selection.opacity
color: blue_bottom.foreground_color
@@ -110,16 +110,31 @@ ReceiveScreen:
BoxLayout:
size_hint: 1, None
height: '48dp'
+ IconButton:
+ icon: 'atlas://gui/kivy/theming/light/save'
+ size_hint: 0.6, None
+ height: '48dp'
+ on_release: s.parent.do_save()
Button:
- text: _('Copy')
+ text: _('Requests')
size_hint: 1, None
height: '48dp'
- on_release: s.parent.do_copy()
+ on_release: Clock.schedule_once(lambda dt: app.requests_dialog(s))
Button:
- text: _('Share')
+ text: _('Copy')
size_hint: 1, None
height: '48dp'
+ on_release: s.parent.do_copy()
+ IconButton:
+ icon: 'atlas://gui/kivy/theming/light/share'
+ size_hint: 0.6, None
+ height: '48dp'
on_release: s.parent.do_share()
+ BoxLayout:
+ size_hint: 1, None
+ height: '48dp'
+ Widget
+ size_hint: 2, 1
Button:
text: _('New')
size_hint: 1, None
diff --git a/gui/kivy/uix/ui_screens/requests.kv b/gui/kivy/uix/ui_screens/requests.kv
@@ -1,66 +0,0 @@
-<RequestLabel@Label>
- #color: .305, .309, .309, 1
- text_size: self.width, None
- halign: 'left'
- valign: 'top'
-
-<RequestItem@CardItem>
- address: ''
- memo: ''
- amount: ''
- status: ''
- date: ''
- icon: 'atlas://gui/kivy/theming/light/important'
- Image:
- id: icon
- source: root.icon
- size_hint: None, 1
- width: self.height *.54
- mipmap: True
- BoxLayout:
- spacing: '8dp'
- height: '32dp'
- orientation: 'vertical'
- Widget
- RequestLabel:
- text: root.address
- shorten: True
- Widget
- RequestLabel:
- text: root.memo
- color: .699, .699, .699, 1
- font_size: '13sp'
- shorten: True
- Widget
- BoxLayout:
- spacing: '8dp'
- height: '32dp'
- orientation: 'vertical'
- Widget
- RequestLabel:
- text: root.amount
- halign: 'right'
- font_size: '15sp'
- Widget
- RequestLabel:
- text: root.status
- halign: 'right'
- font_size: '13sp'
- color: .699, .699, .699, 1
- Widget
-
-
-
-RequestsScreen:
- name: 'requests'
- BoxLayout:
- orientation: 'vertical'
- spacing: '1dp'
- ScrollView:
- GridLayout:
- cols: 1
- id: requests_container
- size_hint_y: None
- height: self.minimum_height
- spacing: '2dp'
- padding: '12dp'
diff --git a/gui/kivy/uix/ui_screens/send.kv b/gui/kivy/uix/ui_screens/send.kv
@@ -34,6 +34,7 @@ SendScreen:
text: s.address if s.address else _('Recipient')
shorten: True
on_release: Clock.schedule_once(lambda dt: app.show_info(_('Copy and paste the recipient address using the Paste button, or use the camera to scan a QR code.')))
+ #on_release: Clock.schedule_once(lambda dt: app.popup_dialog('contacts'))
CardSeparator:
opacity: int(not root.is_pr)
color: blue_bottom.foreground_color
@@ -93,25 +94,29 @@ SendScreen:
size_hint: 1, None
height: '48dp'
IconButton:
- id: qr
size_hint: 0.6, 1
- on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=app.on_qr))
- icon: 'atlas://gui/kivy/theming/light/camera'
+ on_release: s.parent.do_save()
+ icon: 'atlas://gui/kivy/theming/light/save'
+ Button:
+ text: _('Invoices')
+ size_hint: 1, 1
+ on_release: Clock.schedule_once(lambda dt: app.invoices_dialog(s))
Button:
text: _('Paste')
on_release: s.parent.do_paste()
- Button:
- text: _('Clear')
- on_release: s.parent.do_clear()
IconButton:
+ id: qr
size_hint: 0.6, 1
- on_release: s.parent.do_save()
- icon: 'atlas://gui/kivy/theming/light/save'
+ on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=app.on_qr))
+ icon: 'atlas://gui/kivy/theming/light/camera'
BoxLayout:
size_hint: 1, None
height: '48dp'
+ Button:
+ text: _('Clear')
+ on_release: s.parent.do_clear()
Widget:
- size_hint: 2, 1
+ size_hint: 1, 1
Button:
text: _('Pay')
size_hint: 1, 1