diff --git a/plugins/skill_scanner/plugin.py b/plugins/skill_scanner/plugin.py index f4690aa..05c1ed4 100644 --- a/plugins/skill_scanner/plugin.py +++ b/plugins/skill_scanner/plugin.py @@ -150,8 +150,12 @@ class SkillScannerPlugin(BasePlugin): description = "Uses core OCR and Log services" hotkey = "ctrl+shift+s" - # Signal for thread-safe hotkey scanning + # Signals for thread-safe UI updates hotkey_triggered = pyqtSignal() + update_status_signal = pyqtSignal(str, bool, bool) # message, success, error + update_session_table_signal = pyqtSignal(object) # skills dict + update_counters_signal = pyqtSignal() + enable_scan_button_signal = pyqtSignal(bool) def initialize(self): """Setup skill scanner.""" @@ -167,8 +171,12 @@ class SkillScannerPlugin(BasePlugin): self.current_scan_session = {} # Skills collected in current multi-page scan self.pages_scanned = 0 - # Connect hotkey signal + # Connect signals self.hotkey_triggered.connect(self._scan_page_for_multi) + self.update_status_signal.connect(self._update_multi_page_status_slot) + self.update_session_table_signal.connect(self._update_session_table) + self.update_counters_signal.connect(self._update_counters_slot) + self.enable_scan_button_signal.connect(self.scan_page_btn.setEnabled) # Subscribe to skill gain events from core Log service try: @@ -514,7 +522,7 @@ class SkillScannerPlugin(BasePlugin): ocr_service = get_ocr_service() if not ocr_service.is_available(): - self._update_multi_page_status("Error: OCR not available", error=True) + self.update_status_signal.emit("Error: OCR not available", False, True) return # Capture and OCR @@ -530,33 +538,22 @@ class SkillScannerPlugin(BasePlugin): self.pages_scanned += 1 - # Update UI - from PyQt6.QtCore import QMetaObject, Qt, Q_ARG - QMetaObject.invokeMethod( - self, "_update_session_table", - Qt.ConnectionType.QueuedConnection, - Q_ARG(object, self.current_scan_session) - ) + # Update UI via signals (thread-safe) + self.update_session_table_signal.emit(self.current_scan_session) # Show success with checkmark and beep - self._update_multi_page_status( + self.update_status_signal.emit( f"✅ Page {self.pages_scanned} scanned! {len(skills)} skills found. Click Next Page in game →", - success=True + True, False ) # Play beep sound self._play_beep() except Exception as e: - self._update_multi_page_status(f"Error: {str(e)}", error=True) + self.update_status_signal.emit(f"Error: {str(e)}", False, True) finally: - from PyQt6.QtCore import QMetaObject, Qt, Q_ARG - QMetaObject.invokeMethod( - self.scan_page_btn, - "setEnabled", - Qt.ConnectionType.QueuedConnection, - Q_ARG(bool, True) - ) + self.enable_scan_button_signal.emit(True) thread = Thread(target=do_scan) thread.daemon = True @@ -609,38 +606,18 @@ class SkillScannerPlugin(BasePlugin): return skills - def _update_multi_page_status(self, message, success=False, error=False): - """Update multi-page status label.""" - from PyQt6.QtCore import QMetaObject, Qt, Q_ARG - + def _update_multi_page_status_slot(self, message, success=False, error=False): + """Slot for updating multi-page status (called via signal).""" color = "#4ecdc4" if success else "#ff4757" if error else "#ff8c42" - QMetaObject.invokeMethod( - self.multi_page_status, - "setText", - Qt.ConnectionType.QueuedConnection, - Q_ARG(str, message) - ) - QMetaObject.invokeMethod( - self.multi_page_status, - "setStyleSheet", - Qt.ConnectionType.QueuedConnection, - Q_ARG(str, f"color: {color}; font-size: 14px;") - ) - - # Update counters - QMetaObject.invokeMethod( - self.pages_scanned_label, - "setText", - Qt.ConnectionType.QueuedConnection, - Q_ARG(str, f"Pages: {self.pages_scanned}") - ) - QMetaObject.invokeMethod( - self.total_skills_label, - "setText", - Qt.ConnectionType.QueuedConnection, - Q_ARG(str, f"Skills: {len(self.current_scan_session)}") - ) + self.multi_page_status.setText(message) + self.multi_page_status.setStyleSheet(f"color: {color}; font-size: 14px;") + self._update_counters_slot() + + def _update_counters_slot(self): + """Slot for updating counters (called via signal).""" + self.pages_scanned_label.setText(f"Pages: {self.pages_scanned}") + self.total_skills_label.setText(f"Skills: {len(self.current_scan_session)}") def _play_beep(self): """Play a beep sound to notify user.""" @@ -715,7 +692,7 @@ class SkillScannerPlugin(BasePlugin): self._start_auto_scan_with_hotkey() elif mode == 1: # Hotkey only self._register_hotkey() - self._update_multi_page_status("Hotkey F12 ready! Navigate to first page and press F12", success=True) + self.update_status_signal.emit("Hotkey F12 ready! Navigate to first page and press F12", True, False) else: # Manual click self._scan_page_for_multi() @@ -729,7 +706,7 @@ class SkillScannerPlugin(BasePlugin): self._register_hotkey() # Start monitoring - self._update_multi_page_status("🤖 Auto-detect started! Navigate to page 1...", success=True) + self.update_status_signal.emit("🤖 Auto-detect started! Navigate to page 1...", True, False) # Start auto-detection timer self.auto_scan_timer = QTimer() @@ -797,7 +774,7 @@ class SkillScannerPlugin(BasePlugin): # If page changed, trigger scan if self.last_page_number is not None and current_page != self.last_page_number: - self._update_multi_page_status(f"📄 Page change detected: {current_page}/{total_pages}", success=True) + self.update_status_signal.emit(f"📄 Page change detected: {current_page}/{total_pages}", True, False) self._scan_page_for_multi() self.last_page_number = current_page @@ -820,9 +797,9 @@ class SkillScannerPlugin(BasePlugin): self.auto_scan_active = False # Keep hotkey registered - self._update_multi_page_status( + self.update_status_signal.emit( "⚠️ Auto-detect unreliable. Use F12 hotkey to scan each page manually!", - error=True + False, True ) # Play alert sound