1
0

Qt: move nostr_relays to network dialog

This commit is contained in:
ThomasV
2025-05-18 13:39:18 +02:00
parent 79941529d2
commit a213dfca85
3 changed files with 90 additions and 41 deletions

View File

@@ -28,7 +28,8 @@ from enum import IntEnum
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt6.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QMenu, QGridLayout, QComboBox, QLineEdit, QDialog, QVBoxLayout, QHeaderView,
QCheckBox, QTabWidget, QWidget, QLabel, QPushButton, QHBoxLayout
QCheckBox, QTabWidget, QWidget, QLabel, QPushButton, QHBoxLayout,
QListWidget, QListWidgetItem,
)
from PyQt6.QtGui import QIntValidator
@@ -37,10 +38,11 @@ from electrum import blockchain
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL
from electrum.network import Network, ProxySettings, is_valid_host, is_valid_port
from electrum.logging import get_logger
from electrum.util import is_valid_websocket_url
from .util import (
Buttons, CloseButton, HelpButton, read_QIcon, char_width_in_lineedit, PasswordLineEdit, QtEventListener,
qt_event_listener, Spinner
qt_event_listener, Spinner, HelpLabel
)
@@ -56,11 +58,12 @@ class NetworkDialog(QDialog, QtEventListener):
self.setWindowTitle(_('Network'))
self.setMinimumSize(500, 500)
self.tabs = tabs = QTabWidget()
self._blockchain_tab = blockchain_tab = ServerWidget(network)
self._proxy_tab = proxy_tab = ProxyWidget(network)
tabs.addTab(blockchain_tab, _('Overview'))
tabs.addTab(proxy_tab, _('Proxy'))
self._blockchain_tab = ServerWidget(network)
self._proxy_tab = ProxyWidget(network)
self._nostr_tab = NostrWidget(network)
tabs.addTab(self._blockchain_tab, _('Electrum servers'))
tabs.addTab(self._nostr_tab, _('Nostr'))
tabs.addTab(self._proxy_tab, _('Proxy'))
vbox = QVBoxLayout(self)
vbox.addWidget(self.tabs)
vbox.addLayout(Buttons(CloseButton(self)))
@@ -360,6 +363,7 @@ class ProxyWidget(QWidget):
class ServerWidget(QWidget, QtEventListener):
def __init__(self, network: Network, parent=None):
super().__init__(parent)
self.network = network
@@ -502,3 +506,55 @@ class ServerWidget(QWidget, QtEventListener):
net_params = net_params._replace(server=server,
auto_connect=self.autoconnect_cb.isChecked())
self.network.run_from_another_thread(self.network.set_parameters(net_params))
class NostrWidget(QWidget, QtEventListener):
def __init__(self, network: Network, parent=None):
super().__init__(parent)
self.network = network
self.config = network.config
vbox = QVBoxLayout()
self.setLayout(vbox)
nostr_relays_label = HelpLabel.from_configvar(self.config.cv.NOSTR_RELAYS)
self.relays_list = QListWidget()
self.relay_edit = QLineEdit()
self.relay_edit.textChanged.connect(self.on_relay_edited)
vbox.addWidget(nostr_relays_label)
vbox.addWidget(self.relays_list)
vbox.addStretch()
self.add_button = QPushButton(_('Add'))
self.add_button.clicked.connect(self.add_relay)
self.add_button.setEnabled(False)
remove_button = QPushButton(_('Remove'))
remove_button.clicked.connect(self.remove_relay)
reset_button = QPushButton(_('Reset'))
reset_button.clicked.connect(self.reset_relays)
buttons = Buttons(self.relay_edit, self.add_button, remove_button, reset_button)
vbox.addLayout(buttons)
self.update_list()
def on_relay_edited(self, text):
self.add_button.setEnabled(is_valid_websocket_url(text))
def update_list(self):
self.relays_list.clear()
for relay in self.config.get_nostr_relays():
item = QListWidgetItem(relay)
self.relays_list.addItem(item)
def add_relay(self):
relay = self.relay_edit.text()
self.config.add_nostr_relay(relay)
self.update_list()
def remove_relay(self):
item = self.relays_list.currentItem()
if item is None:
return
self.config.remove_nostr_relay(item.text())
self.update_list()
def reset_relays(self):
self.config.NOSTR_RELAYS = None
self.update_list()

View File

@@ -32,7 +32,7 @@ from PyQt6.QtWidgets import (QComboBox, QTabWidget, QDialog, QSpinBox, QCheckB
from electrum.i18n import _, languages
from electrum import util
from electrum.util import base_units_list, event_listener, is_valid_websocket_url
from electrum.util import base_units_list, event_listener
from electrum.gui import messages
@@ -176,22 +176,6 @@ class SettingsDialog(QDialog, QtEventListener):
self.set_alias_color()
self.alias_e.editingFinished.connect(self.on_alias_edit)
nostr_relays_label = HelpLabel.from_configvar(self.config.cv.NOSTR_RELAYS)
nostr_relays = self.config.NOSTR_RELAYS
self.nostr_relays_e = QLineEdit(nostr_relays)
def on_nostr_edit():
relays: Dict[str, None] = dict() # dicts keep insertion order
for url in self.nostr_relays_e.text().split(','):
url = url.strip()
if url and is_valid_websocket_url(url):
relays[url] = None
if relays.keys():
self.config.NOSTR_RELAYS = ",".join(relays.keys())
else: # if no valid relays are given, assign default relays from config
self.config.NOSTR_RELAYS = None
self.nostr_relays_e.setText(self.config.NOSTR_RELAYS)
self.nostr_relays_e.editingFinished.connect(on_nostr_edit)
msat_cb = checkbox_from_configvar(self.config.cv.BTC_AMOUNTS_PREC_POST_SAT)
msat_cb.setChecked(self.config.BTC_AMOUNTS_PREC_POST_SAT > 0)
@@ -402,7 +386,6 @@ class SettingsDialog(QDialog, QtEventListener):
misc_widgets = []
misc_widgets.append((updatecheck_cb, None))
misc_widgets.append((filelogging_cb, None))
misc_widgets.append((nostr_relays_label, self.nostr_relays_e))
misc_widgets.append((alias_label, self.alias_e))
misc_widgets.append((qr_label, qr_combo))

View File

@@ -1,30 +1,23 @@
import json
import threading
import time
import os
import stat
from decimal import Decimal
from typing import Union, Optional, Dict, Sequence, Tuple, Any, Set, Callable, AbstractSet
from numbers import Real
from typing import Union, Optional, Dict, Sequence, Any, Set, Callable, AbstractSet
from functools import cached_property
from copy import deepcopy
from . import util
from . import constants
from . import invoices
from .util import base_units, base_unit_name_to_decimal_point, decimal_point_to_base_unit_name, UnknownBaseUnit, DECIMAL_POINT_DEFAULT
from .util import format_satoshis, format_fee_satoshis, os_chmod
from .util import user_dir, make_dir
from .util import is_valid_websocket_url
from .lnutil import LN_MAX_FUNDING_SAT_LEGACY
from .i18n import _
from .logging import get_logger, Logger
_logger = get_logger(__name__)
@@ -182,7 +175,6 @@ class SimpleConfig(Logger):
# a thread-safe way.
self.lock = threading.RLock()
# The following two functions are there for dependency injection when
# testing.
if read_user_config_function is None:
@@ -401,14 +393,12 @@ class SimpleConfig(Logger):
def convert_version_3(self):
if not self._is_upgrade_method_needed(2, 2):
return
base_unit = self.user_config.get('base_unit')
if isinstance(base_unit, str):
self._set_key_in_user_config('base_unit', None)
map_ = {'btc':8, 'mbtc':5, 'ubtc':2, 'bits':2, 'sat':0}
map_ = {'btc': 8, 'mbtc': 5, 'ubtc': 2, 'bits': 2, 'sat': 0}
decimal_point = map_.get(base_unit.lower())
self._set_key_in_user_config('decimal_point', decimal_point)
self.set_key('config_version', 3)
def _is_upgrade_method_needed(self, min_version, max_version):
@@ -557,6 +547,26 @@ class SimpleConfig(Logger):
def get_decimal_point(self):
return self.decimal_point
def get_nostr_relays(self) -> Sequence[str]:
relays = []
for url in self.NOSTR_RELAYS.split(','):
url = url.strip()
if url and is_valid_websocket_url(url):
relays.append(url)
return relays
def add_nostr_relay(self, relay: str):
l = self.get_nostr_relays()
if is_valid_websocket_url(relay) and relay not in l:
l.append(relay)
self.NOSTR_RELAYS = ','.join(l)
def remove_nostr_relay(self, relay: str):
l = self.get_nostr_relays()
if relay in l:
l.remove(relay)
self.NOSTR_RELAYS = ','.join(l)
def __setattr__(self, name, value):
"""Disallows setting instance attributes outside __init__.
@@ -719,9 +729,9 @@ Warning: setting this to too low will result in lots of payment failures."""),
TEST_SHUTDOWN_FEE_RANGE = ConfigVar('test_shutdown_fee_range', default=None)
TEST_SHUTDOWN_LEGACY = ConfigVar('test_shutdown_legacy', default=False, type_=bool)
FEE_POLICY = ConfigVar('fee_policy', default='eta:2', type_=str) # exposed to GUI
FEE_POLICY_LIGHTNING = ConfigVar('fee_policy_lightning', default='eta:2', type_=str) # for txbatcher (sweeping)
FEE_POLICY_SWAPS = ConfigVar('fee_policy_swaps', default='eta:2', type_=str) # for txbatcher (sweeping and sending if we are a swapserver)
FEE_POLICY = ConfigVar('fee_policy', default='eta:2', type_=str) # exposed to GUI
FEE_POLICY_LIGHTNING = ConfigVar('fee_policy_lightning', default='eta:2', type_=str) # for txbatcher (sweeping)
FEE_POLICY_SWAPS = ConfigVar('fee_policy_swaps', default='eta:2', type_=str) # for txbatcher (sweeping and sending if we are a swapserver)
RPC_USERNAME = ConfigVar('rpcuser', default=None, type_=str)
RPC_PASSWORD = ConfigVar('rpcpassword', default=None, type_=str)