URI: 
       tkivy: remove context menus, cleanup unused files - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e9c32bad1946d8ef07b8018f6578d7ed4782ca7a
   DIR parent 587f8aa48702496407f5044fa3a3d9f9aae36f34
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Fri, 23 Aug 2019 12:15:42 +0200
       
       kivy: remove context menus, cleanup unused files
       
       Diffstat:
         M electrum/gui/kivy/main.kv           |       5 ++---
         M electrum/gui/kivy/main_window.py    |      57 -------------------------------
         D electrum/gui/kivy/uix/context_menu… |      58 ------------------------------
         M electrum/gui/kivy/uix/dialogs/addr… |     111 +++++++++++++++++++++++--------
         D electrum/gui/kivy/uix/dialogs/invo… |     169 -------------------------------
         M electrum/gui/kivy/uix/dialogs/ligh… |     155 +++++++++++++++----------------
         D electrum/gui/kivy/uix/dialogs/ligh… |      65 -------------------------------
         M electrum/gui/kivy/uix/dialogs/requ… |      33 +++++++++++++++++++++++--------
         M electrum/gui/kivy/uix/dialogs/tx_d… |      16 ++++++++++++++++
         M electrum/gui/kivy/uix/screens.py    |      53 +++----------------------------
         D electrum/gui/kivy/uix/ui_screens/i… |      89 -------------------------------
       
       11 files changed, 208 insertions(+), 603 deletions(-)
       ---
   DIR diff --git a/electrum/gui/kivy/main.kv b/electrum/gui/kivy/main.kv
       t@@ -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)
   DIR diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
       t@@ -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():
       t@@ -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:
   DIR diff --git a/electrum/gui/kivy/uix/context_menu.py b/electrum/gui/kivy/uix/context_menu.py
       t@@ -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()
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/addresses.py b/electrum/gui/kivy/uix/dialogs/addresses.py
       t@@ -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>
       t@@ -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):
       t@@ -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 = {}
       t@@ -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()
       t@@ -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
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/invoices.py b/electrum/gui/kivy/uix/dialogs/invoices.py
       t@@ -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
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_channels.py b/electrum/gui/kivy/uix/dialogs/lightning_channels.py
       t@@ -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>
       t@@ -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
       t@@ -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 = {}
       t@@ -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)}
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_invoices.py b/electrum/gui/kivy/uix/dialogs/lightning_invoices.py
       t@@ -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
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/request_dialog.py b/electrum/gui/kivy/uix/dialogs/request_dialog.py
       t@@ -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)
       t@@ -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()
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/tx_dialog.py b/electrum/gui/kivy/uix/dialogs/tx_dialog.py
       t@@ -101,6 +101,11 @@ Builder.load_string('''
                    Button:
                        size_hint: 0.5, None
                        height: '48dp'
       +                text: _('Label')
       +                on_release: root.label_dialog()
       +            Button:
       +                size_hint: 0.5, None
       +                height: '48dp'
                        text: _('Close')
                        on_release: root.dismiss()
        ''')
       t@@ -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()
   DIR diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
       t@@ -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
        
       t@@ -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):
       t@@ -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
       t@@ -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)
       t@@ -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):
       t@@ -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)
       t@@ -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):
       t@@ -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
   DIR diff --git a/electrum/gui/kivy/uix/ui_screens/invoice.kv b/electrum/gui/kivy/uix/ui_screens/invoice.kv
       t@@ -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)