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)