From 6096f4a3009ebe6c06c3258ffb26d0382f2de118 Mon Sep 17 00:00:00 2001 From: rahilmansuri1 Date: Thu, 27 Feb 2025 17:58:47 +0530 Subject: [PATCH] Add: description for RLN node connection type --- .codespellrc | 2 +- iris_wallet_desktop.spec | 1 - src/translations/en_IN.qm | Bin 130832 -> 131717 bytes src/translations/en_IN.ts | 12 + src/views/qss/style.qss | 11 + .../wallet_or_transfer_selection_style.qss | 6 +- src/views/ui_wallet_or_transfer_selection.py | 163 ++++++++++-- .../ui_wallet_or_transfer_selection_test.py | 234 +++++++++++++----- 8 files changed, 346 insertions(+), 83 deletions(-) diff --git a/.codespellrc b/.codespellrc index bf1276d..de6d618 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] # Ignore specific words that are intentional and should not be corrected -ignore-words-list = arbitral +ignore-words-list = arbitral,datas diff --git a/iris_wallet_desktop.spec b/iris_wallet_desktop.spec index 515616c..0755be6 100644 --- a/iris_wallet_desktop.spec +++ b/iris_wallet_desktop.spec @@ -36,7 +36,6 @@ datas = [ ('./src/views/qss/*.qss', './views/qss/'), ('./build_info.json', './build_info.json'), (ln_node_binary, './ln_node_binary/'), - ('binary', './binary/') ] + pyqttoast_datas # Common Analysis diff --git a/src/translations/en_IN.qm b/src/translations/en_IN.qm index 9564cc041f2dd1a031568ed99af8b184c1db872b..8388de49cdd19863715e2e728d6630761858f2a1 100644 GIT binary patch delta 3670 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 WO^A#)UK!jsvuFN+p83p+`2PV>%MLOC delta 3026 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 Remote + + embedded_connection_info + With embedded connection, an RGB Lightning Node is automatically run in the background. + + + remote_connection_info + With remote connection, an RGB Lightning Node needs to be hosted separately and its URL will need to be provided. + + + rln_node_connection_description + An RLN (RGB Lightning Node) instance is necessary to support the app's functionalities. Clicking an option reveals details about it. + diff --git a/src/views/qss/style.qss b/src/views/qss/style.qss index e66fd23..6c2609e 100644 --- a/src/views/qss/style.qss +++ b/src/views/qss/style.qss @@ -23,3 +23,14 @@ QLabel { color: white ; border-radius: 8px; } + + +QFrame #option_2_frame,#option_1_frame{ + font: 15px "Inter"; + border-radius: 8px; + border: 1px solid white; +} + +QLabel#option_2_text_label, #option_1_text_label{ + border:none +} diff --git a/src/views/qss/wallet_or_transfer_selection_style.qss b/src/views/qss/wallet_or_transfer_selection_style.qss index caf6cfa..e623075 100644 --- a/src/views/qss/wallet_or_transfer_selection_style.qss +++ b/src/views/qss/wallet_or_transfer_selection_style.qss @@ -1,4 +1,4 @@ -QWidget#widget_page { +QWidget#widget_page, #info_frame { background: transparent; border: 1px solid rgb(102, 108, 129); background-color: rgb(3, 11, 37); @@ -21,13 +21,13 @@ QFrame#line_2 { border-bottom: 1px solid rgb(27, 35, 59); } -QFrame#option_1_frame,#option_3_frame, QFrame#frame_8 { +QFrame#option_1_frame,#option_3_frame, QFrame#option_2_frame { border-radius: 8px; border: 1px solid rgb(102, 108, 129); border-radius: 8px; } -QFrame#option_1_frame:hover,QFrame#option_3_frame:hover, QFrame#frame_8:hover { +QFrame#option_1_frame:hover,QFrame#option_3_frame:hover, QFrame#option_2_frame:hover { font: 14px "Inter"; color: white; border-radius: 8px; diff --git a/src/views/ui_wallet_or_transfer_selection.py b/src/views/ui_wallet_or_transfer_selection.py index ac91d81..5e79cea 100644 --- a/src/views/ui_wallet_or_transfer_selection.py +++ b/src/views/ui_wallet_or_transfer_selection.py @@ -21,7 +21,6 @@ from PySide6.QtWidgets import QVBoxLayout from PySide6.QtWidgets import QWidget -import src.resources_rc from src.data.repository.setting_repository import SettingRepository from src.model.enums.enums_model import AssetType from src.model.enums.enums_model import LoaderDisplayModel @@ -33,6 +32,7 @@ from src.utils.clickable_frame import ClickableFrame from src.utils.helpers import load_stylesheet from src.viewmodels.main_view_model import MainViewModel +from src.views.components.buttons import PrimaryButton from src.views.components.loading_screen import LoadingTranslucentScreen from src.views.components.wallet_logo_frame import WalletLogoFrame @@ -51,6 +51,7 @@ def __init__(self, view_model, params): self._view_model: MainViewModel = view_model self._params: SelectionPageModel = params self.asset_type = None + self.selected_frame = None if self._params.rgb_asset_page_load_model: self.asset_type = self._params.rgb_asset_page_load_model.asset_type self.grid_layout = QGridLayout(self) @@ -60,7 +61,7 @@ def __init__(self, view_model, params): self.grid_layout.addWidget(self.wallet_logo, 0, 0, 1, 2) self.vertical_spacer_1 = QSpacerItem( - 20, 208, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding, + 20, 208, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed, ) self.grid_layout.addItem(self.vertical_spacer_1, 0, 3, 1, 1) @@ -119,6 +120,19 @@ def __init__(self, view_model, params): self.header_line.setFrameShadow(QFrame.Shadow.Sunken) self.vertical_layout.addWidget(self.header_line) + self.rln_node_connection_description = QLabel(self.widget_page) + self.rln_node_connection_description.setMinimumSize(QSize(0, 54)) + self.rln_node_connection_description.setMaximumSize( + QSize(16777215, 54), + ) + self.rln_node_connection_description.setWordWrap(True) + self.rln_node_connection_description.hide() + + self.rln_node_connection_description.setContentsMargins(40, 20, 20, 0) + + self.vertical_layout.addWidget( + self.rln_node_connection_description, Qt.AlignmentFlag.AlignAbsolute, + ) self.vertical_spacer_2 = QSpacerItem( 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding, @@ -167,7 +181,7 @@ def __init__(self, view_model, params): self.option_2_frame = ClickableFrame( self._params.logo_2_title, self.widget_page, self._params.callback, ) - self.option_2_frame.setObjectName('frame_8') + self.option_2_frame.setObjectName('option_2_frame') self.option_2_frame.setMinimumSize(QSize(220, 200)) self.option_2_frame.setMaximumSize(QSize(220, 200)) @@ -200,13 +214,36 @@ def __init__(self, view_model, params): self.vertical_layout.addLayout(self.select_option_layout) + self.vertical_spacer_5 = QSpacerItem( + 20, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding, + ) + + self.info_frame = QFrame(self) + self.info_frame.setObjectName('info_frame') + self.info_frame.setMinimumSize(QSize(736, 100)) + self.info_frame.setMaximumSize(QSize(736, 100)) + self.info_frame.hide() + + self.info_frame_layout = QHBoxLayout(self.info_frame) + self.info_frame_layout.setContentsMargins(30, 9, 30, 9) + self.wallet_connection_info_label = QLabel(self.info_frame) + self.wallet_connection_info_label.setObjectName( + 'wallet_connection_info_label', + ) + self.wallet_connection_info_label.setWordWrap(True) + self.info_frame_layout.addWidget(self.wallet_connection_info_label) + + self.continue_button = PrimaryButton() + self.info_frame_layout.addWidget(self.continue_button) self.vertical_spacer_3 = QSpacerItem( 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding, ) self.vertical_layout.addItem(self.vertical_spacer_3) - self.grid_layout.addWidget(self.widget_page, 1, 1, 2, 3) + self.grid_layout.addWidget(self.widget_page, 1, 1) + self.grid_layout.addItem(self.vertical_spacer_5, 3, 1) + self.grid_layout.addWidget(self.info_frame, 4, 1) self.horizontal_spacer_2 = QSpacerItem( 268, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum, @@ -218,7 +255,7 @@ def __init__(self, view_model, params): 20, 208, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding, ) - self.grid_layout.addItem(self.vertical_spacer_4, 3, 2, 1, 1) + self.grid_layout.addItem(self.vertical_spacer_4, 5, 2, 1, 1) ln_message = QApplication.translate( 'iris_wallet_desktop', 'ln_message', 'Starting LN node', @@ -226,6 +263,7 @@ def __init__(self, view_model, params): self.__loading_translucent_screen = LoadingTranslucentScreen( parent=self, description_text=ln_message, dot_animation=True, loader_type=LoaderDisplayModel.FULL_SCREEN, ) + self.adjust_size() self.retranslate_ui() self.setup_ui_connection() @@ -246,6 +284,16 @@ def retranslate_ui(self): 'iris_wallet_desktop', self._params.logo_2_title, None, ), ) + self.continue_button.setText( + QCoreApplication.translate( + 'iris_wallet_desktop', 'continue', None, + ), + ) + self.rln_node_connection_description.setText( + QCoreApplication.translate( + 'iris_wallet_desktop', 'rln_node_connection_description', None, + ), + ) def setup_ui_connection(self): """Set up connections for UI elements.""" @@ -255,23 +303,30 @@ def setup_ui_connection(self): self.show_wallet_loading_screen, ) self.close_button.clicked.connect(self.close_button_navigation) + self.continue_button.clicked.connect(self.on_click_continue) def handle_frame_click(self, _id): """Handle the click event for the option_frame_1 and option_frame_2.""" # Retrieve the transfer type from the parameters transfer_type = self._params.callback - # Handle the 'embedded' frame click event - if _id == WalletType.EMBEDDED_TYPE_WALLET.value: - SettingRepository.set_wallet_type(WalletType.EMBEDDED_TYPE_WALLET) - self._view_model.wallet_transfer_selection_view_model.start_node_for_embedded_option() - # Handle the 'remote' frame click event - elif _id == WalletType.REMOTE_TYPE_WALLET.value: - SettingRepository.set_wallet_type(WalletType.REMOTE_TYPE_WALLET) - self._view_model.page_navigation.ln_endpoint_page( - 'wallet_selection_page', - ) + if self.selected_frame == _id: + self.info_frame.setHidden(not self.info_frame.isHidden()) + if self.info_frame.isHidden(): + self.on_click_frame(_id, False) + else: + self.on_click_frame(_id, True) + return + + # If switching to another frame, ensure info_frame is visible + self.info_frame.show() + # Set the appropriate text + self._set_text_for_embedded_or_remote_connection_info(_id) + + # Reset the previously selected frame's style + if self.selected_frame is not None: + self.on_click_frame(self.selected_frame, False) # Handle the 'On chain' frame click event elif _id == TransferType.ON_CHAIN.value: @@ -303,15 +358,39 @@ def handle_frame_click(self, _id): self.asset_type, ) + # Apply styles for the newly selected frame + self.on_click_frame(_id, True) + + # Update the selected frame + self.selected_frame = _id + + def _set_text_for_embedded_or_remote_connection_info(self, _id): + """This method sets the text for the information label for the embedded or remote connection.""" + if _id == WalletType.EMBEDDED_TYPE_WALLET.value: + self.wallet_connection_info_label.setText( + QCoreApplication.translate( + 'iris_wallet_desktop', 'embedded_connection_info', None, + ), + ) + + elif _id == WalletType.REMOTE_TYPE_WALLET.value: + self.wallet_connection_info_label.setText( + QCoreApplication.translate( + 'iris_wallet_desktop', 'remote_connection_info', None, + ), + ) + def show_wallet_loading_screen(self, status): """This method handled show loading screen on wallet selection page""" if status is True: self.option_1_frame.setDisabled(True) self.option_2_frame.setDisabled(True) + self.continue_button.setDisabled(True) self.__loading_translucent_screen.start() if not status: self.option_1_frame.setDisabled(False) self.option_2_frame.setDisabled(False) + self.continue_button.setDisabled(False) self.__loading_translucent_screen.stop() def close_button_navigation(self): @@ -328,3 +407,57 @@ def close_button_navigation(self): self._params.rgb_asset_page_load_model.image_path, self._params.rgb_asset_page_load_model.asset_type, ) + + def on_click_frame(self, _id, is_selected: bool): + """Handles frame click styling.""" + if is_selected: + if _id == WalletType.EMBEDDED_TYPE_WALLET.value: + self.option_1_frame.setStyleSheet( + load_stylesheet( + 'views/qss/style.qss', + ), + ) + elif _id == WalletType.REMOTE_TYPE_WALLET.value: + self.option_2_frame.setStyleSheet( + load_stylesheet( + 'views/qss/style.qss', + ), + ) + + else: + if _id == WalletType.EMBEDDED_TYPE_WALLET.value: + self.option_1_frame.setStyleSheet( + load_stylesheet( + 'views/qss/wallet_or_transfer_selection_style.qss', + ), + ) + elif _id == WalletType.REMOTE_TYPE_WALLET.value: + self.option_2_frame.setStyleSheet( + load_stylesheet( + 'views/qss/wallet_or_transfer_selection_style.qss', + ), + ) + + def on_click_continue(self): + """Handles continue button click.""" + if self.selected_frame == WalletType.EMBEDDED_TYPE_WALLET.value: + SettingRepository.set_wallet_type(WalletType.EMBEDDED_TYPE_WALLET) + self._view_model.wallet_transfer_selection_view_model.start_node_for_embedded_option() + + elif self.selected_frame == WalletType.REMOTE_TYPE_WALLET.value: + SettingRepository.set_wallet_type(WalletType.REMOTE_TYPE_WALLET) + self._view_model.page_navigation.ln_endpoint_page( + 'wallet_selection_page', + ) + + def adjust_size(self): + """This method adjusts the size of the card""" + + if self._params.title == 'connection_type': + self.rln_node_connection_description.show() + self.widget_page.setMinimumSize(QSize(736, 416)) + self.widget_page.setMaximumSize(QSize(736, 542)) + self.option_1_frame.setMinimumSize(QSize(224, 204)) + self.option_1_frame.setMaximumSize(QSize(224, 204)) + self.option_2_frame.setMinimumSize(QSize(224, 204)) + self.option_2_frame.setMaximumSize(QSize(224, 204)) diff --git a/unit_tests/tests/ui_tests/ui_wallet_or_transfer_selection_test.py b/unit_tests/tests/ui_tests/ui_wallet_or_transfer_selection_test.py index d3a2378..cc3a077 100644 --- a/unit_tests/tests/ui_tests/ui_wallet_or_transfer_selection_test.py +++ b/unit_tests/tests/ui_tests/ui_wallet_or_transfer_selection_test.py @@ -5,9 +5,11 @@ from __future__ import annotations from unittest.mock import MagicMock +from unittest.mock import patch import pytest +from src.data.repository.setting_repository import SettingRepository from src.model.enums.enums_model import AssetType from src.model.enums.enums_model import TransferStatusEnumModel from src.model.enums.enums_model import TransferType @@ -17,6 +19,17 @@ from src.viewmodels.main_view_model import MainViewModel from src.views.ui_wallet_or_transfer_selection import WalletOrTransferSelectionWidget +SELECTED_FRAME_STYLESHEET = """ + QFrame{ + font: 15px "Inter"; + border-radius: 8px; + border: 1px solid white; + } + QLabel{ + border:none + } + """ + @pytest.fixture def wallet_or_transfer_selection_widget(qtbot): @@ -33,6 +46,8 @@ def wallet_or_transfer_selection_widget(qtbot): mock_navigation = MagicMock() view_model = MagicMock(MainViewModel(mock_navigation)) widget = WalletOrTransferSelectionWidget(view_model, params) + widget._view_model.page_navigation.send_bitcoin_page = MagicMock() + widget._view_model.page_navigation.receive_bitcoin_page = MagicMock() qtbot.addWidget(widget) return widget @@ -45,49 +60,29 @@ def test_retranslate_ui(wallet_or_transfer_selection_widget: WalletOrTransferSel assert wallet_or_transfer_selection_widget.option_2_text_label.text() == 'remote' -def test_handle_frame_click_embedded_wallet(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): +def test_handle_frame_click_embedded_wallet(wallet_or_transfer_selection_widget, mocker): """Test handle_frame_click for embedded wallet option.""" - # Mock the methods that should be called + # Patch correctly mock_start_node = mocker.patch.object( wallet_or_transfer_selection_widget._view_model.wallet_transfer_selection_view_model, 'start_node_for_embedded_option', ) - mock_set_wallet_type = mocker.patch( - 'src.data.repository.setting_repository.SettingRepository.set_wallet_type', + mock_set_wallet_type = mocker.patch.object( + SettingRepository, 'set_wallet_type', ) - # Call the method with the embedded wallet ID + # Simulate clicking the frame wallet_or_transfer_selection_widget.handle_frame_click( - WalletType.EMBEDDED_TYPE_WALLET.value, - ) - - # Assertions - mock_set_wallet_type.assert_called_once_with( WalletType.EMBEDDED_TYPE_WALLET, ) - mock_start_node.assert_called_once() - -def test_handle_frame_click_connect_wallet(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): - """Test handle_frame_click for connect wallet option.""" - # Mock the methods that should be called - - mock_set_wallet_type = mocker.patch( - 'src.data.repository.setting_repository.SettingRepository.set_wallet_type', - ) - mock_ln_endpoint_page = mocker.patch.object( - wallet_or_transfer_selection_widget._view_model.page_navigation, 'ln_endpoint_page', - ) - - # Call the method with the connect wallet ID - wallet_or_transfer_selection_widget.handle_frame_click( - WalletType.REMOTE_TYPE_WALLET.value, - ) + # Simulate clicking continue + wallet_or_transfer_selection_widget.on_click_continue() # Assertions mock_set_wallet_type.assert_called_once_with( - WalletType.REMOTE_TYPE_WALLET, + WalletType.EMBEDDED_TYPE_WALLET, ) - mock_ln_endpoint_page.assert_called_once_with('wallet_selection_page') + mock_start_node.assert_called_once() def test_handle_frame_click_on_chain_receive(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): @@ -162,23 +157,23 @@ def test_handle_frame_click_off_chain_receive(wallet_or_transfer_selection_widge ) -def test_handle_frame_click_off_chain_send(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): - """Test handle_frame_click for off-chain send option.""" - # Setup the parameters - wallet_or_transfer_selection_widget._params.callback = TransferStatusEnumModel.SEND.value +def test_handle_frame_click_connect_wallet(wallet_or_transfer_selection_widget, mocker): + """Test handle_frame_click for connect wallet option.""" - # Mock the methods that should be called - mock_send_ln_invoice_page = mocker.patch.object( - wallet_or_transfer_selection_widget._view_model.page_navigation, 'send_ln_invoice_page', + mock_set_wallet_type = mocker.patch( + 'src.data.repository.setting_repository.SettingRepository.set_wallet_type', + ) + _ = mocker.patch.object( + wallet_or_transfer_selection_widget._view_model.page_navigation, 'ln_endpoint_page', ) - # Call the method with the off-chain ID wallet_or_transfer_selection_widget.handle_frame_click( - TransferType.LIGHTNING.value, + WalletType.REMOTE_TYPE_WALLET, ) - # Assertions - mock_send_ln_invoice_page.assert_called_once() + wallet_or_transfer_selection_widget.on_click_continue() + + mock_set_wallet_type.assert_called_once_with(WalletType.REMOTE_TYPE_WALLET) def test_show_wallet_loading_screen_true(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): @@ -201,42 +196,28 @@ def test_show_wallet_loading_screen_false(wallet_or_transfer_selection_widget: W assert wallet_or_transfer_selection_widget.option_2_frame.isEnabled() is True -def test_handle_frame_click_btc_send_and_receive(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): - """Test handle_frame_click for on-chain BTC send and receive options.""" - - # Setup the parameters for sending and receiving BTC +def test_handle_frame_click_send_btc(wallet_or_transfer_selection_widget): + """Test handle_frame_click for sending BTC.""" wallet_or_transfer_selection_widget._params.callback = TransferStatusEnumModel.SEND_BTC.value - wallet_or_transfer_selection_widget._params.asset_id = 'test_asset_id' - # Mock the methods that should be called - mock_send_bitcoin_page = mocker.patch.object( - wallet_or_transfer_selection_widget._view_model.page_navigation, 'send_bitcoin_page', - ) - mock_receive_bitcoin_page = mocker.patch.object( - wallet_or_transfer_selection_widget._view_model.page_navigation, 'receive_bitcoin_page', - ) - - # Test case for sending BTC wallet_or_transfer_selection_widget.handle_frame_click( TransferType.ON_CHAIN.value, ) - # Assertions for sending BTC - mock_send_bitcoin_page.assert_called_once_with() + print(wallet_or_transfer_selection_widget._view_model.page_navigation.send_bitcoin_page.call_args_list) - # Reset mocks and test for receiving BTC - mock_send_bitcoin_page.reset_mock() + wallet_or_transfer_selection_widget._view_model.page_navigation.send_bitcoin_page.assert_called_once_with() - # Setup for receiving BTC - wallet_or_transfer_selection_widget._params.callback = TransferStatusEnumModel.RECEIVE_BTC.value - # Call the method for receiving BTC +def test_handle_frame_click_receive_btc(wallet_or_transfer_selection_widget): + """Test handle_frame_click for receiving BTC.""" + + wallet_or_transfer_selection_widget._params.callback = TransferStatusEnumModel.RECEIVE_BTC.value wallet_or_transfer_selection_widget.handle_frame_click( TransferType.ON_CHAIN.value, ) - # Assertions for receiving BTC - mock_receive_bitcoin_page.assert_called_once_with() + wallet_or_transfer_selection_widget._view_model.page_navigation.receive_bitcoin_page.assert_called_once_with() def test_close_button_navigation(wallet_or_transfer_selection_widget: WalletOrTransferSelectionWidget, mocker): @@ -271,3 +252,130 @@ def test_close_button_navigation(wallet_or_transfer_selection_widget: WalletOrTr mock_asset_info.emit.assert_called_once_with( 'test_asset_id', 'test_asset_name', 'test_image_path', 'test_asset_type', ) # Ensure asset info emission was triggered with correct parameters + + +def test_handle_frame_click_toggle_info_frame(wallet_or_transfer_selection_widget): + """Test toggle behavior when clicking the same frame again.""" + + # Set the selected frame to SEND_BTC so that the condition matches + wallet_or_transfer_selection_widget.selected_frame = TransferStatusEnumModel.SEND_BTC.value + + # Store initial visibility state + initial_state = wallet_or_transfer_selection_widget.info_frame.isHidden() + + # Call handle_frame_click with the same _id + wallet_or_transfer_selection_widget.handle_frame_click( + TransferStatusEnumModel.SEND_BTC.value, + ) + + # Assert that info_frame visibility is toggled + assert wallet_or_transfer_selection_widget.info_frame.isHidden() != initial_state + + +def test_on_click_frame_embedded_selected(wallet_or_transfer_selection_widget, mocker): + """Test on_click_frame with embedded wallet selected (is_selected True).""" + # Patch load_stylesheet even though it should not be used in the True branch. + dummy_stylesheet = 'dummy stylesheet' + mocker.patch( + 'src.views.ui_wallet_or_transfer_selection.load_stylesheet', + return_value=SELECTED_FRAME_STYLESHEET, + ) + + widget = wallet_or_transfer_selection_widget + # Set option_1_frame and option_2_frame as mocks + widget.option_1_frame = MagicMock() + widget.option_2_frame = MagicMock() + + # Call with embedded wallet ID and is_selected True + widget.on_click_frame(WalletType.EMBEDDED_TYPE_WALLET.value, True) + + # Expect that option_1_frame gets the hard-coded options_stylesheet + + widget.option_1_frame.setStyleSheet.assert_called_once_with( + SELECTED_FRAME_STYLESHEET, + ) + widget.option_2_frame.setStyleSheet.assert_not_called() + + +def test_on_click_frame_embedded_not_selected(wallet_or_transfer_selection_widget, mocker): + """Test on_click_frame with embedded wallet not selected (is_selected False).""" + dummy_stylesheet = 'dummy stylesheet' + # Patch load_stylesheet to return our dummy stylesheet. + mocker.patch( + 'src.views.ui_wallet_or_transfer_selection.load_stylesheet', + return_value=dummy_stylesheet, + ) + + widget = wallet_or_transfer_selection_widget + widget.option_1_frame = MagicMock() + widget.option_2_frame = MagicMock() + + widget.on_click_frame(WalletType.EMBEDDED_TYPE_WALLET.value, False) + + # In the not selected branch, the stylesheet is loaded via load_stylesheet. + widget.option_1_frame.setStyleSheet.assert_called_once_with( + dummy_stylesheet, + ) + widget.option_2_frame.setStyleSheet.assert_not_called() + + +def test_on_click_frame_remote_selected(wallet_or_transfer_selection_widget, mocker): + """Test on_click_frame with remote wallet selected (is_selected True).""" + dummy_stylesheet = 'dummy stylesheet' + mocker.patch( + 'src.views.ui_wallet_or_transfer_selection.load_stylesheet', + return_value=SELECTED_FRAME_STYLESHEET, + ) + + widget = wallet_or_transfer_selection_widget + widget.option_1_frame = MagicMock() + widget.option_2_frame = MagicMock() + + widget.on_click_frame(WalletType.REMOTE_TYPE_WALLET.value, True) + + widget.option_2_frame.setStyleSheet.assert_called_once_with( + SELECTED_FRAME_STYLESHEET, + ) + widget.option_1_frame.setStyleSheet.assert_not_called() + + +def test_on_click_frame_remote_not_selected(wallet_or_transfer_selection_widget, mocker): + """Test on_click_frame with remote wallet not selected (is_selected False).""" + dummy_stylesheet = 'dummy stylesheet' + mocker.patch( + 'src.views.ui_wallet_or_transfer_selection.load_stylesheet', + return_value=dummy_stylesheet, + ) + + widget = wallet_or_transfer_selection_widget + widget.option_1_frame = MagicMock() + widget.option_2_frame = MagicMock() + + widget.on_click_frame(WalletType.REMOTE_TYPE_WALLET.value, False) + + widget.option_2_frame.setStyleSheet.assert_called_once_with( + dummy_stylesheet, + ) + widget.option_1_frame.setStyleSheet.assert_not_called() + + +@patch('src.views.ui_wallet_or_transfer_selection.SettingRepository.set_wallet_type') +def test_on_click_continue(mock_set_wallet_type, wallet_or_transfer_selection_widget): + """Test on_click_continue handles wallet selection properly.""" + + # Mock view model and navigation + wallet_or_transfer_selection_widget._view_model = MagicMock() + + # Test Embedded Wallet + wallet_or_transfer_selection_widget.selected_frame = WalletType.EMBEDDED_TYPE_WALLET.value + wallet_or_transfer_selection_widget.on_click_continue() + mock_set_wallet_type.assert_called_with(WalletType.EMBEDDED_TYPE_WALLET) + wallet_or_transfer_selection_widget._view_model.wallet_transfer_selection_view_model.start_node_for_embedded_option.assert_called() + + # Test Remote Wallet + wallet_or_transfer_selection_widget.selected_frame = WalletType.REMOTE_TYPE_WALLET.value + wallet_or_transfer_selection_widget.on_click_continue() + mock_set_wallet_type.assert_called_with(WalletType.REMOTE_TYPE_WALLET) + wallet_or_transfer_selection_widget._view_model.page_navigation.ln_endpoint_page.assert_called_with( + 'wallet_selection_page', + )