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")
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren