""" Hauptcontroller für die Social Media Account Generator Anwendung. """ import logging import sys from PyQt5.QtWidgets import QMessageBox, QApplication from views.main_window import MainWindow from views.dialogs.license_activation_dialog import LicenseActivationDialog from controllers.platform_controllers.instagram_controller import InstagramController from controllers.platform_controllers.tiktok_controller import TikTokController from controllers.account_controller import AccountController from controllers.settings_controller import SettingsController from controllers.session_controller import SessionController from database.db_manager import DatabaseManager from utils.proxy_rotator import ProxyRotator from utils.email_handler import EmailHandler from utils.theme_manager import ThemeManager from localization.language_manager import LanguageManager from licensing.license_manager import LicenseManager from updates.update_checker import UpdateChecker logger = logging.getLogger("main") class MainController: """Hauptcontroller, der die Anwendung koordiniert.""" def __init__(self, app): # QApplication Referenz speichern self.app = app # Theme Manager initialisieren self.theme_manager = ThemeManager(app) # Language Manager initialisieren self.language_manager = LanguageManager(app) # Lizenz Manager als erstes initialisieren self.license_manager = LicenseManager() # Lizenz prüfen bevor andere Komponenten geladen werden if not self._check_and_activate_license(): logger.error("Keine gültige Lizenz - Anwendung wird beendet") sys.exit(1) # Modelle initialisieren self.db_manager = DatabaseManager() self.proxy_rotator = ProxyRotator() self.email_handler = EmailHandler() self.update_checker = UpdateChecker(self.license_manager.api_client) # Haupt-View erstellen self.view = MainWindow(self.theme_manager, self.language_manager, self.db_manager) # Untercontroller erstellen self.account_controller = AccountController(self.db_manager) self.account_controller.set_parent_view(self.view) self.settings_controller = SettingsController( self.proxy_rotator, self.email_handler, self.license_manager ) self.session_controller = SessionController(self.db_manager) # Plattform-Controller initialisieren self.platform_controllers = {} # Instagram Controller hinzufügen instagram_controller = InstagramController( self.db_manager, self.proxy_rotator, self.email_handler, self.language_manager ) # Signal für Rückkehr zur Hauptseite verbinden instagram_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset() # SessionController referenz hinzufügen instagram_controller.session_controller = self.session_controller self.platform_controllers["instagram"] = instagram_controller # TikTok Controller hinzufügen tiktok_controller = TikTokController( self.db_manager, self.proxy_rotator, self.email_handler, self.language_manager ) # Signal für Rückkehr zur Hauptseite verbinden tiktok_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset() # SessionController referenz hinzufügen tiktok_controller.session_controller = self.session_controller self.platform_controllers["tiktok"] = tiktok_controller # X (Twitter) Controller hinzufügen from controllers.platform_controllers.x_controller import XController x_controller = XController( self.db_manager, self.proxy_rotator, self.email_handler, self.language_manager ) # Signal für Rückkehr zur Hauptseite verbinden x_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset() # SessionController referenz hinzufügen x_controller.session_controller = self.session_controller self.platform_controllers["x"] = x_controller # Gmail Controller hinzufügen from controllers.platform_controllers.gmail_controller import GmailController gmail_controller = GmailController( self.db_manager, self.proxy_rotator, self.email_handler, self.language_manager ) # Signal für Rückkehr zur Hauptseite verbinden gmail_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset() # SessionController referenz hinzufügen gmail_controller.session_controller = self.session_controller self.platform_controllers["gmail"] = gmail_controller # Hier können in Zukunft weitere Controller hinzugefügt werden: # self.platform_controllers["facebook"] = FacebookController(...) # Signals verbinden self.connect_signals() # Platform Selector Signal-Verbindungen if hasattr(self.view.platform_selector, 'export_requested'): self.view.platform_selector.export_requested.connect( lambda accounts: self.account_controller.export_accounts(None, accounts) ) if hasattr(self.view.platform_selector, 'login_requested'): self.view.platform_selector.login_requested.connect( self.session_controller.perform_one_click_login ) # Session-Status-Update Signal entfernt (Session-Funktionalität deaktiviert) # Login-Result Signals verbinden self.session_controller.login_successful.connect(self._on_login_successful) self.session_controller.login_failed.connect(self._on_login_failed) # Session starten self._start_license_session() # Auf Updates prüfen self.check_for_updates() # Hauptfenster anzeigen self.view.show() def _on_login_successful(self, account_id: str, session_data: dict): """Behandelt erfolgreiches Login""" # GEÄNDERT: Kein Popup mehr - User sieht Erfolg direkt im Browser try: account = self.db_manager.get_account(int(account_id)) username = account.get('username', 'Unknown') if account else 'Unknown' platform = account.get('platform', 'Unknown') if account else 'Unknown' logger.info(f"Login erfolgreich für Account {account_id} ({username}) - Browser bleibt offen") # Popup entfernt - User hat direktes Feedback über Browser-Status except Exception as e: print(f"Error showing success message: {e}") def _on_login_failed(self, account_id: str, error_message: str): """Behandelt fehlgeschlagenes Login""" from PyQt5.QtWidgets import QMessageBox # Account-Details für die Nachricht holen try: account = self.db_manager.get_account(int(account_id)) username = account.get('username', 'Unknown') if account else 'Unknown' msg = QMessageBox(self.view) msg.setIcon(QMessageBox.Warning) msg.setWindowTitle("Login Fehlgeschlagen") msg.setText(f"Ein-Klick-Login fehlgeschlagen!") msg.setInformativeText(f"Account: {username}\nFehler: {error_message}") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() except Exception as e: print(f"Error showing failure message: {e}") def connect_signals(self): """Verbindet alle Signale mit den entsprechenden Slots.""" # Plattformauswahl-Signal verbinden self.view.platform_selected.connect(self.on_platform_selected) # Zurück-Button verbinden self.view.back_to_selector_requested.connect(self.show_platform_selector) # Theme-Toggle verbinden self.view.theme_toggled.connect(self.on_theme_toggled) def on_platform_selected(self, platform: str): """Wird aufgerufen, wenn eine Plattform ausgewählt wird.""" logger.info(f"Plattform ausgewählt: {platform}") # Aktuelle Plattform setzen self.current_platform = platform.lower() # Prüfen, ob die Plattform unterstützt wird if self.current_platform not in self.platform_controllers: logger.error(f"Plattform '{platform}' wird nicht unterstützt") QMessageBox.critical( self.view, "Nicht unterstützt", f"Die Plattform '{platform}' ist noch nicht implementiert." ) return # Plattformspezifischen Controller abrufen platform_controller = self.platform_controllers.get(self.current_platform) # Plattform-View initialisieren self.view.init_platform_ui(platform, platform_controller) # Tab-Hooks verbinden self.connect_tab_hooks(platform_controller) # Plattformspezifische Ansicht anzeigen self.view.show_platform_ui() def on_theme_toggled(self): """Wird aufgerufen, wenn das Theme gewechselt wird.""" if self.theme_manager: theme_name = self.theme_manager.get_current_theme() logger.info(f"Theme gewechselt zu: {theme_name}") # Hier kann zusätzliche Logik für Theme-Wechsel hinzugefügt werden # z.B. UI-Elemente aktualisieren, die nicht automatisch aktualisiert werden def connect_tab_hooks(self, platform_controller): """Verbindet die Tab-Hooks mit dem Plattform-Controller.""" # Generator-Tab-Hooks # HINWEIS: account_created Signal ist nicht mehr verbunden, da Accounts # jetzt über SessionController mit Clean Architecture gespeichert werden if hasattr(platform_controller, "get_generator_tab"): generator_tab = platform_controller.get_generator_tab() # generator_tab.account_created.connect(self.account_controller.on_account_created) # Deaktiviert # Einstellungen-Tab-Hooks if hasattr(platform_controller, "get_settings_tab"): settings_tab = platform_controller.get_settings_tab() settings_tab.proxy_settings_saved.connect(self.settings_controller.save_proxy_settings) settings_tab.proxy_tested.connect(self.settings_controller.test_proxy) settings_tab.email_settings_saved.connect(self.settings_controller.save_email_settings) settings_tab.email_tested.connect(self.settings_controller.test_email) settings_tab.license_activated.connect(self.settings_controller.activate_license) def show_platform_selector(self): """Zeigt den Plattform-Selektor an.""" logger.info("Zurück zur Plattformauswahl") self.view.show_platform_selector() if hasattr(self.view, "platform_selector"): self.view.platform_selector.load_accounts() def show_platform_selector_and_reset(self): """Zeigt den Plattform-Selektor an und setzt die Eingabefelder zurück.""" logger.info("Zurück zur Plattformauswahl mit Reset der Eingabefelder") # Eingabefelder des aktuellen Platform-Controllers zurücksetzen if hasattr(self, 'current_platform') and self.current_platform in self.platform_controllers: controller = self.platform_controllers[self.current_platform] if hasattr(controller, '_generator_tab') and controller._generator_tab: # Tab auf None setzen, damit beim nächsten Öffnen ein neuer erstellt wird controller._generator_tab = None # Zur Plattformauswahl zurückkehren self.show_platform_selector() def _check_and_activate_license(self): """ Prüft die Lizenz und zeigt den Aktivierungsdialog wenn nötig. Returns: True wenn Lizenz gültig, False wenn Benutzer abbricht """ # Versuche Session fortzusetzen if self.license_manager.resume_session(): logger.info("Bestehende Session fortgesetzt") return True # Prüfe ob Lizenz vorhanden ist if self.license_manager.is_licensed(): # Starte neue Session if self.license_manager.start_session(): logger.info("Neue Session gestartet") return True else: logger.error("Session konnte nicht gestartet werden") # Zeige Fehlermeldung statt Aktivierungsdialog # Hole detaillierte Fehlermeldung session_result = self.license_manager.session_manager.start_session( self.license_manager.license_data["key"], self.license_manager.license_data.get("activation_id") ) error_msg = session_result.get("error", "Unbekannter Fehler") QMessageBox.critical( None, "Session-Fehler", f"Die Lizenz ist gültig, aber es konnte keine Session gestartet werden.\n\n" f"Grund: {error_msg}\n\n" "Mögliche Lösungen:\n" "- Schließen Sie andere laufende Instanzen\n" "- Warten Sie einen Moment und versuchen Sie es erneut\n" "- Kontaktieren Sie den Support", QMessageBox.Ok ) return False # Keine gültige Lizenz - zeige Aktivierungsdialog logger.info("Keine gültige Lizenz gefunden - zeige Aktivierungsdialog") dialog = LicenseActivationDialog(self.license_manager) dialog.activation_successful.connect(self._on_license_activated) result = dialog.exec_() return result == dialog.Accepted def _on_license_activated(self): """Wird aufgerufen wenn Lizenz erfolgreich aktiviert wurde.""" logger.info("Lizenz wurde erfolgreich aktiviert") def _start_license_session(self): """Startet die Lizenz-Session für die laufende Anwendung.""" if not self.license_manager.session_manager.is_session_active(): if self.license_manager.is_licensed(): self.license_manager.start_session() def check_license(self): """Überprüft den Lizenzstatus (für UI Updates).""" is_licensed = self.license_manager.is_licensed() license_info = self.license_manager.get_license_info() status_text = self.license_manager.get_status_text() # UI kann hier aktualisiert werden basierend auf Lizenzstatus logger.info(f"Lizenzstatus: {status_text}") return is_licensed def check_for_updates(self): """Prüft auf Updates.""" try: # Mit Lizenzschlüssel prüfen wenn vorhanden license_key = self.license_manager.get_license_info().get("key") update_info = self.update_checker.check_for_updates(license_key=license_key) if update_info["has_update"]: reply = QMessageBox.question( self.view, "Update verfügbar", f"Eine neue Version ist verfügbar: {update_info['latest_version']}\n" f"(Aktuelle Version: {update_info['current_version']})\n\n" f"Release-Datum: {update_info['release_date']}\n" f"Release-Notes:\n{update_info['release_notes']}\n\n" "Möchten Sie das Update jetzt herunterladen?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) if reply == QMessageBox.Yes: self.download_update(update_info) except Exception as e: logger.error(f"Fehler bei der Update-Prüfung: {e}") def download_update(self, update_info): """Lädt ein Update herunter.""" try: download_result = self.update_checker.download_update( update_info["download_url"], update_info["latest_version"] ) if download_result["success"]: QMessageBox.information( self.view, "Download erfolgreich", f"Update wurde heruntergeladen: {download_result['file_path']}\n\n" "Bitte schließen Sie die Anwendung und führen Sie das Update aus." ) else: QMessageBox.warning( self.view, "Download fehlgeschlagen", f"Fehler beim Herunterladen des Updates:\n{download_result['error']}" ) except Exception as e: logger.error(f"Fehler beim Herunterladen des Updates: {e}") QMessageBox.critical( self.view, "Fehler", f"Fehler beim Herunterladen des Updates:\n{str(e)}" )