diff --git a/electrum/gui/qt/confirm_tx_dialog.py b/electrum/gui/qt/confirm_tx_dialog.py index 3935db7fc..3961c0901 100644 --- a/electrum/gui/qt/confirm_tx_dialog.py +++ b/electrum/gui/qt/confirm_tx_dialog.py @@ -28,7 +28,6 @@ from decimal import Decimal from functools import partial from typing import TYPE_CHECKING, Optional, Union -from electrum_aionostr.util import from_nip19 from PyQt6.QtCore import Qt, QTimer from PyQt6.QtGui import QIcon from PyQt6.QtWidgets import (QHBoxLayout, QVBoxLayout, QLabel, QGridLayout, QPushButton, QToolButton, @@ -47,14 +46,13 @@ from electrum.submarine_swaps import NostrTransport, HttpTransport from .seed_dialog import seed_warning_msg from .util import (WindowModalDialog, ColorScheme, HelpLabel, Buttons, CancelButton, WWLabel, - read_QIcon, debug_widget_layouts, qt_event_listener, QtEventListener, IconLabel, - pubkey_to_q_icon) + read_QIcon, debug_widget_layouts, qt_event_listener, QtEventListener, IconLabel) from .transaction_dialog import TxSizeLabel, TxFiatLabel, TxInOutWidget from .fee_slider import FeeSlider, FeeComboBox from .amountedit import FeerateEdit, BTCAmountEdit from .locktimeedit import LockTimeEdit from .my_treeview import QMenuWithConfig -from .swap_dialog import SwapServerDialog +from .swap_dialog import SwapProvidersButton if TYPE_CHECKING: from .main_window import ElectrumWindow @@ -303,7 +301,7 @@ class TxEditor(WindowModalDialog, QtEventListener, Logger): self.tab_widget.removeTab(0) # always show onchain payment tab - self.tab_widget.addTab(self.onchain_tab, _('Onchain')) + self.tab_widget.addTab(self.onchain_tab, _('Onchain Transaction')) allow_swaps = self.allow_preview and self.payee_outputs # allow_preview is false for ln channel opening txs if self.config.WALLET_ENABLE_SUBMARINE_PAYMENTS and allow_swaps: @@ -728,10 +726,7 @@ class TxEditor(WindowModalDialog, QtEventListener, Logger): vbox.addWidget(self.submarine_stacked_widget) vbox.addStretch(1) - self.server_button = QPushButton() - self.server_button.clicked.connect(self.choose_swap_server) - self.server_button.setEnabled(False) - self.server_button.setVisible(False) + self.server_button = SwapProvidersButton(lambda: self.swap_transport, self.config, self.main_window) self.submarine_ok_button = QPushButton(_('OK')) self.submarine_ok_button.setDefault(True) @@ -830,9 +825,8 @@ class TxEditor(WindowModalDialog, QtEventListener, Logger): # we couldn't even connect to the relays, this transport is useless. maybe network issues. return False - def choose_swap_server(self) -> None: - assert isinstance(self.swap_transport, NostrTransport), self.swap_transport - self.main_window.choose_swapserver_dialog(self.swap_transport) + @qt_event_listener + def on_event_swap_provider_changed(self): self.update_submarine_tab() def start_submarine_swap(self): @@ -881,20 +875,7 @@ class TxEditor(WindowModalDialog, QtEventListener, Logger): return # Update the swapserver selection button text - if isinstance(self.swap_transport, NostrTransport): - self.server_button.setVisible(True) - self.server_button.setEnabled(True) - if self.config.SWAPSERVER_NPUB: - pubkey = from_nip19(self.config.SWAPSERVER_NPUB)['object'].hex() - self.server_button.setIcon(pubkey_to_q_icon(pubkey)) - self.server_button.setText( - f' {len(self.swap_transport.get_recent_offers())} ' + - (_('providers') if len(self.swap_transport.get_recent_offers()) != 1 else _('provider')) - ) - else: - # HTTPTransport or no Network, not showing server selection button - self.server_button.setEnabled(False) - self.server_button.setVisible(False) + self.server_button.update() if not self.swap_manager.is_initialized.is_set(): # connected to nostr relays but couldn't find swapserver announcement @@ -996,6 +977,7 @@ class TxEditor(WindowModalDialog, QtEventListener, Logger): @qt_event_listener def on_event_swap_offers_changed(self, _): + self.server_button.update() if self.ongoing_swap_transport_connection_attempt \ and not self.ongoing_swap_transport_connection_attempt.done(): return diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py index cfa85b904..4c501f44c 100644 --- a/electrum/gui/qt/swap_dialog.py +++ b/electrum/gui/qt/swap_dialog.py @@ -9,7 +9,7 @@ from PyQt6.QtWidgets import QTreeWidget, QTreeWidgetItem, QHeaderView from electrum_aionostr.util import from_nip19 from electrum.i18n import _ -from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates, UserCancelled +from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates, UserCancelled, trigger_callback from electrum.bitcoin import DummyAddress from electrum.transaction import PartialTxOutput, PartialTransaction from electrum.fee_policy import FeePolicy @@ -43,6 +43,43 @@ ROLE_NPUB = Qt.ItemDataRole.UserRole + 1000 class InvalidSwapParameters(Exception): pass +class SwapProvidersButton(QPushButton): + + def __init__(self, transport_getter, config, main_window): + """parent must have a transport() method""" + QPushButton.__init__(self) + self.config = config + self.transport_getter = transport_getter + self.main_window = main_window + self.clicked.connect(self.choose_swap_server) + self.update() + + def update(self): + transport = self.transport_getter() + if not isinstance(transport, NostrTransport): + # HTTPTransport or no Network, not showing server selection button + self.setEnabled(False) + self.setVisible(False) + return + self.setEnabled(True) + self.setVisible(True) + offer_count = len(transport.get_recent_offers()) + button_text = f' {offer_count} ' + (_('swap providers') if offer_count != 1 else _('swap provider')) + self.setText(button_text) + # update icon + if self.config.SWAPSERVER_NPUB: + pubkey = from_nip19(self.config.SWAPSERVER_NPUB)['object'].hex() + self.setIcon(pubkey_to_q_icon(pubkey)) + + def choose_swap_server(self) -> None: + transport = self.transport_getter() + assert isinstance(transport, NostrTransport), transport + self.main_window.choose_swapserver_dialog(transport) # type: ignore + self.update() + trigger_callback('swap_provider_changed') + + + class SwapDialog(WindowModalDialog, QtEventListener): def __init__( @@ -63,12 +100,8 @@ class SwapDialog(WindowModalDialog, QtEventListener): self.is_reverse = is_reverse if is_reverse is not None else True vbox = QVBoxLayout(self) - self.server_button = QPushButton() - self.set_server_button_text(len(transport.get_recent_offers()) \ - if not self.config.SWAPSERVER_URL and isinstance(transport, NostrTransport) else 0 - ) - self.server_button.clicked.connect(lambda: self.choose_swap_server(transport)) - self.server_button.setEnabled(not self.config.SWAPSERVER_URL) + self.transport = transport + self.server_button = SwapProvidersButton(lambda: self.transport, self.config, self.window) self.description_label = WWLabel(self.get_description()) self.send_amount_e = BTCAmountEdit(self.window.get_decimal_point) self.recv_amount_e = BTCAmountEdit(self.window.get_decimal_point) @@ -158,7 +191,7 @@ class SwapDialog(WindowModalDialog, QtEventListener): @qt_event_listener def on_event_swap_offers_changed(self, recent_offers: Sequence['SwapOffer']): - self.set_server_button_text(len(recent_offers)) + self.server_button.update() if not self.ok_button.isEnabled(): # only update the dialog with the new offer if the user hasn't entered an amount yet. # if the user has already entered an amount we prefer the swap to fail due to outdated @@ -166,9 +199,10 @@ class SwapDialog(WindowModalDialog, QtEventListener): # due to an update happening just before the user initiated the swap self.update() - def set_server_button_text(self, offer_count: int): - button_text = f' {offer_count} ' + (_('providers') if offer_count != 1 else _('provider')) - self.server_button.setText(button_text) + @qt_event_listener + def on_event_swap_provider_changed(self): + self.update() + self.update_send_receive() def timer_actions(self): if self.needs_tx_update: @@ -298,9 +332,6 @@ class SwapDialog(WindowModalDialog, QtEventListener): self.server_fee_label.setText(server_fee_str) self.server_fee_label.repaint() # macOS hack for #6269 self.needs_tx_update = True - # update icon - pubkey = from_nip19(self.config.SWAPSERVER_NPUB)['object'].hex() if self.config.SWAPSERVER_NPUB else '' - self.server_button.setIcon(pubkey_to_q_icon(pubkey)) def get_client_swap_limits_sat(self) -> Tuple[int, int]: """Returns the (min, max) client swap limits in sat.""" @@ -452,11 +483,6 @@ class SwapDialog(WindowModalDialog, QtEventListener): capacityType="receiving" if self.is_reverse else "sending", ) - def choose_swap_server(self, transport: 'SwapServerTransport') -> None: - self.window.choose_swapserver_dialog(transport) # type: ignore - self.update() - self.update_send_receive() - class SwapServerDialog(WindowModalDialog, QtEventListener):