Files
AccountForger-neuerUpload/views/widgets/icon_factory.py
Claude Project Manager 04585e95b6 Initial commit
2025-08-01 23:50:28 +02:00

192 Zeilen
9.3 KiB
Python

"""
Icon Factory - Zentrale Icon-Verwaltung nach Clean Architecture
"""
from PyQt5.QtWidgets import QLabel
from PyQt5.QtCore import Qt, QByteArray
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QColor
from PyQt5.QtSvg import QSvgRenderer
import os
import logging
from config.paths import PathConfig
logger = logging.getLogger("icon_factory")
class IconFactory:
"""Factory für die Erstellung und Verwaltung von Icons"""
# Cache für geladene Icons
_icon_cache = {}
# Standard SVG Icons
ICONS = {
"mail": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 8L8.44992 11.6333C9.73295 12.4886 10.3745 12.9163 11.0678 13.0825C11.6806 13.2293 12.3194 13.2293 12.9322 13.0825C13.6255 12.9163 14.2671 12.4886 15.5501 11.6333L21 8M6.2 19H17.8C18.9201 19 19.4802 19 19.908 18.782C20.2843 18.5903 20.5903 18.2843 20.782 17.908C21 17.4802 21 16.9201 21 15.8V8.2C21 7.0799 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V15.8C3 16.9201 3 17.4802 3.21799 17.908C3.40973 18.2843 3.71569 18.5903 4.09202 18.782C4.51984 19 5.07989 19 6.2 19Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>''',
"key": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.3212 10.6852L4 19L6 21M7 16L9 18M20 7.5C20 9.98528 17.9853 12 15.5 12C13.0147 12 11 9.98528 11 7.5C11 5.01472 13.0147 3 15.5 3C17.9853 3 20 5.01472 20 7.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>''',
"calendar": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 10H21M7 3V5M17 3V5M6.2 21H17.8C18.9201 21 19.4802 21 19.908 20.782C20.2843 20.5903 20.5903 20.2843 20.782 19.908C21 19.4802 21 18.9201 21 17.8V8.2C21 7.07989 21 6.51984 20.782 6.09202C20.5903 5.71569 20.2843 5.40973 19.908 5.21799C19.4802 5 18.9201 5 17.8 5H6.2C5.0799 5 4.51984 5 4.09202 5.21799C3.71569 5.40973 3.40973 5.71569 3.21799 6.09202C3 6.51984 3 7.07989 3 8.2V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.07989 21 6.2 21Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>''',
"copy": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 8H7.2C6.0799 8 5.51984 8 5.09202 8.21799C4.71569 8.40973 4.40973 8.71569 4.21799 9.09202C4 9.51984 4 10.0799 4 11.2V16.8C4 17.9201 4 18.4802 4.21799 18.908C4.40973 19.2843 4.71569 19.5903 5.09202 19.782C5.51984 20 6.0799 20 7.2 20H12.8C13.9201 20 14.4802 20 14.908 19.782C15.2843 19.5903 15.5903 19.2843 15.782 18.908C16 18.4802 16 17.9201 16 16.8V16M11.2 16H16.8C17.9201 16 18.4802 16 18.908 15.782C19.2843 15.5903 19.5903 15.2843 19.782 14.908C20 14.4802 20 13.9201 20 12.8V7.2C20 6.0799 20 5.51984 19.782 5.09202C19.5903 4.71569 19.2843 4.40973 18.908 4.21799C18.4802 4 17.9201 4 16.8 4H11.2C10.0799 4 9.51984 4 9.09202 4.21799C8.71569 4.40973 8.40973 4.71569 8.21799 5.09202C8 5.51984 8 6.07989 8 7.2V12.8C8 13.9201 8 14.4802 8.21799 14.908C8.40973 15.2843 8.71569 15.5903 9.09202 15.782C9.51984 16 10.0799 16 11.2 16Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>''',
"eye": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.0007 12C15.0007 13.6569 13.6576 15 12.0007 15C10.3439 15 9.00073 13.6569 9.00073 12C9.00073 10.3431 10.3439 9 12.0007 9C13.6576 9 15.0007 10.3431 15.0007 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.0012 5C7.52354 5 3.73326 7.94288 2.45898 12C3.73324 16.0571 7.52354 19 12.0012 19C16.4788 19 20.2691 16.0571 21.5434 12C20.2691 7.94291 16.4788 5 12.0012 5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>''',
"eye-slash": '''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.99902 3L20.999 21M9.8433 9.91364C9.32066 10.4536 8.99902 11.1892 8.99902 12C8.99902 13.6569 10.3422 15 11.999 15C12.8215 15 13.5667 14.669 14.1086 14.133M6.49902 6.64715C4.59972 7.90034 3.15305 9.78394 2.45703 12C3.73128 16.0571 7.52159 19 11.9992 19C13.9881 19 15.8414 18.4194 17.3988 17.4184M10.999 5.04939C11.328 5.01673 11.6617 5 11.9992 5C16.4769 5 20.2672 7.94291 21.5414 12C21.2607 12.894 20.8577 13.7338 20.3522 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>'''
}
@classmethod
def get_icon(cls, icon_name: str, size: int = 16, color: str = "#718096") -> QIcon:
"""
Erstellt ein QIcon aus SVG
Args:
icon_name: Name des Icons
size: Größe des Icons
color: Farbe des Icons (hex)
Returns:
QIcon Objekt
"""
cache_key = f"{icon_name}_{size}_{color}"
if cache_key in cls._icon_cache:
return cls._icon_cache[cache_key]
# Erstelle Pixmap
pixmap = cls.get_pixmap(icon_name, size, color)
icon = QIcon(pixmap)
# Cache das Icon
cls._icon_cache[cache_key] = icon
return icon
@classmethod
def get_pixmap(cls, icon_name: str, size: int = 16, color: str = "#718096") -> QPixmap:
"""
Erstellt ein QPixmap aus SVG
Args:
icon_name: Name des Icons
size: Größe des Icons
color: Farbe des Icons (hex)
Returns:
QPixmap Objekt
"""
# Versuche zuerst aus Datei zu laden
icon_path = PathConfig.get_icon_path(icon_name)
if PathConfig.file_exists(icon_path):
pixmap = QPixmap(icon_path)
if not pixmap.isNull():
return pixmap.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
# Fallback auf eingebettete SVGs
svg_content = cls.ICONS.get(icon_name)
if svg_content:
# Ersetze currentColor durch die angegebene Farbe
svg_content = svg_content.replace('currentColor', color)
# Erstelle SVG Renderer
renderer = QSvgRenderer(QByteArray(svg_content.encode()))
# Erstelle Pixmap
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
# Rendere SVG
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
renderer.render(painter)
painter.end()
return pixmap
# Fallback: Erstelle einen farbigen Kreis
logger.warning(f"Icon '{icon_name}' nicht gefunden, verwende Platzhalter")
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(QColor(color))
painter.setPen(Qt.NoPen)
painter.drawEllipse(0, 0, size, size)
painter.end()
return pixmap
@classmethod
def create_icon_label(cls, icon_name: str, size: int = 16, color: str = "#718096") -> QLabel:
"""
Erstellt ein QLabel mit Icon
Args:
icon_name: Name des Icons
size: Größe des Icons
color: Farbe des Icons (hex)
Returns:
QLabel mit Icon
"""
label = QLabel()
label.setFixedSize(size, size)
# Prüfe ob es eine Plattform ist
platform_names = ["instagram", "facebook", "twitter", "x", "tiktok", "vk", "ok", "gmail"]
if icon_name.lower() in platform_names:
# Verwende get_platform_icon für Plattformen
icon = cls.get_platform_icon(icon_name, size)
pixmap = icon.pixmap(size, size)
else:
# Normale Icons
pixmap = cls.get_pixmap(icon_name, size, color)
label.setPixmap(pixmap)
label.setScaledContents(True)
return label
@classmethod
def get_platform_icon(cls, platform: str, size: int = 18) -> QIcon:
"""
Gibt ein Platform-spezifisches Icon zurück
Args:
platform: Name der Plattform
size: Größe des Icons
Returns:
QIcon für die Plattform
"""
# Spezialbehandlung für Twitter/X
if platform.lower() == "twitter" or platform.lower() == "x":
icon_name = "twitter"
else:
icon_name = platform.lower()
# Platform Icons haben eigene Farben
platform_colors = {
"instagram": "#E4405F",
"facebook": "#1877F2",
"twitter": "#1DA1F2",
"x": "#000000",
"tiktok": "#000000",
"vk": "#0077FF"
}
color = platform_colors.get(icon_name, "#718096")
return cls.get_icon(icon_name, size, color)