diff --git a/electrum/gui/qml/components/ReceiveDialog.qml b/electrum/gui/qml/components/ReceiveDialog.qml index e96291f07..31cc4c083 100644 --- a/electrum/gui/qml/components/ReceiveDialog.qml +++ b/electrum/gui/qml/components/ReceiveDialog.qml @@ -207,10 +207,17 @@ ElDialog { GridLayout { columns: 2 - visible: request.message || !request.amount.isEmpty + // visible: request.message || !request.amount.isEmpty Layout.maximumWidth: buttons.width Layout.alignment: Qt.AlignHCenter + Label { + text: qsTr('Status') + color: Material.accentColor + } + Label { + text: request.status_str + } Label { visible: request.message text: qsTr('Message') @@ -234,7 +241,7 @@ ElDialog { } Rectangle { - visible: request.message || !request.amount.isEmpty + // visible: request.message || !request.amount.isEmpty height: 1 Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: buttons.width diff --git a/electrum/gui/qml/qeinvoice.py b/electrum/gui/qml/qeinvoice.py index aa640fb1c..9e7969b9e 100644 --- a/electrum/gui/qml/qeinvoice.py +++ b/electrum/gui/qml/qeinvoice.py @@ -2,14 +2,14 @@ import threading import asyncio from urllib.parse import urlparse -from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS +from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS, QTimer from electrum import bitcoin from electrum import lnutil from electrum.i18n import _ from electrum.invoices import Invoice from electrum.invoices import (PR_UNPAID, PR_EXPIRED, PR_UNKNOWN, PR_PAID, PR_INFLIGHT, - PR_FAILED, PR_ROUTING, PR_UNCONFIRMED) + PR_FAILED, PR_ROUTING, PR_UNCONFIRMED, LN_EXPIRY_NEVER) from electrum.lnaddr import LnInvoiceException from electrum.logging import get_logger from electrum.transaction import PartialTxOutput @@ -20,6 +20,7 @@ from electrum.bitcoin import COIN from .qetypes import QEAmount from .qewallet import QEWallet +from .util import status_update_timer_interval class QEInvoice(QObject): class Type: @@ -140,6 +141,10 @@ class QEInvoiceParser(QEInvoice): self._amount = QEAmount() self._userinfo = '' + self._timer = QTimer(self) + self._timer.setSingleShot(True) + self._timer.timeout.connect(self.updateStatusString) + self.clear() @pyqtProperty(int, notify=invoiceChanged) @@ -190,6 +195,10 @@ class QEInvoiceParser(QEInvoice): self.determine_can_pay() self.invoiceChanged.emit() + @pyqtProperty('quint64', notify=invoiceChanged) + def time(self): + return self._effectiveInvoice.time if self._effectiveInvoice else 0 + @pyqtProperty('quint64', notify=invoiceChanged) def expiration(self): return self._effectiveInvoice.exp if self._effectiveInvoice else 0 @@ -268,6 +277,21 @@ class QEInvoiceParser(QEInvoice): self.invoiceChanged.emit() self.statusChanged.emit() + self.set_status_timer() + + def set_status_timer(self): + if self.status != PR_EXPIRED: + if self.expiration > 0 and self.expiration != LN_EXPIRY_NEVER: + interval = status_update_timer_interval(self.time + self.expiration) + if interval > 0: + self._timer.setInterval(interval) # msec + self._timer.start() + + @pyqtSlot() + def updateStatusString(self): + self.statusChanged.emit() + self.set_status_timer() + def determine_can_pay(self): self.canPay = False self.userinfo = '' diff --git a/electrum/gui/qml/qerequestdetails.py b/electrum/gui/qml/qerequestdetails.py index 59569c163..95eeac6e4 100644 --- a/electrum/gui/qml/qerequestdetails.py +++ b/electrum/gui/qml/qerequestdetails.py @@ -1,5 +1,3 @@ -from time import time - from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, Q_ENUMS from electrum.logging import get_logger @@ -8,7 +6,7 @@ from electrum.invoices import (PR_UNPAID, PR_EXPIRED, PR_UNKNOWN, PR_PAID, PR_IN from .qewallet import QEWallet from .qetypes import QEAmount -from .util import QtEventListener, event_listener +from .util import QtEventListener, event_listener, status_update_timer_interval class QERequestDetails(QObject, QtEventListener): @@ -38,6 +36,10 @@ class QERequestDetails(QObject, QtEventListener): self._timer = None self._amount = None + self._timer = QTimer(self) + self._timer.setSingleShot(True) + self._timer.timeout.connect(self.updateStatusString) + self.register_callbacks() self.destroyed.connect(lambda: self.on_destroy()) @@ -134,31 +136,16 @@ class QERequestDetails(QObject, QtEventListener): self._amount = QEAmount(from_invoice=self._req) self.detailsChanged.emit() - self.initStatusStringTimer() + self.statusChanged.emit() + self.set_status_timer() - def initStatusStringTimer(self): + def set_status_timer(self): if self.status == PR_UNPAID: if self.expiration > 0 and self.expiration != LN_EXPIRY_NEVER: - self._timer = QTimer(self) - self._timer.setSingleShot(True) - self._timer.timeout.connect(self.updateStatusString) - - # very roughly according to util.time_difference - exp_in = int(self.expiration - time()) - exp_in_min = int(exp_in/60) - - interval = 0 - if exp_in < 0: - interval = 0 - if exp_in_min < 2: - interval = 1000 - elif exp_in_min < 90: - interval = 1000 * 60 - elif exp_in_min < 1440: - interval = 1000 * 60 * 60 - + self._logger.debug(f'set_status_timer, expiration={self.expiration}') + interval = status_update_timer_interval(self.expiration) if interval > 0: - self._logger.debug(f'setting status update timer to {interval}, req expires in {exp_in} seconds') + self._logger.debug(f'setting status update timer to {interval}') self._timer.setInterval(interval) # msec self._timer.start() @@ -166,5 +153,5 @@ class QERequestDetails(QObject, QtEventListener): @pyqtSlot() def updateStatusString(self): self.statusChanged.emit() - self.initStatusStringTimer() + self.set_status_timer() diff --git a/electrum/gui/qml/util.py b/electrum/gui/qml/util.py index 36060e0f5..0ac83721e 100644 --- a/electrum/gui/qml/util.py +++ b/electrum/gui/qml/util.py @@ -1,4 +1,5 @@ from functools import wraps +from time import time from PyQt5.QtCore import pyqtSignal @@ -27,3 +28,22 @@ def qt_event_listener(func): def decorator(self, *args): self.qt_callback_signal.emit( (func,) + args) return decorator + +# return delay in msec when expiry time string should be updated +# returns 0 when expired or expires > 1 day away (no updates needed) +def status_update_timer_interval(exp): + # very roughly according to util.time_difference + exp_in = int(exp - time()) + exp_in_min = int(exp_in/60) + + interval = 0 + if exp_in < 0: + interval = 0 + elif exp_in_min < 2: + interval = 1000 + elif exp_in_min < 90: + interval = 1000 * 60 + elif exp_in_min < 1440: + interval = 1000 * 60 * 60 + + return interval