RollBack Punkt 2025-09-13

Dieser Commit ist enthalten in:
Claude Project Manager
2025-09-13 22:01:58 +02:00
Ursprung ca005ab9f0
Commit ba0ba3fcec
25 geänderte Dateien mit 140 neuen und 6194 gelöschten Zeilen

Datei anzeigen

@ -1,508 +0,0 @@
"""
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

Datei anzeigen

@ -1,625 +0,0 @@
"""
Account Creation Modal V2 - Verbessertes Design mit eindringlicher Warnung
Basierend auf dem Corporate Design Styleguide
"""
import logging
from typing import Optional, List, Dict
from datetime import datetime, timedelta
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QFrame, QWidget, QScrollArea,
QProgressBar, QGraphicsOpacityEffect
)
from PyQt5.QtCore import (
Qt, QTimer, pyqtSignal, QPropertyAnimation,
QEasingCurve, QRect, QSize
)
from PyQt5.QtGui import QFont, QPainter, QBrush, QColor, QPen, QPixmap
logger = logging.getLogger("account_creation_modal_v2")
class AccountCreationModalV2(QDialog):
"""
Verbessertes Modal für Account-Erstellung mit:
- Prominenter Warnung
- Besserer Step-Visualisierung
- Größerem Fenster
- Klarerer Kommunikation
"""
# Signale
cancel_clicked = pyqtSignal()
process_completed = pyqtSignal()
def __init__(self, parent=None, platform: str = "Social Media"):
super().__init__(parent)
self.platform = platform
self.current_step = 0
self.total_steps = 0
self.steps = []
self.start_time = None
self.is_process_running = False
# Timer für Updates
self.update_timer = QTimer()
self.update_timer.timeout.connect(self.update_time_display)
self.update_timer.setInterval(1000) # Jede Sekunde
# Animation Timer für Warning
self.warning_animation_timer = QTimer()
self.warning_animation_timer.timeout.connect(self.animate_warning)
self.warning_animation_timer.setInterval(100) # Smooth animation
self.warning_opacity = 1.0
self.warning_direction = -0.02
self.init_ui()
def init_ui(self):
"""Initialisiert die UI mit verbessertem Design"""
# Modal-Eigenschaften
self.setModal(True)
self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
# Größeres Fenster
self.setFixedSize(650, 700)
# Zentriere auf Parent oder Bildschirm
if self.parent():
parent_rect = self.parent().geometry()
x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
self.move(x, y)
# Hauptlayout
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# Container mit weißem Hintergrund
self.container = QFrame()
self.container.setObjectName("mainContainer")
self.container.setStyleSheet("""
QFrame#mainContainer {
background-color: #FFFFFF;
border: 1px solid #E2E8F0;
border-radius: 16px;
}
""")
container_layout = QVBoxLayout(self.container)
container_layout.setContentsMargins(0, 0, 0, 0)
container_layout.setSpacing(0)
# 1. WARNING BANNER (Sehr auffällig!)
self.warning_banner = self.create_warning_banner()
container_layout.addWidget(self.warning_banner)
# Content Area mit Padding
content_widget = QWidget()
content_layout = QVBoxLayout(content_widget)
content_layout.setContentsMargins(40, 30, 40, 40)
content_layout.setSpacing(24)
# 2. Titel-Bereich
self.title_label = QLabel(f"Account wird erstellt für {self.platform}")
self.title_label.setAlignment(Qt.AlignCenter)
self.title_label.setStyleSheet("""
QLabel {
color: #1A365D;
font-size: 28px;
font-weight: 700;
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
margin-bottom: 8px;
}
""")
content_layout.addWidget(self.title_label)
# 3. Progress-Bereich
progress_widget = self.create_progress_section()
content_layout.addWidget(progress_widget)
# 4. Steps-Liste
self.steps_widget = self.create_steps_list()
content_layout.addWidget(self.steps_widget)
# 5. Live-Status
self.status_widget = self.create_status_section()
content_layout.addWidget(self.status_widget)
# 6. Info-Box
info_box = self.create_info_box()
content_layout.addWidget(info_box)
# Spacer
content_layout.addStretch()
# Container zum Hauptlayout hinzufügen
container_layout.addWidget(content_widget)
main_layout.addWidget(self.container)
def create_warning_banner(self) -> QFrame:
"""Erstellt den auffälligen Warning Banner"""
banner = QFrame()
banner.setObjectName("warningBanner")
banner.setFixedHeight(100)
banner.setStyleSheet("""
QFrame#warningBanner {
background-color: #DC2626;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
border-bottom: none;
}
""")
layout = QVBoxLayout(banner)
layout.setContentsMargins(40, 20, 40, 20)
layout.setSpacing(8)
# Warning Icon + Haupttext
main_warning = QLabel("⚠️ NICHT DEN BROWSER BERÜHREN!")
main_warning.setAlignment(Qt.AlignCenter)
main_warning.setStyleSheet("""
QLabel {
color: #FFFFFF;
font-size: 24px;
font-weight: 700;
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
letter-spacing: 1px;
}
""")
# Untertitel
subtitle = QLabel("Die Automatisierung läuft. Jede Interaktion kann den Prozess unterbrechen.")
subtitle.setAlignment(Qt.AlignCenter)
subtitle.setWordWrap(True)
subtitle.setStyleSheet("""
QLabel {
color: rgba(255, 255, 255, 0.9);
font-size: 14px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
""")
layout.addWidget(main_warning)
layout.addWidget(subtitle)
return banner
def create_progress_section(self) -> QWidget:
"""Erstellt den Progress-Bereich"""
widget = QWidget()
layout = QHBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(24)
# Progress Bar
progress_container = QWidget()
progress_layout = QVBoxLayout(progress_container)
progress_layout.setContentsMargins(0, 0, 0, 0)
progress_layout.setSpacing(8)
self.progress_bar = QProgressBar()
self.progress_bar.setFixedHeight(12)
self.progress_bar.setStyleSheet("""
QProgressBar {
background-color: #E2E8F0;
border: none;
border-radius: 6px;
text-align: center;
}
QProgressBar::chunk {
background-color: #3182CE;
border-radius: 6px;
}
""")
self.progress_label = QLabel("Schritt 0 von 0")
self.progress_label.setStyleSheet("""
QLabel {
color: #4A5568;
font-size: 14px;
font-weight: 500;
}
""")
progress_layout.addWidget(self.progress_bar)
progress_layout.addWidget(self.progress_label)
# Zeit-Anzeige
time_container = QWidget()
time_container.setFixedWidth(180)
time_layout = QVBoxLayout(time_container)
time_layout.setContentsMargins(0, 0, 0, 0)
time_layout.setSpacing(4)
self.time_label = QLabel("~2 Min verbleibend")
self.time_label.setAlignment(Qt.AlignRight)
self.time_label.setStyleSheet("""
QLabel {
color: #1A365D;
font-size: 16px;
font-weight: 600;
font-family: 'Poppins', -apple-system, sans-serif;
}
""")
self.elapsed_label = QLabel("Verstrichene Zeit: 0:00")
self.elapsed_label.setAlignment(Qt.AlignRight)
self.elapsed_label.setStyleSheet("""
QLabel {
color: #718096;
font-size: 12px;
font-weight: 400;
}
""")
time_layout.addWidget(self.time_label)
time_layout.addWidget(self.elapsed_label)
layout.addWidget(progress_container, 1)
layout.addWidget(time_container)
return widget
def create_steps_list(self) -> QWidget:
"""Erstellt die visuelle Steps-Liste"""
container = QFrame()
container.setStyleSheet("""
QFrame {
background-color: #F8FAFC;
border: 1px solid #E2E8F0;
border-radius: 12px;
padding: 20px;
}
""")
self.steps_layout = QVBoxLayout(container)
self.steps_layout.setSpacing(12)
# Wird dynamisch befüllt
return container
def create_status_section(self) -> QWidget:
"""Erstellt den Live-Status Bereich"""
container = QFrame()
container.setStyleSheet("""
QFrame {
background-color: #1A365D;
border-radius: 12px;
padding: 20px;
min-height: 80px;
}
""")
layout = QVBoxLayout(container)
layout.setSpacing(8)
status_title = QLabel("Aktueller Status:")
status_title.setStyleSheet("""
QLabel {
color: rgba(255, 255, 255, 0.7);
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
}
""")
self.current_status_label = QLabel("Initialisiere Browser...")
self.current_status_label.setWordWrap(True)
self.current_status_label.setStyleSheet("""
QLabel {
color: #FFFFFF;
font-size: 16px;
font-weight: 400;
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
line-height: 1.5;
}
""")
layout.addWidget(status_title)
layout.addWidget(self.current_status_label)
return container
def create_info_box(self) -> QWidget:
"""Erstellt die Info-Box"""
container = QFrame()
container.setStyleSheet("""
QFrame {
background-color: #DBEAFE;
border: 1px solid #2563EB;
border-radius: 12px;
padding: 16px;
}
""")
layout = QHBoxLayout(container)
layout.setSpacing(16)
# Info Icon
icon_label = QLabel("")
icon_label.setStyleSheet("""
QLabel {
font-size: 24px;
color: #2563EB;
}
""")
# Info Text
info_layout = QVBoxLayout()
info_layout.setSpacing(4)
info_title = QLabel("Was passiert gerade?")
info_title.setStyleSheet("""
QLabel {
color: #1E40AF;
font-size: 14px;
font-weight: 600;
}
""")
self.info_text = QLabel("Der Browser simuliert menschliches Verhalten beim Ausfüllen des Formulars.")
self.info_text.setWordWrap(True)
self.info_text.setStyleSheet("""
QLabel {
color: #1E40AF;
font-size: 13px;
font-weight: 400;
line-height: 1.4;
}
""")
info_layout.addWidget(info_title)
info_layout.addWidget(self.info_text)
layout.addWidget(icon_label)
layout.addWidget(info_layout, 1)
return container
def set_steps(self, steps: List[str]):
"""Setzt die Steps und erstellt die visuelle Liste"""
self.steps = steps
self.total_steps = len(steps)
self.current_step = 0
# Progress Bar Setup
self.progress_bar.setMaximum(self.total_steps)
self.progress_bar.setValue(0)
# Clear existing steps
for i in reversed(range(self.steps_layout.count())):
self.steps_layout.itemAt(i).widget().setParent(None)
# Create step items
self.step_widgets = []
for i, step in enumerate(steps):
step_widget = self.create_step_item(i, step)
self.steps_layout.addWidget(step_widget)
self.step_widgets.append(step_widget)
def create_step_item(self, index: int, text: str) -> QWidget:
"""Erstellt ein einzelnes Step-Item"""
widget = QWidget()
layout = QHBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(12)
# Status Icon
icon_label = QLabel()
icon_label.setFixedSize(24, 24)
icon_label.setAlignment(Qt.AlignCenter)
icon_label.setObjectName(f"stepIcon_{index}")
# Text
text_label = QLabel(text)
text_label.setObjectName(f"stepText_{index}")
# Initial state (pending)
self.update_step_appearance(widget, 'pending')
layout.addWidget(icon_label)
layout.addWidget(text_label, 1)
return widget
def update_step_appearance(self, widget: QWidget, status: str):
"""Aktualisiert das Aussehen eines Steps basierend auf Status"""
icon_label = widget.findChild(QLabel, QRegExp("stepIcon_*"))
text_label = widget.findChild(QLabel, QRegExp("stepText_*"))
if status == 'completed':
icon_label.setText("")
text_label.setStyleSheet("""
QLabel {
color: #059669;
font-size: 14px;
font-weight: 500;
}
""")
elif status == 'active':
icon_label.setText("🔄")
text_label.setStyleSheet("""
QLabel {
color: #2563EB;
font-size: 14px;
font-weight: 600;
}
""")
# Rotation animation würde hier hinzugefügt
else: # pending
icon_label.setText("")
text_label.setStyleSheet("""
QLabel {
color: #718096;
font-size: 14px;
font-weight: 400;
}
""")
def start_process(self):
"""Startet den Account-Erstellungsprozess"""
self.is_process_running = True
self.start_time = datetime.now()
self.update_timer.start()
self.warning_animation_timer.start()
self.show()
def next_step(self, status_text: str = None, info_text: str = None):
"""Geht zum nächsten Schritt"""
if self.current_step < self.total_steps:
# Aktuellen Step als aktiv markieren
if self.current_step > 0:
self.update_step_appearance(self.step_widgets[self.current_step - 1], 'completed')
if self.current_step < len(self.step_widgets):
self.update_step_appearance(self.step_widgets[self.current_step], 'active')
self.current_step += 1
self.progress_bar.setValue(self.current_step)
self.progress_label.setText(f"Schritt {self.current_step} von {self.total_steps}")
# Update status
if status_text:
self.current_status_label.setText(status_text)
# Update info
if info_text:
self.info_text.setText(info_text)
# Update time estimate
self.update_time_estimate()
def update_time_estimate(self):
"""Aktualisiert die Zeitschätzung"""
if self.total_steps > 0 and self.current_step > 0:
elapsed = (datetime.now() - self.start_time).total_seconds()
avg_time_per_step = elapsed / self.current_step
remaining_steps = self.total_steps - self.current_step
estimated_remaining = remaining_steps * avg_time_per_step
if estimated_remaining < 60:
self.time_label.setText(f"~{int(estimated_remaining)}s verbleibend")
else:
minutes = int(estimated_remaining / 60)
self.time_label.setText(f"~{minutes} Min verbleibend")
def update_time_display(self):
"""Aktualisiert die verstrichene Zeit"""
if self.start_time:
elapsed = datetime.now() - self.start_time
minutes = int(elapsed.total_seconds() / 60)
seconds = int(elapsed.total_seconds() % 60)
self.elapsed_label.setText(f"Verstrichene Zeit: {minutes}:{seconds:02d}")
def animate_warning(self):
"""Animiert den Warning Banner (Pulseffekt)"""
self.warning_opacity += self.warning_direction
if self.warning_opacity <= 0.7:
self.warning_opacity = 0.7
self.warning_direction = 0.02
elif self.warning_opacity >= 1.0:
self.warning_opacity = 1.0
self.warning_direction = -0.02
# Opacity-Effekt anwenden
effect = QGraphicsOpacityEffect()
effect.setOpacity(self.warning_opacity)
self.warning_banner.setGraphicsEffect(effect)
def set_status(self, status: str, info: str = None):
"""Setzt den aktuellen Status"""
self.current_status_label.setText(status)
if info:
self.info_text.setText(info)
def complete_process(self):
"""Beendet den Prozess erfolgreich"""
self.is_process_running = False
self.update_timer.stop()
self.warning_animation_timer.stop()
# Letzten Step als completed markieren
if self.current_step > 0 and self.current_step <= len(self.step_widgets):
self.update_step_appearance(self.step_widgets[self.current_step - 1], 'completed')
# Success message
self.current_status_label.setText("✅ Account erfolgreich erstellt!")
self.info_text.setText("Der Prozess wurde erfolgreich abgeschlossen. Das Fenster schließt sich in wenigen Sekunden.")
# Auto-close nach 3 Sekunden
QTimer.singleShot(3000, self.close)
def paintEvent(self, event):
"""Custom paint event für Transparenz"""
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Semi-transparenter Hintergrund
painter.fillRect(self.rect(), QColor(0, 0, 0, 120))
def keyPressEvent(self, event):
"""Verhindert das Schließen mit ESC"""
if event.key() == Qt.Key_Escape:
event.ignore()
else:
super().keyPressEvent(event)
def closeEvent(self, event):
"""Verhindert das Schließen während der Prozess läuft"""
if self.is_process_running:
event.ignore()
else:
self.update_timer.stop()
self.warning_animation_timer.stop()
super().closeEvent(event)
# Beispiel-Verwendung
if __name__ == "__main__":
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
app = QApplication(sys.argv)
# Test window
main_window = QMainWindow()
main_window.setGeometry(100, 100, 800, 600)
main_window.show()
# Create and show modal
modal = AccountCreationModalV2(main_window, "Instagram")
modal.set_steps([
"Browser vorbereiten",
"Instagram-Seite laden",
"Registrierungsformular öffnen",
"Benutzerdaten eingeben",
"Account erstellen",
"E-Mail-Verifizierung",
"Profil einrichten"
])
# Simulate process
modal.start_process()
# Simulate step progression
def next_step():
modal.next_step(
f"Führe Schritt {modal.current_step + 1} aus...",
"Der Browser füllt automatisch die erforderlichen Felder aus."
)
if modal.current_step < modal.total_steps:
QTimer.singleShot(2000, next_step)
else:
modal.complete_process()
QTimer.singleShot(1000, next_step)
sys.exit(app.exec_())

Datei anzeigen

@ -1,370 +0,0 @@
"""
Forge Animation Widget V2 - Verbessertes Design mit prominenter Warnung
Angepasst an den bestehenden Code mit minimalen Änderungen
"""
from PyQt5.QtWidgets import QDialog, QWidget, QVBoxLayout, QLabel, QTextEdit, QPushButton, QHBoxLayout, QFrame
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtGui import QFont, QMovie, QPixmap
class ForgeAnimationDialog(QDialog):
"""Modal-Dialog für die Account-Erstellung mit verbessertem Design"""
# Signal wenn Abbrechen geklickt wird
cancel_clicked = pyqtSignal()
# Signal wenn Dialog geschlossen wird
closed = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.init_ui()
# Timer für das regelmäßige Nach-vorne-Holen
self.raise_timer = QTimer()
self.raise_timer.timeout.connect(self._raise_to_front)
self.raise_timer.setInterval(500) # Alle 500ms
def init_ui(self):
"""Initialisiert die UI mit verbessertem Design"""
# Nur Dialog im Vordergrund, nicht das ganze Hauptfenster
self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setModal(False) # Nicht modal - blockiert nicht das Hauptfenster
self.setFixedSize(650, 600) # Größer für bessere Sichtbarkeit
# Styling für Light Theme
self.setStyleSheet("""
ForgeAnimationDialog {
background-color: #FFFFFF;
border: 1px solid #E2E8F0;
border-radius: 8px;
}
""")
# Hauptlayout
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# NEUE WARNUNG OBEN - Sehr auffällig!
warning_banner = QFrame()
warning_banner.setFixedHeight(80)
warning_banner.setStyleSheet("""
QFrame {
background-color: #DC2626;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
padding: 15px 30px;
}
""")
warning_layout = QVBoxLayout(warning_banner)
warning_layout.setContentsMargins(0, 10, 0, 10)
# Großer Warning Text
warning_text = QLabel("⚠️ BROWSER NICHT BERÜHREN!")
warning_text.setAlignment(Qt.AlignCenter)
warning_text.setStyleSheet("""
QLabel {
color: #FFFFFF;
font-size: 22px;
font-weight: 700;
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
letter-spacing: 1px;
}
""")
warning_subtext = QLabel("Jede Interaktion kann den Prozess unterbrechen")
warning_subtext.setAlignment(Qt.AlignCenter)
warning_subtext.setStyleSheet("""
QLabel {
color: rgba(255, 255, 255, 0.9);
font-size: 13px;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
""")
warning_layout.addWidget(warning_text)
warning_layout.addWidget(warning_subtext)
layout.addWidget(warning_banner)
# Content Container
content_container = QWidget()
content_layout = QVBoxLayout(content_container)
content_layout.setContentsMargins(30, 25, 30, 30)
content_layout.setSpacing(20)
# Titel (etwas größer)
title_label = QLabel("Account wird erstellt")
title_label.setObjectName("titleLabel")
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("""
QLabel#titleLabel {
color: #1A365D;
font-size: 26px;
font-weight: 600;
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
padding-bottom: 10px;
border: none;
}
""")
content_layout.addWidget(title_label)
# Moderne Info-Karte (angepasst)
info_frame = QFrame()
info_frame.setStyleSheet("""
QFrame {
background: #DBEAFE;
border: 1px solid #2563EB;
border-radius: 12px;
min-height: 100px;
}
""")
info_layout = QHBoxLayout(info_frame)
info_layout.setContentsMargins(20, 15, 20, 15)
info_layout.setSpacing(15)
# Icon Container
icon_container = QFrame()
icon_container.setFixedSize(50, 50)
icon_container.setStyleSheet("""
QFrame {
background: #2563EB;
border-radius: 25px;
}
""")
icon_layout = QVBoxLayout(icon_container)
icon_layout.setContentsMargins(0, 0, 0, 0)
icon_label = QLabel("🤖")
icon_label.setAlignment(Qt.AlignCenter)
icon_label.setStyleSheet("""
QLabel {
font-size: 24px;
background: transparent;
border: none;
color: white;
}
""")
icon_layout.addWidget(icon_label)
# Text Container
text_container = QFrame()
text_layout = QVBoxLayout(text_container)
text_layout.setContentsMargins(0, 0, 0, 0)
text_layout.setSpacing(5)
# Titel
info_title = QLabel("Automatisierung läuft")
info_title.setObjectName("infoTitle")
info_title.setStyleSheet("""
QLabel#infoTitle {
color: #1E40AF;
font-size: 17px;
font-weight: 600;
font-family: 'Segoe UI', -apple-system, sans-serif;
background-color: transparent;
border: none;
}
""")
# Beschreibung (deutlicher)
info_desc = QLabel("Der Browser arbeitet automatisch. Bitte warten Sie, bis der Vorgang abgeschlossen ist.")
info_desc.setObjectName("infoDesc")
info_desc.setWordWrap(True)
info_desc.setStyleSheet("""
QLabel#infoDesc {
color: #1E40AF;
font-size: 14px;
font-weight: 500;
font-family: 'Segoe UI', -apple-system, sans-serif;
background-color: transparent;
border: none;
line-height: 20px;
}
""")
text_layout.addWidget(info_title)
text_layout.addWidget(info_desc)
text_layout.addStretch()
info_layout.addWidget(icon_container)
info_layout.addWidget(text_container, 1)
content_layout.addWidget(info_frame)
# Status Container
status_container = QFrame()
status_container.setStyleSheet("""
QFrame {
background-color: #1A365D;
border-radius: 8px;
padding: 15px;
}
""")
status_layout = QVBoxLayout(status_container)
# Status-Label (größer)
self.status_label = QLabel("Initialisiere...")
self.status_label.setObjectName("statusLabel")
self.status_label.setAlignment(Qt.AlignLeft)
self.status_label.setStyleSheet("""
QLabel#statusLabel {
color: #FFFFFF;
font-size: 16px;
padding: 5px;
font-weight: 500;
border: none;
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
}
""")
status_layout.addWidget(self.status_label)
content_layout.addWidget(status_container)
# Log-Ausgabe (größer)
self.log_output = QTextEdit()
self.log_output.setReadOnly(True)
self.log_output.setMaximumHeight(180) # Etwas größer
self.log_output.setStyleSheet("""
QTextEdit {
background-color: #F8FAFC;
color: #2D3748;
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', monospace;
font-size: 12px;
border: 1px solid #CBD5E0;
border-radius: 8px;
padding: 12px;
}
""")
content_layout.addWidget(self.log_output)
# Button-Container
button_layout = QHBoxLayout()
button_layout.addStretch()
# Abbrechen-Button (weniger prominent)
self.cancel_button = QPushButton("Abbrechen")
self.cancel_button.setStyleSheet("""
QPushButton {
background-color: #F0F4F8;
color: #4A5568;
font-size: 14px;
font-weight: 500;
padding: 8px 24px;
border-radius: 24px;
border: 1px solid #E2E8F0;
min-height: 40px;
}
QPushButton:hover {
background-color: #FEE2E2;
color: #DC2626;
border-color: #DC2626;
}
QPushButton:pressed {
background-color: #DC2626;
color: #FFFFFF;
}
""")
self.cancel_button.clicked.connect(self.cancel_clicked.emit)
button_layout.addWidget(self.cancel_button)
button_layout.addStretch()
content_layout.addLayout(button_layout)
layout.addWidget(content_container)
self.setLayout(layout)
# Volle Sichtbarkeit
self.setWindowOpacity(1.0)
def start_animation(self):
"""Zeigt den Dialog an"""
self.status_label.setText("Initialisiere...")
self.raise_timer.start() # Starte Timer für Always-on-Top
def stop_animation(self):
"""Stoppt die Animation und den Timer"""
self.raise_timer.stop()
def set_status(self, status: str):
"""Aktualisiert den Status-Text"""
self.status_label.setText(status)
def add_log(self, message: str):
"""Fügt eine Log-Nachricht hinzu"""
self.log_output.append(message)
# Auto-scroll zum Ende
scrollbar = self.log_output.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
def clear_log(self):
"""Löscht alle Log-Nachrichten"""
self.log_output.clear()
def set_progress(self, value: int):
"""Setzt den Fortschritt (0-100) - wird ignoriert da wir Spinner nutzen"""
pass
def closeEvent(self, event):
"""Wird aufgerufen wenn der Dialog geschlossen wird"""
self.stop_animation()
self.closed.emit()
event.accept()
def keyPressEvent(self, event):
"""Verhindert das Schließen mit ESC"""
if event.key() == Qt.Key_Escape:
event.ignore()
else:
super().keyPressEvent(event)
def _raise_to_front(self):
"""Holt den Dialog in den Vordergrund"""
self.raise_()
def show(self):
"""Überschreibt show() um den Dialog richtig zu positionieren"""
super().show()
self._raise_to_front() # Initial in den Vordergrund holen
# Zusätzliche Widget-Klasse für den AccountForger
class ForgeAnimationWidget(QLabel):
"""
Einfaches Animation Widget für den Progress Modal
Kann einen Spinner oder andere Animation anzeigen
"""
def __init__(self):
super().__init__()
self.setText("⚙️") # Placeholder Icon
self.setAlignment(Qt.AlignCenter)
self.setStyleSheet("""
QLabel {
font-size: 48px;
color: #3182CE;
}
""")
# Animation Timer
self.animation_timer = QTimer()
self.animation_timer.timeout.connect(self.rotate_icon)
self.rotation_state = 0
def start_animation(self):
"""Startet die Animation"""
self.animation_timer.start(100)
def stop_animation(self):
"""Stoppt die Animation"""
self.animation_timer.stop()
def rotate_icon(self):
"""Einfache Rotation Animation"""
icons = ["⚙️", "🔧", "🔨", "⚒️"]
self.setText(icons[self.rotation_state % len(icons)])
self.rotation_state += 1