From a6d787a2b3a1461b21655eb59e993898f4bed905 Mon Sep 17 00:00:00 2001 From: AreteDriver Date: Sun, 26 Apr 2026 03:17:07 -0700 Subject: [PATCH 1/2] chore: surface v3.2.0 intel settings in Settings tab Adds an "Intel" panel to the Settings tab with controls for the new v3.2.0 keys, so users can tune them from the UI instead of editing settings.json: - intel.track_character_locations (checkbox) Toggles the per-character Local-log tracker. Tooltip explains it drives smart fan-out and chip system labels. Restart-required. - intel.threat_jumps_threshold (spinbox, 0-5) How many jumps from an alert system a character can be and still see a threat tint. 0 = exact-match only. Tooltip explains the falloff. - replay_strip_enabled (read-only summary) Shows how many characters have the per-character toggle enabled and points users to the right-click menu where it lives. Surfacing the feature here is the discoverability fix; the actual toggle stays per-frame. Wires the panel into SettingsTab's panel stack and category tree between Hotkeys and Appearance. 7 new tests (6 IntelPanel state/wiring + 1 updated existing test_setup_ui_creates_all_panels for the new mock). Suite: 2397 passed, 5 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/argus_overview/ui/settings_tab.py | 109 +++++++++++++++++++++++++- tests/test_settings_tab.py | 92 ++++++++++++++++++++++ 2 files changed, 198 insertions(+), 3 deletions(-) diff --git a/src/argus_overview/ui/settings_tab.py b/src/argus_overview/ui/settings_tab.py index 8c20376..c596af4 100644 --- a/src/argus_overview/ui/settings_tab.py +++ b/src/argus_overview/ui/settings_tab.py @@ -410,6 +410,102 @@ def _reset_hotkey(self): ) +class IntelPanel(QWidget): + """ + Intel settings — exposes the v3.2.0 chrome controls so users don't + have to edit settings.json directly. + + Surfaces: + - intel.track_character_locations (bool, default true) + - intel.threat_jumps_threshold (int, default 1, range 0-5) + """ + + setting_changed = Signal(str, object) + + def __init__(self, settings_manager): + super().__init__() + self.settings_manager = settings_manager + self._setup_ui() + + def _setup_ui(self): + layout = QVBoxLayout() + + # ---- Per-character location tracker --------------------------- + loc_group = QGroupBox("Per-Character Location Tracking") + loc_form = QFormLayout() + + self.track_locations_check = QCheckBox() + self.track_locations_check.setChecked( + self.settings_manager.get("intel.track_character_locations", True) + ) + self.track_locations_check.stateChanged.connect( + lambda: self.setting_changed.emit( + "intel.track_character_locations", + self.track_locations_check.isChecked(), + ) + ) + self.track_locations_check.setToolTip( + "Read each EVE client's Local channel log to track which " + "system that character is currently in.\n" + "Required for smart per-character threat fan-out and the " + "system label on each chip in the dock.\n" + "Takes effect on next app restart." + ) + loc_form.addRow("Track per-character location:", self.track_locations_check) + + loc_group.setLayout(loc_form) + layout.addWidget(loc_group) + + # ---- Adjacent-system threat tinting --------------------------- + threat_group = QGroupBox("Adjacent-System Threat Tinting") + threat_form = QFormLayout() + + self.jumps_threshold_spin = QSpinBox() + self.jumps_threshold_spin.setRange(0, 5) + self.jumps_threshold_spin.setValue( + int(self.settings_manager.get("intel.threat_jumps_threshold", 1)) + ) + self.jumps_threshold_spin.setSuffix(" jumps") + self.jumps_threshold_spin.valueChanged.connect( + lambda v: self.setting_changed.emit("intel.threat_jumps_threshold", v) + ) + self.jumps_threshold_spin.setToolTip( + "How many jumps away from an alert system a character can be " + "and still see a threat tint on their preview frame and chip.\n" + "0 = exact-match only (no adjacent tinting).\n" + "1 = same system + immediate neighbors (default).\n" + "Higher values cast a wider net at proportionally lower alpha.\n" + "Takes effect on next app restart." + ) + threat_form.addRow("Max jumps for tinting:", self.jumps_threshold_spin) + + threat_group.setLayout(threat_form) + layout.addWidget(threat_group) + + # ---- Replay strip toggle (read-only summary) ------------------ + # Per-character toggles live in each window's right-click menu; + # we surface the count here so users discover the feature exists. + replay_group = QGroupBox("Replay Strip") + replay_form = QFormLayout() + + store = self.settings_manager.get("replay_strip_enabled", {}) or {} + active_count = sum(1 for v in store.values() if v) if isinstance(store, dict) else 0 + replay_label = QLabel( + f"{active_count} character(s) have the replay strip enabled.\n" + "Right-click a preview frame and choose 'Toggle Replay Strip' " + "to enable or disable per character." + ) + replay_label.setWordWrap(True) + replay_label.setStyleSheet("color: #aaa; padding: 4px;") + replay_form.addRow(replay_label) + + replay_group.setLayout(replay_form) + layout.addWidget(replay_group) + + layout.addStretch() + self.setLayout(layout) + + class AppearancePanel(QWidget): """Appearance settings""" @@ -632,6 +728,12 @@ def _setup_ui(self): self.hotkeys_panel.setting_changed.connect(self._on_setting_changed) self.panel_stack.addWidget(self.hotkeys_panel) + # Intel panel surfaces the v3.2.0 chrome controls (per-character + # location tracking, jumps-from threshold, replay strip summary). + self.intel_panel = IntelPanel(self.settings_manager) + self.intel_panel.setting_changed.connect(self._on_setting_changed) + self.panel_stack.addWidget(self.intel_panel) + self.appearance_panel = AppearancePanel(self.settings_manager) self.appearance_panel.setting_changed.connect(self._on_setting_changed) self.panel_stack.addWidget(self.appearance_panel) @@ -663,7 +765,7 @@ def _create_category_tree(self) -> QWidget: self.category_tree = QTreeWidget() self.category_tree.setHeaderHidden(True) - categories = ["General", "Performance", "Hotkeys", "Appearance", "Advanced"] + categories = ["General", "Performance", "Hotkeys", "Intel", "Appearance", "Advanced"] for category in categories: item = QTreeWidgetItem([category]) @@ -687,8 +789,9 @@ def _on_category_changed(self, current, previous): "General": 0, "Performance": 1, "Hotkeys": 2, - "Appearance": 3, - "Advanced": 4, + "Intel": 3, + "Appearance": 4, + "Advanced": 5, } category = current.text(0) if category in categories: diff --git a/tests/test_settings_tab.py b/tests/test_settings_tab.py index 86b49b8..3531380 100644 --- a/tests/test_settings_tab.py +++ b/tests/test_settings_tab.py @@ -195,6 +195,95 @@ def test_signal_exists(self): assert hasattr(AppearancePanel, "setting_changed") +class TestIntelPanel: + """Tests for IntelPanel (v3.2.0 chrome controls).""" + + def _settings_mock(self, overrides=None): + """Per-key settings mock so unrelated lookups return their defaults.""" + store = { + "intel.track_character_locations": True, + "intel.threat_jumps_threshold": 1, + "replay_strip_enabled": {}, + } + if overrides: + store.update(overrides) + sm = MagicMock() + sm.get.side_effect = lambda key, default=None: store.get(key, default) + return sm + + def test_signal_exists(self): + from argus_overview.ui.settings_tab import IntelPanel + + assert hasattr(IntelPanel, "setting_changed") + + def test_init_reads_defaults(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock() + panel = IntelPanel(sm) + try: + assert panel.track_locations_check.isChecked() is True + assert panel.jumps_threshold_spin.value() == 1 + finally: + panel.deleteLater() + + def test_init_reads_overridden_values(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock( + { + "intel.track_character_locations": False, + "intel.threat_jumps_threshold": 3, + } + ) + panel = IntelPanel(sm) + try: + assert panel.track_locations_check.isChecked() is False + assert panel.jumps_threshold_spin.value() == 3 + finally: + panel.deleteLater() + + def test_track_locations_emits_signal(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock() + panel = IntelPanel(sm) + received: list[tuple[str, object]] = [] + panel.setting_changed.connect(lambda k, v: received.append((k, v))) + try: + panel.track_locations_check.setChecked(False) + assert ( + "intel.track_character_locations", + False, + ) in received + finally: + panel.deleteLater() + + def test_jumps_threshold_emits_signal(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock() + panel = IntelPanel(sm) + received: list[tuple[str, object]] = [] + panel.setting_changed.connect(lambda k, v: received.append((k, v))) + try: + panel.jumps_threshold_spin.setValue(2) + assert ("intel.threat_jumps_threshold", 2) in received + finally: + panel.deleteLater() + + def test_jumps_threshold_clamped_to_range(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock({"intel.threat_jumps_threshold": 99}) + panel = IntelPanel(sm) + try: + # Spinbox max is 5 — value should clamp on init. + assert panel.jumps_threshold_spin.value() == 5 + finally: + panel.deleteLater() + + # Test AdvancedPanel class TestAdvancedPanel: """Tests for AdvancedPanel""" @@ -994,12 +1083,14 @@ class TestSettingsTabSetupUI: @patch("argus_overview.ui.settings_tab.GeneralPanel") @patch("argus_overview.ui.settings_tab.PerformancePanel") @patch("argus_overview.ui.settings_tab.HotkeysPanel") + @patch("argus_overview.ui.settings_tab.IntelPanel") @patch("argus_overview.ui.settings_tab.AppearancePanel") @patch("argus_overview.ui.settings_tab.AdvancedPanel") def test_setup_ui_creates_all_panels( self, mock_adv, mock_app, + mock_intel, mock_hk, mock_perf, mock_gen, @@ -1025,6 +1116,7 @@ def test_setup_ui_creates_all_panels( assert mock_gen.called assert mock_perf.called assert mock_hk.called + assert mock_intel.called assert mock_app.called assert mock_adv.called From eac73501000114c20c65691e43cab3d55fd99243 Mon Sep 17 00:00:00 2001 From: AreteDriver Date: Sun, 26 Apr 2026 03:27:55 -0700 Subject: [PATCH 2/2] feat(intel): master toggle for intel-aware preview chrome MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some users won't want the v3.2.0 threat tints — they may not use chat-log intel, may find the chrome distracting, or may prefer plain previews. Adds a master toggle (intel.preview_chrome_enabled, default true) that suppresses ALL threat chrome on previews and chips while leaving the parser, audio alerts, tray notifications, system labels, and replay strip untouched. Implementation: - New setting intel.preview_chrome_enabled (default true) added to SettingsManager.DEFAULT_SETTINGS, alongside formalized defaults for the other v3.2.0 keys (track_character_locations, threat_jumps_threshold). - MainWindowV21._on_intel_alert reads the setting (defensive getattr for bypassed-init test sites) and skips the fan-out to WindowManager.apply_threat_state and StatusDock.set_threat_state when off. Other AlertTypes (audio, tray) keep firing. - MainWindowV21._clear_threat_chrome flushes both surfaces with CLEAR so a toggle-off takes effect immediately rather than waiting for the 30s decay timer. - MainWindowV21._apply_setting routes the toggle-off case through it. - IntelPanel adds the checkbox at the top of the panel with a tooltip spelling out exactly what the toggle does and does NOT affect. 19 new tests covering on/off fan-out, critical-tray independence, default-on for missing settings, _clear_threat_chrome surface coverage, _apply_setting routing, and IntelPanel checkbox state/signal. Suite: 2411 passed, 5 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/argus_overview/ui/main_window_v21.py | 34 ++++- src/argus_overview/ui/settings_manager.py | 10 ++ src/argus_overview/ui/settings_tab.py | 29 ++++ tests/test_main_tab.py | 167 ++++++++++++++++++++++ tests/test_settings_tab.py | 34 +++++ 5 files changed, 273 insertions(+), 1 deletion(-) diff --git a/src/argus_overview/ui/main_window_v21.py b/src/argus_overview/ui/main_window_v21.py index d8dd4ae..20f7c51 100644 --- a/src/argus_overview/ui/main_window_v21.py +++ b/src/argus_overview/ui/main_window_v21.py @@ -709,10 +709,18 @@ def _on_intel_alert(self, report, alert_type): if not isinstance(report, IntelReport): return + # Master toggle (v3.2.0): when off, suppress all visual chrome but + # still let other AlertTypes fire (audio, tray notification). The + # parser keeps running, only the preview/dock tints are gated. + # Defensive getattr: bypassed-init test helpers don't set + # settings_manager — default to chrome on. + sm = getattr(self, "settings_manager", None) + chrome_enabled = sm.get("intel.preview_chrome_enabled", True) if sm is not None else True + # Fan out threat state to preview frames + status dock once per report # (filter on VISUAL_BORDER so we only trigger on a single AlertType # emission per report, not on every type the dispatcher fires). - if alert_type == AlertType.VISUAL_BORDER and hasattr(self, "main_tab"): + if chrome_enabled and alert_type == AlertType.VISUAL_BORDER and hasattr(self, "main_tab"): window_manager = getattr(self.main_tab, "window_manager", None) if window_manager is not None and hasattr(window_manager, "apply_threat_state"): window_manager.apply_threat_state(report.threat_level, report.system) @@ -728,6 +736,24 @@ def _on_intel_alert(self, report, alert_type): f"{report.hostile_count or '?'} hostiles - {', '.join(report.ship_types[:2]) or 'unknown ships'}", ) + def _clear_threat_chrome(self) -> None: + """Force-clear any active threat tints across previews + chips. + + Called when the user toggles intel.preview_chrome_enabled off so + the change takes effect immediately rather than waiting for the + 30s decay timer. + """ + from argus_overview.intel.parser import ThreatLevel + + if not hasattr(self, "main_tab"): + return + wm = getattr(self.main_tab, "window_manager", None) + if wm is not None and hasattr(wm, "apply_threat_state"): + wm.apply_threat_state(ThreatLevel.CLEAR, None) + dock = getattr(self.main_tab, "status_dock", None) + if dock is not None and hasattr(dock, "set_threat_state"): + dock.set_threat_state(ThreatLevel.CLEAR, None) + @Slot(object) def _on_intel_received(self, report): """Handle intel received from intel tab.""" @@ -908,6 +934,12 @@ def _apply_setting(self, key: str, value): # Will be implemented with hotkey functionality pass + elif key == "intel.preview_chrome_enabled" and not value: + # User just turned threat chrome off — flush any active tints + # so the change is visible immediately, not after the 30s + # decay window. + self._clear_threat_chrome() + def _apply_low_power_mode(self, enabled: bool): """ Apply low power mode settings. diff --git a/src/argus_overview/ui/settings_manager.py b/src/argus_overview/ui/settings_manager.py index 73e850d..823ad2d 100644 --- a/src/argus_overview/ui/settings_manager.py +++ b/src/argus_overview/ui/settings_manager.py @@ -94,6 +94,16 @@ class SettingsManager: "cooldown_seconds": 5, # Minimum time between alerts for same system "current_system": "", # Player's current system for jump calculations "custom_log_path": "", # Custom path to EVE chat logs + # v3.2.0 intel-aware preview chrome — master toggle. When False, + # parser/alerts still run but threat tints + dots + badges are + # suppressed on previews and chips. + "preview_chrome_enabled": True, + # v3.2.0 — read each EVE client's Local channel log to track + # which system that character is in. + "track_character_locations": True, + # v3.2.0 — max jumps from an alert system that a character can + # be and still see threat tinting. 0 disables adjacent tinting. + "threat_jumps_threshold": 1, }, } diff --git a/src/argus_overview/ui/settings_tab.py b/src/argus_overview/ui/settings_tab.py index c596af4..a39703d 100644 --- a/src/argus_overview/ui/settings_tab.py +++ b/src/argus_overview/ui/settings_tab.py @@ -430,6 +430,35 @@ def __init__(self, settings_manager): def _setup_ui(self): layout = QVBoxLayout() + # ---- Master toggle — chrome on/off --------------------------- + master_group = QGroupBox("Intel-Aware Preview Chrome") + master_form = QFormLayout() + + self.chrome_enabled_check = QCheckBox() + self.chrome_enabled_check.setChecked( + self.settings_manager.get("intel.preview_chrome_enabled", True) + ) + self.chrome_enabled_check.stateChanged.connect( + lambda: self.setting_changed.emit( + "intel.preview_chrome_enabled", + self.chrome_enabled_check.isChecked(), + ) + ) + self.chrome_enabled_check.setToolTip( + "Master toggle for the v3.2.0 intel-aware preview chrome.\n\n" + "When OFF, threat tints / pulses / dots / +Nj badges are\n" + "suppressed on previews and chips. The intel parser, audio\n" + "alerts, tray notifications, system labels on chips, and the\n" + "replay strip all keep working.\n\n" + "Use this if you find threat tints distracting or you don't\n" + "use chat-log intel — the rest of Argus is unaffected." + ) + self.chrome_enabled_check.setStyleSheet("QCheckBox { font-weight: bold; }") + master_form.addRow("Show threat chrome on previews:", self.chrome_enabled_check) + + master_group.setLayout(master_form) + layout.addWidget(master_group) + # ---- Per-character location tracker --------------------------- loc_group = QGroupBox("Per-Character Location Tracking") loc_form = QFormLayout() diff --git a/tests/test_main_tab.py b/tests/test_main_tab.py index fab376b..c8924a2 100644 --- a/tests/test_main_tab.py +++ b/tests/test_main_tab.py @@ -10710,3 +10710,170 @@ def test_init_restores_strip_from_settings(self, qapp): assert widget.is_replay_strip_enabled() is True finally: widget.deleteLater() + + +# ============================================================================= +# Master toggle: intel.preview_chrome_enabled (v3.2.0 follow-up) +# ============================================================================= + + +def _make_window_with_settings(chrome_enabled: bool): + """Build a bypassed-init MainWindowV21 with a settings_manager mock.""" + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + sm = MagicMock() + sm.get.side_effect = lambda key, default=None: ( + chrome_enabled if key == "intel.preview_chrome_enabled" else default + ) + window.settings_manager = sm + window.main_tab = MagicMock() + window.main_tab.window_manager = MagicMock() + window.main_tab.status_dock = MagicMock() + window.system_tray = MagicMock() + return window + + +class TestMainWindowV21ChromeMasterToggle: + """When intel.preview_chrome_enabled is False, fan-out is suppressed.""" + + def _make_report(self): + from argus_overview.intel.parser import IntelReport, ThreatLevel + + return IntelReport( + system="HED-GP", + threat_level=ThreatLevel.DANGER, + hostile_count=2, + ship_types=[], + player_names=[], + raw_message="hostiles", + ) + + def test_chrome_on_calls_fan_out(self): + from argus_overview.intel.alerts import AlertType + + window = _make_window_with_settings(chrome_enabled=True) + window._on_intel_alert(self._make_report(), AlertType.VISUAL_BORDER) + window.main_tab.window_manager.apply_threat_state.assert_called_once() + window.main_tab.status_dock.set_threat_state.assert_called_once() + + def test_chrome_off_suppresses_fan_out(self): + from argus_overview.intel.alerts import AlertType + + window = _make_window_with_settings(chrome_enabled=False) + window._on_intel_alert(self._make_report(), AlertType.VISUAL_BORDER) + window.main_tab.window_manager.apply_threat_state.assert_not_called() + window.main_tab.status_dock.set_threat_state.assert_not_called() + + def test_chrome_off_still_fires_critical_tray_notification(self): + from argus_overview.intel.alerts import AlertType + from argus_overview.intel.parser import IntelReport, ThreatLevel + + window = _make_window_with_settings(chrome_enabled=False) + critical = IntelReport( + system="Jita", + threat_level=ThreatLevel.CRITICAL, + hostile_count=10, + ship_types=["titan"], + player_names=[], + raw_message="hot drop", + ) + window._on_intel_alert(critical, AlertType.VISUAL_BORDER) + # Tray notification independent of the chrome toggle + window.system_tray.show_notification.assert_called_once() + + def test_no_settings_manager_defaults_to_on(self): + """Bypassed-init sites without settings_manager should still fan out.""" + from argus_overview.intel.alerts import AlertType + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + # No settings_manager set + window.main_tab = MagicMock() + window.main_tab.window_manager = MagicMock() + window.main_tab.status_dock = MagicMock() + window.system_tray = MagicMock() + + window._on_intel_alert(self._make_report(), AlertType.VISUAL_BORDER) + + window.main_tab.window_manager.apply_threat_state.assert_called_once() + + +class TestMainWindowV21ClearThreatChrome: + """_clear_threat_chrome flushes both surfaces with CLEAR.""" + + def test_clear_calls_both_surfaces(self): + from argus_overview.intel.parser import ThreatLevel + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + window.main_tab = MagicMock() + window.main_tab.window_manager = MagicMock() + window.main_tab.status_dock = MagicMock() + + window._clear_threat_chrome() + + window.main_tab.window_manager.apply_threat_state.assert_called_once_with( + ThreatLevel.CLEAR, None + ) + window.main_tab.status_dock.set_threat_state.assert_called_once_with( + ThreatLevel.CLEAR, None + ) + + def test_clear_no_main_tab_safe(self): + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + # No main_tab — should not raise + window._clear_threat_chrome() + + def test_clear_dock_optional(self): + from argus_overview.intel.parser import ThreatLevel + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + window.main_tab = MagicMock(spec=["window_manager"]) + window.main_tab.window_manager = MagicMock() + + window._clear_threat_chrome() + + window.main_tab.window_manager.apply_threat_state.assert_called_once_with( + ThreatLevel.CLEAR, None + ) + + +class TestMainWindowV21ApplySettingChromeToggle: + """_apply_setting routes the toggle-off case to _clear_threat_chrome.""" + + def test_toggle_off_clears_chrome(self): + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + window.logger = MagicMock() + window._clear_threat_chrome = MagicMock() + + window._apply_setting("intel.preview_chrome_enabled", False) + + window._clear_threat_chrome.assert_called_once() + + def test_toggle_on_does_not_clear(self): + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + window.logger = MagicMock() + window._clear_threat_chrome = MagicMock() + + window._apply_setting("intel.preview_chrome_enabled", True) + + window._clear_threat_chrome.assert_not_called() + + def test_unrelated_key_does_not_clear(self): + from argus_overview.ui.main_window_v21 import MainWindowV21 + + window = MainWindowV21.__new__(MainWindowV21) + window.logger = MagicMock() + window._clear_threat_chrome = MagicMock() + + window._apply_setting("performance.default_refresh_rate", 30) + + window._clear_threat_chrome.assert_not_called() diff --git a/tests/test_settings_tab.py b/tests/test_settings_tab.py index 3531380..a28d2b7 100644 --- a/tests/test_settings_tab.py +++ b/tests/test_settings_tab.py @@ -201,6 +201,7 @@ class TestIntelPanel: def _settings_mock(self, overrides=None): """Per-key settings mock so unrelated lookups return their defaults.""" store = { + "intel.preview_chrome_enabled": True, "intel.track_character_locations": True, "intel.threat_jumps_threshold": 1, "replay_strip_enabled": {}, @@ -283,6 +284,39 @@ def test_jumps_threshold_clamped_to_range(self, qapp): finally: panel.deleteLater() + def test_chrome_toggle_default_on(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock() + panel = IntelPanel(sm) + try: + assert panel.chrome_enabled_check.isChecked() is True + finally: + panel.deleteLater() + + def test_chrome_toggle_init_off(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock({"intel.preview_chrome_enabled": False}) + panel = IntelPanel(sm) + try: + assert panel.chrome_enabled_check.isChecked() is False + finally: + panel.deleteLater() + + def test_chrome_toggle_emits_setting_changed(self, qapp): + from argus_overview.ui.settings_tab import IntelPanel + + sm = self._settings_mock() + panel = IntelPanel(sm) + received: list[tuple[str, object]] = [] + panel.setting_changed.connect(lambda k, v: received.append((k, v))) + try: + panel.chrome_enabled_check.setChecked(False) + assert ("intel.preview_chrome_enabled", False) in received + finally: + panel.deleteLater() + # Test AdvancedPanel class TestAdvancedPanel: