URI: 
       tgui: show incoming lightning requests, add on-chain icon - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 7bb4ea150f8cbc9da3edc589c94883c195a72d9a
   DIR parent 2af178a5864891fa003aa037b35a6c813c658096
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 30 Jan 2019 11:10:11 +0100
       
       gui: show incoming lightning requests, add on-chain icon
       
       Diffstat:
         M electrum/gui/qt/invoice_list.py     |      51 ++++++++++++++++++++++---------
         M electrum/gui/qt/main_window.py      |       6 ++++--
         M electrum/gui/qt/request_list.py     |      58 +++++++++++++------------------
         M electrum/gui/qt/util.py             |       3 ++-
         M electrum/paymentrequest.py          |       3 +++
         A icons/bitcoin.png                   |       0 
       
       6 files changed, 71 insertions(+), 50 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py
       t@@ -30,7 +30,9 @@ from PyQt5.QtGui import QStandardItemModel, QStandardItem, QFont
        from PyQt5.QtWidgets import QHeaderView, QMenu
        
        from electrum.i18n import _
       -from electrum.util import format_time
       +from electrum.util import format_time, pr_tooltips, PR_UNPAID
       +from electrum.lnutil import lndecode
       +from electrum.bitcoin import COIN
        
        from .util import (MyTreeView, read_QIcon, MONOSPACE_FONT, PR_UNPAID,
                           pr_tooltips, import_meta_gui, export_meta_gui, pr_icons)
       t@@ -40,26 +42,23 @@ class InvoiceList(MyTreeView):
        
            class Columns(IntEnum):
                DATE = 0
       -        REQUESTOR = 1
       -        DESCRIPTION = 2
       -        AMOUNT = 3
       -        STATUS = 4
       +        DESCRIPTION = 1
       +        AMOUNT = 2
       +        STATUS = 3
        
            headers = {
                Columns.DATE: _('Expires'),
       -        Columns.REQUESTOR: _('Requestor'),
                Columns.DESCRIPTION: _('Description'),
                Columns.AMOUNT: _('Amount'),
                Columns.STATUS: _('Status'),
            }
       -    filter_columns = [Columns.DATE, Columns.REQUESTOR, Columns.DESCRIPTION, Columns.AMOUNT]
       +    filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT]
        
            def __init__(self, parent):
                super().__init__(parent, self.create_menu,
                                 stretch_column=self.Columns.DESCRIPTION,
                                 editable_columns=[])
                self.setSortingEnabled(True)
       -        self.setColumnWidth(self.Columns.REQUESTOR, 200)
                self.setModel(QStandardItemModel(self))
                self.update()
        
       t@@ -67,26 +66,50 @@ class InvoiceList(MyTreeView):
                inv_list = self.parent.invoices.unpaid_invoices()
                self.model().clear()
                self.update_headers(self.__class__.headers)
       -        self.header().setSectionResizeMode(self.Columns.REQUESTOR, QHeaderView.Interactive)
                for idx, pr in enumerate(inv_list):
                    key = pr.get_id()
                    status = self.parent.invoices.get_status(key)
                    if status is None:
                        continue
                    requestor = pr.get_requestor()
       -            exp = pr.get_expiration_date()
       +            exp = pr.get_time()
                    date_str = format_time(exp) if exp else _('Never')
       -            labels = [date_str, requestor, pr.memo, self.parent.format_amount(pr.get_amount(), whitespaces=True), pr_tooltips.get(status,'')]
       +            labels = [date_str, '[%s] '%requestor + pr.memo, self.parent.format_amount(pr.get_amount(), whitespaces=True), pr_tooltips.get(status,'')]
                    items = [QStandardItem(e) for e in labels]
                    self.set_editability(items)
       +            items[self.Columns.DATE].setIcon(read_QIcon('bitcoin.png'))
                    items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status)))
                    items[self.Columns.DATE].setData(key, role=Qt.UserRole)
       -            items[self.Columns.REQUESTOR].setFont(QFont(MONOSPACE_FONT))
       -            items[self.Columns.AMOUNT].setFont(QFont(MONOSPACE_FONT))
                    self.model().insertRow(idx, items)
       +
       +        lnworker = self.parent.wallet.lnworker
       +        for key, (preimage_hex, invoice, is_received, pay_timestamp) in lnworker.invoices.items():
       +            if is_received:
       +                continue
       +            status = lnworker.get_invoice_status(key)
       +            lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
       +            amount_sat = lnaddr.amount*COIN if lnaddr.amount else None
       +            amount_str = self.parent.format_amount(amount_sat) if amount_sat else ''
       +            description = ''
       +            for k,v in lnaddr.tags:
       +                if k == 'd':
       +                    description = v
       +                    break
       +            date_str = format_time(lnaddr.date)
       +            labels = [date_str, description, amount_str, pr_tooltips.get(status,'')]
       +            items = [QStandardItem(e) for e in labels]
       +            #items[0].setData(REQUEST_TYPE_LN, ROLE_REQUEST_TYPE)
       +            #items[0].setData(key, ROLE_RHASH_OR_ADDR)
       +            items[0].setIcon(self.icon_cache.get(':icons/lightning.png'))
       +            items[3].setIcon(self.icon_cache.get(pr_icons.get(status)))
       +            self.model().insertRow(self.model().rowCount(), items)
       +
                self.selectionModel().select(self.model().index(0,0), QItemSelectionModel.SelectCurrent)
       +        # sort requests by date
       +        self.model().sort(0)
       +        # hide list if empty
                if self.parent.isVisible():
       -            b = len(inv_list) > 0
       +            b = self.model().rowCount() > 0
                    self.setVisible(b)
                    self.parent.invoices_label.setVisible(b)
                self.filter()
   DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
       t@@ -953,8 +953,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                grid.addWidget(self.expires_label, 2, 1)
        
                self.create_invoice_button = QPushButton(_('On-chain'))
       +        self.create_invoice_button.setIcon(QIcon(":icons/bitcoin.png"))
                self.create_invoice_button.clicked.connect(lambda: self.create_invoice(False))
                self.create_lightning_invoice_button = QPushButton(_('Lightning'))
       +        self.create_lightning_invoice_button.setIcon(QIcon(":icons/lightning.png"))
                self.create_lightning_invoice_button.clicked.connect(lambda: self.create_invoice(True))
                self.receive_buttons = buttons = QHBoxLayout()
                buttons.addStretch(1)
       t@@ -974,7 +976,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                self.receive_qr.enterEvent = lambda x: self.app.setOverrideCursor(QCursor(Qt.PointingHandCursor))
                self.receive_qr.leaveEvent = lambda x: self.app.setOverrideCursor(QCursor(Qt.ArrowCursor))
        
       -        self.receive_requests_label = QLabel(_('Requests'))
       +        self.receive_requests_label = QLabel(_('Incoming invoices'))
        
                from .request_list import RequestList
                self.request_list = RequestList(self)
       t@@ -1395,7 +1397,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                self.fee_e.textChanged.connect(entry_changed)
                self.feerate_e.textChanged.connect(entry_changed)
        
       -        self.invoices_label = QLabel(_('Invoices'))
       +        self.invoices_label = QLabel(_('Outgoing invoices'))
                from .invoice_list import InvoiceList
                self.invoice_list = InvoiceList(self)
        
   DIR diff --git a/electrum/gui/qt/request_list.py b/electrum/gui/qt/request_list.py
       t@@ -51,14 +51,12 @@ class RequestList(MyTreeView):
        
            class Columns(IntEnum):
                DATE = 0
       -        TYPE = 1
       -        DESCRIPTION = 2
       -        AMOUNT = 3
       -        STATUS = 4
       +        DESCRIPTION = 1
       +        AMOUNT = 2
       +        STATUS = 3
        
            headers = {
                Columns.DATE: _('Date'),
       -        Columns.TYPE: _('Type'),
                Columns.DESCRIPTION: _('Description'),
                Columns.AMOUNT: _('Amount'),
                Columns.STATUS: _('Status'),
       t@@ -68,7 +66,7 @@ class RequestList(MyTreeView):
            def __init__(self, parent):
                super().__init__(parent, self.create_menu,
                                 stretch_column=self.Columns.DESCRIPTION,
       -                         editable_columns=[])
       +                         editable_columns=[self.Columns.AMOUNT])
                self.setModel(QStandardItemModel(self))
                self.setSortingEnabled(True)
                self.update()
       t@@ -76,7 +74,7 @@ class RequestList(MyTreeView):
        
            def select_key(self, key):
                for i in range(self.model().rowCount()):
       -            item = self.model().index(i, 0)
       +            item = self.model().index(i, self.Columns.DATE)
                    row_key = item.data(ROLE_RHASH_OR_ADDR)
                    if item.data(ROLE_REQUEST_TYPE) == REQUEST_TYPE_LN:
                        row_key = self.wallet.lnworker.invoices[row_key][1]
       t@@ -86,7 +84,7 @@ class RequestList(MyTreeView):
        
            def item_changed(self, idx):
                # TODO use siblingAtColumn when min Qt version is >=5.11
       -        item = self.model().itemFromIndex(idx.sibling(idx.row(), 0))
       +        item = self.model().itemFromIndex(idx.sibling(idx.row(), self.Columns.DATE))
                request_type = item.data(ROLE_REQUEST_TYPE)
                key = item.data(ROLE_RHASH_OR_ADDR)
                if request_type == REQUEST_TYPE_BITCOIN:
       t@@ -104,19 +102,8 @@ class RequestList(MyTreeView):
        
            def update(self):
                self.wallet = self.parent.wallet
       -        # hide receive tab if no receive requests available
       -        if self.parent.isVisible():
       -            b = len(self.wallet.receive_requests) > 0 or len(self.wallet.lnworker.invoices) > 0
       -            self.setVisible(b)
       -            self.parent.receive_requests_label.setVisible(b)
       -            if not b:
       -                self.parent.expires_label.hide()
       -                self.parent.expires_combo.show()
       -
                domain = self.wallet.get_receiving_addresses()
       -
                self.parent.update_receive_address_styling()
       -
                self.model().clear()
                self.update_headers(self.__class__.headers)
                for req in self.wallet.get_sorted_requests(self.config):
       t@@ -132,17 +119,18 @@ class RequestList(MyTreeView):
                    signature = req.get('sig')
                    requestor = req.get('name', '')
                    amount_str = self.parent.format_amount(amount) if amount else ""
       -            labels = [date, 'on-chain', message, amount_str, pr_tooltips.get(status,'')]
       +            labels = [date, message, amount_str, pr_tooltips.get(status,'')]
                    items = [QStandardItem(e) for e in labels]
                    self.set_editability(items)
                    if signature is not None:
       -                items[self.Columns.TYPE].setIcon(read_QIcon("seal.png"))
       -                items[self.Columns.TYPE].setToolTip(f'signed by {requestor}')
       -            if status is not PR_UNKNOWN:
       -                items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status)))
       +                items[self.Columns.DATE].setIcon(read_QIcon("seal.png"))
       +                items[self.Columns.DATE].setToolTip(f'signed by {requestor}')
       +            else:
       +                items[self.Columns.DATE].setIcon(read_QIcon("bitcoin.png"))
       +            items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status)))
                    self.model().insertRow(self.model().rowCount(), items)
       -            items[0].setData(REQUEST_TYPE_BITCOIN, ROLE_REQUEST_TYPE)
       -            items[0].setData(address, ROLE_RHASH_OR_ADDR)
       +            items[self.Columns.DATE].setData(REQUEST_TYPE_BITCOIN, ROLE_REQUEST_TYPE)
       +            items[self.Columns.DATE].setData(address, ROLE_RHASH_OR_ADDR)
                self.filter()
                # lightning
                lnworker = self.wallet.lnworker
       t@@ -159,16 +147,20 @@ class RequestList(MyTreeView):
                            description = v
                            break
                    date = format_time(lnaddr.date)
       -            labels = [date, 'lightning', description, amount_str, pr_tooltips.get(status,'')]
       +            labels = [date, description, amount_str, pr_tooltips.get(status,'')]
                    items = [QStandardItem(e) for e in labels]
       -            items[1].setIcon(self.icon_cache.get(":icons/lightning.png"))
       -            items[0].setData(REQUEST_TYPE_LN, ROLE_REQUEST_TYPE)
       -            items[0].setData(key, ROLE_RHASH_OR_ADDR)
       -            if status is not PR_UNKNOWN:
       -                items[4].setIcon(self.icon_cache.get(pr_icons.get(status)))
       +            items[self.Columns.DATE].setIcon(self.icon_cache.get(":icons/lightning.png"))
       +            items[self.Columns.DATE].setData(REQUEST_TYPE_LN, ROLE_REQUEST_TYPE)
       +            items[self.Columns.DATE].setData(key, ROLE_RHASH_OR_ADDR)
       +            items[self.Columns.STATUS].setIcon(self.icon_cache.get(pr_icons.get(status)))
                    self.model().insertRow(self.model().rowCount(), items)
                # sort requests by date
       -        self.model().sort(0)
       +        self.model().sort(self.Columns.DATE)
       +        # hide list if empty
       +        if self.parent.isVisible():
       +            b = self.model().rowCount() > 0
       +            self.setVisible(b)
       +            self.parent.receive_requests_label.setVisible(b)
        
            def create_menu(self, position):
                idx = self.indexAt(position)
   DIR diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py
       t@@ -24,7 +24,7 @@ from PyQt5.QtWidgets import (QPushButton, QLabel, QMessageBox, QHBoxLayout,
        
        from electrum.i18n import _, languages
        from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, PrintError, resource_path
       -from electrum.util import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT
       +from electrum.util import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN
        
        if TYPE_CHECKING:
            from .main_window import ElectrumWindow
       t@@ -41,6 +41,7 @@ else:
        dialogs = []
        
        pr_icons = {
       +    PR_UNKNOWN:"unpaid.png",
            PR_UNPAID:"unpaid.png",
            PR_PAID:"confirmed.png",
            PR_EXPIRED:"expired.png",
   DIR diff --git a/electrum/paymentrequest.py b/electrum/paymentrequest.py
       t@@ -246,6 +246,9 @@ class PaymentRequest:
                    return None
                return self.details.expires and self.details.expires < int(time.time())
        
       +    def get_time(self):
       +        return self.details.time
       +
            def get_expiration_date(self):
                return self.details.expires
        
   DIR diff --git a/icons/bitcoin.png b/icons/bitcoin.png
       Binary files differ.