Initial commit
Dieser Commit ist enthalten in:
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
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren