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 9564cc0..8388de4 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 04b0f81..8e61cc2 100644 --- a/src/translations/en_IN.ts +++ b/src/translations/en_IN.ts @@ -1688,5 +1688,17 @@ If you understand the above remarks and wish to proceed, press the button below remote 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', + )