auto-remove paid invoices from GUI
- delay 3 seconds in GUI - kivy remove 'delete' buttons from send/receive screens
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user