1
0

auto-remove paid invoices from GUI

- delay 3 seconds in GUI
 - kivy remove 'delete' buttons from send/receive screens
This commit is contained in:
ThomasV
2020-12-06 10:58:04 +01:00
parent 90abfda12b
commit a2122a8c19
8 changed files with 77 additions and 47 deletions

View File

@@ -242,9 +242,12 @@ class ElectrumWindow(App, Logger):
self._trigger_update_history()
def on_request_status(self, event, wallet, key, status):
if key not in self.wallet.receive_requests:
req = self.wallet.receive_requests.get(key)
if req is None:
return
self.update_tab('receive')
if self.receive_screen:
self.receive_screen.update_item(key, req)
Clock.schedule_once(lambda dt: self.receive_screen.update(), 3)
if self.request_popup and self.request_popup.key == key:
self.request_popup.update_status()
if status == PR_PAID:
@@ -255,9 +258,10 @@ class ElectrumWindow(App, Logger):
req = self.wallet.get_invoice(key)
if req is None:
return
status = self.wallet.get_invoice_status(req)
# todo: update single item
self.update_tab('send')
if self.send_screen:
self.send_screen.update_item(key, req)
Clock.schedule_once(lambda dt: self.send_screen.update(), 3)
if self.invoice_popup and self.invoice_popup.key == key:
self.invoice_popup.update_status()

View File

@@ -218,11 +218,23 @@ class SendScreen(CScreen, Logger):
def update(self):
if self.app.wallet is None:
return
_list = self.app.wallet.get_invoices()
_list = self.app.wallet.get_unpaid_invoices()
_list.reverse()
payments_container = self.ids.payments_container
payments_container.data = [self.get_card(item) for item in _list]
def update_item(self, key, invoice):
payments_container = self.ids.payments_container
data = payments_container.data
for item in data:
if item['key'] == key:
status = self.app.wallet.get_invoice_status(invoice)
status_str = invoice.get_status_str(status)
item['status'] = status
item['status_str'] = status_str
payments_container.data = data
payments_container.refresh_from_data()
def show_item(self, obj):
self.app.show_invoice(obj.is_lightning, obj.key)
@@ -421,20 +433,6 @@ class SendScreen(CScreen, Logger):
else:
self.app.tx_dialog(tx)
def clear_invoices_dialog(self):
invoices = self.app.wallet.get_invoices()
if not invoices:
return
def callback(c):
if c:
for req in invoices:
key = req.rhash if req.is_lightning() else req.get_address()
self.app.wallet.delete_invoice(key)
self.update()
n = len(invoices)
d = Question(_('Delete {} invoices?').format(n), callback)
d.open()
class ReceiveScreen(CScreen):
@@ -531,11 +529,23 @@ class ReceiveScreen(CScreen):
def update(self):
if self.app.wallet is None:
return
_list = self.app.wallet.get_sorted_requests()
_list = self.app.wallet.get_unpaid_requests()
_list.reverse()
requests_container = self.ids.requests_container
requests_container.data = [self.get_card(item) for item in _list]
def update_item(self, key, request):
payments_container = self.ids.requests_container
data = payments_container.data
for item in data:
if item['key'] == key:
status = self.app.wallet.get_request_status(key)
status_str = request.get_status_str(status)
item['status'] = status
item['status_str'] = status_str
payments_container.data = data # needed?
payments_container.refresh_from_data()
def show_item(self, obj):
self.app.show_request(obj.is_lightning, obj.key)
@@ -546,19 +556,6 @@ class ReceiveScreen(CScreen):
d = ChoiceDialog(_('Expiration date'), pr_expiration_values, self.expiry(), callback)
d.open()
def clear_requests_dialog(self):
requests = self.app.wallet.get_sorted_requests()
if not requests:
return
def callback(c):
if c:
self.app.wallet.clear_requests()
self.update()
n = len(requests)
d = Question(_('Delete {} requests?').format(n), callback)
d.open()
class TabbedCarousel(Factory.TabbedPanel):
'''Custom TabbedPanel using a carousel used in the Main Screen

View File

@@ -134,11 +134,6 @@
BoxLayout:
size_hint: 1, None
height: '48dp'
IconButton:
icon: f'atlas://{KIVY_GUI_PATH}/theming/light/delete'
size_hint: 0.5, None
height: '48dp'
on_release: Clock.schedule_once(lambda dt: s.clear_requests_dialog())
IconButton:
icon: f'atlas://{KIVY_GUI_PATH}/theming/light/clock1'
size_hint: 0.5, None

View File

@@ -150,10 +150,6 @@
BoxLayout:
size_hint: 1, None
height: '48dp'
IconButton:
icon: f'atlas://{KIVY_GUI_PATH}/theming/light/delete'
size_hint: 0.5, 1
on_release: Clock.schedule_once(lambda dt: s.clear_invoices_dialog())
IconButton:
size_hint: 0.5, 1
on_release: s.do_save()

View File

@@ -98,7 +98,7 @@ class InvoiceList(MyTreeView):
self.proxy.setDynamicSortFilter(False) # temp. disable re-sorting after every change
self.std_model.clear()
self.update_headers(self.__class__.headers)
for idx, item in enumerate(self.parent.wallet.get_invoices()):
for idx, item in enumerate(self.parent.wallet.get_unpaid_invoices()):
if item.is_lightning():
key = item.rhash
icon_name = 'lightning.png'

View File

@@ -40,6 +40,7 @@ from typing import Optional, TYPE_CHECKING, Sequence, List, Union
from PyQt5.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont
from PyQt5.QtCore import Qt, QRect, QStringListModel, QSize, pyqtSignal
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import (QMessageBox, QComboBox, QSystemTrayIcon, QTabWidget,
QMenuBar, QFileDialog, QCheckBox, QLabel,
QVBoxLayout, QGridLayout, QLineEdit,
@@ -1516,8 +1517,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
def on_request_status(self, wallet, key, status):
if wallet != self.wallet:
return
if key not in self.wallet.receive_requests:
req = self.wallet.receive_requests.get(key)
if req is None:
return
# update item
self.request_list.update_item(key, req)
# update list later
self.timer = QTimer()
self.timer.timeout.connect(self.request_list.update)
self.timer.start(3000)
if status == PR_PAID:
self.notify(_('Payment received') + '\n' + key)
self.need_update.set()
@@ -1528,7 +1537,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
req = self.wallet.get_invoice(key)
if req is None:
return
# update item
self.invoice_list.update_item(key, req)
# update list later.
self.timer = QTimer()
self.timer.timeout.connect(self.invoice_list.update)
self.timer.start(3000)
def on_payment_succeeded(self, wallet, key):
description = self.wallet.get_label(key)

View File

@@ -34,6 +34,7 @@ from electrum.i18n import _
from electrum.util import format_time
from electrum.invoices import PR_TYPE_ONCHAIN, PR_TYPE_LN, LNInvoice, OnchainInvoice
from electrum.plugin import run_hook
from electrum.invoices import Invoice
from .util import MyTreeView, pr_icons, read_QIcon, webopen, MySortModel
@@ -126,13 +127,27 @@ class RequestList(MyTreeView):
status_item.setText(status_str)
status_item.setIcon(read_QIcon(pr_icons.get(status)))
def update_item(self, key, invoice: Invoice):
model = self.std_model
for row in range(0, model.rowCount()):
item = model.item(row, 0)
if item.data(ROLE_KEY) == key:
break
else:
return
status_item = model.item(row, self.Columns.STATUS)
status = self.parent.wallet.get_request_status(key)
status_str = invoice.get_status_str(status)
status_item.setText(status_str)
status_item.setIcon(read_QIcon(pr_icons.get(status)))
def update(self):
# not calling maybe_defer_update() as it interferes with conditional-visibility
self.parent.update_receive_address_styling()
self.proxy.setDynamicSortFilter(False) # temp. disable re-sorting after every change
self.std_model.clear()
self.update_headers(self.__class__.headers)
for req in self.wallet.get_sorted_requests():
for req in self.wallet.get_unpaid_requests():
if req.is_lightning():
assert isinstance(req, LNInvoice)
key = req.rhash

View File

@@ -761,10 +761,13 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
def get_invoices(self):
out = list(self.invoices.values())
#out = list(filter(None, out)) filter out ln
out.sort(key=lambda x:x.time)
return out
def get_unpaid_invoices(self):
invoices = self.get_invoices()
return [x for x in invoices if self.get_invoice_status(x) != PR_PAID]
def get_invoice(self, key):
return self.invoices.get(key)
@@ -2035,6 +2038,12 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
out.sort(key=lambda x: x.time)
return out
def get_unpaid_requests(self):
out = [self.get_request(x) for x in self.receive_requests.keys() if self.get_request_status(x) != PR_PAID]
out = [x for x in out if x is not None]
out.sort(key=lambda x: x.time)
return out
@abstractmethod
def get_fingerprint(self) -> str:
"""Returns a string that can be used to identify this wallet.