Merge pull request #9784 from f321x/allow_lnaddress_contacts
qt: allow lightning addresses in contacts
This commit is contained in:
@@ -29,7 +29,7 @@ from dns.exception import DNSException
|
|||||||
|
|
||||||
from . import bitcoin
|
from . import bitcoin
|
||||||
from . import dnssec
|
from . import dnssec
|
||||||
from .util import read_json_file, write_json_file, to_string
|
from .util import read_json_file, write_json_file, to_string, is_valid_email
|
||||||
from .logging import Logger, get_logger
|
from .logging import Logger, get_logger
|
||||||
from .util import trigger_callback
|
from .util import trigger_callback
|
||||||
|
|
||||||
@@ -83,6 +83,7 @@ class Contacts(dict, Logger):
|
|||||||
res = dict.pop(self, key)
|
res = dict.pop(self, key)
|
||||||
self.save()
|
self.save()
|
||||||
return res
|
return res
|
||||||
|
return None
|
||||||
|
|
||||||
def resolve(self, k):
|
def resolve(self, k):
|
||||||
if bitcoin.is_address(k):
|
if bitcoin.is_address(k):
|
||||||
@@ -90,11 +91,12 @@ class Contacts(dict, Logger):
|
|||||||
'address': k,
|
'address': k,
|
||||||
'type': 'address'
|
'type': 'address'
|
||||||
}
|
}
|
||||||
if k in self.keys():
|
for address, (_type, label) in self.items():
|
||||||
_type, addr = self[k]
|
if k.casefold() != label.casefold():
|
||||||
if _type == 'address':
|
continue
|
||||||
|
if _type in ('address', 'lnaddress'):
|
||||||
return {
|
return {
|
||||||
'address': addr,
|
'address': address,
|
||||||
'type': 'contact'
|
'type': 'contact'
|
||||||
}
|
}
|
||||||
if openalias := self.resolve_openalias(k):
|
if openalias := self.resolve_openalias(k):
|
||||||
@@ -159,6 +161,8 @@ class Contacts(dict, Logger):
|
|||||||
if not address:
|
if not address:
|
||||||
continue
|
continue
|
||||||
return address, name, validated
|
return address, name, validated
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_regex(haystack, needle):
|
def find_regex(haystack, needle):
|
||||||
@@ -172,11 +176,11 @@ class Contacts(dict, Logger):
|
|||||||
for k, v in list(data.items()):
|
for k, v in list(data.items()):
|
||||||
if k == 'contacts':
|
if k == 'contacts':
|
||||||
return self._validate(v)
|
return self._validate(v)
|
||||||
if not bitcoin.is_address(k):
|
if not (bitcoin.is_address(k) or is_valid_email(k)):
|
||||||
data.pop(k)
|
data.pop(k)
|
||||||
else:
|
else:
|
||||||
_type, _ = v
|
_type, _ = v
|
||||||
if _type != 'address':
|
if _type not in ('address', 'lnaddress'):
|
||||||
data.pop(k)
|
data.pop(k)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ from electrum.i18n import _
|
|||||||
from electrum.bitcoin import is_address
|
from electrum.bitcoin import is_address
|
||||||
from electrum.util import block_explorer_URL
|
from electrum.util import block_explorer_URL
|
||||||
from electrum.plugin import run_hook
|
from electrum.plugin import run_hook
|
||||||
|
from electrum.gui.qt.util import read_QIcon
|
||||||
|
|
||||||
from .util import webopen
|
from .util import webopen
|
||||||
from .my_treeview import MyTreeView
|
from .my_treeview import MyTreeView
|
||||||
@@ -118,6 +119,9 @@ class ContactList(MyTreeView):
|
|||||||
items[self.Columns.NAME].setEditable(contact_type != 'openalias')
|
items[self.Columns.NAME].setEditable(contact_type != 'openalias')
|
||||||
items[self.Columns.ADDRESS].setEditable(False)
|
items[self.Columns.ADDRESS].setEditable(False)
|
||||||
items[self.Columns.NAME].setData(key, self.ROLE_CONTACT_KEY)
|
items[self.Columns.NAME].setData(key, self.ROLE_CONTACT_KEY)
|
||||||
|
items[self.Columns.NAME].setIcon(
|
||||||
|
read_QIcon("lightning" if contact_type == 'lnaddress' else "bitcoin")
|
||||||
|
)
|
||||||
row_count = self.model().rowCount()
|
row_count = self.model().rowCount()
|
||||||
self.model().insertRow(row_count, items)
|
self.model().insertRow(row_count, items)
|
||||||
if key == current_key:
|
if key == current_key:
|
||||||
|
|||||||
@@ -54,8 +54,10 @@ from electrum.bitcoin import COIN, is_address, DummyAddress
|
|||||||
from electrum.plugin import run_hook
|
from electrum.plugin import run_hook
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import (format_time, UserCancelled, profiler, bfh, InvalidPassword,
|
from electrum.util import (format_time, UserCancelled, profiler, bfh, InvalidPassword,
|
||||||
UserFacingException, get_new_wallet_name, send_exception_to_crash_reporter,
|
UserFacingException, get_new_wallet_name,
|
||||||
AddTransactionException, os_chmod, UI_UNIT_NAME_TXSIZE_VBYTES, ChoiceItem)
|
send_exception_to_crash_reporter,
|
||||||
|
AddTransactionException, os_chmod, UI_UNIT_NAME_TXSIZE_VBYTES,
|
||||||
|
is_valid_email, ChoiceItem)
|
||||||
from electrum.bip21 import BITCOIN_BIP21_URI_SCHEME
|
from electrum.bip21 import BITCOIN_BIP21_URI_SCHEME
|
||||||
from electrum.payment_identifier import PaymentIdentifier
|
from electrum.payment_identifier import PaymentIdentifier
|
||||||
from electrum.invoices import PR_PAID, Invoice
|
from electrum.invoices import PR_PAID, Invoice
|
||||||
@@ -1614,11 +1616,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
self.send_tab.payto_contacts(labels)
|
self.send_tab.payto_contacts(labels)
|
||||||
|
|
||||||
def set_contact(self, label, address):
|
def set_contact(self, label, address):
|
||||||
if not is_address(address):
|
if not (is_address(address) or is_valid_email(address)): # email = lightning address
|
||||||
self.show_error(_('Invalid Address'))
|
self.show_error(_('Invalid Address'))
|
||||||
self.contact_list.update() # Displays original unchanged value
|
self.contact_list.update() # Displays original unchanged value
|
||||||
return False
|
return False
|
||||||
self.contacts[address] = ('address', label)
|
address_type = 'address' if is_address(address) else 'lnaddress'
|
||||||
|
self.contacts[address] = (address_type, label)
|
||||||
self.contact_list.update()
|
self.contact_list.update()
|
||||||
self.history_list.update()
|
self.history_list.update()
|
||||||
self.update_completions()
|
self.update_completions()
|
||||||
@@ -2008,7 +2011,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
line1.setFixedWidth(32 * char_width_in_lineedit())
|
line1.setFixedWidth(32 * char_width_in_lineedit())
|
||||||
line2 = QLineEdit()
|
line2 = QLineEdit()
|
||||||
line2.setFixedWidth(32 * char_width_in_lineedit())
|
line2.setFixedWidth(32 * char_width_in_lineedit())
|
||||||
grid.addWidget(QLabel(_("Address")), 1, 0)
|
address_label = QLabel(_("Address"))
|
||||||
|
address_label.setToolTip(_("Bitcoin- or Lightning address"))
|
||||||
|
grid.addWidget(address_label, 1, 0)
|
||||||
grid.addWidget(line1, 1, 1)
|
grid.addWidget(line1, 1, 1)
|
||||||
grid.addWidget(QLabel(_("Name")), 2, 0)
|
grid.addWidget(QLabel(_("Name")), 2, 0)
|
||||||
grid.addWidget(line2, 2, 1)
|
grid.addWidget(line2, 2, 1)
|
||||||
|
|||||||
@@ -801,7 +801,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
def payto_contacts(self, labels):
|
def payto_contacts(self, labels):
|
||||||
paytos = [self.window.get_contact_payto(label) for label in labels]
|
paytos = [self.window.get_contact_payto(label) for label in labels]
|
||||||
self.window.show_send_tab()
|
self.window.show_send_tab()
|
||||||
self.payto_e.do_clear()
|
self.do_clear()
|
||||||
if len(paytos) == 1:
|
if len(paytos) == 1:
|
||||||
self.logger.debug('payto_e setText 1')
|
self.logger.debug('payto_e setText 1')
|
||||||
self.payto_e.setText(paytos[0])
|
self.payto_e.setText(paytos[0])
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ class PaymentIdentifier(Logger):
|
|||||||
'label': contact['name']
|
'label': contact['name']
|
||||||
}
|
}
|
||||||
self.set_state(PaymentIdentifierState.AVAILABLE)
|
self.set_state(PaymentIdentifierState.AVAILABLE)
|
||||||
elif contact['type'] == 'openalias':
|
elif contact['type'] in ('openalias', 'lnaddress'):
|
||||||
self._type = PaymentIdentifierType.EMAILLIKE
|
self._type = PaymentIdentifierType.EMAILLIKE
|
||||||
self.emaillike = contact['address']
|
self.emaillike = contact['address']
|
||||||
self.set_state(PaymentIdentifierState.NEED_RESOLVE)
|
self.set_state(PaymentIdentifierState.NEED_RESOLVE)
|
||||||
@@ -649,9 +649,6 @@ class PaymentIdentifier(Logger):
|
|||||||
return pubkey, amount, description
|
return pubkey, amount, description
|
||||||
|
|
||||||
async def resolve_openalias(self, key: str) -> Optional[dict]:
|
async def resolve_openalias(self, key: str) -> Optional[dict]:
|
||||||
# TODO: below check needed? we already matched RE_EMAIL/RE_DOMAIN
|
|
||||||
# if not (('.' in key) and ('<' not in key) and (' ' not in key)):
|
|
||||||
# return None
|
|
||||||
parts = key.split(sep=',') # assuming single line
|
parts = key.split(sep=',') # assuming single line
|
||||||
if parts and len(parts) > 0 and bitcoin.is_address(parts[0]):
|
if parts and len(parts) > 0 and bitcoin.is_address(parts[0]):
|
||||||
return None
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user