mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
kivy: remove context menus, cleanup unused files
This commit is contained in:
parent
587f8aa487
commit
e9c32bad19
11 changed files with 206 additions and 601 deletions
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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):
|
||||
|
||||
def __init__(self, chan, app, **kwargs):
|
||||
super(ChannelDetailsPopup,self).__init__(**kwargs)
|
||||
self.data = data
|
||||
|
||||
class LightningChannelsDialog(Factory.Popup):
|
||||
def __init__(self, app):
|
||||
super(LightningChannelsDialog, self).__init__()
|
||||
self.clocks = []
|
||||
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()
|
||||
self.chan = chan
|
||||
self.title = _('Channel details')
|
||||
self.data = [{'text': key, 'value': str(value)} for key, value in self.details().items()]
|
||||
|
||||
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 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_channel(self, obj):
|
||||
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)}
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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…
Add table
Reference in a new issue