diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index c850cdb..5abf99e 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 0.1.1
+current_version = 0.1.2
commit = False
tag = False
allow_dirty = True
diff --git a/.gitignore b/.gitignore
index bc69401..cf114ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ build_info.json
settings.json
/appimages/
temp_build_constant.py
+.DS_Store
diff --git a/binary/native_auth_windows.exe b/binary/native_auth_windows.exe
deleted file mode 100644
index c20a154..0000000
Binary files a/binary/native_auth_windows.exe and /dev/null differ
diff --git a/pylint_logs.txt b/pylint_logs.txt
deleted file mode 100644
index 6666ced..0000000
--- a/pylint_logs.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-
---------------------------------------------------------------------
-Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
diff --git a/pyproject.toml b/pyproject.toml
index e70309b..c14cbcb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "iris-wallet-desktop"
-version = "0.1.1"
+version = "0.1.2"
description = ""
readme = "README.md"
license = ""
diff --git a/src/main.py b/src/main.py
index 62eb4db..abf219f 100755
--- a/src/main.py
+++ b/src/main.py
@@ -58,7 +58,6 @@ def __init_ui__(self):
def resizeEvent(self, event): # pylint:disable=invalid-name
"""Handle window resize and trigger toaster repositioning."""
- # ToasterManager.on_resize(event.size())
ToasterManager.reposition_toasters()
super().resizeEvent(event)
@@ -72,7 +71,7 @@ def closeEvent(self, event): # pylint:disable=invalid-name
cache.invalidate_cache()
wallet_type: WalletType = SettingRepository.get_wallet_type()
if wallet_type.value == WalletType.REMOTE_TYPE_WALLET.value or page_name in excluded_page:
- QApplication.instance().quit()
+ QApplication.instance().exit()
else:
self.show_backup_progress()
# Ignore the close event until the backup is complete
@@ -95,7 +94,6 @@ def show_backup_progress(self):
backup_configure_dialog_box.exec()
else:
self.progress_dialog.exec(True)
- # self.progress_dialog.start_process(True)
self.progress_dialog.exec()
diff --git a/src/model/help_card_content_model.py b/src/model/help_card_content_model.py
index dcc0760..d0e1956 100644
--- a/src/model/help_card_content_model.py
+++ b/src/model/help_card_content_model.py
@@ -7,12 +7,15 @@
from pydantic import BaseModel
from pydantic import HttpUrl
+from src.data.repository.setting_repository import SettingRepository
+from src.model.enums.enums_model import NetworkEnumModel
+
class HelpCardModel(BaseModel):
"""Model for a single help card."""
title: str
detail: str
- links: list[HttpUrl]
+ links: list[HttpUrl] | None = None
class HelpCardContentModel(BaseModel):
@@ -24,24 +27,45 @@ def create_default(cls):
"""Factory method to create a default instance of HelpCardContentModel"""
card_content = [
HelpCardModel(
- title='Why can I get TESTNET Bitcoins?',
- detail='You can get Testnet Bitcoin by using one of the many available faucets. Below are a few linked examples, but you can always find more using a search engine:',
- links=[
- 'https://testnet-faucet.mempool.co/',
- 'https://bitcoinfaucet.uo1.net/',
- 'https://coinfaucet.eu/en/btc-testnet/',
- 'https://testnet-faucet.com/btc-testnet/',
- ],
+ title='Where can I learn more about RGB?',
+ detail='Visit rgb.info for resources and documentation.',
),
HelpCardModel(
title="Why do I see outgoing Bitcoin transactions that I didn't authorize?",
- detail='You can get Testnet Bitcoin by using one of the many available faucet, below are few linked examples but you can always find more using a search engine:',
+ detail='In the RGB protocol assets need to be assigned to a Bitcoin output, if you do not have available UTXOs to receive, issue, or send yourself change assets, the wallet will use the available bitcoin balance to generate new UTXOs. Such transactions are marked in the transaction list as "internal"',
+ ),
+ HelpCardModel(
+ title='What is the minimum bitcoin balance needed to issue and receive RGB assets?',
+ detail='To create a set of UTXOs needed to issue and receive assets the initial bitcoin balance needs to be at least 10,000 satoshis',
+ ),
+ HelpCardModel(
+ title='Where can I send feedback or ask for support?',
+ detail='For support and feedback there is a dedicated Telegram group:',
links=[
- 'https://testnet-faucet.mempool.co/',
- 'https://bitcoinfaucet.uo1.net/',
- 'https://coinfaucet.eu/en/btc-testnet/',
- 'https://testnet-faucet.com/btc-testnet/',
+ 'https://t.me/IrisWallet',
],
),
]
+ network = SettingRepository.get_wallet_network()
+ if network == NetworkEnumModel.REGTEST:
+ card_content.append(
+ HelpCardModel(
+ title='Where can I get REGTEST Bitcoins?',
+ detail='You can receive Regtest Bitcoin by using our Telegram bot. Click the link below to request funds:',
+ links=['https://t.me/rgb_lightning_bot'],
+ ),
+ )
+ else: # Default to Testnet
+ card_content.append(
+ HelpCardModel(
+ title='Where can I get TESTNET Bitcoins?',
+ detail='You can get Testnet Bitcoin by using one of the many available faucets. Below are a few linked examples, but you can always find more using a search engine:',
+ links=[
+ 'https://testnet-faucet.mempool.co/',
+ 'https://bitcoinfaucet.uo1.net/',
+ 'https://coinfaucet.eu/en/btc-testnet/',
+ 'https://testnet-faucet.com/btc-testnet/',
+ ],
+ ),
+ )
return cls(card_content=card_content)
diff --git a/src/translations/en_IN.qm b/src/translations/en_IN.qm
index a07bdf5..9564cc0 100644
Binary files a/src/translations/en_IN.qm and b/src/translations/en_IN.qm differ
diff --git a/src/translations/en_IN.ts b/src/translations/en_IN.ts
index 1437701..04b0f81 100644
--- a/src/translations/en_IN.ts
+++ b/src/translations/en_IN.ts
@@ -1665,8 +1665,20 @@ If you understand the above remarks and wish to proceed, press the button below
RGB invoice
- copied
- Copied!
+ copied
+ Copied!
+
+
+ local_balance
+ Local Balance
+
+
+ remote_balance
+ Remote Balance
+
+
+ asset
+ Asset
data_directory_path_label
diff --git a/src/utils/common_utils.py b/src/utils/common_utils.py
index 15793f1..b44eb8a 100644
--- a/src/utils/common_utils.py
+++ b/src/utils/common_utils.py
@@ -509,7 +509,7 @@ def sigterm_handler(_sig, _frame):
# Stop the LN node server and quit the application
ln_node_manager = LnNodeServerManager.get_instance()
ln_node_manager.stop_server_from_close_button()
- QApplication.instance().quit()
+ QApplication.instance().exit()
def set_number_validator(input_widget: QLineEdit) -> None:
diff --git a/src/version.py b/src/version.py
index dbdd9e0..e366a01 100644
--- a/src/version.py
+++ b/src/version.py
@@ -6,4 +6,4 @@
"""
from __future__ import annotations
-__version__ = '0.1.1'
+__version__ = '0.1.2'
diff --git a/src/viewmodels/enter_password_view_model.py b/src/viewmodels/enter_password_view_model.py
index 2b3c203..e9b509a 100644
--- a/src/viewmodels/enter_password_view_model.py
+++ b/src/viewmodels/enter_password_view_model.py
@@ -121,7 +121,7 @@ def on_error(self, error: CommonException):
if error.message == ERROR_NETWORK_MISMATCH:
local_store.clear_settings()
MessageBox('critical', error.message)
- QApplication.instance().quit()
+ QApplication.instance().exit()
self.message.emit(
ToastPreset.ERROR,
error.message or ERROR_SOMETHING_WENT_WRONG,
diff --git a/src/viewmodels/header_frame_view_model.py b/src/viewmodels/header_frame_view_model.py
index 73c6b0f..fd74c39 100644
--- a/src/viewmodels/header_frame_view_model.py
+++ b/src/viewmodels/header_frame_view_model.py
@@ -5,6 +5,7 @@
from PySide6.QtCore import QObject
from PySide6.QtCore import QThread
+from PySide6.QtCore import QTimer
from PySide6.QtCore import Signal
from src.utils.constant import PING_DNS_ADDRESS_FOR_NETWORK_CHECK
@@ -12,26 +13,17 @@
class NetworkCheckerThread(QThread):
- """View model to handle network connectivity"""
+ """Thread to handle network connectivity checking."""
network_status_signal = Signal(bool)
- _instance = None
-
- def __init__(self):
- super().__init__()
- self.running = True
def run(self):
- """Run the network checking loop."""
- while self.running:
- is_connected = self.check_internet_conn()
- self.network_status_signal.emit(is_connected)
- # Wait 5 seconds before the next check
- self.msleep(PING_DNS_SERVER_CALL_INTERVAL)
+ """Run the network check once."""
+ is_connected = self.check_internet_conn()
+ self.network_status_signal.emit(is_connected)
def check_internet_conn(self):
- """Check internet connection by making a request to the specified URL."""
+ """Check internet connection and return status."""
try:
- # Attempt to resolve the hostname of Google to test internet
socket.create_connection(
(PING_DNS_ADDRESS_FOR_NETWORK_CHECK, 53), timeout=3,
)
@@ -39,19 +31,26 @@ def check_internet_conn(self):
except OSError:
return False
- def stop(self):
- """Stop the thread."""
- self.running = False
- self.quit()
- self.wait()
-
class HeaderFrameViewModel(QObject):
- """Handle network connectivity"""
+ """Handles network connectivity in the UI."""
network_status_signal = Signal(bool)
def __init__(self):
- super().__init__() # Call the parent constructor
+ super().__init__()
+
+ self.network_checker = None
+
+ # Use QTimer in the main thread
+ self.timer = QTimer(self)
+ self.timer.setInterval(PING_DNS_SERVER_CALL_INTERVAL)
+ self.timer.timeout.connect(self.start_network_check)
+
+ # Start checking
+ self.timer.start()
+
+ def start_network_check(self):
+ """Start a new network check using a separate thread."""
self.network_checker = NetworkCheckerThread()
self.network_checker.network_status_signal.connect(
self.handle_network_status,
@@ -59,9 +58,9 @@ def __init__(self):
self.network_checker.start()
def handle_network_status(self, is_connected):
- """Handle the network status change."""
+ """Emit network status signal."""
self.network_status_signal.emit(is_connected)
def stop_network_checker(self):
- """Stop the network checker when no longer needed."""
- self.network_checker.stop()
+ """Stop network checking when it's no longer needed."""
+ self.timer.stop()
diff --git a/src/viewmodels/main_view_model.py b/src/viewmodels/main_view_model.py
index c7d9683..d0f710a 100644
--- a/src/viewmodels/main_view_model.py
+++ b/src/viewmodels/main_view_model.py
@@ -12,6 +12,7 @@
from src.viewmodels.enter_password_view_model import EnterWalletPasswordViewModel
from src.viewmodels.faucets_view_model import FaucetsViewModel
from src.viewmodels.fee_rate_view_model import EstimateFeeViewModel
+from src.viewmodels.header_frame_view_model import HeaderFrameViewModel
from src.viewmodels.issue_rgb20_view_model import IssueRGB20ViewModel
from src.viewmodels.issue_rgb25_view_model import IssueRGB25ViewModel
from src.viewmodels.ln_endpoint_view_model import LnEndpointViewModel
@@ -108,3 +109,5 @@ def __init__(self, page_navigation):
)
self.estimate_fee_view_model = EstimateFeeViewModel()
+
+ self.header_frame_view_model = HeaderFrameViewModel()
diff --git a/src/viewmodels/set_wallet_password_view_model.py b/src/viewmodels/set_wallet_password_view_model.py
index bfdd6fa..3e32ced 100644
--- a/src/viewmodels/set_wallet_password_view_model.py
+++ b/src/viewmodels/set_wallet_password_view_model.py
@@ -181,7 +181,7 @@ def on_error(self, exc: CommonException):
if exc.message == ERROR_NETWORK_MISMATCH:
local_store.clear_settings()
MessageBox('critical', exc.message)
- QApplication.instance().quit()
+ QApplication.instance().exit()
self.message.emit(
ToastPreset.ERROR,
exc.message or 'Something went wrong',
diff --git a/src/viewmodels/setting_view_model.py b/src/viewmodels/setting_view_model.py
index 532f270..95909aa 100644
--- a/src/viewmodels/setting_view_model.py
+++ b/src/viewmodels/setting_view_model.py
@@ -544,7 +544,7 @@ def set_bitcoind_host(self, bitcoind_host: str, password: str):
)
def set_bitcoind_port(self, bitcoind_port: int, password: str):
- """Sets the Default bitcoind host."""
+ """Sets the Default bitcoind port."""
self.is_loading.emit(True)
try:
self.password = password
@@ -562,7 +562,7 @@ def set_bitcoind_port(self, bitcoind_port: int, password: str):
)
def set_announce_address(self, announce_address: str, password: str):
- """Sets the Default bitcoind host."""
+ """Sets the Default announce address."""
self.is_loading.emit(True)
try:
@@ -581,7 +581,7 @@ def set_announce_address(self, announce_address: str, password: str):
)
def set_announce_alias(self, announce_alias: str, password: str):
- """Sets the Default bitcoind host."""
+ """Sets the Default announce alias."""
self.is_loading.emit(True)
try:
self.password = password
@@ -599,7 +599,7 @@ def set_announce_alias(self, announce_alias: str, password: str):
)
def set_min_confirmation(self, min_confirmation: int):
- """Sets the default fee rate."""
+ """Sets the default min confirmation."""
try:
success: IsDefaultMinConfirmationSet = SettingCardRepository.set_default_min_confirmation(
min_confirmation,
diff --git a/src/viewmodels/splash_view_model.py b/src/viewmodels/splash_view_model.py
index 8ccaa6f..3ee4681 100644
--- a/src/viewmodels/splash_view_model.py
+++ b/src/viewmodels/splash_view_model.py
@@ -68,7 +68,7 @@ def on_error(self, error: Exception):
error, CommonException,
) else ERROR_SOMETHING_WENT_WRONG
ToastManager.error(description=description)
- QApplication.instance().quit()
+ QApplication.instance().exit()
def is_login_authentication_enabled(self, view_model: WalletTransferSelectionViewModel):
"""Check login authentication enabled"""
@@ -121,7 +121,7 @@ def on_error_of_unlock_api(self, error: Exception):
if error_message in [ERROR_CONNECTION_FAILED_WITH_LN, ERROR_REQUEST_TIMEOUT]:
MessageBox('critical', message_text=ERROR_CONNECTION_FAILED_WITH_LN)
- QApplication.instance().quit()
+ QApplication.instance().exit()
# Log the error and display a toast message
logger.error(
diff --git a/src/viewmodels/wallet_and_transfer_selection_viewmodel.py b/src/viewmodels/wallet_and_transfer_selection_viewmodel.py
index cb6a994..2d3c20f 100644
--- a/src/viewmodels/wallet_and_transfer_selection_viewmodel.py
+++ b/src/viewmodels/wallet_and_transfer_selection_viewmodel.py
@@ -131,7 +131,7 @@ def on_ln_node_error(self, code: int, error: str):
str(error), str(code),
)
MessageBox('critical', message_text=ERROR_UNABLE_TO_START_NODE)
- QApplication.instance().quit()
+ QApplication.instance().exit()
def on_ln_node_already_running(self):
"""Log and toast when node already running"""
diff --git a/src/views/components/keyring_error_dialog.py b/src/views/components/keyring_error_dialog.py
index 878f2b7..0995abb 100644
--- a/src/views/components/keyring_error_dialog.py
+++ b/src/views/components/keyring_error_dialog.py
@@ -285,7 +285,7 @@ def handle_when_origin_page_set_wallet(self):
else:
local_store.clear_settings()
self.close()
- QApplication.instance().quit()
+ QApplication.instance().exit()
except CommonException as exc:
self.error.emit(exc.message)
ToastManager.error(
diff --git a/src/views/components/on_close_progress_dialog.py b/src/views/components/on_close_progress_dialog.py
index 1193d0b..09e30ab 100644
--- a/src/views/components/on_close_progress_dialog.py
+++ b/src/views/components/on_close_progress_dialog.py
@@ -1,7 +1,7 @@
"""
Module for handling the OnCloseDialogBox, which manages the closing process of application
"""
-# pylint: disable=E1121
+# pylint: disable=E1121,too-many-instance-attributes
from __future__ import annotations
from PySide6.QtCore import QProcess
@@ -27,6 +27,7 @@
from src.utils.ln_node_manage import LnNodeServerManager
from src.utils.logging import logger
from src.utils.worker import ThreadManager
+from src.viewmodels.header_frame_view_model import HeaderFrameViewModel
from src.views.ui_restore_mnemonic import RestoreMnemonicWidget
@@ -59,6 +60,7 @@ def __init__(self, parent=None):
self.ln_node_manage.process_finished_on_request_app_close_error.connect(
self._on_error_of_closing_node,
)
+ self.header_frame_view_model = HeaderFrameViewModel()
# Set minimum size for flexibility but still prevent excessive resizing
self.setMinimumSize(200, 200)
@@ -190,7 +192,7 @@ def _on_error_of_closing_node(self):
self._update_status(ERROR_UNABLE_TO_STOP_NODE)
self.qmessage_info = ERROR_UNABLE_TO_STOP_NODE
QMessageBox.critical(self, 'Failed', self.qmessage_info)
- QApplication.instance().quit()
+ QApplication.instance().exit()
def _on_success_close_node(self):
"""
@@ -198,7 +200,8 @@ def _on_success_close_node(self):
"""
self.is_node_closing_onprogress = False
self._update_status('The node closed successfully!')
- QApplication.instance().quit()
+ self.header_frame_view_model.stop_network_checker()
+ QApplication.instance().exit()
def _close_node_app(self):
"""
@@ -216,7 +219,8 @@ def _close_node_app(self):
self.dialog_title = 'Node closing in progress'
self.ln_node_manage.stop_server_from_close_button()
else:
- QApplication.instance().quit()
+ self.header_frame_view_model.stop_network_checker()
+ QApplication.instance().exit()
# pylint disable(invalid-name) because of closeEvent is internal function of QWidget
def closeEvent(self, event): # pylint:disable=invalid-name
@@ -246,4 +250,4 @@ def closeEvent(self, event): # pylint:disable=invalid-name
)
else:
event.accept()
- QApplication.instance().quit()
+ QApplication.instance().exit()
diff --git a/src/views/qss/channel_management_style.qss b/src/views/qss/channel_management_style.qss
index 2a5f5b2..935e75e 100644
--- a/src/views/qss/channel_management_style.qss
+++ b/src/views/qss/channel_management_style.qss
@@ -103,3 +103,44 @@ QWidget#btc_scroll_area_widget_contents{
background:transparent;
border: none;
}
+
+#asset_id_label,
+#asset_name_label,
+#local_balance_label,
+#status_label,
+#remote_balance_label{
+ border: none;
+ background: transparent;
+ font: 14px "Inter";
+ color: white;
+ font-weight: 600;
+}
+
+#remote_balance_value,
+#local_balance_value,
+#asset_id,
+#asset_name{
+ border: none;
+ background: transparent;
+ font: 14px "Inter";
+ color: white;
+}
+
+#list_frame{
+ background:transparent;
+ background-color: rgba(21, 28, 52, 1);
+ color:white;
+ font:14px Inter;
+ border-radius:8px;
+ border:none;
+}
+
+#channel_header{
+ border-radius: 8px;
+ background: transparent;
+ background-color: rgb(27, 35, 59);
+}
+QToolTip{
+ background-color: rgba(21, 28, 52, 1);
+ color:white;
+}
diff --git a/src/views/ui_channel_management.py b/src/views/ui_channel_management.py
index c58d7e6..163636d 100644
--- a/src/views/ui_channel_management.py
+++ b/src/views/ui_channel_management.py
@@ -30,6 +30,7 @@
from src.utils.clickable_frame import ClickableFrame
from src.utils.common_utils import generate_identicon
from src.utils.common_utils import get_bitcoin_info_by_network
+from src.utils.common_utils import translate_value
from src.utils.helpers import create_circular_pixmap
from src.utils.helpers import load_stylesheet
from src.utils.render_timer import RenderTimer
@@ -66,11 +67,6 @@ def __init__(self, view_model):
self.list_h_box_layout = None
self.counter_party = None
self.pub_key = None
- self.opened_date = None
- self.asset_remote_balance = None
- self.asset = None
- self.channel_status = None
- self.status = None
self.scroll_v_spacer = None
self.asset_local_balance = None
self.channel_management_loading_screen = None
@@ -80,11 +76,12 @@ def __init__(self, view_model):
self.asset_name = None
self.local_balance = None
self.remote_balance = None
- self.asset_name_logo = None
self.nia_asset_lookup = {}
- self.grid_layout_2 = None
- self.asset_logo_container = None
- self.horizontal_layout_3 = None
+ self.status_pixmap = None
+ self.local_balance_value = None
+ self.remote_balance_value = None
+ self.channel_frame_horizontal_layout = None
+ self.asset_id_value = None
self.setObjectName('channel_management_page')
self.vertical_layout_channel = QVBoxLayout(self)
@@ -132,15 +129,6 @@ def __init__(self, view_model):
self.main_list_v_layout.setObjectName('main_list_v_layout')
self.main_list_v_layout.setContentsMargins(0, 0, 0, 0)
- self.frame = QFrame(self)
- self.frame.setObjectName('header')
- self.frame.setMinimumSize(QSize(0, 70))
-
- self.frame.setFrameShape(QFrame.StyledPanel)
- self.frame.setFrameShadow(QFrame.Raised)
- self.grid_layout = QGridLayout(self.frame)
- self.grid_layout.setContentsMargins(20, 0, 22, 0)
-
self.scroll_area = QScrollArea(self)
self.scroll_area.setObjectName('scroll_area')
self.scroll_area.setAutoFillBackground(False)
@@ -171,8 +159,71 @@ def __init__(self, view_model):
self.vertical_layout_channel.addWidget(self.widget_channel)
self.vertical_layout_2_channel.addLayout(self.horizontal_layout_2)
+ self.channel_header = QFrame(self)
+ self.channel_header.setObjectName('channel_header')
+ self.channel_header.setMinimumSize(QSize(900, 70))
+ self.channel_header.setMaximumSize(QSize(16777215, 70))
+ self.channel_header.setFrameShape(QFrame.Shape.StyledPanel)
+ self.channel_header.setFrameShadow(QFrame.Shadow.Raised)
+
+ self.channel_header_layout = QHBoxLayout(self.channel_header)
+ self.channel_header_layout.setSpacing(6)
+ self.channel_header_layout.setObjectName('channel_header_layout')
+
+ self.asset_logo_label = QLabel(self.channel_header)
+ self.asset_logo_label.setObjectName('asset_logo_label')
+ self.asset_logo_label.setMinimumSize(QSize(40, 40))
+ self.asset_logo_label.setMaximumSize(QSize(40, 40))
+
+ self.channel_header_layout.addWidget(self.asset_logo_label)
+
+ self.asset_name_label = QLabel(self.channel_header)
+ self.asset_name_label.setObjectName('asset_name_label')
+ self.asset_name_label.setMinimumSize(QSize(136, 40))
+ self.channel_header_layout.addWidget(self.asset_name_label)
+
+ self.asset_id_label = QLabel(self.channel_header)
+ self.asset_id_label.setObjectName('asset_id_label')
+ self.asset_id_label.setMinimumSize(QSize(450, 0))
+ self.asset_id_label.setMaximumSize(QSize(16777215, 16777215))
+ self.asset_id_label.setAlignment(
+ Qt.AlignmentFlag.AlignLeading | Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.channel_header_layout.addWidget(self.asset_id_label)
+
+ self.local_balance_label = QLabel(self.channel_header)
+ self.local_balance_label.setObjectName('local_balance_label')
+ self.local_balance_label.setMinimumSize(QSize(136, 0))
+ self.local_balance_label.setAlignment(
+ Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignLeading | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.channel_header_layout.addWidget(self.local_balance_label)
+
+ self.remote_balance_label = QLabel(self.channel_header)
+ self.remote_balance_label.setObjectName('remote_balance_label')
+ self.remote_balance_label.setMinimumSize(QSize(136, 0))
+ self.remote_balance_label.setAlignment(
+ Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignLeading | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.channel_header_layout.addWidget(self.remote_balance_label)
+
+ self.status_label = QLabel(self.channel_header)
+ self.status_label.setObjectName('status_label')
+ self.status_label.setMinimumSize(QSize(60, 0))
+ self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
+
+ self.channel_header_layout.addWidget(self.status_label)
+
+ self.vertical_spacer = QSpacerItem(
+ 20, 78, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding,
+ )
+
+ self.vertical_layout_2_channel.addWidget(self.channel_header)
+
self.scroll_area.setWidget(self.scroll_area_widget_contents)
- self.setup_headers()
self.main_list_v_layout.addWidget(self.scroll_area)
self.vertical_layout_2_channel.addWidget(self.channel_list_widget)
self.retranslate_ui()
@@ -180,44 +231,6 @@ def __init__(self, view_model):
self._view_model.channel_view_model.available_channels()
self._view_model.channel_view_model.get_asset_list()
- def create_header_label(self, text, min_width, alignment):
- """
- Helper function to create header labels.
- """
- label = QLabel(self.frame)
- label.setObjectName('header_label')
- label.setMinimumWidth(min_width)
- label.setText(QCoreApplication.translate('iris_wallet', text, None))
- label.setWordWrap(True)
- label.setStyleSheet(
- 'color: white;font: 14px \"Inter\";\n'
- 'background: transparent;\n'
- 'border: none;\n'
- 'font-weight: 600;\n',
- )
- self.grid_layout.addWidget(
- label, 0, alignment, Qt.AlignLeft if alignment != 1 else Qt.AlignCenter,
- )
- return label
-
- def setup_headers(self):
- """
- Creates and adds header labels to the grid layout.
- """
- column_counter = 0
- for header in self.header_col:
- if header == 'Asset ID':
- self.header_label_asset_id = self.create_header_label(
- header, 450, 1,
- )
- else:
- self.header_labels = self.create_header_label(
- header, 136, column_counter,
- )
- column_counter += 1
-
- self.main_list_v_layout.addWidget(self.frame)
-
def show_available_channels(self):
"""This method shows the available channels."""
for i in reversed(range(self.list_v_box_layout.count())):
@@ -239,27 +252,33 @@ def show_available_channels(self):
self.list_frame.setObjectName('list_frame')
self.list_frame.setMinimumSize(QSize(0, 70))
self.list_frame.setMaximumSize(QSize(16777215, 70))
- self.list_frame.setStyleSheet(
- 'background:transparent;'
- 'background-color: rgba(21, 28, 52, 1);\n'
- 'color:white;\n'
- 'font:14px Inter;\n'
- 'border-radius:8px;\n'
- 'border:none\n',
+ self.list_frame.setFrameShape(QFrame.Shape.StyledPanel)
+ self.list_frame.setFrameShadow(QFrame.Shadow.Raised)
+
+ self.channel_frame_horizontal_layout = QHBoxLayout(self.list_frame)
+ self.channel_frame_horizontal_layout.setSpacing(6)
+ self.channel_frame_horizontal_layout.setContentsMargins(
+ 20, 0, 20, 0,
)
- self.list_frame.setFrameShape(QFrame.StyledPanel)
- self.list_frame.setFrameShadow(QFrame.Raised)
- self.grid_layout_2 = QGridLayout(self.list_frame)
- self.grid_layout_2.setContentsMargins(20, 0, 20, 0)
- self.asset_logo_container = QWidget()
- self.horizontal_layout_3 = QHBoxLayout(self.asset_logo_container)
- self.horizontal_layout_3.setContentsMargins(0, 0, 0, 0)
-
- self.asset_logo = QLabel(self.asset_logo_container)
+
+ self.asset_logo = QLabel(self.list_frame)
self.asset_logo.setObjectName('asset_logo')
- self.asset_logo.setMaximumWidth(40)
+ self.asset_logo.setMinimumSize(QSize(40, 0))
+ self.asset_logo.setMaximumSize(QSize(40, 16777215))
+
+ self.channel_frame_horizontal_layout.addWidget(
+ self.asset_logo, Qt.AlignmentFlag.AlignLeading | Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.asset_name = QLabel(self.list_frame)
+ self.asset_name.setObjectName('asset_name')
+ self.asset_name.setMinimumSize(QSize(136, 40))
if channel.asset_id:
+ for key, value in self._view_model.channel_view_model.total_asset_lookup_list.items():
+ if channel.asset_id == key:
+ self.asset_name.setText(value)
+
img_str = generate_identicon(channel.asset_id)
image = QImage.fromData(
QByteArray.fromBase64(img_str.encode()),
@@ -267,58 +286,58 @@ def show_available_channels(self):
pixmap = QPixmap.fromImage(image)
self.asset_logo.setPixmap(pixmap)
- self.horizontal_layout_3.addWidget(self.asset_logo)
+ self.channel_frame_horizontal_layout.addWidget(self.asset_name)
- self.asset_name = QLabel(self.asset_logo)
- self.asset_name.setObjectName('asset_name')
+ self.asset_id_value = QLabel(self.list_frame)
+ self.asset_id_value.setObjectName('asset_id')
+ self.asset_id_value.setMinimumSize(QSize(450, 0))
+ self.asset_id_value.setText(channel.asset_id)
- if channel.asset_id:
- for key, value in self._view_model.channel_view_model.total_asset_lookup_list.items():
- if channel.asset_id == key:
- self.asset_name.setText(value)
- self.horizontal_layout_3.addWidget(self.asset_name)
- self.asset_logo_container.setMinimumWidth(136)
- self.asset_logo_container.setMinimumHeight(40)
- self.grid_layout_2.addWidget(self.asset_logo_container, 0, 0)
-
- self.asset = QLabel(self.list_frame)
- self.asset.setObjectName('asset_id')
- self.asset.setMinimumWidth(450)
- self.asset.setText(channel.asset_id)
-
- self.grid_layout_2.addWidget(self.asset, 0, 1, Qt.AlignLeft)
-
- self.local_balance = QLabel(self.list_frame)
- self.local_balance.setObjectName('local_balance')
- self.local_balance.setMinimumWidth(136)
- self.local_balance.setText(
+ self.channel_frame_horizontal_layout.addWidget(self.asset_id_value)
+
+ self.local_balance_value = QLabel(self.list_frame)
+ self.local_balance_value.setObjectName('local_balance_value')
+ self.local_balance_value.setMinimumSize(QSize(136, 0))
+ self.local_balance_value.setText(
str(
channel.asset_local_amount if channel.asset_id else int(
channel.outbound_balance_msat/1000,
),
),
)
- self.grid_layout_2.addWidget(
- self.local_balance, 0, 2, Qt.AlignLeft,
+ self.local_balance_value.setAlignment(
+ Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.channel_frame_horizontal_layout.addWidget(
+ self.local_balance_value,
)
- self.remote_balance = QLabel(self.list_frame)
- self.remote_balance.setObjectName('remote_balance')
- self.remote_balance.setMinimumWidth(136)
- self.remote_balance.setText(
+ self.remote_balance_value = QLabel(self.list_frame)
+ self.remote_balance_value.setObjectName('remote_balance_value')
+ self.remote_balance_value.setMinimumSize(QSize(136, 0))
+ self.remote_balance_value.setText(
str(
channel.asset_remote_amount if channel.asset_id else int(
channel.inbound_balance_msat/1000,
),
),
)
+ self.remote_balance_value.setAlignment(
+ Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter,
+ )
+
+ self.channel_frame_horizontal_layout.addWidget(
+ self.remote_balance_value,
+ )
- self.grid_layout_2.addWidget(
- self.remote_balance, 0, 3, Qt.AlignLeft,
+ self.status_pixmap = QLabel(self.list_frame)
+ self.status_pixmap.setObjectName('status_pixmap')
+ self.status_pixmap.setMinimumSize(QSize(60, 0))
+ self.status_pixmap.setStyleSheet(
+ 'padding-left:25px;',
)
- self.status = QLabel(self.list_frame)
- self.status.setObjectName('status')
- self.status.setMaximumSize(QSize(40, 40))
+
color = (
QColor(235, 90, 90) if channel.status == 'Closing' else
QColor(0, 201, 145) if channel.is_usable else
@@ -326,7 +345,7 @@ def show_available_channels(self):
QColor(255, 255, 0)
)
- self.status.setToolTip(
+ self.status_pixmap.setToolTip(
QCoreApplication.translate('iris_wallet_desktop', 'closing', None) if color == QColor(235, 90, 90) else
QCoreApplication.translate('iris_wallet_desktop', 'opening', None) if color == QColor(0, 201, 145) else
QCoreApplication.translate('iris_wallet_desktop', 'offline', None) if color == QColor(169, 169, 169) else
@@ -334,17 +353,16 @@ def show_available_channels(self):
'iris_wallet_desktop', 'pending', None,
),
)
+ self.status_pixmap.setAlignment(Qt.AlignmentFlag.AlignCenter)
pixmap = create_circular_pixmap(16, color)
- self.status.setPixmap(pixmap)
- self.status.setStyleSheet(
- 'padding-left: 20px;',
- )
+ self.status_pixmap.setPixmap(pixmap)
+
+ self.channel_frame_horizontal_layout.addWidget(self.status_pixmap)
- self.grid_layout_2.addWidget(self.status, 0, 4, Qt.AlignLeft)
self.list_v_box_layout.addWidget(self.list_frame)
if channel.asset_id is None:
bitcoin_asset = get_bitcoin_info_by_network()
- self.asset.setText(bitcoin_asset[0])
+ self.asset_id_value.setText(bitcoin_asset[0])
self.asset_name.setText(bitcoin_asset[1])
self.asset_logo.setPixmap(QPixmap(bitcoin_asset[2]))
@@ -410,6 +428,32 @@ def retranslate_ui(self):
'iris_wallet_desktop', 'create_channel', None,
),
)
+ self.status_label.setText(
+ QCoreApplication.translate(
+ 'iris_wallet_desktop', 'status', None,
+ ),
+ )
+
+ self.asset_id_label.setText(
+ QCoreApplication.translate(
+ 'iris_wallet_desktop', 'asset_id', None,
+ ),
+ )
+ self.asset_name_label.setText(
+ QCoreApplication.translate(
+ 'iris_wallet_desktop', 'asset', None,
+ ),
+ )
+ self.local_balance_label.setText(
+ QCoreApplication.translate(
+ 'iris_wallet_desktop', 'local_balance', None,
+ ),
+ )
+ self.remote_balance_label.setText(
+ QCoreApplication.translate(
+ 'iris_wallet_desktop', 'remote_balance', None,
+ ),
+ )
def trigger_render_and_refresh(self):
"""This method start the render timer and perform the channel list refresh"""
diff --git a/src/views/ui_fungible_asset.py b/src/views/ui_fungible_asset.py
index ffc117a..08960fd 100644
--- a/src/views/ui_fungible_asset.py
+++ b/src/views/ui_fungible_asset.py
@@ -102,7 +102,6 @@ def __init__(self, view_model):
self.outbound_amount_header = None
self.symbol_header = None
self.outbound_balance = None
- self.signal_connected = False
self.vertical_layout_fungible_2.addWidget(self.title_frame)
@@ -169,11 +168,6 @@ def __init__(self, view_model):
def show_assets(self):
"""This method creates all the fungible assets elements of the main asset page."""
- self._view_model.receive_bitcoin_view_model.get_bitcoin_address()
- if self.signal_connected:
- self._view_model.receive_bitcoin_view_model.address.disconnect()
- self.signal_connected = False
-
for i in reversed(range(self.vertical_layout_3.count())):
widget = self.vertical_layout_3.itemAt(i).widget()
if widget is not None:
@@ -202,6 +196,9 @@ def show_assets(self):
self.address_header.setMinimumSize(QSize(600, 0))
self.address_header.setMaximumSize(QSize(16777215, 16777215))
self.header_layout.addWidget(self.address_header, 0, 2, Qt.AlignLeft)
+ self.address_header.setStyleSheet(
+ 'padding-left: 10px;',
+ )
self.amount_header = QLabel(self.header_frame)
self.amount_header.setObjectName('amount_header')
@@ -250,7 +247,7 @@ def show_assets(self):
)
self.address_header.setText(
QCoreApplication.translate(
- 'iris_wallet_desktop', 'address', None,
+ 'iris_wallet_desktop', 'asset_id', None,
),
)
self.amount_header.setText(
@@ -325,16 +322,16 @@ def create_fungible_card(self, asset, img_path=None):
self.address.setObjectName('address')
self.address.setMinimumSize(QSize(600, 0))
self.address.setMaximumSize(QSize(16777215, 16777215))
+ self.address.setStyleSheet(
+ 'padding-left:10px;',
+ )
if asset.asset_iface == AssetType.BITCOIN:
- # Connect signal to update label when the address is updated
- self.asset_name.setMinimumSize(QSize(130, 40))
- self._view_model.receive_bitcoin_view_model.address.connect(
- lambda addr, label=self.address: self.set_bitcoin_address(
- label, addr,
- ),
- )
- self.signal_connected = True
+ network = SettingRepository.get_wallet_network()
+ if network == NetworkEnumModel.REGTEST:
+ self.address.setText(TokenSymbol.REGTEST_BITCOIN)
+ elif network == NetworkEnumModel.TESTNET:
+ self.address.setText(TokenSymbol.TESTNET_BITCOIN)
else:
self.asset_name.setMinimumSize(QSize(135, 40))
self.address.setText(asset.asset_id)
@@ -521,7 +518,3 @@ def show_faucet_unavailability_message(self):
ToastManager.info(
description=INFO_FAUCET_NOT_AVAILABLE,
)
-
- def set_bitcoin_address(self, label: QLabel, address: str):
- """Set the Bitcoin address in the provided QLabel."""
- label.setText(address)
diff --git a/src/views/ui_help.py b/src/views/ui_help.py
index 61cad61..8bdbb71 100644
--- a/src/views/ui_help.py
+++ b/src/views/ui_help.py
@@ -11,6 +11,7 @@
from PySide6.QtGui import QCursor
from PySide6.QtWidgets import QFrame
from PySide6.QtWidgets import QGridLayout
+from PySide6.QtWidgets import QHBoxLayout
from PySide6.QtWidgets import QLabel
from PySide6.QtWidgets import QScrollArea
from PySide6.QtWidgets import QSizePolicy
@@ -111,12 +112,34 @@ def retranslate_ui(self):
)
def create_help_frames(self):
- """This method creates the help frames according to the faucet list"""
- for card in self._model.card_content:
- faucet_frame = self.create_help_card(
+ """Creates the help frames and distributes them into two columns."""
+ help_card_horizontal_layout = QHBoxLayout()
+
+ help_card_left_vertical_layout = QVBoxLayout()
+ help_card_right_vertical_layout = QVBoxLayout()
+
+ card_list = self._model.card_content
+ for i, card in enumerate(card_list):
+ help_card = self.create_help_card(
card.title, card.detail, card.links,
)
- self.vertical_layout_4.addWidget(faucet_frame)
+
+ if i % 2 == 0:
+ help_card_left_vertical_layout.addWidget(help_card)
+ else:
+ help_card_right_vertical_layout.addWidget(help_card)
+
+ help_card_left_vertical_layout.addStretch()
+ help_card_right_vertical_layout.addStretch()
+ self.main_horizontal_spacer = QSpacerItem(
+ 40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum,
+ )
+ help_card_horizontal_layout.addLayout(help_card_left_vertical_layout)
+ help_card_horizontal_layout.addLayout(help_card_right_vertical_layout)
+ help_card_horizontal_layout.addItem(self.main_horizontal_spacer)
+
+ self.vertical_layout_4.addLayout(help_card_horizontal_layout)
+
self.main_vertical_spacer = QSpacerItem(
20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding,
)
@@ -152,20 +175,19 @@ def create_help_card(self, title, detail, links):
self.url_vertical_layout = QVBoxLayout()
self.url_vertical_layout.setObjectName('url_vertical_layout')
- for link in links:
- self.url = QLabel(self.help_card_frame)
- self.url.setObjectName(str(link))
- self.url.setText(
- f"{link}",
- )
- self.url.setMinimumSize(QSize(0, 15))
- self.url.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
- self.url.setTextInteractionFlags(Qt.TextBrowserInteraction)
- self.url.setOpenExternalLinks(True)
- self.url_vertical_layout.addWidget(self.url)
+ if links:
+ for link in links:
+ self.url = QLabel(self.help_card_frame)
+ self.url.setObjectName(str(link))
+ self.url.setText(
+ f"{link}",
+ )
+ self.url.setMinimumSize(QSize(0, 15))
+ self.url.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
+ self.url.setTextInteractionFlags(Qt.TextBrowserInteraction)
+ self.url.setOpenExternalLinks(True)
+ self.url_vertical_layout.addWidget(self.url)
self.vertical_layout_3.addLayout(self.url_vertical_layout)
- # self.verticalLayout_4.addWidget(self.help_card_frame)
-
return self.help_card_frame
diff --git a/src/views/ui_settings.py b/src/views/ui_settings.py
index 2fc981b..025ce31 100644
--- a/src/views/ui_settings.py
+++ b/src/views/ui_settings.py
@@ -639,7 +639,7 @@ def _set_proxy_endpoint(self):
)
def _set_bitcoind_host(self):
- """ Set the default announce address based on user input."""
+ """ Set the default bitcoind host based on user input."""
password = self._check_keyring_state()
if password:
self._view_model.setting_view_model.set_bitcoind_host(
@@ -647,7 +647,7 @@ def _set_bitcoind_host(self):
)
def _set_bitcoind_port(self):
- """Set the default announce address based on user input."""
+ """Set the default bitcoind port based on user input."""
password = self._check_keyring_state()
if password:
self._view_model.setting_view_model.set_bitcoind_port(
diff --git a/unit_tests/tests/ui_tests/components/keyring_error_diaog_test.py b/unit_tests/tests/ui_tests/components/keyring_error_diaog_test.py
index 4cc4122..71c218b 100644
--- a/unit_tests/tests/ui_tests/components/keyring_error_diaog_test.py
+++ b/unit_tests/tests/ui_tests/components/keyring_error_diaog_test.py
@@ -208,7 +208,7 @@ def test_handle_when_origin_page_set_wallet_unchecked(keyring_error_dialog_widge
'src.utils.local_store.local_store.clear_settings',
)
mock_close = mocker.patch.object(keyring_error_dialog_widget, 'close')
- mock_quit = mocker.patch('PySide6.QtWidgets.QApplication.instance')
+ mock_exit = mocker.patch('PySide6.QtWidgets.QApplication.instance')
# Set checkbox to unchecked
keyring_error_dialog_widget.check_box.setChecked(False)
@@ -219,7 +219,7 @@ def test_handle_when_origin_page_set_wallet_unchecked(keyring_error_dialog_widge
# Verify the unchecked path
mock_clear_settings.assert_called_once()
mock_close.assert_called_once()
- mock_quit.return_value.quit.assert_called_once()
+ mock_exit.return_value.exit.assert_called_once()
def test_handle_when_origin_page_set_wallet_common_exception(keyring_error_dialog_widget, mocker):
diff --git a/unit_tests/tests/ui_tests/components/on_close_progress_dialog_test.py b/unit_tests/tests/ui_tests/components/on_close_progress_dialog_test.py
index 67ebd62..e9d02c0 100644
--- a/unit_tests/tests/ui_tests/components/on_close_progress_dialog_test.py
+++ b/unit_tests/tests/ui_tests/components/on_close_progress_dialog_test.py
@@ -106,18 +106,18 @@ def test_on_error_of_backup(mock_close_node, mock_critical, on_close_progress_di
@patch.object(QMessageBox, 'critical')
-@patch.object(QApplication, 'quit')
-def test_on_error_of_closing_node(mock_quit, mock_critical, on_close_progress_dialog_widget):
+@patch.object(QApplication, 'exit')
+def test_on_error_of_closing_node(mock_exit, mock_critical, on_close_progress_dialog_widget):
"""Test _on_error_of_closing_node method to ensure error handling during node closing."""
on_close_progress_dialog_widget._on_error_of_closing_node()
assert on_close_progress_dialog_widget.is_node_closing_onprogress is False
mock_critical.assert_called_once_with(
on_close_progress_dialog_widget, 'Failed', ERROR_UNABLE_TO_STOP_NODE,
)
- mock_quit.assert_called_once()
+ mock_exit.assert_called_once()
-@patch.object(QApplication, 'quit')
+@patch.object(QApplication, 'exit')
def test_on_success_close_node(mock_quit, on_close_progress_dialog_widget):
"""Test _on_success_close_node method to ensure application quits after node closes."""
on_close_progress_dialog_widget._on_success_close_node()
@@ -126,8 +126,8 @@ def test_on_success_close_node(mock_quit, on_close_progress_dialog_widget):
@patch.object(LnNodeServerManager, 'stop_server_from_close_button')
-@patch.object(QApplication, 'quit')
-def test_close_node_app_when_node_running(mock_quit, mock_stop_server, on_close_progress_dialog_widget):
+@patch.object(QApplication, 'exit')
+def test_close_node_app_when_node_running(mock_exit, mock_stop_server, on_close_progress_dialog_widget):
"""Test _close_node_app method when node is still running."""
mock_state = MagicMock(return_value=QProcess.Running)
on_close_progress_dialog_widget.ln_node_manage.process.state = mock_state
@@ -135,16 +135,16 @@ def test_close_node_app_when_node_running(mock_quit, mock_stop_server, on_close_
assert on_close_progress_dialog_widget.is_backup_onprogress is False
assert on_close_progress_dialog_widget.is_node_closing_onprogress is True
mock_stop_server.assert_called_once()
- mock_quit.assert_not_called()
+ mock_exit.assert_not_called()
-@patch.object(QApplication, 'quit')
-def test_close_node_app_when_node_not_running(mock_quit, on_close_progress_dialog_widget):
+@patch.object(QApplication, 'exit')
+def test_close_node_app_when_node_not_running(mock_exit, on_close_progress_dialog_widget):
"""Test _close_node_app method when node is not running."""
mock_state = MagicMock(return_value=QProcess.NotRunning)
on_close_progress_dialog_widget.ln_node_manage.process.state = mock_state
on_close_progress_dialog_widget._close_node_app()
- mock_quit.assert_called_once()
+ mock_exit.assert_called_once()
def test_close_event_backup_in_progress(on_close_progress_dialog_widget):
diff --git a/unit_tests/tests/ui_tests/ui_channel_management_test.py b/unit_tests/tests/ui_tests/ui_channel_management_test.py
index 09a3adf..67b9775 100644
--- a/unit_tests/tests/ui_tests/ui_channel_management_test.py
+++ b/unit_tests/tests/ui_tests/ui_channel_management_test.py
@@ -77,10 +77,10 @@ def test_show_available_channels_positive(channel_management_widget, qtbot):
assert channel_management_widget.list_v_box_layout.count() > 1
assert isinstance(channel_management_widget.list_frame, QFrame)
- assert isinstance(channel_management_widget.local_balance, QLabel)
- assert channel_management_widget.local_balance.text() == '1000'
- assert isinstance(channel_management_widget.remote_balance, QLabel)
- assert channel_management_widget.remote_balance.text() == '500'
+ assert isinstance(channel_management_widget.local_balance_value, QLabel)
+ assert isinstance(channel_management_widget.remote_balance_value, QLabel)
+ assert channel_management_widget.local_balance_value.text() == '1000'
+ assert channel_management_widget.remote_balance_value.text() == '500'
def test_show_available_channels_no_channels(channel_management_widget):
@@ -177,10 +177,10 @@ def test_show_available_channels_with_none_asset_id(mock_create_pixmap, channel_
# 1 for the channel, 1 for the spacer
assert channel_management_widget.list_v_box_layout.count() == 2
assert channel_management_widget.list_frame.findChild(
- QLabel, 'local_balance',
+ QLabel, 'local_balance_value',
).text() == '1000'
assert channel_management_widget.list_frame.findChild(
- QLabel, 'remote_balance',
+ QLabel, 'remote_balance_value',
).text() == '500'
@@ -231,13 +231,13 @@ def test_show_available_channels_with_asset_id(mock_create_pixmap, channel_manag
# 1 for the channel, 1 for spacer
assert channel_management_widget.list_v_box_layout.count() == 2
assert channel_management_widget.list_frame.findChild(
- QLabel, 'local_balance',
+ QLabel, 'local_balance_value',
).text() == '777'
assert channel_management_widget.list_frame.findChild(
- QLabel, 'remote_balance',
+ QLabel, 'remote_balance_value',
).text() == '0'
tooltip = channel_management_widget.list_frame.findChild(
- QLabel, 'status',
+ QLabel, 'status_pixmap',
).toolTip()
assert tooltip == 'opening'
asset_label = channel_management_widget.list_frame.findChild(
@@ -354,7 +354,7 @@ def test_show_available_channels_status_change(channel_management_widget, qtbot)
# Assert status color and tooltip for "Closing"
assert channel_management_widget.list_frame.findChild(
- QLabel, 'status',
+ QLabel, 'status_pixmap',
).toolTip() == 'closing'
# Change channel status
@@ -363,7 +363,7 @@ def test_show_available_channels_status_change(channel_management_widget, qtbot)
# Assert status color and tooltip for "Opening"
assert channel_management_widget.list_frame.findChild(
- QLabel, 'status',
+ QLabel, 'status_pixmap',
).toolTip() == 'opening'
@@ -424,3 +424,38 @@ def test_channel_detail_event(channel_management_widget):
# Assert that the exec method was called on the dialog box
mock_channel_detail_dialog_box.return_value.exec.assert_called_once()
+
+
+@patch('src.utils.helpers.create_circular_pixmap')
+def test_show_available_channels_with_asset_id_lookup(mock_create_pixmap, channel_management_widget):
+ """Test show_available_channels with asset lookup functionality."""
+ # Mock the return value of create_circular_pixmap to be a QPixmap instance
+ mock_create_pixmap.return_value = QPixmap(16, 16)
+
+ # Mock valid channel data with asset_id
+ mock_channel = MagicMock()
+ mock_channel.peer_pubkey = 'mock_pubkey'
+ mock_channel.asset_local_amount = 777
+ mock_channel.asset_remote_amount = 0
+ mock_channel.asset_id = 'test_asset_123'
+ mock_channel.ready = True
+
+ # Set up the asset lookup dictionary
+ channel_management_widget._view_model.channel_view_model.total_asset_lookup_list = {
+ 'test_asset_123': 'Test Asset Name',
+ }
+
+ channel_management_widget._view_model.channel_view_model.channels = [
+ mock_channel,
+ ]
+
+ channel_management_widget.show_available_channels()
+
+ # Assertions to verify the correct display of channel information
+ assert channel_management_widget.list_v_box_layout.count() == 2
+ assert channel_management_widget.list_frame.findChild(
+ QLabel, 'asset_name',
+ ).text() == 'Test Asset Name'
+ assert channel_management_widget.list_frame.findChild(
+ QLabel, 'asset_id',
+ ).text() == 'test_asset_123'
diff --git a/unit_tests/tests/ui_tests/ui_fungible_asset_test.py b/unit_tests/tests/ui_tests/ui_fungible_asset_test.py
index 6c2e499..a917ddc 100644
--- a/unit_tests/tests/ui_tests/ui_fungible_asset_test.py
+++ b/unit_tests/tests/ui_tests/ui_fungible_asset_test.py
@@ -44,15 +44,6 @@ def mock_fungible_asset_view_model():
return mock_view_model
-# @pytest.fixture
-# def fungible_asset_nodeinfo_mock():
-# """Provides a mock for fungible asset nodeinfo."""
-# mock = MagicMock()
-# mock.is_ready = MagicMock(return_value=True)
-# mock.get_network_name = MagicMock(return_value='Testnet')
-# return mock
-
-
@pytest.fixture
def create_fungible_asset_widget(qtbot, mock_fungible_asset_view_model):
"""Fixture to create the FungibleAssetWidget."""
@@ -93,7 +84,7 @@ def test_fungible_asset_widget_show_assets(create_fungible_asset_widget: Fungibl
bitcoin_mock.name = 'bitcoin'
bitcoin_mock.balance.future = '0.5'
bitcoin_mock.ticker = 'BTC'
- bitcoin_mock.asset_id = 'rgb123rgb'
+ bitcoin_mock.asset_id = 'rBTC'
# Set the mock assets in the view model
widget._view_model.main_asset_view_model.assets.vanilla = bitcoin_mock
@@ -104,7 +95,7 @@ def test_fungible_asset_widget_show_assets(create_fungible_asset_widget: Fungibl
# Check that the asset name was set correctly
assert widget.asset_name.text() == 'bitcoin'
- assert widget.address.text() == 'rgb123rgb'
+ assert widget.address.text() == 'rBTC'
assert widget.amount.text() == '0.5'
assert widget.asset_logo.pixmap() is not None
@@ -193,7 +184,7 @@ def test_show_assets_with_various_assets(create_fungible_asset_widget, qtbot):
'iris_wallet_desktop', 'asset_name', None,
)
assert widget.address_header.text() == QCoreApplication.translate(
- 'iris_wallet_desktop', 'address', None,
+ 'iris_wallet_desktop', 'asset_id', None,
)
assert widget.amount_header.text() == QCoreApplication.translate(
'iris_wallet_desktop', 'on_chain_balance', None,
@@ -235,14 +226,9 @@ def test_update_faucet_availability_when_unavailable(create_fungible_asset_widge
# Check if the stylesheet was set correctly
faucet_mock.setStyleSheet.assert_called_once_with(
- 'Text-align:left;'
- 'font: 15px "Inter";'
- 'color: rgb(120, 120, 120);'
- 'padding: 17.5px 16px;'
- 'background-image: url(:/assets/right_small.png);'
- 'background-repeat: no-repeat;'
- 'background-position: right center;'
- 'background-origin: content;',
+ 'Text-align:left;font: 15px "Inter";color: rgb(120, 120, 120);padding: 17.5px 16px;'
+ 'background-image: url(:/assets/right_small.png);background-repeat: no-repeat;'
+ 'background-position: right center;background-origin: content;',
)
# Check if the click event handler was disconnected
@@ -304,24 +290,6 @@ def test_show_faucet_unavailability_message(mocker, mock_fungible_asset_view_mod
)
-def test_set_bitcoin_address(mock_fungible_asset_view_model):
- """Test that the set_bitcoin_address method sets the text of the provided QLabel."""
- # Create a mock QLabel
- label_mock = MagicMock(spec=QLabel)
-
- # Example Bitcoin address
- bitcoin_address = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'
-
- # Create an instance of the widget
- widget = FungibleAssetWidget(mock_fungible_asset_view_model)
-
- # Call the method
- widget.set_bitcoin_address(label=label_mock, address=bitcoin_address)
-
- # Verify that QLabel.setText is called with the correct address
- label_mock.setText.assert_called_once_with(bitcoin_address)
-
-
def test_stop_fungible_loading_screen(create_fungible_asset_widget):
"""Test that the stop_fungible_loading_screen method stops the loading screen and enables refresh button."""
widget = create_fungible_asset_widget
@@ -571,9 +539,6 @@ def test_create_fungible_card(create_fungible_asset_widget, qtbot):
AssetType.BITCOIN.value.lower()
}'
- # Test signal connection for Bitcoin address updates
- assert widget.signal_connected is True
-
def test_show_assets(create_fungible_asset_widget, qtbot):
"""Test the show_assets method to ensure assets are cleared and the Bitcoin address signal is managed correctly."""
@@ -613,20 +578,3 @@ def test_show_assets(create_fungible_asset_widget, qtbot):
# Call show_assets
widget.show_assets()
-
- # Ensure get_bitcoin_address is called
- widget._view_model.receive_bitcoin_view_model.get_bitcoin_address.assert_called_once()
-
- # Check that address.disconnect() was called if signal_connected is True
- widget._view_model.receive_bitcoin_view_model.address.disconnect.assert_called_once()
-
- # Check if signal_connected is set to False after disconnection
- assert widget.signal_connected is False
-
- # Test the case when signal_connected is False and no disconnection should happen
- widget.signal_connected = False
- widget.show_assets() # Should not attempt to disconnect again
-
- # Ensure address.disconnect is not called in this case
- # Should still be called once from previous check
- widget._view_model.receive_bitcoin_view_model.address.disconnect.assert_called_once()
diff --git a/unit_tests/tests/ui_tests/ui_help_test.py b/unit_tests/tests/ui_tests/ui_help_test.py
index 238478e..4a80fcd 100644
--- a/unit_tests/tests/ui_tests/ui_help_test.py
+++ b/unit_tests/tests/ui_tests/ui_help_test.py
@@ -1,14 +1,16 @@
"""Unit test for Enter Help UI."""
# Disable the redefined-outer-name warning as
# it's normal to pass mocked objects in test functions
-# pylint: disable=redefined-outer-name,unused-argument
+# pylint: disable=redefined-outer-name,unused-argument,protected-access
from __future__ import annotations
from unittest.mock import MagicMock
import pytest
+from PySide6.QtCore import Qt
from PySide6.QtWidgets import QFrame
from PySide6.QtWidgets import QLabel
+from PySide6.QtWidgets import QVBoxLayout
from src.viewmodels.main_view_model import MainViewModel
from src.views.ui_help import HelpWidget
@@ -51,13 +53,21 @@ def test_create_help_card(help_widget):
assert isinstance(help_card_frame, QFrame)
assert help_card_frame.objectName() == 'help_card_frame'
+ assert help_card_frame.minimumSize().width() == 492
+ assert help_card_frame.minimumSize().height() == 70
+ assert help_card_frame.maximumSize().width() == 335
+ assert help_card_frame.maximumSize().height() == 16777215
+ assert help_card_frame.frameShape() == QFrame.StyledPanel
+ assert help_card_frame.frameShadow() == QFrame.Raised
# Check that the title and detail are set correctly
title_label = help_card_frame.findChild(QLabel, 'help_card_title_label')
assert title_label.text() == title
+ assert title_label.wordWrap() is True
detail_label = help_card_frame.findChild(QLabel, 'help_card_detail_label')
assert detail_label.text() == detail
+ assert detail_label.wordWrap() is True
# Check that the links are set correctly
for link in links:
@@ -65,3 +75,70 @@ def test_create_help_card(help_widget):
assert link_label.text() == f"{link}"
+ assert link_label.minimumSize().height() == 15
+ assert link_label.cursor().shape() == Qt.CursorShape.PointingHandCursor
+ assert link_label.textInteractionFlags() == Qt.TextBrowserInteraction
+ assert link_label.openExternalLinks() is True
+
+ # Test with no links
+ help_card_frame = help_widget.create_help_card(title, detail, None)
+ assert help_card_frame.findChild(QLabel, 'http://example.com') is None
+
+ # Test vertical layout properties
+ vertical_layout = help_card_frame.findChild(
+ QVBoxLayout, 'verticalLayout_3',
+ )
+ assert vertical_layout.spacing() == 15
+ margins = vertical_layout.contentsMargins()
+ assert (
+ margins.left(), margins.top(), margins.right(),
+ margins.bottom(),
+ ) == (15, 20, 15, 20)
+
+
+def test_create_help_frames(help_widget, qtbot):
+ """Test that help frames are created and distributed correctly into two columns."""
+ # Call the method
+ help_widget.create_help_frames()
+
+ # Get the card list from the model
+ card_list = help_widget._model.card_content
+
+ # Verify horizontal layout exists and has correct spacer
+ assert help_widget.main_horizontal_spacer is not None
+ assert help_widget.main_horizontal_spacer.sizeHint().width() == 40
+ assert help_widget.main_horizontal_spacer.sizeHint().height() == 20
+
+ # Verify vertical spacer exists and has correct properties
+ assert help_widget.main_vertical_spacer is not None
+ assert help_widget.main_vertical_spacer.sizeHint().width() == 20
+ assert help_widget.main_vertical_spacer.sizeHint().height() == 40
+
+ # Find all help card frames
+ help_cards = help_widget.findChildren(QFrame, 'help_card_frame')
+
+ # Clear any existing cards before checking
+ for card in help_cards[len(card_list):]:
+ card.deleteLater()
+ help_cards = help_cards[:len(card_list)]
+
+ # Verify number of cards matches model content
+ assert len(help_cards) == len(card_list)
+
+ # Verify each card's content
+ for i, card in enumerate(card_list):
+ help_card = help_cards[i]
+
+ title_label = help_card.findChild(QLabel, 'help_card_title_label')
+ detail_label = help_card.findChild(QLabel, 'help_card_detail_label')
+
+ assert title_label.text() == card.title
+ assert detail_label.text() == card.detail
+
+ if card.links:
+ for link in card.links:
+ link_label = help_card.findChild(QLabel, str(link))
+ assert link_label is not None
+ assert link_label.text() == f"{link}"
diff --git a/unit_tests/tests/ui_tests/ui_send_bitcoin_test.py b/unit_tests/tests/ui_tests/ui_send_bitcoin_test.py
index ca70dd0..a9a7ee4 100644
--- a/unit_tests/tests/ui_tests/ui_send_bitcoin_test.py
+++ b/unit_tests/tests/ui_tests/ui_send_bitcoin_test.py
@@ -97,20 +97,44 @@ def test_send_bitcoin_button(send_bitcoin_widget: SendBitcoinWidget, qtbot):
def test_handle_button_enabled(send_bitcoin_widget: SendBitcoinWidget):
"""Test the handle_button_enabled method."""
+ # Test valid address, amount, fee and payment
send_bitcoin_widget.send_bitcoin_page.asset_address_value.setText(
'1BitcoinAddress',
)
send_bitcoin_widget.send_bitcoin_page.asset_amount_value.setText('0.001')
send_bitcoin_widget.send_bitcoin_page.fee_rate_value.setText('0.0001')
+ send_bitcoin_widget.send_bitcoin_page.pay_amount = 1000
+ send_bitcoin_widget.send_bitcoin_page.spendable_amount = 2000
send_bitcoin_widget.handle_button_enabled()
-
assert send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
- # Clear one of the inputs to disable the button again
+ # Test invalid address (empty)
send_bitcoin_widget.send_bitcoin_page.asset_address_value.clear()
send_bitcoin_widget.handle_button_enabled()
+ assert not send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
+
+ # Test invalid amount (zero)
+ send_bitcoin_widget.send_bitcoin_page.asset_amount_value.setText('0')
+ send_bitcoin_widget.handle_button_enabled()
+ assert not send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
+
+ # Test invalid fee (empty)
+ send_bitcoin_widget.send_bitcoin_page.asset_amount_value.setText('0.001')
+ send_bitcoin_widget.send_bitcoin_page.fee_rate_value.clear()
+ send_bitcoin_widget.handle_button_enabled()
+ assert not send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
+ # Test invalid fee (zero)
+ send_bitcoin_widget.send_bitcoin_page.fee_rate_value.setText('0')
+ send_bitcoin_widget.handle_button_enabled()
+ assert not send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
+
+ # Test invalid payment (pay_amount > spendable_amount)
+ send_bitcoin_widget.send_bitcoin_page.fee_rate_value.setText('0.0001')
+ send_bitcoin_widget.send_bitcoin_page.pay_amount = 3000
+ send_bitcoin_widget.send_bitcoin_page.spendable_amount = 2000
+ send_bitcoin_widget.handle_button_enabled()
assert not send_bitcoin_widget.send_bitcoin_page.send_btn.isEnabled()
diff --git a/unit_tests/tests/ui_tests/ui_send_rgb_asset_test.py b/unit_tests/tests/ui_tests/ui_send_rgb_asset_test.py
index e3d3ee3..3216ff5 100644
--- a/unit_tests/tests/ui_tests/ui_send_rgb_asset_test.py
+++ b/unit_tests/tests/ui_tests/ui_send_rgb_asset_test.py
@@ -75,9 +75,22 @@ def test_handle_button_enabled(send_rgb_asset_widget: SendRGBAssetWidget, qtbot)
'blind_utxo_123',
)
send_rgb_asset_widget.send_rgb_asset_page.asset_amount_value.setText('10')
+
+ # Mocking the spendable balance to be greater than 0
+ send_rgb_asset_widget.asset_spendable_balance = 50
send_rgb_asset_widget.handle_button_enabled()
assert send_rgb_asset_widget.send_rgb_asset_page.send_btn.isEnabled() is True
+ # Test with invalid amount (zero)
+ send_rgb_asset_widget.send_rgb_asset_page.asset_amount_value.setText('0')
+ send_rgb_asset_widget.handle_button_enabled()
+ assert send_rgb_asset_widget.send_rgb_asset_page.send_btn.isEnabled() is False
+
+ # Test with valid address and invalid spendable balance
+ send_rgb_asset_widget.asset_spendable_balance = 0
+ send_rgb_asset_widget.handle_button_enabled()
+ assert send_rgb_asset_widget.send_rgb_asset_page.send_btn.isEnabled() is False
+
def test_set_asset_balance(send_rgb_asset_widget: SendRGBAssetWidget, qtbot):
"""Test the set_asset_balance method."""
diff --git a/unit_tests/tests/utils_test/common_utils_test.py b/unit_tests/tests/utils_test/common_utils_test.py
index 04405f3..972c141 100644
--- a/unit_tests/tests/utils_test/common_utils_test.py
+++ b/unit_tests/tests/utils_test/common_utils_test.py
@@ -968,7 +968,7 @@ def test_sigterm_handler(mock_qapp_instance, mock_ln_node_manager_get_instance,
QMessageBox.Ok | QMessageBox.Cancel,
)
mock_ln_node_manager.stop_server_from_close_button.assert_called_once()
- mock_qapp.quit.assert_called_once()
+ mock_qapp.exit.assert_called_once()
# Reset mocks for next case
mock_qmessagebox_warning.reset_mock()
diff --git a/unit_tests/tests/viewmodel_tests/header_frame_view_model_test.py b/unit_tests/tests/viewmodel_tests/header_frame_view_model_test.py
index 3f36684..f1105ca 100644
--- a/unit_tests/tests/viewmodel_tests/header_frame_view_model_test.py
+++ b/unit_tests/tests/viewmodel_tests/header_frame_view_model_test.py
@@ -2,172 +2,127 @@
# pylint: disable=redefined-outer-name,unused-argument
from __future__ import annotations
-from unittest.mock import MagicMock
-from unittest.mock import Mock
-from unittest.mock import patch
-
-import pytest
-
+from src.utils.constant import PING_DNS_SERVER_CALL_INTERVAL
from src.viewmodels.header_frame_view_model import HeaderFrameViewModel
from src.viewmodels.header_frame_view_model import NetworkCheckerThread
-@pytest.fixture
-def mock_network_checker():
- """Mock NetworkCheckerThread"""
- with patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread') as mock:
- mock_thread = MagicMock()
- mock.return_value = mock_thread
- yield mock_thread
+def test_network_checker_thread_success(mocker, qtbot):
+ """Test that NetworkCheckerThread emits True when network is available."""
+ network_checker = NetworkCheckerThread()
+
+ mocker.patch.object(
+ network_checker, 'check_internet_conn', return_value=True,
+ )
+
+ def signal_received(value):
+ assert value is True
+
+ network_checker.network_status_signal.connect(signal_received)
+
+ network_checker.start()
+ qtbot.waitSignal(network_checker.finished, timeout=1000)
+
+
+def test_network_checker_thread_failure(mocker, qtbot):
+ """Test that NetworkCheckerThread emits False when network is unavailable."""
+ network_checker = NetworkCheckerThread()
+
+ mocker.patch.object(
+ network_checker, 'check_internet_conn', return_value=False,
+ )
+
+ def signal_received(value):
+ assert value is False
+
+ network_checker.network_status_signal.connect(signal_received)
+
+ network_checker.start()
+ qtbot.waitSignal(network_checker.finished, timeout=1000)
+
+
+def test_check_internet_conn_success(mocker):
+ """Test check_internet_conn returns True when socket connection succeeds."""
+ network_checker = NetworkCheckerThread()
+
+ mocker.patch('socket.create_connection', return_value=True)
+ assert network_checker.check_internet_conn() is True
+
+
+def test_check_internet_conn_failure(mocker):
+ """Test check_internet_conn returns False when socket connection fails."""
+ network_checker = NetworkCheckerThread()
+
+ mocker.patch('socket.create_connection', side_effect=OSError)
+
+ assert network_checker.check_internet_conn() is False
+
+
+def test_header_frame_view_model_init(mocker):
+ """Test that HeaderFrameViewModel initializes correctly with a running timer."""
+ mock_timer = mocker.patch(
+ 'src.viewmodels.header_frame_view_model.QTimer',
+ )
-@pytest.fixture
-def header_frame_view_model(mock_network_checker):
- """Fixture for creating a HeaderFrameViewModel instance."""
view_model = HeaderFrameViewModel()
- return view_model
+ # Ensure QTimer was instantiated
+ mock_timer.assert_called_once()
+
+ # Retrieve the mocked QTimer instance
+ mock_timer_instance = mock_timer.return_value
-def test_header_frame_view_model_init(mock_network_checker):
- """Test HeaderFrameViewModel initialization."""
+ # Ensure timer settings and start behavior are correct
+ mock_timer_instance.setInterval.assert_called_once_with(
+ PING_DNS_SERVER_CALL_INTERVAL,
+ )
+ mock_timer_instance.timeout.connect.assert_called_once_with(
+ view_model.start_network_check,
+ )
+ mock_timer_instance.start.assert_called_once()
+
+
+def test_header_frame_view_model_network_check(mocker):
+ """Test that start_network_check creates a NetworkCheckerThread and starts it."""
view_model = HeaderFrameViewModel()
- assert hasattr(view_model, 'network_checker')
- assert view_model.network_checker == mock_network_checker
- mock_network_checker.start.assert_called_once()
+ mock_thread = mocker.patch(
+ 'src.viewmodels.header_frame_view_model.NetworkCheckerThread',
+ )
+ mock_instance = mock_thread.return_value
+ view_model.start_network_check()
-def test_handle_network_status(header_frame_view_model):
- """Test handle_network_status method."""
- mock_signal = Mock()
- header_frame_view_model.network_status_signal.connect(mock_signal)
+ mock_thread.assert_called_once()
+ mock_instance.network_status_signal.connect.assert_called_once_with(
+ view_model.handle_network_status,
+ )
+ mock_instance.start.assert_called_once()
- header_frame_view_model.handle_network_status(True)
- mock_signal.assert_called_once_with(True)
+def test_header_frame_view_model_handle_network_status():
+ """Test that handle_network_status emits the correct signal."""
+ view_model = HeaderFrameViewModel()
+ received_signals = []
+
+ def signal_received(value):
+ received_signals.append(value)
+ view_model.network_status_signal.connect(signal_received)
-def test_stop_network_checker(header_frame_view_model, mock_network_checker):
- """Test stop_network_checker method."""
- header_frame_view_model.stop_network_checker()
+ view_model.handle_network_status(True)
+ view_model.handle_network_status(False)
- mock_network_checker.stop.assert_called_once()
+ assert received_signals == [True, False]
+
+
+def test_header_frame_view_model_stop_network_checker(mocker):
+ """Test that stop_network_checker stops the timer."""
+ view_model = HeaderFrameViewModel()
+ mock_timer = mocker.patch.object(view_model.timer, 'stop')
-@patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread')
-def test_network_checker_thread_init(mock_thread_class):
- """Test NetworkCheckerThread initialization."""
- mock_thread = mock_thread_class.return_value
- mock_thread.running = True
-
- thread = mock_thread_class()
- assert thread.running is True
-
+ view_model.stop_network_checker()
-@patch('socket.create_connection')
-@patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread')
-def test_check_internet_conn_success(mock_thread_class, mock_socket):
- """Test check_internet_conn method when connection succeeds."""
- mock_thread = mock_thread_class.return_value
- mock_socket.return_value = True
-
- # Don't mock check_internet_conn itself since we want to test the actual implementation
- result = NetworkCheckerThread.check_internet_conn(mock_thread)
- mock_socket.assert_called_once_with(('8.8.8.8', 53), timeout=3)
- assert result is True
-
-
-@patch('socket.create_connection')
-@patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread')
-def test_check_internet_conn_failure(mock_thread_class, mock_socket):
- """Test check_internet_conn method when connection fails."""
- mock_thread = mock_thread_class.return_value
- mock_socket.side_effect = OSError()
-
- # Don't mock check_internet_conn itself since we want to test the actual implementation
- result = NetworkCheckerThread.check_internet_conn(mock_thread)
- mock_socket.assert_called_once_with(('8.8.8.8', 53), timeout=3)
- assert result is False
-
-
-@patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread')
-def test_network_checker_stop(mock_thread_class):
- """Test NetworkCheckerThread stop method."""
- mock_thread = mock_thread_class.return_value
- mock_thread.running = True
-
- mock_thread.stop()
- mock_thread.running = False
- mock_thread.isRunning.return_value = False
-
- assert not mock_thread.running
- assert not mock_thread.isRunning()
-
-
-@patch('PySide6.QtCore.QThread.quit')
-@patch('PySide6.QtCore.QThread.wait')
-def test_network_checker_thread_stop_complete(mock_wait, mock_quit):
- """Test NetworkCheckerThread stop method completely stops the thread."""
- # Arrange
- thread = NetworkCheckerThread()
- thread.running = True
- thread.check_internet_conn = Mock() # Mock method to ensure it doesn't run
- # Mock signal to avoid real signal emission
- thread.network_status_signal = Mock()
- thread.msleep = Mock() # Mock msleep to prevent delay
-
- # Mock `run` method so it doesn't loop infinitely
- def mocked_run():
- while thread.running:
- # This is just to simulate run behavior
- thread.check_internet_conn()
- thread.network_status_signal.emit(True)
- thread.msleep(5000)
-
- # Replace `run` with mocked logic
- thread.run = mocked_run
-
- # Act
- thread.stop()
-
- # Assert
- # Check if `running` is False after stopping
- assert thread.running is False
- # Ensure that `quit` and `wait` methods were called once
- mock_quit.assert_called_once()
- mock_wait.assert_called_once()
-
-
-@patch('src.viewmodels.header_frame_view_model.NetworkCheckerThread')
-def test_network_checker_run(mock_thread_class):
- """Test NetworkCheckerThread run method."""
- # Arrange
- mock_thread = mock_thread_class.return_value
- mock_thread.running = True
- mock_thread.check_internet_conn = Mock(
- side_effect=[True, False],
- ) # Mock network check
- mock_thread.network_status_signal = Mock() # Mock signal
- mock_thread.msleep = Mock() # Mock sleep to prevent delay
-
- def mocked_run():
- """Simulate the run method logic."""
- while mock_thread.running:
- is_connected = mock_thread.check_internet_conn()
- mock_thread.network_status_signal.emit(is_connected)
- mock_thread.running = False # Stop after one iteration
- mock_thread.msleep(5000)
-
- # Replace `run` with mocked logic
- mock_thread.run = mocked_run
-
- # Act
- mock_thread.run()
-
- # Assert
- # Ensure `check_internet_conn` was called once
- mock_thread.check_internet_conn.assert_called_once()
- # Verify `msleep` was called once with the correct interval
- mock_thread.msleep.assert_called_once_with(5000)
- # Check that the signal was emitted with the correct value
- mock_thread.network_status_signal.emit.assert_called_once_with(True)
+ mock_timer.assert_called_once()
diff --git a/unit_tests/tests/viewmodel_tests/splash_view_model_test.py b/unit_tests/tests/viewmodel_tests/splash_view_model_test.py
index dc43f99..1076d0e 100644
--- a/unit_tests/tests/viewmodel_tests/splash_view_model_test.py
+++ b/unit_tests/tests/viewmodel_tests/splash_view_model_test.py
@@ -49,7 +49,7 @@ def test_on_error_common_exception(mock_qapp, mock_toast_manager, mock_setting_r
mock_toast_manager.error.assert_called_once_with(
description='Custom error message',
)
- mock_qapp.instance().quit.assert_called_once()
+ mock_qapp.instance().exit.assert_called_once()
@patch('src.viewmodels.splash_view_model.SettingRepository')
@@ -66,7 +66,7 @@ def test_on_error_general_exception(mock_qapp, mock_toast_manager, mock_setting_
mock_toast_manager.error.assert_called_once_with(
description=ERROR_SOMETHING_WENT_WRONG,
)
- mock_qapp.instance().quit.assert_called_once()
+ mock_qapp.instance().exit.assert_called_once()
@patch('src.viewmodels.splash_view_model.SettingRepository')
diff --git a/unit_tests/tests/viewmodel_tests/wallet_transfer_selection_view_model_test.py b/unit_tests/tests/viewmodel_tests/wallet_transfer_selection_view_model_test.py
index 8de2f75..5f24121 100644
--- a/unit_tests/tests/viewmodel_tests/wallet_transfer_selection_view_model_test.py
+++ b/unit_tests/tests/viewmodel_tests/wallet_transfer_selection_view_model_test.py
@@ -49,7 +49,7 @@ def test_on_ln_node_error(wallet_transfer_selection_view_model):
mock_message_box.assert_called_once_with(
'critical', message_text='Unable to start node,Please close application and restart',
)
- mock_instance.quit.assert_called_once()
+ mock_instance.exit.assert_called_once()
def test_on_ln_node_already_running(wallet_transfer_selection_view_model):