Initial commit
Dieser Commit ist enthalten in:
331
views/tabs/accounts_tab.py
Normale Datei
331
views/tabs/accounts_tab.py
Normale Datei
@ -0,0 +1,331 @@
|
||||
"""
|
||||
Tab zur Verwaltung der erstellten Social-Media-Accounts.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QTableWidget,
|
||||
QTableWidgetItem, QPushButton, QHeaderView, QMessageBox
|
||||
)
|
||||
from PyQt5.QtCore import pyqtSignal, Qt, QEvent
|
||||
from PyQt5.QtGui import QWheelEvent, QColor
|
||||
|
||||
logger = logging.getLogger("accounts_tab")
|
||||
|
||||
|
||||
class HorizontalScrollTableWidget(QTableWidget):
|
||||
"""Custom QTableWidget that supports horizontal scrolling with mouse wheel."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Install event filter to handle wheel events
|
||||
self.viewport().installEventFilter(self)
|
||||
|
||||
def eventFilter(self, source, event):
|
||||
"""Event filter to handle horizontal scrolling with mouse wheel."""
|
||||
if source == self.viewport() and event.type() == QEvent.Wheel:
|
||||
# Cast to QWheelEvent
|
||||
wheel_event = event
|
||||
|
||||
# Check if horizontal scrollbar is visible and vertical is not needed
|
||||
h_bar = self.horizontalScrollBar()
|
||||
v_bar = self.verticalScrollBar()
|
||||
|
||||
# If Shift is pressed, use default behavior (horizontal scroll)
|
||||
if event.modifiers() & Qt.ShiftModifier:
|
||||
return super().eventFilter(source, event)
|
||||
|
||||
# Smart scrolling logic
|
||||
if h_bar.isVisible():
|
||||
# Check if vertical scrolling is at limits or not needed
|
||||
vertical_at_limit = (
|
||||
not v_bar.isVisible() or
|
||||
(v_bar.value() == v_bar.minimum() and wheel_event.angleDelta().y() > 0) or
|
||||
(v_bar.value() == v_bar.maximum() and wheel_event.angleDelta().y() < 0)
|
||||
)
|
||||
|
||||
# If vertical is not needed or at limit, scroll horizontally
|
||||
if not v_bar.isVisible() or vertical_at_limit:
|
||||
# Get the delta (negative for scroll down, positive for scroll up)
|
||||
delta = wheel_event.angleDelta().y()
|
||||
|
||||
# Calculate new position (invert delta for natural scrolling)
|
||||
step = h_bar.singleStep() * 3 # Make scrolling faster
|
||||
new_value = h_bar.value() - (delta // 120) * step
|
||||
|
||||
# Apply the new position
|
||||
h_bar.setValue(new_value)
|
||||
|
||||
# Mark event as handled
|
||||
return True
|
||||
|
||||
return super().eventFilter(source, event)
|
||||
|
||||
|
||||
class AccountsTab(QWidget):
|
||||
"""Widget für den Konten-Tab."""
|
||||
|
||||
# Signale
|
||||
export_requested = pyqtSignal()
|
||||
delete_requested = pyqtSignal(int) # account_id
|
||||
login_requested = pyqtSignal(str, str) # account_id, platform
|
||||
|
||||
def __init__(self, platform_name=None, db_manager=None, language_manager=None):
|
||||
super().__init__()
|
||||
self.platform_name = platform_name
|
||||
self.db_manager = db_manager
|
||||
self.language_manager = language_manager
|
||||
self.init_ui()
|
||||
if self.language_manager:
|
||||
self.language_manager.language_changed.connect(self.update_texts)
|
||||
self.update_texts()
|
||||
|
||||
# Konten laden, falls db_manager vorhanden
|
||||
if self.db_manager:
|
||||
self.load_accounts()
|
||||
|
||||
def init_ui(self):
|
||||
"""Initialisiert die Benutzeroberfläche."""
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Konten-Tabelle mit horizontalem Mausrad-Support
|
||||
self.accounts_table = HorizontalScrollTableWidget()
|
||||
self.accounts_table.setColumnCount(9)
|
||||
self.accounts_table.setHorizontalHeaderLabels([
|
||||
"ID",
|
||||
"Benutzername",
|
||||
"Passwort",
|
||||
"E-Mail",
|
||||
"Handynummer",
|
||||
"Name",
|
||||
"Plattform",
|
||||
"Erstellt am",
|
||||
"Session"
|
||||
])
|
||||
# Enable horizontal scrolling and set minimum column widths
|
||||
self.accounts_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
|
||||
self.accounts_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.accounts_table.setHorizontalScrollMode(QTableWidget.ScrollPerPixel)
|
||||
|
||||
# Set minimum column widths to prevent text overlap
|
||||
self.accounts_table.setColumnWidth(0, 50) # ID
|
||||
self.accounts_table.setColumnWidth(1, 150) # Benutzername
|
||||
self.accounts_table.setColumnWidth(2, 150) # Passwort
|
||||
self.accounts_table.setColumnWidth(3, 250) # E-Mail
|
||||
self.accounts_table.setColumnWidth(4, 150) # Handynummer
|
||||
self.accounts_table.setColumnWidth(5, 150) # Name
|
||||
self.accounts_table.setColumnWidth(6, 130) # Plattform
|
||||
self.accounts_table.setColumnWidth(7, 150) # Erstellt am
|
||||
# ID-Spalte verstecken
|
||||
self.accounts_table.setColumnHidden(0, True)
|
||||
|
||||
# Explizite Zeilenhöhe setzen, um Abschneiden zu verhindern
|
||||
self.accounts_table.verticalHeader().setDefaultSectionSize(40)
|
||||
self.accounts_table.verticalHeader().setMinimumSectionSize(35)
|
||||
|
||||
layout.addWidget(self.accounts_table)
|
||||
|
||||
# Button-Leiste
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
self.login_button = QPushButton("🔑 Login")
|
||||
self.login_button.clicked.connect(self.on_login_clicked)
|
||||
self.login_button.setToolTip("Mit gespeicherter Session einloggen")
|
||||
|
||||
self.export_button = QPushButton("Exportieren")
|
||||
self.export_button.clicked.connect(self.on_export_clicked)
|
||||
|
||||
self.delete_button = QPushButton("Löschen")
|
||||
self.delete_button.clicked.connect(self.on_delete_clicked)
|
||||
|
||||
button_layout.addWidget(self.login_button)
|
||||
button_layout.addWidget(self.export_button)
|
||||
button_layout.addWidget(self.delete_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
def load_accounts(self):
|
||||
"""Lädt Konten aus der Datenbank und zeigt sie in der Tabelle an."""
|
||||
try:
|
||||
if (self.platform_name and str(self.platform_name).lower() not in ["all", ""]
|
||||
and hasattr(self.db_manager, "get_accounts_by_platform")):
|
||||
accounts = self.db_manager.get_accounts_by_platform(self.platform_name.lower())
|
||||
else:
|
||||
accounts = self.db_manager.get_all_accounts()
|
||||
if self.platform_name and str(self.platform_name).lower() not in ["all", ""]:
|
||||
accounts = [
|
||||
acc for acc in accounts
|
||||
if acc.get("platform", "").lower() == str(self.platform_name).lower()
|
||||
]
|
||||
|
||||
self.display_accounts(accounts)
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der Konten: {e}")
|
||||
QMessageBox.critical(self, "Fehler", f"Fehler beim Laden der Konten:\n{str(e)}")
|
||||
|
||||
def display_accounts(self, accounts):
|
||||
"""Zeigt die Konten in der Tabelle an."""
|
||||
self.accounts_table.setRowCount(len(accounts))
|
||||
|
||||
for row, account in enumerate(accounts):
|
||||
self.accounts_table.setItem(row, 0, QTableWidgetItem(str(account.get("id", ""))))
|
||||
self.accounts_table.setItem(row, 1, QTableWidgetItem(account.get("username", "")))
|
||||
self.accounts_table.setItem(row, 2, QTableWidgetItem(account.get("password", "")))
|
||||
self.accounts_table.setItem(row, 3, QTableWidgetItem(account.get("email", "")))
|
||||
self.accounts_table.setItem(row, 4, QTableWidgetItem(account.get("phone", "")))
|
||||
self.accounts_table.setItem(row, 5, QTableWidgetItem(account.get("full_name", "")))
|
||||
self.accounts_table.setItem(row, 6, QTableWidgetItem(account.get("platform", "")))
|
||||
self.accounts_table.setItem(row, 7, QTableWidgetItem(account.get("created_at", "")))
|
||||
|
||||
# Account Status hinzufügen mit visueller Darstellung
|
||||
status = account.get("status", "active") # Standard: active (grün)
|
||||
status_text = self._format_status_text(status)
|
||||
status_item = QTableWidgetItem(status_text)
|
||||
status_item.setToolTip(self._get_status_tooltip(status))
|
||||
|
||||
# Status-basierte Hintergrundfarben für Tabellenzellen (nur Grün/Rot)
|
||||
if status == "active":
|
||||
status_item.setBackground(QColor("#F0FDF4")) # Helles Grün
|
||||
elif status == "inactive":
|
||||
status_item.setBackground(QColor("#FEF2F2")) # Helles Rot
|
||||
else:
|
||||
# Fallback auf active (grün)
|
||||
status_item.setBackground(QColor("#F0FDF4"))
|
||||
|
||||
self.accounts_table.setItem(row, 8, status_item)
|
||||
|
||||
def on_login_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Login-Button geklickt wird."""
|
||||
selected_rows = self.accounts_table.selectionModel().selectedRows()
|
||||
if not selected_rows:
|
||||
title = "Kein Konto ausgewählt"
|
||||
text = "Bitte wählen Sie ein Konto zum Einloggen aus."
|
||||
if self.language_manager:
|
||||
title = self.language_manager.get_text(
|
||||
"accounts_tab.no_selection_title", title
|
||||
)
|
||||
text = self.language_manager.get_text(
|
||||
"accounts_tab.no_login_selection_text", text
|
||||
)
|
||||
QMessageBox.warning(self, title, text)
|
||||
return
|
||||
|
||||
row = selected_rows[0].row()
|
||||
account_id = self.accounts_table.item(row, 0).text()
|
||||
platform = self.accounts_table.item(row, 6).text()
|
||||
|
||||
self.login_requested.emit(account_id, platform)
|
||||
|
||||
def on_export_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Exportieren-Button geklickt wird."""
|
||||
self.export_requested.emit()
|
||||
|
||||
def update_session_status(self, account_id: str, status: dict):
|
||||
"""
|
||||
Session-Status-Update deaktiviert (Session-Funktionalität entfernt).
|
||||
"""
|
||||
# Session-Funktionalität wurde entfernt - diese Methode macht nichts mehr
|
||||
pass
|
||||
|
||||
def on_delete_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Löschen-Button geklickt wird."""
|
||||
selected_rows = self.accounts_table.selectionModel().selectedRows()
|
||||
if not selected_rows:
|
||||
title = "Kein Konto ausgewählt"
|
||||
text = "Bitte wählen Sie ein Konto zum Löschen aus."
|
||||
if self.language_manager:
|
||||
title = self.language_manager.get_text(
|
||||
"accounts_tab.no_selection_title", title
|
||||
)
|
||||
text = self.language_manager.get_text(
|
||||
"accounts_tab.no_selection_text", text
|
||||
)
|
||||
QMessageBox.warning(self, title, text)
|
||||
return
|
||||
|
||||
account_id = int(self.accounts_table.item(selected_rows[0].row(), 0).text())
|
||||
username = self.accounts_table.item(selected_rows[0].row(), 1).text()
|
||||
|
||||
q_title = "Konto löschen"
|
||||
q_text = f"Möchten Sie das Konto '{username}' wirklich löschen?"
|
||||
if self.language_manager:
|
||||
q_title = self.language_manager.get_text("accounts_tab.delete_title", q_title)
|
||||
q_text = self.language_manager.get_text(
|
||||
"accounts_tab.delete_text", q_text
|
||||
).format(username=username)
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
q_title,
|
||||
q_text,
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No,
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.delete_requested.emit(account_id)
|
||||
|
||||
# Direkt aktualisieren, falls db_manager vorhanden
|
||||
if self.db_manager:
|
||||
success = self.db_manager.delete_account(account_id)
|
||||
if success:
|
||||
self.load_accounts()
|
||||
suc_title = "Erfolg"
|
||||
suc_text = f"Konto '{username}' wurde gelöscht."
|
||||
if self.language_manager:
|
||||
suc_title = self.language_manager.get_text(
|
||||
"accounts_tab.delete_success_title", suc_title
|
||||
)
|
||||
suc_text = self.language_manager.get_text(
|
||||
"accounts_tab.delete_success_text", suc_text
|
||||
).format(username=username)
|
||||
QMessageBox.information(self, suc_title, suc_text)
|
||||
else:
|
||||
err_title = "Fehler"
|
||||
err_text = f"Konto '{username}' konnte nicht gelöscht werden."
|
||||
if self.language_manager:
|
||||
err_title = self.language_manager.get_text(
|
||||
"accounts_tab.delete_error_title", err_title
|
||||
)
|
||||
err_text = self.language_manager.get_text(
|
||||
"accounts_tab.delete_error_text", err_text
|
||||
).format(username=username)
|
||||
QMessageBox.critical(self, err_title, err_text)
|
||||
|
||||
def update_texts(self):
|
||||
"""Aktualisiert UI-Texte gemäß aktueller Sprache."""
|
||||
if not self.language_manager:
|
||||
return
|
||||
lm = self.language_manager
|
||||
self.login_button.setText(lm.get_text("buttons.login", "🔑 Login"))
|
||||
self.export_button.setText(lm.get_text("buttons.export", "Exportieren"))
|
||||
self.delete_button.setText(lm.get_text("buttons.delete", "Löschen"))
|
||||
headers = lm.get_text(
|
||||
"accounts_tab.headers",
|
||||
[
|
||||
"ID",
|
||||
"Benutzername",
|
||||
"Passwort",
|
||||
"E-Mail",
|
||||
"Handynummer",
|
||||
"Name",
|
||||
"Plattform",
|
||||
"Erstellt am",
|
||||
],
|
||||
)
|
||||
self.accounts_table.setHorizontalHeaderLabels(headers)
|
||||
|
||||
def _format_status_text(self, status: str) -> str:
|
||||
"""Formatiert den Status-Text für die Tabelle"""
|
||||
status_texts = {
|
||||
"active": "🟢 Funktioniert",
|
||||
"inactive": "🔴 Problem"
|
||||
}
|
||||
return status_texts.get(status, "🟢 Funktioniert") # Standard: grün
|
||||
|
||||
def _get_status_tooltip(self, status: str) -> str:
|
||||
"""Erstellt Tooltip-Text für den Status"""
|
||||
status_tooltips = {
|
||||
"active": "Account funktioniert normal - letzter Check erfolgreich",
|
||||
"inactive": "Problem: Account gesperrt, eingeschränkt oder Aktion erforderlich"
|
||||
}
|
||||
return status_tooltips.get(status, "Account funktioniert normal")
|
||||
318
views/tabs/generator_tab.py
Normale Datei
318
views/tabs/generator_tab.py
Normale Datei
@ -0,0 +1,318 @@
|
||||
# Pfad: views/tabs/generator_tab_simple.py
|
||||
|
||||
"""
|
||||
Vereinfachter Tab zur Erstellung von Social-Media-Accounts ohne Log-Widget.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QGridLayout,
|
||||
QGroupBox, QLabel, QLineEdit, QSpinBox, QRadioButton,
|
||||
QCheckBox, QComboBox, QPushButton, QProgressBar,
|
||||
QMessageBox, QSizePolicy, QSpacerItem
|
||||
)
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
|
||||
logger = logging.getLogger("generator_tab")
|
||||
|
||||
class GeneratorTab(QWidget):
|
||||
"""Widget für den Account-Generator-Tab ohne Log."""
|
||||
|
||||
# Signale
|
||||
start_requested = pyqtSignal(dict)
|
||||
stop_requested = pyqtSignal()
|
||||
account_created = pyqtSignal(str, dict) # (platform, account_data)
|
||||
|
||||
def __init__(self, platform_name, language_manager=None):
|
||||
super().__init__()
|
||||
self.platform_name = platform_name
|
||||
self.language_manager = language_manager
|
||||
self.init_ui()
|
||||
if self.language_manager:
|
||||
self.language_manager.language_changed.connect(self.update_texts)
|
||||
self.update_texts()
|
||||
|
||||
def init_ui(self):
|
||||
"""Initialisiert die Benutzeroberfläche."""
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
layout.setSpacing(20)
|
||||
|
||||
# Formularbereich - mit Grid-Layout für bessere Anordnung
|
||||
self.form_group = QGroupBox()
|
||||
grid_layout = QGridLayout()
|
||||
grid_layout.setHorizontalSpacing(15)
|
||||
grid_layout.setVerticalSpacing(10)
|
||||
self.form_group.setLayout(grid_layout)
|
||||
|
||||
# Zeile 0: Vorname und Nachname
|
||||
self.first_name_label = QLabel()
|
||||
self.first_name_input = QLineEdit()
|
||||
grid_layout.addWidget(self.first_name_label, 0, 0)
|
||||
grid_layout.addWidget(self.first_name_input, 0, 1)
|
||||
|
||||
self.last_name_label = QLabel()
|
||||
self.last_name_input = QLineEdit()
|
||||
grid_layout.addWidget(self.last_name_label, 0, 2)
|
||||
grid_layout.addWidget(self.last_name_input, 0, 3)
|
||||
|
||||
# Zeile 1: Alter
|
||||
self.age_label = QLabel()
|
||||
self.age_input = QLineEdit()
|
||||
self.age_input.setMaximumWidth(100)
|
||||
grid_layout.addWidget(self.age_label, 1, 0)
|
||||
grid_layout.addWidget(self.age_input, 1, 1)
|
||||
|
||||
# Plattformspezifische Parameter hinzufügen
|
||||
self.add_platform_specific_fields(grid_layout)
|
||||
|
||||
# Formular zum Layout hinzufügen
|
||||
layout.addWidget(self.form_group)
|
||||
|
||||
# Fortschrittsanzeige
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setRange(0, 100)
|
||||
self.progress_bar.setValue(0)
|
||||
self.progress_bar.setMaximumHeight(20)
|
||||
self.progress_bar.setMinimumWidth(300)
|
||||
self.progress_bar.hide() # Versteckt bis zur Nutzung
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
# Buttons
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.addStretch()
|
||||
|
||||
self.start_button = QPushButton()
|
||||
self.start_button.setMinimumWidth(150)
|
||||
self.start_button.clicked.connect(self.on_start_clicked)
|
||||
|
||||
self.stop_button = QPushButton()
|
||||
self.stop_button.setMinimumWidth(150)
|
||||
self.stop_button.clicked.connect(self.on_stop_clicked)
|
||||
self.stop_button.setEnabled(False)
|
||||
|
||||
button_layout.addWidget(self.start_button)
|
||||
button_layout.addWidget(self.stop_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# Spacer am Ende
|
||||
layout.addStretch()
|
||||
|
||||
# Event-Verbindungen entfernt - Registrierung erfolgt immer per Email
|
||||
|
||||
def add_platform_specific_fields(self, grid_layout):
|
||||
"""
|
||||
Fügt plattformspezifische Felder hinzu.
|
||||
"""
|
||||
platform = self.platform_name.lower()
|
||||
current_row = 2 # Nach den Standard-Feldern (nur Name und Alter)
|
||||
|
||||
|
||||
|
||||
def on_start_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Start-Button geklickt wird."""
|
||||
# Parameter sammeln
|
||||
params = self.get_params()
|
||||
|
||||
# Eingaben validieren
|
||||
valid, error_msg = self.validate_inputs(params)
|
||||
if not valid:
|
||||
self.show_error(error_msg)
|
||||
return
|
||||
|
||||
# Status aktualisieren
|
||||
self.set_status("Starte Account-Erstellung...")
|
||||
|
||||
# Signal auslösen
|
||||
self.start_requested.emit(params)
|
||||
|
||||
def on_stop_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Stop-Button geklickt wird."""
|
||||
self.stop_requested.emit()
|
||||
|
||||
def get_params(self):
|
||||
"""Sammelt alle Parameter für die Account-Erstellung."""
|
||||
# Vorname und Nachname kombinieren für den vollständigen Namen
|
||||
first_name = self.first_name_input.text().strip()
|
||||
last_name = self.last_name_input.text().strip()
|
||||
full_name = f"{first_name} {last_name}"
|
||||
|
||||
params = {
|
||||
"first_name": first_name,
|
||||
"last_name": last_name,
|
||||
"full_name": full_name,
|
||||
"age_text": self.age_input.text().strip(),
|
||||
"registration_method": "email", # Immer Email-Registrierung
|
||||
"headless": False, # Browser immer sichtbar
|
||||
"debug": True, # Debug ist jetzt immer aktiviert
|
||||
"email_domain": "z5m7q9dk3ah2v1plx6ju.com" # Fest eingestellt
|
||||
}
|
||||
|
||||
# Proxy ist jetzt immer deaktiviert
|
||||
params["use_proxy"] = False
|
||||
|
||||
# Plattformspezifische Parameter
|
||||
additional_params = self.get_platform_specific_params()
|
||||
if additional_params:
|
||||
params["additional_params"] = additional_params
|
||||
|
||||
return params
|
||||
|
||||
def validate_inputs(self, params):
|
||||
"""
|
||||
Validiert die Eingaben für die Account-Erstellung.
|
||||
|
||||
Returns:
|
||||
tuple: (gültig, Fehlermeldung)
|
||||
"""
|
||||
# Namen prüfen
|
||||
if not params.get("first_name"):
|
||||
msg = "Bitte geben Sie einen Vornamen ein."
|
||||
if self.language_manager:
|
||||
msg = self.language_manager.get_text(
|
||||
"generator_tab.first_name_error",
|
||||
"Bitte geben Sie einen Vornamen ein.",
|
||||
)
|
||||
return False, msg
|
||||
|
||||
if not params.get("last_name"):
|
||||
msg = "Bitte geben Sie einen Nachnamen ein."
|
||||
if self.language_manager:
|
||||
msg = self.language_manager.get_text(
|
||||
"generator_tab.last_name_error",
|
||||
"Bitte geben Sie einen Nachnamen ein.",
|
||||
)
|
||||
return False, msg
|
||||
|
||||
# Alter prüfen
|
||||
age_text = params.get("age_text", "")
|
||||
if not age_text:
|
||||
msg = "Bitte geben Sie ein Alter ein."
|
||||
if self.language_manager:
|
||||
msg = self.language_manager.get_text(
|
||||
"generator_tab.age_empty_error",
|
||||
"Bitte geben Sie ein Alter ein.",
|
||||
)
|
||||
return False, msg
|
||||
|
||||
# Alter muss eine Zahl sein
|
||||
try:
|
||||
age = int(age_text)
|
||||
params["age"] = age
|
||||
except ValueError:
|
||||
msg = "Das Alter muss eine ganze Zahl sein."
|
||||
if self.language_manager:
|
||||
msg = self.language_manager.get_text(
|
||||
"generator_tab.age_int_error",
|
||||
"Das Alter muss eine ganze Zahl sein.",
|
||||
)
|
||||
return False, msg
|
||||
|
||||
# Alter-Bereich prüfen
|
||||
if age < 13 or age > 99:
|
||||
msg = "Das Alter muss zwischen 13 und 99 liegen."
|
||||
if self.language_manager:
|
||||
msg = self.language_manager.get_text(
|
||||
"generator_tab.age_range_error",
|
||||
"Das Alter muss zwischen 13 und 99 liegen.",
|
||||
)
|
||||
return False, msg
|
||||
|
||||
# Telefonnummer-Validierung entfernt - nur Email-Registrierung
|
||||
|
||||
return True, ""
|
||||
|
||||
def get_platform_specific_params(self):
|
||||
"""
|
||||
Gibt plattformspezifische Parameter zurück.
|
||||
"""
|
||||
platform = self.platform_name.lower()
|
||||
additional_params = {}
|
||||
|
||||
|
||||
return additional_params
|
||||
|
||||
def set_running(self, running: bool):
|
||||
"""Setzt den Status auf 'Wird ausgeführt' oder 'Bereit'."""
|
||||
self.start_button.setEnabled(not running)
|
||||
self.stop_button.setEnabled(running)
|
||||
|
||||
if running:
|
||||
self.set_status("Läuft...")
|
||||
else:
|
||||
self.progress_bar.setValue(0)
|
||||
self.progress_bar.hide()
|
||||
|
||||
def set_progress(self, value: int):
|
||||
"""Setzt den Fortschritt der Fortschrittsanzeige."""
|
||||
if value > 0:
|
||||
self.progress_bar.show()
|
||||
self.progress_bar.setValue(value)
|
||||
if value >= 100:
|
||||
self.progress_bar.hide()
|
||||
|
||||
def set_status(self, message: str):
|
||||
"""Setzt die Statusnachricht."""
|
||||
# Status-Label wurde entfernt
|
||||
# Log to console for debugging
|
||||
logger.info(f"Status: {message}")
|
||||
|
||||
def show_error(self, message: str):
|
||||
"""Zeigt eine Fehlermeldung an."""
|
||||
title = "Fehler"
|
||||
if self.language_manager:
|
||||
title = self.language_manager.get_text(
|
||||
"generator_tab.error_title", "Fehler"
|
||||
)
|
||||
else:
|
||||
title = "Fehler"
|
||||
|
||||
from views.widgets.modern_message_box import show_error
|
||||
show_error(self, title, message)
|
||||
self.set_status("Fehler aufgetreten")
|
||||
|
||||
def show_success(self, message: str):
|
||||
"""Zeigt eine Erfolgsmeldung an."""
|
||||
title = "Erfolg"
|
||||
if self.language_manager:
|
||||
title = self.language_manager.get_text(
|
||||
"generator_tab.success_title", "Erfolg"
|
||||
)
|
||||
|
||||
from views.widgets.modern_message_box import show_success
|
||||
show_success(self, title, message)
|
||||
self.set_status("Erfolgreich abgeschlossen")
|
||||
|
||||
def update_texts(self):
|
||||
"""Aktualisiert UI-Texte gemäß der aktuellen Sprache."""
|
||||
if not self.language_manager:
|
||||
return
|
||||
|
||||
lm = self.language_manager
|
||||
|
||||
self.form_group.setTitle(lm.get_text("generator_tab.form_title", "Account-Informationen"))
|
||||
self.first_name_label.setText(lm.get_text("generator_tab.first_name_label", "Vorname:"))
|
||||
self.first_name_input.setPlaceholderText(lm.get_text("generator_tab.first_name_placeholder", "z.B. Max"))
|
||||
self.last_name_label.setText(lm.get_text("generator_tab.last_name_label", "Nachname:"))
|
||||
self.last_name_input.setPlaceholderText(lm.get_text("generator_tab.last_name_placeholder", "z.B. Mustermann"))
|
||||
self.age_label.setText(lm.get_text("generator_tab.age_label", "Alter:"))
|
||||
|
||||
platform = self.platform_name.lower()
|
||||
|
||||
self.start_button.setText(lm.get_text("buttons.create", "Account erstellen"))
|
||||
self.stop_button.setText(lm.get_text("buttons.cancel", "Abbrechen"))
|
||||
|
||||
# Kompatibilitätsmethoden für bestehenden Code
|
||||
def clear_log(self):
|
||||
"""Kompatibilitätsmethode - tut nichts, da kein Log vorhanden."""
|
||||
pass
|
||||
|
||||
def add_log(self, message: str):
|
||||
"""Kompatibilitätsmethode - gibt an die Konsole aus."""
|
||||
logger.info(message)
|
||||
|
||||
def store_created_account(self, result_data: dict):
|
||||
"""Speichert die erstellten Account-Daten."""
|
||||
if "account_data" in result_data:
|
||||
self.account_created.emit(self.platform_name, result_data["account_data"])
|
||||
508
views/tabs/generator_tab_modern.py
Normale Datei
508
views/tabs/generator_tab_modern.py
Normale Datei
@ -0,0 +1,508 @@
|
||||
"""
|
||||
Moderner Account Generator Tab - Ohne Log-Widget, mit besserem Layout
|
||||
"""
|
||||
|
||||
import logging
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QGridLayout,
|
||||
QGroupBox, QLabel, QLineEdit, QSpinBox, QRadioButton,
|
||||
QCheckBox, QComboBox, QPushButton, QProgressBar,
|
||||
QMessageBox, QFrame, QScrollArea
|
||||
)
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QPropertyAnimation, QEasingCurve
|
||||
from PyQt5.QtGui import QFont, QPalette
|
||||
|
||||
logger = logging.getLogger("generator_tab")
|
||||
|
||||
class ModernGeneratorTab(QWidget):
|
||||
"""Modernes Widget für Account-Generierung ohne Log."""
|
||||
|
||||
# Signale
|
||||
start_requested = pyqtSignal(dict)
|
||||
stop_requested = pyqtSignal()
|
||||
account_created = pyqtSignal(str, dict)
|
||||
|
||||
def __init__(self, platform_name, language_manager=None):
|
||||
super().__init__()
|
||||
self.platform_name = platform_name
|
||||
self.language_manager = language_manager
|
||||
self.init_ui()
|
||||
if self.language_manager:
|
||||
self.language_manager.language_changed.connect(self.update_texts)
|
||||
self.update_texts()
|
||||
|
||||
def init_ui(self):
|
||||
"""Initialisiert die moderne Benutzeroberfläche."""
|
||||
# Haupt-Layout mit Scroll-Bereich
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# Scroll-Bereich für bessere Anpassung
|
||||
scroll = QScrollArea()
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll.setFrameShape(QFrame.NoFrame)
|
||||
scroll_widget = QWidget()
|
||||
scroll_layout = QVBoxLayout(scroll_widget)
|
||||
scroll_layout.setContentsMargins(40, 30, 40, 30)
|
||||
scroll_layout.setSpacing(30)
|
||||
|
||||
# Header mit Titel und Status
|
||||
header_widget = self.create_header()
|
||||
scroll_layout.addWidget(header_widget)
|
||||
|
||||
# Haupt-Formular als Card
|
||||
form_card = self.create_form_card()
|
||||
scroll_layout.addWidget(form_card)
|
||||
|
||||
# Erweiterte Optionen
|
||||
options_card = self.create_options_card()
|
||||
scroll_layout.addWidget(options_card)
|
||||
|
||||
# Action-Bereich mit Buttons
|
||||
action_widget = self.create_action_area()
|
||||
scroll_layout.addWidget(action_widget)
|
||||
|
||||
scroll_layout.addStretch()
|
||||
|
||||
scroll.setWidget(scroll_widget)
|
||||
main_layout.addWidget(scroll)
|
||||
|
||||
# Event-Verbindungen
|
||||
self.email_radio.toggled.connect(self.toggle_phone_input)
|
||||
self.phone_radio.toggled.connect(self.toggle_phone_input)
|
||||
|
||||
# Initialer Status
|
||||
self.toggle_phone_input()
|
||||
|
||||
def create_header(self):
|
||||
"""Erstellt den Header-Bereich mit Titel und Status."""
|
||||
header = QWidget()
|
||||
layout = QHBoxLayout(header)
|
||||
layout.setContentsMargins(0, 0, 0, 20)
|
||||
|
||||
# Titel
|
||||
title = QLabel("Account erstellen")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(24)
|
||||
title_font.setWeight(QFont.Bold)
|
||||
title.setFont(title_font)
|
||||
layout.addWidget(title)
|
||||
|
||||
layout.addStretch()
|
||||
|
||||
# Status-Widget entfernt für cleanes Design
|
||||
|
||||
return header
|
||||
|
||||
def create_form_card(self):
|
||||
"""Erstellt die Haupt-Formular-Card."""
|
||||
card = QFrame()
|
||||
card.setObjectName("formCard")
|
||||
card.setStyleSheet("""
|
||||
#formCard {
|
||||
background-color: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
}
|
||||
""")
|
||||
|
||||
layout = QVBoxLayout(card)
|
||||
|
||||
# Section Title
|
||||
section_title = QLabel("Account-Informationen")
|
||||
section_font = QFont()
|
||||
section_font.setPointSize(16)
|
||||
section_font.setWeight(QFont.DemiBold)
|
||||
section_title.setFont(section_font)
|
||||
layout.addWidget(section_title)
|
||||
layout.addSpacing(20)
|
||||
|
||||
# Grid-Layout für bessere Anordnung
|
||||
grid = QGridLayout()
|
||||
grid.setHorizontalSpacing(20)
|
||||
grid.setVerticalSpacing(20)
|
||||
|
||||
# Erste Zeile: Vorname und Nachname
|
||||
self.first_name_label = self.create_label("Vorname")
|
||||
self.first_name_input = self.create_input("z.B. Max")
|
||||
grid.addWidget(self.first_name_label, 0, 0)
|
||||
grid.addWidget(self.first_name_input, 1, 0)
|
||||
|
||||
self.last_name_label = self.create_label("Nachname")
|
||||
self.last_name_input = self.create_input("z.B. Mustermann")
|
||||
grid.addWidget(self.last_name_label, 0, 1)
|
||||
grid.addWidget(self.last_name_input, 1, 1)
|
||||
|
||||
# Zweite Zeile: Alter
|
||||
self.age_label = self.create_label("Alter")
|
||||
self.age_input = self.create_input("z.B. 25")
|
||||
grid.addWidget(self.age_label, 2, 0)
|
||||
grid.addWidget(self.age_input, 3, 0)
|
||||
|
||||
# Dritte Zeile: Registrierungsmethode
|
||||
self.reg_method_label = self.create_label("Registrierungsmethode")
|
||||
grid.addWidget(self.reg_method_label, 4, 0, 1, 2)
|
||||
|
||||
# Radio Buttons in horizontaler Anordnung
|
||||
radio_widget = QWidget()
|
||||
radio_layout = QHBoxLayout(radio_widget)
|
||||
radio_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.email_radio = QRadioButton("E-Mail")
|
||||
self.phone_radio = QRadioButton("Telefon")
|
||||
self.email_radio.setChecked(True)
|
||||
|
||||
# Styling für Radio Buttons
|
||||
radio_style = """
|
||||
QRadioButton {
|
||||
font-size: 14px;
|
||||
spacing: 8px;
|
||||
}
|
||||
QRadioButton::indicator {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
"""
|
||||
self.email_radio.setStyleSheet(radio_style)
|
||||
self.phone_radio.setStyleSheet(radio_style)
|
||||
|
||||
radio_layout.addWidget(self.email_radio)
|
||||
radio_layout.addWidget(self.phone_radio)
|
||||
radio_layout.addStretch()
|
||||
|
||||
grid.addWidget(radio_widget, 5, 0, 1, 2)
|
||||
|
||||
# Vierte Zeile: Kontaktfeld (E-Mail Domain oder Telefon)
|
||||
self.email_domain_label = self.create_label("E-Mail Domain")
|
||||
self.email_domain_input = self.create_input("")
|
||||
self.email_domain_input.setText("z5m7q9dk3ah2v1plx6ju.com")
|
||||
grid.addWidget(self.email_domain_label, 6, 0)
|
||||
grid.addWidget(self.email_domain_input, 7, 0)
|
||||
|
||||
self.phone_label = self.create_label("Telefonnummer")
|
||||
self.phone_input = self.create_input("z.B. +49123456789")
|
||||
self.phone_label.hide()
|
||||
self.phone_input.hide()
|
||||
grid.addWidget(self.phone_label, 6, 1)
|
||||
grid.addWidget(self.phone_input, 7, 1)
|
||||
|
||||
layout.addLayout(grid)
|
||||
|
||||
# Plattform-spezifische Felder
|
||||
self.add_platform_specific_fields(layout)
|
||||
|
||||
return card
|
||||
|
||||
def create_options_card(self):
|
||||
"""Erstellt die Card für erweiterte Optionen."""
|
||||
card = QFrame()
|
||||
card.setObjectName("optionsCard")
|
||||
card.setStyleSheet("""
|
||||
#optionsCard {
|
||||
background-color: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
}
|
||||
""")
|
||||
|
||||
layout = QVBoxLayout(card)
|
||||
|
||||
# Section Title
|
||||
section_title = QLabel("Erweiterte Optionen")
|
||||
section_font = QFont()
|
||||
section_font.setPointSize(16)
|
||||
section_font.setWeight(QFont.DemiBold)
|
||||
section_title.setFont(section_font)
|
||||
layout.addWidget(section_title)
|
||||
layout.addSpacing(15)
|
||||
|
||||
# Optionen als moderne Checkboxen
|
||||
self.headless_check = self.create_checkbox("Browser im Hintergrund ausführen")
|
||||
self.headless_check.setToolTip("Der Browser wird nicht sichtbar sein")
|
||||
layout.addWidget(self.headless_check)
|
||||
|
||||
return card
|
||||
|
||||
def create_action_area(self):
|
||||
"""Erstellt den Bereich mit Aktions-Buttons und Progress."""
|
||||
widget = QWidget()
|
||||
layout = QVBoxLayout(widget)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# Progress Bar (initial versteckt)
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setMinimumHeight(6)
|
||||
self.progress_bar.setTextVisible(False)
|
||||
self.progress_bar.setStyleSheet("""
|
||||
QProgressBar {
|
||||
background-color: #f0f0f0;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background-color: #2196F3;
|
||||
border-radius: 3px;
|
||||
}
|
||||
""")
|
||||
self.progress_bar.hide()
|
||||
layout.addWidget(self.progress_bar)
|
||||
layout.addSpacing(20)
|
||||
|
||||
# Buttons
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.addStretch()
|
||||
|
||||
self.stop_button = self.create_button("Abbrechen", primary=False)
|
||||
self.stop_button.clicked.connect(self.on_stop_clicked)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.stop_button.hide()
|
||||
button_layout.addWidget(self.stop_button)
|
||||
|
||||
self.start_button = self.create_button("Account erstellen", primary=True)
|
||||
self.start_button.clicked.connect(self.on_start_clicked)
|
||||
button_layout.addWidget(self.start_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
return widget
|
||||
|
||||
def create_label(self, text):
|
||||
"""Erstellt ein modernes Label."""
|
||||
label = QLabel(text)
|
||||
label.setStyleSheet("""
|
||||
QLabel {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
""")
|
||||
return label
|
||||
|
||||
def create_input(self, placeholder=""):
|
||||
"""Erstellt ein modernes Input-Feld."""
|
||||
input_field = QLineEdit()
|
||||
input_field.setPlaceholderText(placeholder)
|
||||
input_field.setMinimumHeight(42)
|
||||
input_field.setStyleSheet("""
|
||||
QLineEdit {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 10px 15px;
|
||||
font-size: 14px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
border-color: #2196F3;
|
||||
background-color: white;
|
||||
}
|
||||
QLineEdit:hover {
|
||||
border-color: #bdbdbd;
|
||||
}
|
||||
""")
|
||||
return input_field
|
||||
|
||||
def create_checkbox(self, text):
|
||||
"""Erstellt eine moderne Checkbox."""
|
||||
checkbox = QCheckBox(text)
|
||||
checkbox.setStyleSheet("""
|
||||
QCheckBox {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
spacing: 10px;
|
||||
}
|
||||
QCheckBox::indicator {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid #e0e0e0;
|
||||
background-color: white;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #2196F3;
|
||||
border-color: #2196F3;
|
||||
image: url(check_white.png);
|
||||
}
|
||||
QCheckBox::indicator:hover {
|
||||
border-color: #2196F3;
|
||||
}
|
||||
""")
|
||||
return checkbox
|
||||
|
||||
def create_button(self, text, primary=False):
|
||||
"""Erstellt einen modernen Button."""
|
||||
button = QPushButton(text)
|
||||
button.setMinimumHeight(45)
|
||||
button.setCursor(Qt.PointingHandCursor)
|
||||
|
||||
if primary:
|
||||
button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 12px 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #1976D2;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #0D47A1;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #BBBBBB;
|
||||
}
|
||||
""")
|
||||
else:
|
||||
button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: white;
|
||||
color: #666;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 12px 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:hover {
|
||||
border-color: #bdbdbd;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #BBBBBB;
|
||||
border-color: #eeeeee;
|
||||
}
|
||||
""")
|
||||
|
||||
return button
|
||||
|
||||
def add_platform_specific_fields(self, parent_layout):
|
||||
"""Fügt plattformspezifische Felder hinzu."""
|
||||
platform = self.platform_name.lower()
|
||||
|
||||
|
||||
def toggle_phone_input(self):
|
||||
"""Wechselt zwischen E-Mail und Telefon-Eingabe."""
|
||||
if self.email_radio.isChecked():
|
||||
self.email_domain_label.show()
|
||||
self.email_domain_input.show()
|
||||
self.phone_label.hide()
|
||||
self.phone_input.hide()
|
||||
else:
|
||||
self.email_domain_label.hide()
|
||||
self.email_domain_input.hide()
|
||||
self.phone_label.show()
|
||||
self.phone_input.show()
|
||||
|
||||
def on_start_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Start-Button geklickt wird."""
|
||||
params = self.get_params()
|
||||
|
||||
valid, error_msg = self.validate_inputs(params)
|
||||
if not valid:
|
||||
self.show_error(error_msg)
|
||||
return
|
||||
|
||||
# UI für laufenden Prozess anpassen
|
||||
self.set_running(True)
|
||||
self.progress_bar.show()
|
||||
self.progress_bar.setValue(0)
|
||||
|
||||
# Signal auslösen
|
||||
self.start_requested.emit(params)
|
||||
|
||||
def on_stop_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Stop-Button geklickt wird."""
|
||||
self.stop_requested.emit()
|
||||
|
||||
def get_params(self):
|
||||
"""Sammelt alle Parameter für die Account-Erstellung."""
|
||||
first_name = self.first_name_input.text().strip()
|
||||
last_name = self.last_name_input.text().strip()
|
||||
full_name = f"{first_name} {last_name}"
|
||||
|
||||
params = {
|
||||
"first_name": first_name,
|
||||
"last_name": last_name,
|
||||
"full_name": full_name,
|
||||
"age_text": self.age_input.text().strip(),
|
||||
"registration_method": "email" if self.email_radio.isChecked() else "phone",
|
||||
"headless": self.headless_check.isChecked(),
|
||||
"debug": True,
|
||||
"email_domain": self.email_domain_input.text().strip(),
|
||||
"use_proxy": False
|
||||
}
|
||||
|
||||
if self.phone_radio.isChecked():
|
||||
params["phone_number"] = self.phone_input.text().strip()
|
||||
|
||||
|
||||
return params
|
||||
|
||||
def validate_inputs(self, params):
|
||||
"""Validiert die Eingaben."""
|
||||
if not params.get("first_name"):
|
||||
return False, "Bitte geben Sie einen Vornamen ein."
|
||||
|
||||
if not params.get("last_name"):
|
||||
return False, "Bitte geben Sie einen Nachnamen ein."
|
||||
|
||||
age_text = params.get("age_text", "")
|
||||
if not age_text:
|
||||
return False, "Bitte geben Sie ein Alter ein."
|
||||
|
||||
try:
|
||||
age = int(age_text)
|
||||
params["age"] = age
|
||||
except ValueError:
|
||||
return False, "Das Alter muss eine ganze Zahl sein."
|
||||
|
||||
if age < 13 or age > 99:
|
||||
return False, "Das Alter muss zwischen 13 und 99 liegen."
|
||||
|
||||
if params.get("registration_method") == "phone" and not params.get("phone_number"):
|
||||
return False, "Bitte geben Sie eine Telefonnummer ein."
|
||||
|
||||
return True, ""
|
||||
|
||||
def set_running(self, running: bool):
|
||||
"""Setzt den Status auf 'Wird ausgeführt' oder 'Bereit'."""
|
||||
if running:
|
||||
self.start_button.hide()
|
||||
self.stop_button.show()
|
||||
self.stop_button.setEnabled(True)
|
||||
# Status-Dot entfernt
|
||||
# Status-Text entfernt
|
||||
else:
|
||||
self.start_button.show()
|
||||
self.stop_button.hide()
|
||||
self.stop_button.setEnabled(False)
|
||||
self.progress_bar.hide()
|
||||
# Status-Dot entfernt
|
||||
# Status-Text entfernt
|
||||
|
||||
def set_progress(self, value: int):
|
||||
"""Setzt den Fortschritt."""
|
||||
self.progress_bar.setValue(value)
|
||||
|
||||
def set_status(self, message: str):
|
||||
"""Setzt die Statusnachricht."""
|
||||
# Status-Text entfernt
|
||||
logger.info(f"Status: {message}")
|
||||
|
||||
def show_error(self, message: str):
|
||||
"""Zeigt eine moderne Fehlermeldung an."""
|
||||
from views.widgets.modern_message_box import show_error
|
||||
show_error(self, "Fehler", message)
|
||||
|
||||
def update_texts(self):
|
||||
"""Aktualisiert UI-Texte gemäß der aktuellen Sprache."""
|
||||
# Hier würden die Übersetzungen implementiert
|
||||
pass
|
||||
315
views/tabs/settings_tab.py
Normale Datei
315
views/tabs/settings_tab.py
Normale Datei
@ -0,0 +1,315 @@
|
||||
"""
|
||||
Tab für die Einstellungen der Anwendung.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
|
||||
QGroupBox, QLabel, QLineEdit, QSpinBox, QTextEdit,
|
||||
QPushButton, QCheckBox, QComboBox
|
||||
)
|
||||
from PyQt5.QtCore import pyqtSignal, Qt
|
||||
|
||||
logger = logging.getLogger("settings_tab")
|
||||
|
||||
class SettingsTab(QWidget):
|
||||
"""Widget für den Einstellungen-Tab."""
|
||||
|
||||
# Signale
|
||||
proxy_settings_saved = pyqtSignal(dict)
|
||||
proxy_tested = pyqtSignal(str) # proxy_type
|
||||
email_settings_saved = pyqtSignal(dict)
|
||||
email_tested = pyqtSignal(dict) # email_settings
|
||||
license_activated = pyqtSignal(str) # license_key
|
||||
|
||||
def __init__(self, platform_name, proxy_rotator=None, email_handler=None, license_manager=None, language_manager=None):
|
||||
super().__init__()
|
||||
self.platform_name = platform_name
|
||||
self.proxy_rotator = proxy_rotator
|
||||
self.email_handler = email_handler
|
||||
self.license_manager = license_manager
|
||||
self.language_manager = language_manager
|
||||
self.init_ui()
|
||||
if self.language_manager:
|
||||
self.language_manager.language_changed.connect(self.update_texts)
|
||||
self.update_texts()
|
||||
|
||||
# Einstellungen laden, falls Handler vorhanden
|
||||
self.load_settings()
|
||||
|
||||
def init_ui(self):
|
||||
"""Initialisiert die Benutzeroberfläche."""
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Proxy-Einstellungen
|
||||
proxy_group = QGroupBox("Proxy-Einstellungen")
|
||||
proxy_layout = QVBoxLayout(proxy_group)
|
||||
|
||||
# IPv4 Proxies
|
||||
ipv4_form = QFormLayout()
|
||||
self.ipv4_proxy_input = QTextEdit()
|
||||
self.ipv4_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
|
||||
ipv4_form.addRow("IPv4 Proxies:", self.ipv4_proxy_input)
|
||||
proxy_layout.addLayout(ipv4_form)
|
||||
|
||||
# IPv6 Proxies
|
||||
ipv6_form = QFormLayout()
|
||||
self.ipv6_proxy_input = QTextEdit()
|
||||
self.ipv6_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
|
||||
ipv6_form.addRow("IPv6 Proxies:", self.ipv6_proxy_input)
|
||||
proxy_layout.addLayout(ipv6_form)
|
||||
|
||||
# Mobile Proxies
|
||||
mobile_form = QFormLayout()
|
||||
self.mobile_proxy_input = QTextEdit()
|
||||
self.mobile_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
|
||||
mobile_form.addRow("Mobile Proxies:", self.mobile_proxy_input)
|
||||
proxy_layout.addLayout(mobile_form)
|
||||
|
||||
# Mobile Proxy API Keys
|
||||
api_key_layout = QFormLayout()
|
||||
self.marsproxy_api_input = QLineEdit()
|
||||
api_key_layout.addRow("MarsProxies API Key:", self.marsproxy_api_input)
|
||||
|
||||
self.iproyal_api_input = QLineEdit()
|
||||
api_key_layout.addRow("IPRoyal API Key:", self.iproyal_api_input)
|
||||
|
||||
proxy_layout.addLayout(api_key_layout)
|
||||
|
||||
# Test-Button
|
||||
proxy_button_layout = QHBoxLayout()
|
||||
|
||||
self.test_proxy_button = QPushButton("Proxy testen")
|
||||
self.test_proxy_button.clicked.connect(self.on_test_proxy_clicked)
|
||||
|
||||
self.save_proxy_button = QPushButton("Proxy-Einstellungen speichern")
|
||||
self.save_proxy_button.clicked.connect(self.on_save_proxy_clicked)
|
||||
|
||||
proxy_button_layout.addWidget(self.test_proxy_button)
|
||||
proxy_button_layout.addWidget(self.save_proxy_button)
|
||||
|
||||
proxy_layout.addLayout(proxy_button_layout)
|
||||
|
||||
layout.addWidget(proxy_group)
|
||||
|
||||
# E-Mail-Einstellungen
|
||||
email_group = QGroupBox("E-Mail-Einstellungen")
|
||||
email_layout = QFormLayout(email_group)
|
||||
|
||||
self.imap_server_input = QLineEdit("imap.ionos.de")
|
||||
email_layout.addRow("IMAP-Server:", self.imap_server_input)
|
||||
|
||||
self.imap_port_input = QSpinBox()
|
||||
self.imap_port_input.setRange(1, 65535)
|
||||
self.imap_port_input.setValue(993)
|
||||
email_layout.addRow("IMAP-Port:", self.imap_port_input)
|
||||
|
||||
self.imap_user_input = QLineEdit()
|
||||
email_layout.addRow("IMAP-Benutzername:", self.imap_user_input)
|
||||
|
||||
self.imap_pass_input = QLineEdit()
|
||||
self.imap_pass_input.setEchoMode(QLineEdit.Password)
|
||||
email_layout.addRow("IMAP-Passwort:", self.imap_pass_input)
|
||||
|
||||
email_button_layout = QHBoxLayout()
|
||||
|
||||
self.test_email_button = QPushButton("E-Mail testen")
|
||||
self.test_email_button.clicked.connect(self.on_test_email_clicked)
|
||||
|
||||
self.save_email_button = QPushButton("E-Mail-Einstellungen speichern")
|
||||
self.save_email_button.clicked.connect(self.on_save_email_clicked)
|
||||
|
||||
email_button_layout.addWidget(self.test_email_button)
|
||||
email_button_layout.addWidget(self.save_email_button)
|
||||
|
||||
email_layout.addRow("", email_button_layout)
|
||||
|
||||
layout.addWidget(email_group)
|
||||
|
||||
# Plattformspezifische Einstellungen
|
||||
if self.platform_name.lower() != "instagram":
|
||||
self.add_platform_specific_settings(layout)
|
||||
|
||||
# Lizenz-Gruppe
|
||||
license_group = QGroupBox("Lizenz")
|
||||
license_layout = QFormLayout(license_group)
|
||||
|
||||
self.license_key_input = QLineEdit()
|
||||
license_layout.addRow("Lizenzschlüssel:", self.license_key_input)
|
||||
|
||||
self.activate_license_button = QPushButton("Lizenz aktivieren")
|
||||
self.activate_license_button.clicked.connect(self.on_activate_license_clicked)
|
||||
license_layout.addRow("", self.activate_license_button)
|
||||
|
||||
layout.addWidget(license_group)
|
||||
|
||||
# Stretch am Ende hinzufügen
|
||||
layout.addStretch(1)
|
||||
|
||||
def add_platform_specific_settings(self, layout):
|
||||
"""
|
||||
Fügt plattformspezifische Einstellungen hinzu.
|
||||
Diese Methode kann in abgeleiteten Klassen überschrieben werden.
|
||||
|
||||
Args:
|
||||
layout: Das Layout, zu dem die Einstellungen hinzugefügt werden sollen
|
||||
"""
|
||||
platform = self.platform_name.lower()
|
||||
|
||||
platform_settings_group = QGroupBox(f"{self.platform_name}-spezifische Einstellungen")
|
||||
platform_settings_layout = QFormLayout(platform_settings_group)
|
||||
|
||||
# Je nach Plattform unterschiedliche Einstellungen
|
||||
if platform == "twitter":
|
||||
self.twitter_api_key = QLineEdit()
|
||||
platform_settings_layout.addRow("Twitter API Key:", self.twitter_api_key)
|
||||
|
||||
self.twitter_api_secret = QLineEdit()
|
||||
platform_settings_layout.addRow("Twitter API Secret:", self.twitter_api_secret)
|
||||
|
||||
elif platform == "tiktok":
|
||||
self.video_upload = QCheckBox("Video automatisch hochladen")
|
||||
platform_settings_layout.addRow("", self.video_upload)
|
||||
|
||||
self.follower_action = QCheckBox("Automatisch anderen Nutzern folgen")
|
||||
platform_settings_layout.addRow("", self.follower_action)
|
||||
|
||||
elif platform == "facebook":
|
||||
self.page_creation = QCheckBox("Seite automatisch erstellen")
|
||||
platform_settings_layout.addRow("", self.page_creation)
|
||||
|
||||
self.privacy_level = QComboBox()
|
||||
self.privacy_level.addItems(["Öffentlich", "Freunde", "Nur ich"])
|
||||
platform_settings_layout.addRow("Datenschutzeinstellung:", self.privacy_level)
|
||||
|
||||
# Speichern-Button für plattformspezifische Einstellungen
|
||||
self.platform_save_button = QPushButton(f"{self.platform_name}-Einstellungen speichern")
|
||||
self.platform_save_button.clicked.connect(self.on_save_platform_settings_clicked)
|
||||
platform_settings_layout.addRow("", self.platform_save_button)
|
||||
|
||||
layout.addWidget(platform_settings_group)
|
||||
|
||||
def load_settings(self):
|
||||
"""Lädt die Einstellungen aus den Handlern."""
|
||||
# Proxy-Einstellungen laden
|
||||
if self.proxy_rotator:
|
||||
try:
|
||||
proxy_config = self.proxy_rotator.get_config() or {}
|
||||
|
||||
# IPv4 Proxies
|
||||
ipv4_proxies = proxy_config.get("ipv4", [])
|
||||
self.ipv4_proxy_input.setPlainText("\n".join(ipv4_proxies))
|
||||
|
||||
# IPv6 Proxies
|
||||
ipv6_proxies = proxy_config.get("ipv6", [])
|
||||
self.ipv6_proxy_input.setPlainText("\n".join(ipv6_proxies))
|
||||
|
||||
# Mobile Proxies
|
||||
mobile_proxies = proxy_config.get("mobile", [])
|
||||
self.mobile_proxy_input.setPlainText("\n".join(mobile_proxies))
|
||||
|
||||
# API Keys
|
||||
mobile_api = proxy_config.get("mobile_api", {})
|
||||
self.marsproxy_api_input.setText(mobile_api.get("marsproxies", ""))
|
||||
self.iproyal_api_input.setText(mobile_api.get("iproyal", ""))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der Proxy-Einstellungen: {e}")
|
||||
|
||||
# E-Mail-Einstellungen laden
|
||||
if self.email_handler:
|
||||
try:
|
||||
email_config = self.email_handler.get_config() or {}
|
||||
|
||||
self.imap_server_input.setText(email_config.get("imap_server", "imap.ionos.de"))
|
||||
self.imap_port_input.setValue(email_config.get("imap_port", 993))
|
||||
self.imap_user_input.setText(email_config.get("imap_user", ""))
|
||||
self.imap_pass_input.setText(email_config.get("imap_pass", ""))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der E-Mail-Einstellungen: {e}")
|
||||
|
||||
# Lizenzeinstellungen laden
|
||||
if self.license_manager:
|
||||
try:
|
||||
license_info = self.license_manager.get_license_info()
|
||||
self.license_key_input.setText(license_info.get("key", ""))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der Lizenzeinstellungen: {e}")
|
||||
|
||||
def on_save_proxy_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Proxy-Speichern-Button geklickt wird."""
|
||||
# Proxy-Einstellungen sammeln
|
||||
settings = {
|
||||
"ipv4_proxies": self.ipv4_proxy_input.toPlainText(),
|
||||
"ipv6_proxies": self.ipv6_proxy_input.toPlainText(),
|
||||
"mobile_proxies": self.mobile_proxy_input.toPlainText(),
|
||||
"mobile_api": {
|
||||
"marsproxies": self.marsproxy_api_input.text().strip(),
|
||||
"iproyal": self.iproyal_api_input.text().strip()
|
||||
}
|
||||
}
|
||||
|
||||
# Signal auslösen
|
||||
self.proxy_settings_saved.emit(settings)
|
||||
|
||||
def on_test_proxy_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Proxy-Test-Button geklickt wird."""
|
||||
# Proxy-Typ aus der Combobox in der Generator-Tab holen
|
||||
# Da wir keine direkte Referenz haben, nehmen wir den ersten Eintrag
|
||||
proxy_type = "ipv4"
|
||||
|
||||
# Signal auslösen
|
||||
self.proxy_tested.emit(proxy_type)
|
||||
|
||||
def on_save_email_clicked(self):
|
||||
"""Wird aufgerufen, wenn der E-Mail-Speichern-Button geklickt wird."""
|
||||
# E-Mail-Einstellungen sammeln
|
||||
settings = {
|
||||
"imap_server": self.imap_server_input.text().strip(),
|
||||
"imap_port": self.imap_port_input.value(),
|
||||
"imap_user": self.imap_user_input.text().strip(),
|
||||
"imap_pass": self.imap_pass_input.text()
|
||||
}
|
||||
|
||||
# Signal auslösen
|
||||
self.email_settings_saved.emit(settings)
|
||||
|
||||
def on_test_email_clicked(self):
|
||||
"""Wird aufgerufen, wenn der E-Mail-Test-Button geklickt wird."""
|
||||
# E-Mail-Einstellungen sammeln
|
||||
settings = {
|
||||
"imap_server": self.imap_server_input.text().strip(),
|
||||
"imap_port": self.imap_port_input.value(),
|
||||
"imap_user": self.imap_user_input.text().strip(),
|
||||
"imap_pass": self.imap_pass_input.text()
|
||||
}
|
||||
|
||||
# Signal auslösen
|
||||
self.email_tested.emit(settings)
|
||||
|
||||
def on_save_platform_settings_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Plattform-Einstellungen-Speichern-Button geklickt wird."""
|
||||
# Hier könnte ein plattformspezifisches Signal ausgelöst werden
|
||||
logger.info(f"{self.platform_name}-Einstellungen gespeichert")
|
||||
|
||||
def on_activate_license_clicked(self):
|
||||
"""Wird aufgerufen, wenn der Lizenz-Aktivieren-Button geklickt wird."""
|
||||
license_key = self.license_key_input.text().strip()
|
||||
|
||||
if not license_key:
|
||||
return
|
||||
|
||||
# Signal auslösen
|
||||
self.license_activated.emit(license_key)
|
||||
|
||||
def update_texts(self):
|
||||
"""Aktualisiert UI-Texte gemäß aktueller Sprache."""
|
||||
if not self.language_manager:
|
||||
return
|
||||
self.test_proxy_button.setText(self.language_manager.get_text("buttons.test_proxy", "Proxy testen"))
|
||||
self.save_proxy_button.setText(self.language_manager.get_text("buttons.save_proxy", "Proxy-Einstellungen speichern"))
|
||||
self.test_email_button.setText(self.language_manager.get_text("buttons.test_email", "E-Mail testen"))
|
||||
self.save_email_button.setText(self.language_manager.get_text("buttons.save_email", "E-Mail-Einstellungen speichern"))
|
||||
self.activate_license_button.setText(self.language_manager.get_text("buttons.activate_license", "Lizenz aktivieren"))
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren