X-Problem gelöst
Dieser Commit ist enthalten in:
@ -14,7 +14,8 @@
|
|||||||
"Bash(claude config list:*)",
|
"Bash(claude config list:*)",
|
||||||
"Bash(claude mcp)",
|
"Bash(claude mcp)",
|
||||||
"Bash(claude mcp:*)",
|
"Bash(claude mcp:*)",
|
||||||
"Bash(sqlite3:*)"
|
"Bash(sqlite3:*)",
|
||||||
|
"Bash(python -m pip install:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"defaultMode": "acceptEdits",
|
"defaultMode": "acceptEdits",
|
||||||
|
|||||||
139
application/services/platform_service.py
Normale Datei
139
application/services/platform_service.py
Normale Datei
@ -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
55
config/platforms.yaml
Normale Datei
@ -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"
|
||||||
@ -21,6 +21,7 @@ from utils.theme_manager import ThemeManager
|
|||||||
from localization.language_manager import LanguageManager
|
from localization.language_manager import LanguageManager
|
||||||
from licensing.license_manager import LicenseManager
|
from licensing.license_manager import LicenseManager
|
||||||
from updates.update_checker import UpdateChecker
|
from updates.update_checker import UpdateChecker
|
||||||
|
from application.services.platform_service import PlatformService
|
||||||
|
|
||||||
logger = logging.getLogger("main")
|
logger = logging.getLogger("main")
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ class MainController:
|
|||||||
self.proxy_rotator = ProxyRotator()
|
self.proxy_rotator = ProxyRotator()
|
||||||
self.email_handler = EmailHandler()
|
self.email_handler = EmailHandler()
|
||||||
self.update_checker = UpdateChecker(self.license_manager.api_client)
|
self.update_checker = UpdateChecker(self.license_manager.api_client)
|
||||||
|
self.platform_service = PlatformService(self.db_manager)
|
||||||
|
|
||||||
# Haupt-View erstellen
|
# Haupt-View erstellen
|
||||||
self.view = MainWindow(self.theme_manager, self.language_manager, self.db_manager)
|
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)
|
self.session_controller = SessionController(self.db_manager)
|
||||||
|
|
||||||
# Plattform-Controller initialisieren
|
# Plattform-Controller initialisieren - nur für aktive Plattformen
|
||||||
self.platform_controllers = {}
|
self.platform_controllers = {}
|
||||||
|
self._initialize_active_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
|
|
||||||
|
|
||||||
# Signals verbinden
|
# Signals verbinden
|
||||||
self.connect_signals()
|
self.connect_signals()
|
||||||
@ -407,3 +346,64 @@ class MainController:
|
|||||||
"Fehler",
|
"Fehler",
|
||||||
f"Fehler beim Herunterladen des Updates:\n{str(e)}"
|
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}")
|
||||||
@ -129,10 +129,14 @@ class SessionController(QObject):
|
|||||||
Dict mit success, account_id und message
|
Dict mit success, account_id und message
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# Platform-Name standardisieren
|
||||||
|
from domain.value_objects.platform_name import PlatformName
|
||||||
|
platform_obj = PlatformName(platform)
|
||||||
|
|
||||||
# Account in DB speichern
|
# Account in DB speichern
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
account_record = {
|
account_record = {
|
||||||
"platform": platform.lower(),
|
"platform": platform_obj.canonical, # Verwendet kanonischen Namen (lowercase)
|
||||||
"username": account_data.get("username", ""),
|
"username": account_data.get("username", ""),
|
||||||
"password": account_data.get("password", ""),
|
"password": account_data.get("password", ""),
|
||||||
"email": account_data.get("email", ""),
|
"email": account_data.get("email", ""),
|
||||||
@ -142,6 +146,18 @@ class SessionController(QObject):
|
|||||||
}
|
}
|
||||||
|
|
||||||
account_id = self.db_manager.add_account(account_record)
|
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})")
|
logger.info(f"Account in Datenbank gespeichert: {account_record['username']} (ID: {account_id})")
|
||||||
|
|
||||||
# Fingerprint für Account generieren
|
# Fingerprint für Account generieren
|
||||||
|
|||||||
Binäre Datei nicht angezeigt.
@ -117,6 +117,11 @@ class DatabaseManager:
|
|||||||
if field not in account_data:
|
if field not in account_data:
|
||||||
logger.error(f"Fehlendes Pflichtfeld: {field}")
|
logger.error(f"Fehlendes Pflichtfeld: {field}")
|
||||||
return -1
|
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
|
# Sicherstellen, dass created_at vorhanden ist
|
||||||
if "created_at" not in account_data:
|
if "created_at" not in account_data:
|
||||||
@ -218,11 +223,21 @@ class DatabaseManager:
|
|||||||
Liste von Dictionaries mit Account-Daten
|
Liste von Dictionaries mit Account-Daten
|
||||||
"""
|
"""
|
||||||
try:
|
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 = sqlite3.connect(self.db_path)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
cursor = conn.cursor()
|
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()
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
@ -377,7 +392,17 @@ class DatabaseManager:
|
|||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if platform:
|
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:
|
else:
|
||||||
cursor.execute("SELECT COUNT(*) FROM accounts")
|
cursor.execute("SELECT COUNT(*) FROM accounts")
|
||||||
|
|
||||||
|
|||||||
74
domain/entities/platform.py
Normale Datei
74
domain/entities/platform.py
Normale Datei
@ -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})"
|
||||||
160
domain/value_objects/platform_name.py
Normale Datei
160
domain/value_objects/platform_name.py
Normale Datei
@ -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()))
|
||||||
@ -12,6 +12,7 @@ IMAPClient>=2.1.0
|
|||||||
python-dateutil>=2.8.1
|
python-dateutil>=2.8.1
|
||||||
Pillow>=8.0.0
|
Pillow>=8.0.0
|
||||||
cryptography>=3.4.0
|
cryptography>=3.4.0
|
||||||
|
PyYAML>=6.0
|
||||||
|
|
||||||
# Web automation and anti-detection
|
# Web automation and anti-detection
|
||||||
random-user-agent>=1.0.1
|
random-user-agent>=1.0.1
|
||||||
|
|||||||
85
scripts/fix_x_accounts.py
Normale Datei
85
scripts/fix_x_accounts.py
Normale Datei
@ -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()
|
||||||
@ -11,6 +11,7 @@ from PyQt5.QtCore import Qt, pyqtSignal
|
|||||||
from PyQt5.QtGui import QFont
|
from PyQt5.QtGui import QFont
|
||||||
|
|
||||||
from views.widgets.account_card import AccountCard
|
from views.widgets.account_card import AccountCard
|
||||||
|
from application.services.platform_service import PlatformService
|
||||||
|
|
||||||
logger = logging.getLogger("accounts_overview")
|
logger = logging.getLogger("accounts_overview")
|
||||||
|
|
||||||
@ -19,9 +20,11 @@ class SidebarFilter(QWidget):
|
|||||||
"""Sidebar mit Plattform-Filter nach Styleguide"""
|
"""Sidebar mit Plattform-Filter nach Styleguide"""
|
||||||
filter_changed = pyqtSignal(str)
|
filter_changed = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, language_manager=None):
|
def __init__(self, language_manager=None, db_manager=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.language_manager = language_manager
|
self.language_manager = language_manager
|
||||||
|
self.db_manager = db_manager
|
||||||
|
self.platform_service = PlatformService(db_manager)
|
||||||
self.filter_buttons = []
|
self.filter_buttons = []
|
||||||
self.account_counts = {}
|
self.account_counts = {}
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
@ -41,18 +44,15 @@ class SidebarFilter(QWidget):
|
|||||||
|
|
||||||
# Title removed - no longer needed
|
# Title removed - no longer needed
|
||||||
|
|
||||||
# Filter Buttons
|
# Build filter list dynamically
|
||||||
self.filters = [
|
self.filters = [("Alle", "all")]
|
||||||
("Alle", "all"),
|
|
||||||
("Instagram", "instagram"),
|
|
||||||
("TikTok", "tiktok"),
|
|
||||||
("Facebook", "facebook"),
|
|
||||||
("X (Twitter)", "x"),
|
|
||||||
("VK", "vk"),
|
|
||||||
("OK.ru", "ok"),
|
|
||||||
("Gmail", "gmail")
|
|
||||||
]
|
|
||||||
|
|
||||||
|
# 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:
|
for name, key in self.filters:
|
||||||
btn = self._create_filter_button(name, key)
|
btn = self._create_filter_button(name, key)
|
||||||
self.filter_buttons.append((btn, key))
|
self.filter_buttons.append((btn, key))
|
||||||
@ -136,7 +136,7 @@ class AccountsOverviewView(QWidget):
|
|||||||
main_layout.setSpacing(0)
|
main_layout.setSpacing(0)
|
||||||
|
|
||||||
# Sidebar
|
# 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)
|
self.sidebar.filter_changed.connect(self._on_filter_changed)
|
||||||
main_layout.addWidget(self.sidebar)
|
main_layout.addWidget(self.sidebar)
|
||||||
|
|
||||||
@ -212,9 +212,13 @@ class AccountsOverviewView(QWidget):
|
|||||||
if self.current_filter == "all":
|
if self.current_filter == "all":
|
||||||
filtered_accounts = self.accounts
|
filtered_accounts = self.accounts
|
||||||
else:
|
else:
|
||||||
|
# Use PlatformName for consistent filtering
|
||||||
|
from domain.value_objects.platform_name import PlatformName
|
||||||
|
filter_platform = PlatformName(self.current_filter)
|
||||||
filtered_accounts = [
|
filtered_accounts = [
|
||||||
acc for acc in self.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
|
# Gruppiere nach Plattform wenn "Alle" ausgewählt
|
||||||
@ -317,13 +321,19 @@ class AccountsOverviewView(QWidget):
|
|||||||
"""Behandelt Filter-Änderungen"""
|
"""Behandelt Filter-Änderungen"""
|
||||||
self.current_filter = filter_key
|
self.current_filter = filter_key
|
||||||
|
|
||||||
# Update title
|
# Update title using PlatformName for consistency
|
||||||
if filter_key == "all":
|
if filter_key == "all":
|
||||||
self.title.setText("Alle Accounts")
|
self.title.setText("Alle Accounts")
|
||||||
else:
|
else:
|
||||||
|
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()
|
platform_name = filter_key.capitalize()
|
||||||
if filter_key == "x":
|
if filter_key == "x":
|
||||||
platform_name = "X (Twitter)"
|
platform_name = "X"
|
||||||
self.title.setText(f"{platform_name} Accounts")
|
self.title.setText(f"{platform_name} Accounts")
|
||||||
|
|
||||||
self._update_display()
|
self._update_display()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from PyQt5.QtCore import pyqtSignal, Qt
|
|||||||
from PyQt5.QtGui import QFont
|
from PyQt5.QtGui import QFont
|
||||||
|
|
||||||
from views.widgets.platform_button import PlatformButton
|
from views.widgets.platform_button import PlatformButton
|
||||||
|
from application.services.platform_service import PlatformService
|
||||||
|
|
||||||
|
|
||||||
class PlatformGridView(QWidget):
|
class PlatformGridView(QWidget):
|
||||||
@ -19,9 +20,11 @@ class PlatformGridView(QWidget):
|
|||||||
# Signal wird ausgelöst, wenn eine Plattform ausgewählt wird
|
# Signal wird ausgelöst, wenn eine Plattform ausgewählt wird
|
||||||
platform_selected = pyqtSignal(str)
|
platform_selected = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, language_manager=None):
|
def __init__(self, language_manager=None, db_manager=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.language_manager = language_manager
|
self.language_manager = language_manager
|
||||||
|
self.db_manager = db_manager
|
||||||
|
self.platform_service = PlatformService(db_manager)
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
if self.language_manager:
|
if self.language_manager:
|
||||||
@ -53,49 +56,38 @@ class PlatformGridView(QWidget):
|
|||||||
grid_layout = QGridLayout(platforms_container)
|
grid_layout = QGridLayout(platforms_container)
|
||||||
grid_layout.setSpacing(24) # Styleguide Grid-Gap
|
grid_layout.setSpacing(24) # Styleguide Grid-Gap
|
||||||
|
|
||||||
# Definiere verfügbare Plattformen
|
# Lade nur aktive Plattformen aus dem Service
|
||||||
platforms = [
|
active_platforms = self.platform_service.get_active_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}
|
|
||||||
]
|
|
||||||
|
|
||||||
# Icon-Pfade
|
# Icon-Pfade
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
parent_dir = os.path.dirname(os.path.dirname(current_dir))
|
parent_dir = os.path.dirname(os.path.dirname(current_dir))
|
||||||
icons_dir = os.path.join(parent_dir, "resources", "icons")
|
icons_dir = os.path.join(parent_dir, "resources", "icons")
|
||||||
|
|
||||||
# Platziere Buttons in einem 2x4 Grid
|
# Platziere Buttons in einem 2x2 Grid (nur 4 Plattformen)
|
||||||
for i, platform in enumerate(platforms):
|
for i, platform in enumerate(active_platforms):
|
||||||
row = i // 4
|
row = i // 2 # 2 Spalten
|
||||||
col = i % 4
|
col = i % 2
|
||||||
|
|
||||||
# Icon-Pfad erstellen
|
# Icon-Pfad erstellen
|
||||||
platform_icon_name = platform['name'].lower()
|
icon_path = os.path.join(icons_dir, platform.icon)
|
||||||
if platform['name'] == "X":
|
if not os.path.exists(icon_path):
|
||||||
platform_icon_name = "twitter"
|
# Fallback für X/Twitter
|
||||||
elif platform['name'] == "OK.ru":
|
if platform.id == "x":
|
||||||
platform_icon_name = "ok"
|
icon_path = os.path.join(icons_dir, "twitter.svg")
|
||||||
icon_path = os.path.join(icons_dir, f"{platform_icon_name}.svg")
|
|
||||||
|
|
||||||
if not os.path.exists(icon_path):
|
if not os.path.exists(icon_path):
|
||||||
icon_path = None
|
icon_path = None
|
||||||
|
|
||||||
# Platform Button erstellen
|
# Platform Button erstellen
|
||||||
button = PlatformButton(
|
button = PlatformButton(
|
||||||
platform["name"],
|
platform.display_name,
|
||||||
icon_path,
|
icon_path,
|
||||||
platform["enabled"]
|
True # Alle aktiven Plattformen sind enabled
|
||||||
)
|
)
|
||||||
|
|
||||||
# Signal verbinden
|
# Signal verbinden
|
||||||
platform_signal_name = "x" if platform["name"] == "X" else platform["name"]
|
|
||||||
button.clicked.connect(
|
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)
|
grid_layout.addWidget(button, row, col, Qt.AlignCenter)
|
||||||
|
|||||||
@ -51,7 +51,7 @@ class PlatformSelector(QWidget):
|
|||||||
self.content_stack.setObjectName("content_stack") # For QSS targeting, no inline styles!
|
self.content_stack.setObjectName("content_stack") # For QSS targeting, no inline styles!
|
||||||
|
|
||||||
# Platform Grid View (Tab 0)
|
# 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.platform_grid.platform_selected.connect(self.platform_selected.emit)
|
||||||
self.content_stack.addWidget(self.platform_grid)
|
self.content_stack.addWidget(self.platform_grid)
|
||||||
|
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren