diff --git a/plugins/skill_scanner/plugin.py b/plugins/skill_scanner/plugin.py index e483a20..25d0939 100644 --- a/plugins/skill_scanner/plugin.py +++ b/plugins/skill_scanner/plugin.py @@ -348,6 +348,15 @@ class SkillOCRThread(QThread): return skills +class SignalHelper(QObject): + """Helper QObject to hold signals since BasePlugin doesn't inherit from QObject.""" + 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) + + class SkillScannerPlugin(BasePlugin): """Scan skills using core OCR and track gains via core Log service.""" @@ -357,15 +366,11 @@ class SkillScannerPlugin(BasePlugin): description = "Uses core OCR and Log services" hotkey = "ctrl+shift+s" - # 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.""" + # Create signal helper (QObject) for thread-safe UI updates + self._signals = SignalHelper() + self.data_file = Path("data/skill_tracker.json") self.data_file.parent.mkdir(parents=True, exist_ok=True) @@ -378,12 +383,12 @@ class SkillScannerPlugin(BasePlugin): self.current_scan_session = {} # Skills collected in current multi-page scan self.pages_scanned = 0 - # 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) + # Connect signals (using signal helper QObject) + self._signals.hotkey_triggered.connect(self._scan_page_for_multi) + self._signals.update_status_signal.connect(self._update_multi_page_status_slot) + self._signals.update_session_table_signal.connect(self._update_session_table) + self._signals.update_counters_signal.connect(self._update_counters_slot) + # Note: enable_scan_button_signal connected in get_ui() after button created # Subscribe to skill gain events from core Log service try: @@ -558,6 +563,9 @@ class SkillScannerPlugin(BasePlugin): self.scan_page_btn.clicked.connect(self._start_smart_scan) mp_buttons_layout.addWidget(self.scan_page_btn) + # Connect signal helper for button enabling (now that button exists) + self._signals.enable_scan_button_signal.connect(self.scan_page_btn.setEnabled) + save_all_btn = QPushButton("💾 Save All Scanned") save_all_btn.setStyleSheet(""" QPushButton { @@ -729,7 +737,7 @@ class SkillScannerPlugin(BasePlugin): ocr_service = get_ocr_service() if not ocr_service.is_available(): - self.update_status_signal.emit("Error: OCR not available", False, True) + self._signals.update_status_signal.emit("Error: OCR not available", False, True) return # Capture and OCR @@ -746,10 +754,10 @@ class SkillScannerPlugin(BasePlugin): self.pages_scanned += 1 # Update UI via signals (thread-safe) - self.update_session_table_signal.emit(self.current_scan_session) + self._signals.update_session_table_signal.emit(self.current_scan_session) # Show success with checkmark and beep - self.update_status_signal.emit( + self._signals.update_status_signal.emit( f"✅ Page {self.pages_scanned} scanned! {len(skills)} skills found. Click Next Page in game →", True, False ) @@ -758,9 +766,9 @@ class SkillScannerPlugin(BasePlugin): self._play_beep() except Exception as e: - self.update_status_signal.emit(f"Error: {str(e)}", False, True) + self._signals.update_status_signal.emit(f"Error: {str(e)}", False, True) finally: - self.enable_scan_button_signal.emit(True) + self._signals.enable_scan_button_signal.emit(True) thread = Thread(target=do_scan) thread.daemon = True @@ -899,7 +907,7 @@ class SkillScannerPlugin(BasePlugin): self._start_auto_scan_with_hotkey() elif mode == 1: # Hotkey only self._register_hotkey() - self.update_status_signal.emit("Hotkey F12 ready! Navigate to first page and press F12", True, False) + self._signals.update_status_signal.emit("Hotkey F12 ready! Navigate to first page and press F12", True, False) else: # Manual click self._scan_page_for_multi() @@ -913,7 +921,7 @@ class SkillScannerPlugin(BasePlugin): self._register_hotkey() # Start monitoring - self.update_status_signal.emit("🤖 Auto-detect started! Navigate to page 1...", True, False) + self._signals.update_status_signal.emit("🤖 Auto-detect started! Navigate to page 1...", True, False) # Start auto-detection timer self.auto_scan_timer = QTimer() @@ -948,7 +956,7 @@ class SkillScannerPlugin(BasePlugin): def _hotkey_scan(self): """Scan triggered by F12 hotkey - thread safe via signal.""" # Emit signal to safely call from hotkey thread - self.hotkey_triggered.emit() + self._signals.hotkey_triggered.emit() def _check_for_page_change(self): """Auto-detect page changes by monitoring page number area.""" @@ -981,7 +989,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_status_signal.emit(f"📄 Page change detected: {current_page}/{total_pages}", True, False) + self._signals.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 @@ -1004,7 +1012,7 @@ class SkillScannerPlugin(BasePlugin): self.auto_scan_active = False # Keep hotkey registered - self.update_status_signal.emit( + self._signals.update_status_signal.emit( "⚠️ Auto-detect unreliable. Use F12 hotkey to scan each page manually!", False, True )