Browse Source

kivy: remove context menus, cleanup unused files

dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
ThomasV 6 years ago
parent
commit
e9c32bad19
  1. 5
      electrum/gui/kivy/main.kv
  2. 57
      electrum/gui/kivy/main_window.py
  3. 58
      electrum/gui/kivy/uix/context_menu.py
  4. 111
      electrum/gui/kivy/uix/dialogs/addresses.py
  5. 169
      electrum/gui/kivy/uix/dialogs/invoices.py
  6. 155
      electrum/gui/kivy/uix/dialogs/lightning_channels.py
  7. 65
      electrum/gui/kivy/uix/dialogs/lightning_invoices.py
  8. 33
      electrum/gui/kivy/uix/dialogs/request_dialog.py
  9. 16
      electrum/gui/kivy/uix/dialogs/tx_dialog.py
  10. 53
      electrum/gui/kivy/uix/screens.py
  11. 89
      electrum/gui/kivy/uix/ui_screens/invoice.kv

5
electrum/gui/kivy/main.kv

@ -231,15 +231,14 @@
size: self.size
pos: self.pos
<CardItem@ToggleButtonBehavior+BoxLayout>
<CardItem@ButtonBehavior+BoxLayout>
size_hint: 1, None
height: '65dp'
group: 'requests'
padding: dp(12)
spacing: dp(5)
screen: None
on_state:
self.screen.show_menu(args[0]) if self.state == 'down' else self.screen.hide_menu()
on_release: self.screen.show_item(args[0])
canvas.before:
Color:
rgba: (0.192, .498, 0.745, 1) if self.state == 'down' else (0.15, 0.15, 0.17, 1)

57
electrum/gui/kivy/main_window.py

@ -418,41 +418,6 @@ class ElectrumWindow(App):
self.request_popup.set_status(status)
self.request_popup.open()
def show_pr_details(self, req, status, is_invoice):
from electrum.util import format_time
requestor = req.get('requestor')
exp = req.get('exp')
memo = req.get('memo')
amount = req.get('amount')
fund = req.get('fund')
popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/invoice.kv')
popup.is_invoice = is_invoice
popup.amount = amount
popup.requestor = requestor if is_invoice else req.get('address')
popup.exp = format_time(exp) if exp else ''
popup.description = memo if memo else ''
popup.signature = req.get('signature', '')
popup.status = status
popup.fund = fund if fund else 0
txid = req.get('txid')
popup.tx_hash = txid or ''
popup.on_open = lambda: popup.ids.output_list.update(req.get('outputs', []))
popup.export = self.export_private_keys
popup.open()
def show_addr_details(self, req, status):
from electrum.util import format_time
fund = req.get('fund')
isaddr = 'y'
popup = Builder.load_file('electrum/gui/kivy/uix/ui_screens/invoice.kv')
popup.isaddr = isaddr
popup.is_invoice = False
popup.status = status
popup.requestor = req.get('address')
popup.fund = fund if fund else 0
popup.export = self.export_private_keys
popup.open()
def qr_dialog(self, title, data, show_text=False, text_for_clipboard=None):
from .uix.dialogs.qr_dialog import QRDialog
def on_qr_failure():
@ -1035,28 +1000,6 @@ class ElectrumWindow(App):
popup = AmountDialog(show_max, amount, cb)
popup.open()
def lightning_invoices_dialog(self, cb):
from .uix.dialogs.lightning_invoices import LightningInvoicesDialog
report = self.wallet.lnworker._list_invoices()
if not report['unsettled']:
self.show_info(_('No unsettled invoices. Type in an amount to generate a new one.'))
return
popup = LightningInvoicesDialog(report, 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 addresses_dialog(self):
from .uix.dialogs.addresses import AddressesDialog
if self._addresses_dialog is None:

58
electrum/gui/kivy/uix/context_menu.py

@ -1,58 +0,0 @@
#!python
#!/usr/bin/env python
from kivy.app import App
from kivy.uix.bubble import Bubble
from kivy.animation import Animation
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.factory import Factory
from kivy.clock import Clock
from electrum.gui.kivy.i18n import _
Builder.load_string('''
<MenuItem@Button>
background_normal: ''
background_color: (0.192, .498, 0.745, 1)
height: '48dp'
size_hint: 1, None
<ContextMenu>
size_hint: 1, None
height: '60dp'
pos: (0, 0)
show_arrow: False
arrow_pos: 'top_mid'
padding: 0
orientation: 'horizontal'
background_color: (0.1, 0.1, 0.1, 1)
background_image: ''
BoxLayout:
size_hint: 1, 1
height: '54dp'
padding: '0dp', '0dp'
spacing: '3dp'
orientation: 'horizontal'
id: buttons
''')
class MenuItem(Factory.Button):
pass
class ContextMenu(Bubble):
def __init__(self, obj, action_list):
Bubble.__init__(self)
self.obj = obj
for k, v in action_list:
l = MenuItem()
l.text = _(k)
def func(f=v):
Clock.schedule_once(lambda dt: f(obj), 0.15)
l.on_release = func
self.ids.buttons.add_widget(l)
def hide(self):
if self.parent:
self.parent.hide_menu()

111
electrum/gui/kivy/uix/dialogs/addresses.py

@ -3,6 +3,9 @@ from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from decimal import Decimal
from kivy.uix.popup import Popup
from electrum.gui.kivy.i18n import _
Builder.load_string('''
<AddressLabel@Label>
@ -95,11 +98,85 @@ Builder.load_string('''
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
<AddressPopup@Popup>:
address: ''
balance: ''
status: ''
pk: ''
BoxLayout:
orientation: 'vertical'
ScrollView:
GridLayout:
cols: 1
height: self.minimum_height
size_hint_y: None
padding: '10dp'
spacing: '10dp'
GridLayout:
cols: 1
size_hint_y: None
height: self.minimum_height
spacing: '10dp'
BoxLabel:
text: _('Address')
value: root.address
BoxLabel:
text: _('Balance')
value: root.balance
BoxLabel:
text: _('Status')
value: root.status
TopLabel:
text: _('Private Key')
RefLabel:
id: pk_label
touched: True if not self.touched else True
data: root.pk
Widget:
size_hint: 1, 0.1
BoxLayout:
size_hint: 1, None
height: '48dp'
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Hide key') if pk_label.data else _('Show key')
on_release:
setattr(pk_label, 'data', '') if pk_label.data else root.do_export(pk_label)
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Use')
on_release: root.do_use()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Close')
on_release: root.dismiss()
''')
from electrum.gui.kivy.i18n import _
from electrum.gui.kivy.uix.context_menu import ContextMenu
class AddressPopup(Popup):
def __init__(self, parent, address, balance, status, **kwargs):
super(AddressPopup, self).__init__(**kwargs)
self.title = _('Address')
self.parent_dialog = parent
self.app = parent.app
self.address = address
self.status = status
self.balance = self.app.format_amount_and_units(balance)
def do_use(self):
self.dismiss()
self.parent_dialog.dismiss()
self.app.switch_to('receive')
self.app.receive_screen.set_address(self.address)
def do_export(self, pk_label):
self.app.export_private_keys(pk_label, self.address)
class AddressesDialog(Factory.Popup):
@ -107,7 +184,6 @@ class AddressesDialog(Factory.Popup):
def __init__(self, app):
Factory.Popup.__init__(self)
self.app = app
self.context_menu = None
def get_card(self, addr, balance, is_used, label):
ci = {}
@ -119,7 +195,6 @@ class AddressesDialog(Factory.Popup):
return ci
def update(self):
self.menu_actions = [(_('Use'), self.do_use), (_('Details'), self.do_view)]
wallet = self.app.wallet
if self.show_change == 0:
_list = wallet.get_receiving_addresses()
@ -150,30 +225,12 @@ class AddressesDialog(Factory.Popup):
if not n:
self.app.show_error('No address matching your search')
def do_use(self, obj):
self.hide_menu()
self.dismiss()
self.app.switch_to('receive')
self.app.receive_screen.set_address(obj.address)
def do_view(self, obj):
req = { 'address': obj.address, 'status' : obj.status }
status = obj.status
c, u, x = self.app.wallet.get_addr_balance(obj.address)
def show_item(self, obj):
address = obj.address
c, u, x = self.app.wallet.get_addr_balance(address)
balance = c + u + x
if balance > 0:
req['fund'] = balance
self.app.show_addr_details(req, status)
d = AddressPopup(self, address, balance, obj.status)
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

169
electrum/gui/kivy/uix/dialogs/invoices.py

@ -1,169 +0,0 @@
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://electrum/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://electrum/gui/kivy/theming/light/important',
PR_UNKNOWN: 'atlas://electrum/gui/kivy/theming/light/important',
PR_PAID: 'atlas://electrum/gui/kivy/theming/light/confirmed',
PR_EXPIRED: 'atlas://electrum/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

155
electrum/gui/kivy/uix/dialogs/lightning_channels.py

@ -4,10 +4,10 @@ from kivy.lang import Builder
from kivy.factory import Factory
from kivy.uix.popup import Popup
from kivy.clock import Clock
from electrum.gui.kivy.uix.context_menu import ContextMenu
from electrum.util import bh2u
from electrum.lnutil import LOCAL, REMOTE, format_short_channel_id
from electrum.gui.kivy.i18n import _
from .question import Question
Builder.load_string(r'''
<LightningChannelItem@CardItem>
@ -71,38 +71,11 @@ Builder.load_string(r'''
text: _('New channel...')
on_press: popup.app.popup_dialog('lightning_open_channel_dialog')
<ChannelDetailsItem@BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
text: root.value
text_size: self.size # this makes the text not overflow, but wrap
<ChannelDetailsRow@BoxLayout>:
keyName: ''
value: ''
ChannelDetailsItem:
value: root.keyName
size_hint_x: 0.5 # this makes the column narrower
# see https://blog.kivy.org/2014/07/wrapping-text-in-kivys-label/
ScrollView:
Label:
text: root.value
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
<ChannelDetailsList@RecycleView>:
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'ChannelDetailsRow'
viewclass: 'BoxLabel'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
@ -114,64 +87,102 @@ Builder.load_string(r'''
<ChannelDetailsPopup@Popup>:
id: popuproot
data: []
ChannelDetailsList:
data: popuproot.data
BoxLayout:
orientation: 'vertical'
ScrollView:
ChannelDetailsList:
data: popuproot.data
Widget:
size_hint: 1, 0.1
BoxLayout:
size_hint: 1, None
height: '48dp'
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Close channel')
on_release: root.close()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Force-close')
on_release: root.force_close()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Dismiss')
on_release: root.dismiss()
''')
class ChannelDetailsPopup(Popup):
def __init__(self, data, **kwargs):
super(ChannelDetailsPopup,self).__init__(**kwargs)
self.data = data
class LightningChannelsDialog(Factory.Popup):
def __init__(self, app):
super(LightningChannelsDialog, self).__init__()
self.clocks = []
def __init__(self, chan, app, **kwargs):
super(ChannelDetailsPopup,self).__init__(**kwargs)
self.app = app
self.context_menu = None
self.app.wallet.network.register_callback(self.on_channels, ['channels'])
self.app.wallet.network.register_callback(self.on_channel, ['channel'])
self.update()
def show_channel_details(self, obj):
p = Factory.ChannelDetailsPopup()
p.title = _('Details for channel ') + format_short_channel_id(obj.chan.short_channel_id)
p.data = [{'keyName': key, 'value': str(obj.details[key])} for key in obj.details.keys()]
p.open()
def close_channel(self, obj):
self.chan = chan
self.title = _('Channel details')
self.data = [{'text': key, 'value': str(value)} for key, value in self.details().items()]
def details(self):
chan = self.chan
return {
_('Short Chan ID'): format_short_channel_id(chan.short_channel_id),
_('Initiator'): 'Local' if chan.constraints.is_initiator else 'Remote',
_('State'): chan.get_state(),
_('Capacity'): self.app.format_amount_and_units(chan.constraints.capacity),
_('Can send'): self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000),
_('Current feerate'): str(chan.get_latest_feerate(LOCAL)),
_('Node ID'): bh2u(chan.node_id),
_('Channel ID'): bh2u(chan.channel_id),
_('Funding TXID'): chan.funding_outpoint.txid,
}
def close(self):
Question(_('Close channel?'), self._close).open()
def _close(self, b):
if not b:
return
loop = self.app.wallet.network.asyncio_loop
coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.close_channel(obj._chan.channel_id), loop)
coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.close_channel(self._chan.channel_id), loop)
try:
coro.result(5)
self.app.show_info(_('Channel closed'))
except Exception as e:
self.app.show_info(_('Could not close channel: ') + repr(e)) # repr because str(Exception()) == ''
def force_close_channel(self, obj):
if obj._chan.get_state() == 'CLOSED':
def force_close(self):
Question(_('Force-close channel?'), self._force_close).open()
def _force_close(self, b):
if not b:
return
if self.chan.get_state() == 'CLOSED':
self.app.show_error(_('Channel already closed'))
return
loop = self.app.wallet.network.asyncio_loop
coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.force_close_channel(obj._chan.channel_id), loop)
coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.force_close_channel(self.chan.channel_id), loop)
try:
coro.result(1)
self.app.show_info(_('Channel closed, you may need to wait at least {} blocks, because of CSV delays'.format(obj._chan.config[REMOTE].to_self_delay)))
self.app.show_info(_('Channel closed, you may need to wait at least {} blocks, because of CSV delays'.format(self.chan.config[REMOTE].to_self_delay)))
except Exception as e:
self.app.show_info(_('Could not force close channel: ') + repr(e)) # repr because str(Exception()) == ''
def show_menu(self, obj):
self.hide_menu()
self.context_menu = ContextMenu(obj, [
(_("Force close"), self.force_close_channel),
(_("Co-op close"), self.close_channel),
(_("Details"), self.show_channel_details)])
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
class LightningChannelsDialog(Factory.Popup):
def __init__(self, app):
super(LightningChannelsDialog, self).__init__()
self.clocks = []
self.app = app
self.app.wallet.network.register_callback(self.on_channels, ['channels'])
self.app.wallet.network.register_callback(self.on_channel, ['channel'])
self.update()
def show_item(self, obj):
p = ChannelDetailsPopup(obj._chan, self.app)
p.open()
def format_fields(self, chan):
labels = {}
@ -213,18 +224,6 @@ class LightningChannelsDialog(Factory.Popup):
item = Factory.LightningChannelItem()
item.screen = self
item.active = i.node_id in lnworker.peers
item.details = self.channel_details(i)
item._chan = i
self.update_item(item)
channel_cards.add_widget(item)
def channel_details(self, chan):
return {_('Node ID'): bh2u(chan.node_id),
_('Channel ID'): bh2u(chan.channel_id),
_('Capacity'): self.app.format_amount_and_units(chan.constraints.capacity),
_('Funding TXID'): chan.funding_outpoint.txid,
_('Short Chan ID'): bh2u(chan.short_channel_id) if chan.short_channel_id else _('Not available'),
_('Available to spend'): self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000),
_('State'): chan.get_state(),
_('Initiator'): 'Opened/funded by us' if chan.constraints.is_initiator else 'Opened/funded by remote party',
_('Current feerate'): chan.get_latest_feerate(LOCAL)}

65
electrum/gui/kivy/uix/dialogs/lightning_invoices.py

@ -1,65 +0,0 @@
from kivy.factory import Factory
from kivy.lang import Builder
from electrum.gui.kivy.i18n import _
from kivy.uix.recycleview import RecycleView
from electrum.gui.kivy.uix.context_menu import ContextMenu
Builder.load_string('''
<Item@CardItem>
addr: ''
desc: ''
screen: None
BoxLayout:
orientation: 'vertical'
Label
text: root.addr
text_size: self.width, None
shorten: True
Label
text: root.desc if root.desc else _('No description')
text_size: self.width, None
shorten: True
font_size: '10dp'
<LightningInvoicesDialog@Popup>
id: popup
title: _('Lightning Invoices')
BoxLayout:
orientation: 'vertical'
id: box
RecycleView:
viewclass: 'Item'
id: recycleview
data: []
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
''')
class LightningInvoicesDialog(Factory.Popup):
def __init__(self, report, callback):
super().__init__()
self.context_menu = None
self.callback = callback
self.menu_actions = [(_('Show'), self.do_show)]
for addr, preimage, pay_req in report['unsettled']:
self.ids.recycleview.data.append({'screen': self, 'addr': pay_req, 'desc': dict(addr.tags).get('d', '')})
def do_show(self, obj):
self.hide_menu()
self.dismiss()
self.callback(obj.addr)
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

33
electrum/gui/kivy/uix/dialogs/request_dialog.py

@ -42,30 +42,33 @@ Builder.load_string('''
Button:
size_hint: 1, None
height: '48dp'
text: _('Copy')
on_release:
root.copy_to_clipboard()
text: _('Delete')
on_release: root.delete_dialog()
IconButton:
icon: 'atlas://electrum/gui/kivy/theming/light/copy'
size_hint: 0.5, None
height: '48dp'
on_release: root.copy_to_clipboard()
IconButton:
icon: 'atlas://electrum/gui/kivy/theming/light/share'
size_hint: 0.6, None
size_hint: 0.5, None
height: '48dp'
on_release: s.parent.do_share()
on_release: root.do_share()
Button:
size_hint: 1, None
height: '48dp'
text: _('Close')
on_release:
popup.dismiss()
on_release: popup.dismiss()
''')
class RequestDialog(Factory.Popup):
def __init__(self, title, data, key):
Factory.Popup.__init__(self)
self.app = App.get_running_app()
self.title = title
self.data = data
self.key = key
#self.text_for_clipboard = text_for_clipboard if text_for_clipboard else data
def on_open(self):
self.ids.qr.set_data(self.data)
@ -80,3 +83,17 @@ class RequestDialog(Factory.Popup):
Clipboard.copy(self.data)
msg = _('Text copied to clipboard.')
Clock.schedule_once(lambda dt: self.app.show_info(msg))
def do_share(self):
self.app.do_share(self.data, _("Share Bitcoin Request"))
self.dismiss()
def delete_dialog(self):
from .question import Question
def cb(result):
if result:
self.app.wallet.delete_request(self.key)
self.dismiss()
self.app.receive_screen.update()
d = Question(_('Delete request?'), cb)
d.open()

16
electrum/gui/kivy/uix/dialogs/tx_dialog.py

@ -98,6 +98,11 @@ Builder.load_string('''
height: '48dp'
icon: 'atlas://electrum/gui/kivy/theming/light/qrcode'
on_release: root.show_qr()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Label')
on_release: root.label_dialog()
Button:
size_hint: 0.5, None
height: '48dp'
@ -271,3 +276,14 @@ class TxDialog(Factory.Popup):
self.dismiss()
d = Question(question, on_prompt)
d.open()
def label_dialog(self):
from .label_dialog import LabelDialog
key = self.tx.txid()
text = self.app.wallet.get_label(key)
def callback(text):
self.app.wallet.set_label(key, text)
self.update()
self.app.history_screen.update()
d = LabelDialog(_('Enter Transaction Label'), text, callback)
d.open()

53
electrum/gui/kivy/uix/screens.py

@ -33,7 +33,6 @@ from electrum import simple_config
from electrum.lnaddr import lndecode
from electrum.lnutil import RECEIVED, SENT, PaymentFailure
from .context_menu import ContextMenu
from .dialogs.question import Question
from .dialogs.lightning_open_channel import LightningOpenChannelDialog
@ -55,8 +54,6 @@ class CScreen(Factory.Screen):
action_view = ObjectProperty(None)
loaded = False
kvname = None
context_menu = None
menu_actions = []
app = App.get_running_app()
def _change_action_view(self):
@ -94,17 +91,7 @@ class CScreen(Factory.Screen):
self.dispatch('on_deactivate')
def on_deactivate(self):
self.hide_menu()
def hide_menu(self):
if self.context_menu is not None:
self.remove_widget(self.context_menu)
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)
pass
# note: this list needs to be kept in sync with another in qt
@ -130,24 +117,15 @@ class HistoryScreen(CScreen):
def __init__(self, **kwargs):
self.ra_dialog = None
super(HistoryScreen, self).__init__(**kwargs)
self.menu_actions = [ ('Label', self.label_dialog), ('Details', self.show_tx)]
def show_tx(self, obj):
def show_item(self, obj):
print(obj)
key = obj.key
tx = self.app.wallet.db.get_transaction(key)
if not tx:
return
self.app.tx_dialog(tx)
def label_dialog(self, obj):
from .dialogs.label_dialog import LabelDialog
key = obj.key
text = self.app.wallet.get_label(key)
def callback(text):
self.app.wallet.set_label(key, text)
self.update()
d = LabelDialog(_('Enter Transaction Label'), text, callback)
d.open()
def get_card(self, tx_item): #tx_hash, tx_mined_status, value, balance):
is_lightning = tx_item.get('lightning', False)
@ -406,7 +384,6 @@ class ReceiveScreen(CScreen):
def __init__(self, **kwargs):
super(ReceiveScreen, self).__init__(**kwargs)
self.menu_actions = [(_('Show'), self.do_show), (_('Delete'), self.delete_request_dialog)]
Clock.schedule_interval(lambda dt: self.update(), 5)
def expiry(self):
@ -440,10 +417,6 @@ class ReceiveScreen(CScreen):
amount = Decimal(a) * pow(10, self.app.decimal_point())
return create_bip21_uri(self.screen.address, amount, self.screen.message)
def do_share(self):
uri = self.get_URI()
self.app.do_share(uri, _("Share Bitcoin Request"))
def do_copy(self):
uri = self.get_URI()
self.app._clipboard.copy(uri)
@ -498,8 +471,7 @@ class ReceiveScreen(CScreen):
requests_container = self.screen.ids.requests_container
requests_container.data = [self.get_card(item) for item in _list if item.get('status') != PR_PAID]
def do_show(self, obj):
self.hide_menu()
def show_item(self, obj):
self.app.show_request(obj.is_lightning, obj.key)
def expiration_dialog(self, obj):
@ -523,24 +495,7 @@ class ReceiveScreen(CScreen):
d = Question(_('Delete expired requests?'), callback)
d.open()
def delete_request_dialog(self, req):
def cb(result):
if result:
self.app.wallet.delete_request(req.key)
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.add_widget(self.context_menu)
def hide_menu(self):
if self.context_menu is not None:
self.remove_widget(self.context_menu)
self.context_menu = None
class TabbedCarousel(Factory.TabbedPanel):
'''Custom TabbedPanel using a carousel used in the Main Screen

89
electrum/gui/kivy/uix/ui_screens/invoice.kv

@ -1,89 +0,0 @@
#:import Decimal decimal.Decimal
Popup:
id: popup
is_invoice: True
amount: 0
requestor: ''
exp: ''
description: ''
status: ''
signature: ''
isaddr: ''
fund: 0
pk: ''
title: _('Invoice') if popup.is_invoice else _('Request')
tx_hash: ''
BoxLayout:
orientation: 'vertical'
ScrollView:
GridLayout:
cols: 1
height: self.minimum_height
size_hint_y: None
padding: '10dp'
spacing: '10dp'
GridLayout:
cols: 1
size_hint_y: None
height: self.minimum_height
spacing: '10dp'
BoxLabel:
text: (_('Status') if popup.amount or popup.is_invoice or popup.isaddr == 'y' else _('Amount received')) if root.status else ''
value: root.status
BoxLabel:
text: _('Request amount') if root.amount else ''
value: app.format_amount_and_units(root.amount) if root.amount else ''
BoxLabel:
text: _('Requestor') if popup.is_invoice else _('Address')
value: root.requestor
BoxLabel:
text: _('Signature') if root.signature else ''
value: root.signature
BoxLabel:
text: _('Expiration') if root.exp else ''
value: root.exp
BoxLabel:
text: _('Description') if root.description else ''
value: root.description
BoxLabel:
text: _('Balance') if popup.fund else ''
value: app.format_amount_and_units(root.fund) if root.fund else ''
TopLabel:
text: _('Private Key')
RefLabel:
id: pk_label
touched: True if not self.touched else True
data: root.pk
TopLabel:
text: _('Outputs') if popup.is_invoice else ''
OutputList:
id: output_list
TopLabel:
text: _('Transaction ID') if popup.tx_hash else ''
TxHashLabel:
data: popup.tx_hash
name: _('Transaction ID')
Widget:
size_hint: 1, 0.1
BoxLayout:
size_hint: 1, None
height: '48dp'
Widget:
size_hint: 0.5, None
height: '48dp'
Button:
size_hint: 2, None
height: '48dp'
text: _('Close')
on_release: popup.dismiss()
Button:
size_hint: 2, None
height: '48dp'
text: _('Hide private key') if pk_label.data else _('Export private key')
on_release:
setattr(pk_label, 'data', '') if pk_label.data else popup.export(pk_label, popup.requestor)
Loading…
Cancel
Save