X-Problem gelöst

Dieser Commit ist enthalten in:
Claude Project Manager
2025-09-14 02:47:52 +02:00
Ursprung ba0ba3fcec
Commit f0320a9298
14 geänderte Dateien mit 674 neuen und 116 gelöschten Zeilen

Datei anzeigen

@ -14,7 +14,8 @@
"Bash(claude config list:*)",
"Bash(claude mcp)",
"Bash(claude mcp:*)",
"Bash(sqlite3:*)"
"Bash(sqlite3:*)",
"Bash(python -m pip install:*)"
],
"deny": [],
"defaultMode": "acceptEdits",

Datei anzeigen

@ -0,0 +1,139 @@
"""
Platform Service - Business logic for platform management
"""
import os
import yaml
import logging
from typing import List, Dict, Any, Optional
from pathlib import Path
from domain.entities.platform import Platform, PlatformStatus
logger = logging.getLogger("platform_service")
class PlatformService:
"""
Service for managing platform configuration and availability.
Clean Architecture: Application Service
"""
def __init__(self, db_manager=None):
self.db_manager = db_manager
self._platforms_cache = None
self._config_path = Path(__file__).parent.parent.parent / "config" / "platforms.yaml"
def _load_platforms(self) -> Dict[str, Platform]:
"""Load platforms from configuration file"""
if self._platforms_cache is not None:
return self._platforms_cache
try:
with open(self._config_path, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
platforms = {}
for platform_id, platform_data in config.get('platforms', {}).items():
platform = Platform(
id=platform_data.get('id', platform_id),
display_name=platform_data.get('display_name', platform_id.title()),
enabled=platform_data.get('enabled', False),
icon=platform_data.get('icon', f"{platform_id}.svg"),
color=platform_data.get('color', '#000000')
)
platforms[platform.id] = platform
self._platforms_cache = platforms
return platforms
except FileNotFoundError:
logger.warning(f"Platform config not found at {self._config_path}, using defaults")
return self._get_default_platforms()
except Exception as e:
logger.error(f"Error loading platform config: {e}")
return self._get_default_platforms()
def _get_default_platforms(self) -> Dict[str, Platform]:
"""Get default platform configuration"""
defaults = {
'instagram': Platform('instagram', 'Instagram', True, 'instagram.svg', '#E4405F'),
'facebook': Platform('facebook', 'Facebook', True, 'facebook.svg', '#1877F2'),
'tiktok': Platform('tiktok', 'TikTok', True, 'tiktok.svg', '#000000'),
'x': Platform('x', 'X', True, 'twitter.svg', '#000000'),
'gmail': Platform('gmail', 'Gmail', False, 'gmail.svg', '#EA4335'),
'vk': Platform('vk', 'VK', False, 'vk.svg', '#0077FF'),
'ok': Platform('ok', 'OK.ru', False, 'ok.svg', '#FF6600')
}
return defaults
def get_all_platforms(self) -> List[Platform]:
"""Get all platforms (enabled and disabled)"""
platforms = self._load_platforms()
return list(platforms.values())
def get_active_platforms(self) -> List[Platform]:
"""Get only enabled platforms for UI display"""
platforms = self._load_platforms()
return [p for p in platforms.values() if p.is_enabled]
def get_platform_by_id(self, platform_id: str) -> Optional[Platform]:
"""Get a specific platform by ID"""
platforms = self._load_platforms()
return platforms.get(platform_id.lower())
def is_platform_enabled(self, platform_id: str) -> bool:
"""Check if a platform is enabled"""
platform = self.get_platform_by_id(platform_id)
return platform.is_enabled if platform else False
def get_filter_platforms(self) -> List[Platform]:
"""
Get platforms for sidebar filters.
Shows:
- All enabled platforms
- Disabled platforms that have existing accounts
"""
platforms = self._load_platforms()
filter_platforms = []
for platform in platforms.values():
if platform.is_enabled:
# Always show enabled platforms
filter_platforms.append(platform)
elif self.db_manager:
# Show disabled platforms only if they have accounts
try:
count = self.db_manager.get_account_count(platform.id)
if count > 0:
filter_platforms.append(platform)
except Exception as e:
logger.error(f"Error checking accounts for {platform.id}: {e}")
return filter_platforms
def get_platforms_with_accounts(self) -> Dict[str, int]:
"""
Get platform IDs with their account counts.
Returns dict: {platform_id: count}
"""
if not self.db_manager:
return {}
platforms = self._load_platforms()
counts = {}
for platform_id in platforms.keys():
try:
count = self.db_manager.get_account_count(platform_id)
if count > 0:
counts[platform_id] = count
except Exception as e:
logger.error(f"Error getting count for {platform_id}: {e}")
counts[platform_id] = 0
return counts
def reload_configuration(self):
"""Force reload of platform configuration"""
self._platforms_cache = None
logger.info("Platform configuration reloaded")

55
config/platforms.yaml Normale Datei
Datei anzeigen

@ -0,0 +1,55 @@
# Platform Configuration
# Controls which platforms are active in the UI
# Set enabled: true to activate a platform
platforms:
# Currently active platforms (shown in UI)
instagram:
id: instagram
display_name: Instagram
enabled: true
icon: instagram.svg
color: "#E4405F"
facebook:
id: facebook
display_name: Facebook
enabled: true
icon: facebook.svg
color: "#1877F2"
tiktok:
id: tiktok
display_name: TikTok
enabled: true
icon: tiktok.svg
color: "#000000"
x:
id: x
display_name: "X"
enabled: true
icon: twitter.svg
color: "#000000"
# Disabled platforms (hidden in UI, but accounts remain accessible)
gmail:
id: gmail
display_name: Gmail
enabled: false
icon: gmail.svg
color: "#EA4335"
vk:
id: vk
display_name: VK
enabled: false
icon: vk.svg
color: "#0077FF"
ok:
id: ok
display_name: OK.ru
enabled: false
icon: ok.svg
color: "#FF6600"

Datei anzeigen

@ -21,6 +21,7 @@ from utils.theme_manager import ThemeManager
from localization.language_manager import LanguageManager
from licensing.license_manager import LicenseManager
from updates.update_checker import UpdateChecker
from application.services.platform_service import PlatformService
logger = logging.getLogger("main")
@ -50,6 +51,7 @@ class MainController:
self.proxy_rotator = ProxyRotator()
self.email_handler = EmailHandler()
self.update_checker = UpdateChecker(self.license_manager.api_client)
self.platform_service = PlatformService(self.db_manager)
# Haupt-View erstellen
self.view = MainWindow(self.theme_manager, self.language_manager, self.db_manager)
@ -64,72 +66,9 @@ class MainController:
)
self.session_controller = SessionController(self.db_manager)
# Plattform-Controller initialisieren
# Plattform-Controller initialisieren - nur für aktive Plattformen
self.platform_controllers = {}
# Instagram Controller hinzufügen
instagram_controller = InstagramController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
# Signal für Rückkehr zur Hauptseite verbinden
instagram_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
# SessionController referenz hinzufügen
instagram_controller.session_controller = self.session_controller
self.platform_controllers["instagram"] = instagram_controller
# TikTok Controller hinzufügen
tiktok_controller = TikTokController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
# Signal für Rückkehr zur Hauptseite verbinden
tiktok_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
# SessionController referenz hinzufügen
tiktok_controller.session_controller = self.session_controller
self.platform_controllers["tiktok"] = tiktok_controller
# X (Twitter) Controller hinzufügen
from controllers.platform_controllers.x_controller import XController
x_controller = XController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
# Signal für Rückkehr zur Hauptseite verbinden
x_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
# SessionController referenz hinzufügen
x_controller.session_controller = self.session_controller
self.platform_controllers["x"] = x_controller
# Gmail Controller hinzufügen
from controllers.platform_controllers.gmail_controller import GmailController
gmail_controller = GmailController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
# Signal für Rückkehr zur Hauptseite verbinden
gmail_controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
# SessionController referenz hinzufügen
gmail_controller.session_controller = self.session_controller
self.platform_controllers["gmail"] = gmail_controller
# Facebook Controller hinzufügen
from controllers.platform_controllers.facebook_controller import FacebookController
facebook_controller = FacebookController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
self.platform_controllers["facebook"] = facebook_controller
self._initialize_active_platform_controllers()
# Signals verbinden
self.connect_signals()
@ -406,4 +345,65 @@ class MainController:
self.view,
"Fehler",
f"Fehler beim Herunterladen des Updates:\n{str(e)}"
)
)
def _initialize_active_platform_controllers(self):
"""Initialisiert nur Controller für aktive Plattformen."""
active_platforms = self.platform_service.get_active_platforms()
for platform in active_platforms:
platform_id = platform.id.lower()
try:
if platform_id == "instagram":
controller = InstagramController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
controller.session_controller = self.session_controller
self.platform_controllers["instagram"] = controller
elif platform_id == "tiktok":
controller = TikTokController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
controller.session_controller = self.session_controller
self.platform_controllers["tiktok"] = controller
elif platform_id == "x":
from controllers.platform_controllers.x_controller import XController
controller = XController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
controller.session_controller = self.session_controller
self.platform_controllers["x"] = controller
elif platform_id == "facebook":
from controllers.platform_controllers.facebook_controller import FacebookController
controller = FacebookController(
self.db_manager,
self.proxy_rotator,
self.email_handler,
self.language_manager
)
controller.return_to_main_requested = lambda: self.show_platform_selector_and_reset()
controller.session_controller = self.session_controller
self.platform_controllers["facebook"] = controller
logger.info(f"Controller für Plattform '{platform_id}' initialisiert")
except ImportError as e:
logger.warning(f"Controller für Plattform '{platform_id}' konnte nicht geladen werden: {e}")
except Exception as e:
logger.error(f"Fehler beim Initialisieren des Controllers für '{platform_id}': {e}")

Datei anzeigen

@ -129,10 +129,14 @@ class SessionController(QObject):
Dict mit success, account_id und message
"""
try:
# Platform-Name standardisieren
from domain.value_objects.platform_name import PlatformName
platform_obj = PlatformName(platform)
# Account in DB speichern
from datetime import datetime
account_record = {
"platform": platform.lower(),
"platform": platform_obj.canonical, # Verwendet kanonischen Namen (lowercase)
"username": account_data.get("username", ""),
"password": account_data.get("password", ""),
"email": account_data.get("email", ""),
@ -142,6 +146,18 @@ class SessionController(QObject):
}
account_id = self.db_manager.add_account(account_record)
# Prüfe ob DB-Operation erfolgreich war
if account_id == -1 or account_id is None:
error_msg = f"Fehler beim Speichern des Accounts {account_record['username']} in der Datenbank"
logger.error(error_msg)
return {
'success': False,
'account_id': None,
'error': error_msg,
'message': error_msg
}
logger.info(f"Account in Datenbank gespeichert: {account_record['username']} (ID: {account_id})")
# Fingerprint für Account generieren

Binäre Datei nicht angezeigt.

Datei anzeigen

@ -117,6 +117,11 @@ class DatabaseManager:
if field not in account_data:
logger.error(f"Fehlendes Pflichtfeld: {field}")
return -1
# Prüfe auch ob Felder nicht leer sind
if not account_data[field] or account_data[field] == "":
logger.error(f"Pflichtfeld ist leer: {field} = '{account_data[field]}'")
logger.error(f"Account-Daten: {account_data}")
return -1
# Sicherstellen, dass created_at vorhanden ist
if "created_at" not in account_data:
@ -218,11 +223,21 @@ class DatabaseManager:
Liste von Dictionaries mit Account-Daten
"""
try:
# Platform-Name standardisieren
from domain.value_objects.platform_name import PlatformName
try:
platform_obj = PlatformName(platform)
canonical_platform = platform_obj.canonical
except ValueError:
# Fallback für unbekannte Platforms
canonical_platform = platform.lower()
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM accounts WHERE platform = ? ORDER BY id DESC", (platform.lower(),))
# Case-insensitive Suche mit LOWER() für Backward-Compatibility
cursor.execute("SELECT * FROM accounts WHERE LOWER(platform) = LOWER(?) ORDER BY id DESC", (canonical_platform,))
rows = cursor.fetchall()
conn.close()
@ -377,7 +392,17 @@ class DatabaseManager:
cursor = conn.cursor()
if platform:
cursor.execute("SELECT COUNT(*) FROM accounts WHERE platform = ?", (platform.lower(),))
# Platform-Name standardisieren
from domain.value_objects.platform_name import PlatformName
try:
platform_obj = PlatformName(platform)
canonical_platform = platform_obj.canonical
except ValueError:
# Fallback für unbekannte Platforms
canonical_platform = platform.lower()
# Case-insensitive Suche
cursor.execute("SELECT COUNT(*) FROM accounts WHERE LOWER(platform) = LOWER(?)", (canonical_platform,))
else:
cursor.execute("SELECT COUNT(*) FROM accounts")

74
domain/entities/platform.py Normale Datei
Datei anzeigen

@ -0,0 +1,74 @@
"""
Platform Entity - Represents a social media platform
"""
from dataclasses import dataclass
from typing import Optional, Dict, Any
from enum import Enum
class PlatformStatus(Enum):
"""Platform availability status"""
ENABLED = "enabled"
DISABLED = "disabled"
UPCOMING = "upcoming"
@dataclass
class Platform:
"""
Platform entity representing a social media platform.
Clean Architecture: Domain Entity
"""
id: str
display_name: str
status: PlatformStatus
icon: str
color: str
def __init__(
self,
id: str,
display_name: str,
enabled: bool = True,
icon: str = None,
color: str = "#000000"
):
self.id = id
self.display_name = display_name
self.status = PlatformStatus.ENABLED if enabled else PlatformStatus.DISABLED
self.icon = icon or f"{id}.svg"
self.color = color
@property
def is_enabled(self) -> bool:
"""Check if platform is enabled"""
return self.status == PlatformStatus.ENABLED
@property
def is_disabled(self) -> bool:
"""Check if platform is disabled"""
return self.status == PlatformStatus.DISABLED
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary"""
return {
'id': self.id,
'display_name': self.display_name,
'status': self.status.value,
'icon': self.icon,
'color': self.color
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Platform':
"""Create from dictionary"""
return cls(
id=data.get('id'),
display_name=data.get('display_name'),
enabled=data.get('enabled', True),
icon=data.get('icon'),
color=data.get('color', '#000000')
)
def __repr__(self) -> str:
return f"Platform(id={self.id}, name={self.display_name}, status={self.status.value})"

Datei anzeigen

@ -0,0 +1,160 @@
"""
Platform Name Value Object - Standardisiert Platform-Namen
"""
from typing import Optional
class PlatformName:
"""
Value Object für standardisierte Platform-Namen.
Stellt sicher, dass Platform-Namen konsistent behandelt werden.
"""
# Mapping von verschiedenen Schreibweisen zu kanonischen Namen
PLATFORM_MAPPINGS = {
# Kanonische Namen (für DB und interne Verwendung)
'instagram': 'instagram',
'facebook': 'facebook',
'tiktok': 'tiktok',
'x': 'x',
'gmail': 'gmail',
'vk': 'vk',
'ok': 'ok',
# Alternative Schreibweisen
'X': 'x',
'twitter': 'x',
'Twitter': 'x',
'X (Twitter)': 'x',
'ok.ru': 'ok',
'OK.ru': 'ok',
'VK': 'vk',
'Gmail': 'gmail',
'Instagram': 'instagram',
'Facebook': 'facebook',
'TikTok': 'tiktok'
}
# Display-Namen für UI
DISPLAY_NAMES = {
'instagram': 'Instagram',
'facebook': 'Facebook',
'tiktok': 'TikTok',
'x': 'X',
'gmail': 'Gmail',
'vk': 'VK',
'ok': 'OK.ru'
}
def __init__(self, name: str):
"""
Initialisiert ein PlatformName Value Object.
Args:
name: Platform-Name in beliebiger Schreibweise
"""
self._canonical_name = self._normalize(name)
if not self._canonical_name:
raise ValueError(f"Unknown platform: {name}")
def _normalize(self, name: str) -> Optional[str]:
"""
Normalisiert einen Platform-Namen zu seiner kanonischen Form.
Args:
name: Platform-Name in beliebiger Schreibweise
Returns:
Kanonischer Platform-Name oder None
"""
if not name:
return None
# Trimmen und in Mapping suchen
normalized = name.strip()
return self.PLATFORM_MAPPINGS.get(normalized, self.PLATFORM_MAPPINGS.get(normalized.lower()))
@property
def canonical(self) -> str:
"""
Gibt den kanonischen Namen zurück (für DB und interne Verwendung).
Immer lowercase.
"""
return self._canonical_name
@property
def display(self) -> str:
"""
Gibt den Display-Namen zurück (für UI).
Mit korrekter Groß-/Kleinschreibung.
"""
return self.DISPLAY_NAMES.get(self._canonical_name, self._canonical_name.title())
@property
def db_value(self) -> str:
"""
Gibt den Wert für Datenbank-Speicherung zurück.
Alias für canonical.
"""
return self.canonical
def matches(self, other: str) -> bool:
"""
Prüft, ob ein anderer Platform-Name diesem entspricht.
Args:
other: Zu vergleichender Platform-Name
Returns:
True wenn die Platforms übereinstimmen
"""
other_normalized = self._normalize(other)
return other_normalized == self._canonical_name if other_normalized else False
def __str__(self) -> str:
"""String-Repräsentation (Display-Name)."""
return self.display
def __repr__(self) -> str:
"""Debug-Repräsentation."""
return f"PlatformName(canonical='{self.canonical}', display='{self.display}')"
def __eq__(self, other) -> bool:
"""Gleichheitsvergleich."""
if isinstance(other, PlatformName):
return self._canonical_name == other._canonical_name
elif isinstance(other, str):
return self.matches(other)
return False
def __hash__(self) -> int:
"""Hash-Wert für Set/Dict-Verwendung."""
return hash(self._canonical_name)
@classmethod
def is_valid(cls, name: str) -> bool:
"""
Prüft, ob ein Platform-Name gültig ist.
Args:
name: Zu prüfender Platform-Name
Returns:
True wenn der Name gültig ist
"""
try:
cls(name)
return True
except ValueError:
return False
@classmethod
def get_all_canonical(cls) -> list:
"""
Gibt alle kanonischen Platform-Namen zurück.
Returns:
Liste aller kanonischen Platform-Namen
"""
return list(set(cls.PLATFORM_MAPPINGS.values()))

Datei anzeigen

@ -12,6 +12,7 @@ IMAPClient>=2.1.0
python-dateutil>=2.8.1
Pillow>=8.0.0
cryptography>=3.4.0
PyYAML>=6.0
# Web automation and anti-detection
random-user-agent>=1.0.1

85
scripts/fix_x_accounts.py Normale Datei
Datei anzeigen

@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
Script to fix existing X accounts in the database.
Updates platform names from various formats to canonical 'x'.
"""
import sqlite3
import os
import sys
from pathlib import Path
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from domain.value_objects.platform_name import PlatformName
def fix_x_accounts(db_path: str):
"""
Fix X accounts in the database by standardizing platform names.
Args:
db_path: Path to the database file
"""
if not os.path.exists(db_path):
print(f"❌ Database not found: {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Find all potential X accounts with different naming
possible_x_names = ['X', 'x', 'twitter', 'Twitter', 'X (Twitter)']
total_fixed = 0
for name in possible_x_names:
cursor.execute("SELECT COUNT(*) FROM accounts WHERE platform = ?", (name,))
count = cursor.fetchone()[0]
if count > 0:
print(f"Found {count} accounts with platform='{name}'")
# Update to canonical name
cursor.execute("UPDATE accounts SET platform = ? WHERE platform = ?", ('x', name))
total_fixed += count
print(f"✅ Updated {count} accounts from '{name}' to 'x'")
# Check for accounts that might have been missed
cursor.execute("SELECT DISTINCT platform FROM accounts")
all_platforms = cursor.fetchall()
print("\n📊 Current platforms in database:")
for platform in all_platforms:
cursor.execute("SELECT COUNT(*) FROM accounts WHERE platform = ?", (platform[0],))
count = cursor.fetchone()[0]
print(f" - {platform[0]}: {count} accounts")
# Commit changes
if total_fixed > 0:
conn.commit()
print(f"\n✅ Successfully fixed {total_fixed} accounts")
else:
print("\n✨ No accounts needed fixing")
conn.close()
def main():
"""Main function."""
# Database path
db_path = Path(__file__).parent.parent / "database" / "accounts.db"
print("🔧 X Platform Name Fix Script")
print("=" * 40)
print(f"Database: {db_path}")
print()
fix_x_accounts(str(db_path))
print("\n🎉 Done!")
if __name__ == "__main__":
main()

Datei anzeigen

@ -11,6 +11,7 @@ from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QFont
from views.widgets.account_card import AccountCard
from application.services.platform_service import PlatformService
logger = logging.getLogger("accounts_overview")
@ -19,9 +20,11 @@ class SidebarFilter(QWidget):
"""Sidebar mit Plattform-Filter nach Styleguide"""
filter_changed = pyqtSignal(str)
def __init__(self, language_manager=None):
def __init__(self, language_manager=None, db_manager=None):
super().__init__()
self.language_manager = language_manager
self.db_manager = db_manager
self.platform_service = PlatformService(db_manager)
self.filter_buttons = []
self.account_counts = {}
self.init_ui()
@ -41,18 +44,15 @@ class SidebarFilter(QWidget):
# Title removed - no longer needed
# Filter Buttons
self.filters = [
("Alle", "all"),
("Instagram", "instagram"),
("TikTok", "tiktok"),
("Facebook", "facebook"),
("X (Twitter)", "x"),
("VK", "vk"),
("OK.ru", "ok"),
("Gmail", "gmail")
]
# Build filter list dynamically
self.filters = [("Alle", "all")]
# Get platforms that should be shown in filters
filter_platforms = self.platform_service.get_filter_platforms()
for platform in filter_platforms:
self.filters.append((platform.display_name, platform.id))
# Create filter buttons
for name, key in self.filters:
btn = self._create_filter_button(name, key)
self.filter_buttons.append((btn, key))
@ -136,7 +136,7 @@ class AccountsOverviewView(QWidget):
main_layout.setSpacing(0)
# Sidebar
self.sidebar = SidebarFilter(self.language_manager)
self.sidebar = SidebarFilter(self.language_manager, self.db_manager)
self.sidebar.filter_changed.connect(self._on_filter_changed)
main_layout.addWidget(self.sidebar)
@ -212,9 +212,13 @@ class AccountsOverviewView(QWidget):
if self.current_filter == "all":
filtered_accounts = self.accounts
else:
# Use PlatformName for consistent filtering
from domain.value_objects.platform_name import PlatformName
filter_platform = PlatformName(self.current_filter)
filtered_accounts = [
acc for acc in self.accounts
if acc.get("platform", "").lower() == self.current_filter
if PlatformName.is_valid(acc.get("platform", "")) and
PlatformName(acc.get("platform", "")) == filter_platform
]
# Gruppiere nach Plattform wenn "Alle" ausgewählt
@ -317,13 +321,19 @@ class AccountsOverviewView(QWidget):
"""Behandelt Filter-Änderungen"""
self.current_filter = filter_key
# Update title
# Update title using PlatformName for consistency
if filter_key == "all":
self.title.setText("Alle Accounts")
else:
platform_name = filter_key.capitalize()
if filter_key == "x":
platform_name = "X (Twitter)"
try:
from domain.value_objects.platform_name import PlatformName
platform_obj = PlatformName(filter_key)
platform_name = platform_obj.display
except:
# Fallback
platform_name = filter_key.capitalize()
if filter_key == "x":
platform_name = "X"
self.title.setText(f"{platform_name} Accounts")
self._update_display()

Datei anzeigen

@ -8,6 +8,7 @@ from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtGui import QFont
from views.widgets.platform_button import PlatformButton
from application.services.platform_service import PlatformService
class PlatformGridView(QWidget):
@ -19,9 +20,11 @@ class PlatformGridView(QWidget):
# Signal wird ausgelöst, wenn eine Plattform ausgewählt wird
platform_selected = pyqtSignal(str)
def __init__(self, language_manager=None):
def __init__(self, language_manager=None, db_manager=None):
super().__init__()
self.language_manager = language_manager
self.db_manager = db_manager
self.platform_service = PlatformService(db_manager)
self.init_ui()
if self.language_manager:
@ -53,49 +56,38 @@ class PlatformGridView(QWidget):
grid_layout = QGridLayout(platforms_container)
grid_layout.setSpacing(24) # Styleguide Grid-Gap
# Definiere verfügbare Plattformen
platforms = [
{"name": "Instagram", "enabled": True},
{"name": "Facebook", "enabled": True},
{"name": "TikTok", "enabled": True},
{"name": "X", "enabled": True},
{"name": "VK", "enabled": True},
{"name": "OK.ru", "enabled": True},
{"name": "Gmail", "enabled": True}
]
# Lade nur aktive Plattformen aus dem Service
active_platforms = self.platform_service.get_active_platforms()
# Icon-Pfade
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(os.path.dirname(current_dir))
icons_dir = os.path.join(parent_dir, "resources", "icons")
# Platziere Buttons in einem 2x4 Grid
for i, platform in enumerate(platforms):
row = i // 4
col = i % 4
# Platziere Buttons in einem 2x2 Grid (nur 4 Plattformen)
for i, platform in enumerate(active_platforms):
row = i // 2 # 2 Spalten
col = i % 2
# Icon-Pfad erstellen
platform_icon_name = platform['name'].lower()
if platform['name'] == "X":
platform_icon_name = "twitter"
elif platform['name'] == "OK.ru":
platform_icon_name = "ok"
icon_path = os.path.join(icons_dir, f"{platform_icon_name}.svg")
icon_path = os.path.join(icons_dir, platform.icon)
if not os.path.exists(icon_path):
icon_path = None
# Fallback für X/Twitter
if platform.id == "x":
icon_path = os.path.join(icons_dir, "twitter.svg")
if not os.path.exists(icon_path):
icon_path = None
# Platform Button erstellen
button = PlatformButton(
platform["name"],
platform.display_name,
icon_path,
platform["enabled"]
True # Alle aktiven Plattformen sind enabled
)
# Signal verbinden
platform_signal_name = "x" if platform["name"] == "X" else platform["name"]
button.clicked.connect(
lambda checked=False, p=platform_signal_name: self.platform_selected.emit(p.lower())
lambda checked=False, p=platform.id: self.platform_selected.emit(p)
)
grid_layout.addWidget(button, row, col, Qt.AlignCenter)

Datei anzeigen

@ -51,7 +51,7 @@ class PlatformSelector(QWidget):
self.content_stack.setObjectName("content_stack") # For QSS targeting, no inline styles!
# Platform Grid View (Tab 0)
self.platform_grid = PlatformGridView(self.language_manager)
self.platform_grid = PlatformGridView(self.language_manager, self.db_manager)
self.platform_grid.platform_selected.connect(self.platform_selected.emit)
self.content_stack.addWidget(self.platform_grid)