DarkMode ist existent yeah
Dieser Commit ist enthalten in:
@ -14,6 +14,12 @@ class AboutDialog(QDialog):
|
||||
# Remove the standard "?" help button that appears on some platforms
|
||||
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
|
||||
self.language_manager = language_manager
|
||||
self.theme_manager = None
|
||||
|
||||
# Try to get theme manager from parent (MainWindow)
|
||||
if parent and hasattr(parent, 'theme_manager'):
|
||||
self.theme_manager = parent.theme_manager
|
||||
|
||||
self._setup_ui()
|
||||
if self.language_manager:
|
||||
self.language_manager.language_changed.connect(self.update_texts)
|
||||
@ -21,49 +27,54 @@ class AboutDialog(QDialog):
|
||||
|
||||
def _setup_ui(self):
|
||||
self.setWindowTitle("About")
|
||||
# Dialog-Größe festlegen für bessere Zentrierung
|
||||
self.setMinimumWidth(500)
|
||||
self.setMinimumHeight(400)
|
||||
# Dialog-Größe festlegen
|
||||
self.setFixedSize(550, 450) # Fixed size for consistent appearance
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(30, 30, 30, 30)
|
||||
layout.setSpacing(20)
|
||||
layout.setAlignment(Qt.AlignCenter) # Layout auch zentrieren
|
||||
layout.setContentsMargins(20, 20, 40, 40) # Less margin on top/left for logo
|
||||
layout.setSpacing(25)
|
||||
|
||||
# Add logo
|
||||
# Add logo in top-left corner
|
||||
logo_label = QLabel()
|
||||
logo_label.setAlignment(Qt.AlignCenter)
|
||||
logo_label.setAlignment(Qt.AlignLeft) # Align left instead of center
|
||||
|
||||
# Get the logo path
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
parent_dir = os.path.dirname(current_dir)
|
||||
logo_path = os.path.join(parent_dir, "resources", "icons", "intelsight-logo.svg")
|
||||
# Get the theme-aware logo path
|
||||
if self.theme_manager:
|
||||
# Use theme manager to get correct logo based on current theme
|
||||
logo_path = self.theme_manager.get_icon_path("intelsight-logo")
|
||||
else:
|
||||
# Fallback to light logo if no theme manager
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
parent_dir = os.path.dirname(current_dir)
|
||||
logo_path = os.path.join(parent_dir, "resources", "icons", "intelsight-logo.svg")
|
||||
|
||||
if os.path.exists(logo_path):
|
||||
# Load logo and display it at a larger size
|
||||
# Load logo and display it at a smaller size for corner placement
|
||||
logo_pixmap = QPixmap(logo_path)
|
||||
# Scale the logo to a reasonable size while maintaining aspect ratio
|
||||
# Scale the logo smaller for top-left corner
|
||||
scaled_pixmap = logo_pixmap.scaled(
|
||||
300, 120, # Etwas kleiner für bessere Proportionen
|
||||
200, 60, # Smaller size for corner placement
|
||||
Qt.KeepAspectRatio,
|
||||
Qt.SmoothTransformation
|
||||
)
|
||||
logo_label.setPixmap(scaled_pixmap)
|
||||
# Feste Größe für das Label setzen, um Zentrierung zu gewährleisten
|
||||
logo_label.setFixedSize(scaled_pixmap.size())
|
||||
else:
|
||||
# Fallback if logo not found
|
||||
logo_label.setText("IntelSight")
|
||||
logo_label.setStyleSheet("font-size: 24px; font-weight: bold;")
|
||||
logo_label.setStyleSheet("font-size: 18px; font-weight: bold;")
|
||||
|
||||
# Logo mit Alignment hinzufügen
|
||||
layout.addWidget(logo_label, 0, Qt.AlignCenter)
|
||||
# Logo in top-left corner
|
||||
layout.addWidget(logo_label, 0, Qt.AlignLeft | Qt.AlignTop)
|
||||
|
||||
# Add some space after logo
|
||||
layout.addSpacing(20)
|
||||
|
||||
self.info_label = QLabel()
|
||||
self.info_label.setAlignment(Qt.AlignCenter)
|
||||
self.info_label.setWordWrap(True)
|
||||
self.info_label.setMaximumWidth(450) # Maximale Breite für bessere Lesbarkeit
|
||||
layout.addWidget(self.info_label, 0, Qt.AlignCenter)
|
||||
layout.addWidget(self.info_label, 1, Qt.AlignCenter) # Use stretch factor 1
|
||||
|
||||
# Spacer für bessere vertikale Verteilung
|
||||
layout.addStretch()
|
||||
|
||||
7
views/base/__init__.py
Normale Datei
7
views/base/__init__.py
Normale Datei
@ -0,0 +1,7 @@
|
||||
"""
|
||||
Base View Components - Theme-aware base classes for all UI elements
|
||||
"""
|
||||
|
||||
from views.base.theme_aware_widget import ThemeAwareWidget
|
||||
|
||||
__all__ = ['ThemeAwareWidget']
|
||||
99
views/base/theme_aware_widget.py
Normale Datei
99
views/base/theme_aware_widget.py
Normale Datei
@ -0,0 +1,99 @@
|
||||
"""
|
||||
Theme-Aware Base Widget - Base class for all custom widgets
|
||||
Provides automatic theme updates and color access
|
||||
"""
|
||||
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ThemeAwareWidget(QWidget):
|
||||
"""
|
||||
Base class for all custom widgets that need theme support.
|
||||
Automatically connects to theme changes and provides helper methods.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""
|
||||
Initialize theme-aware widget.
|
||||
|
||||
Args:
|
||||
parent: Parent widget
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self._theme_manager = None
|
||||
self._setup_theme_connection()
|
||||
|
||||
def _setup_theme_connection(self):
|
||||
"""Setup connection to theme manager for automatic updates."""
|
||||
try:
|
||||
# Try to find theme manager in main window
|
||||
main_window = self.window()
|
||||
if main_window and hasattr(main_window, 'theme_manager'):
|
||||
self._theme_manager = main_window.theme_manager
|
||||
# Connect to theme change signal
|
||||
self._theme_manager.theme_changed.connect(self._on_theme_changed)
|
||||
logger.debug(f"{self.__class__.__name__} connected to theme manager")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not connect to theme manager: {e}")
|
||||
|
||||
@pyqtSlot(str)
|
||||
def _on_theme_changed(self, theme_name: str):
|
||||
"""
|
||||
Called when theme changes.
|
||||
Override in subclasses to handle theme-specific updates.
|
||||
|
||||
Args:
|
||||
theme_name: Name of the new theme ('light' or 'dark')
|
||||
"""
|
||||
# Subclasses should override this method
|
||||
pass
|
||||
|
||||
def get_theme_color(self, color_key: str) -> str:
|
||||
"""
|
||||
Get a color from the current theme.
|
||||
|
||||
Args:
|
||||
color_key: Key of the color in theme configuration
|
||||
|
||||
Returns:
|
||||
Color value as hex string, or empty string if not found
|
||||
"""
|
||||
if self._theme_manager:
|
||||
return self._theme_manager.get_color(color_key)
|
||||
return ''
|
||||
|
||||
def get_current_theme(self) -> str:
|
||||
"""
|
||||
Get the current theme name.
|
||||
|
||||
Returns:
|
||||
Current theme name ('light' or 'dark'), or 'light' as default
|
||||
"""
|
||||
if self._theme_manager:
|
||||
return self._theme_manager.get_current_theme()
|
||||
return 'light'
|
||||
|
||||
def is_dark_mode(self) -> bool:
|
||||
"""
|
||||
Check if dark mode is currently active.
|
||||
|
||||
Returns:
|
||||
True if dark mode is active, False otherwise
|
||||
"""
|
||||
if self._theme_manager:
|
||||
return self._theme_manager.is_dark_mode()
|
||||
return False
|
||||
|
||||
def showEvent(self, event):
|
||||
"""
|
||||
Override showEvent to ensure theme connection is established.
|
||||
Some widgets might not have access to main window during __init__.
|
||||
"""
|
||||
super().showEvent(event)
|
||||
# Try to setup theme connection again if not established
|
||||
if not self._theme_manager:
|
||||
self._setup_theme_connection()
|
||||
@ -33,12 +33,7 @@ class SidebarFilter(QWidget):
|
||||
def init_ui(self):
|
||||
"""Initialisiert die UI nach Styleguide"""
|
||||
self.setMaximumWidth(260) # Styleguide: Sidebar-Breite
|
||||
self.setStyleSheet("""
|
||||
QWidget {
|
||||
background-color: #FFFFFF;
|
||||
border-right: 1px solid #E2E8F0;
|
||||
}
|
||||
""")
|
||||
self.setObjectName("filter_sidebar") # For QSS targeting
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
@ -70,29 +65,7 @@ class SidebarFilter(QWidget):
|
||||
btn = QPushButton(f"{name} (0)")
|
||||
btn.setObjectName(key)
|
||||
btn.setCursor(Qt.PointingHandCursor)
|
||||
btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-align: left;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
color: #4A5568;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #F7FAFC;
|
||||
color: #2D3748;
|
||||
}
|
||||
QPushButton[selected="true"] {
|
||||
background-color: #E6F2FF;
|
||||
color: #1E40AF;
|
||||
font-weight: 500;
|
||||
border-left: 3px solid #3182CE;
|
||||
padding-left: 13px;
|
||||
}
|
||||
""")
|
||||
btn.setObjectName("filter_button") # For QSS targeting
|
||||
btn.clicked.connect(lambda: self._on_filter_clicked(key))
|
||||
|
||||
# Erste Option als aktiv setzen
|
||||
@ -155,11 +128,7 @@ class AccountsOverviewView(QWidget):
|
||||
|
||||
def init_ui(self):
|
||||
"""Initialisiert die UI nach Styleguide"""
|
||||
self.setStyleSheet("""
|
||||
QWidget {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
""")
|
||||
self.setObjectName("accounts_overview") # For QSS targeting
|
||||
|
||||
# Hauptlayout
|
||||
main_layout = QHBoxLayout(self)
|
||||
@ -173,7 +142,7 @@ class AccountsOverviewView(QWidget):
|
||||
|
||||
# Content Area
|
||||
content_widget = QWidget()
|
||||
content_widget.setStyleSheet("background-color: #F8FAFC;")
|
||||
content_widget.setObjectName("accounts_content") # For QSS targeting
|
||||
content_layout = QVBoxLayout(content_widget)
|
||||
content_layout.setContentsMargins(40, 30, 40, 30)
|
||||
content_layout.setSpacing(20)
|
||||
@ -185,10 +154,7 @@ class AccountsOverviewView(QWidget):
|
||||
title_font = QFont("Poppins", 24)
|
||||
title_font.setBold(True)
|
||||
self.title.setFont(title_font)
|
||||
self.title.setStyleSheet("""
|
||||
color: #1A365D;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
self.title.setObjectName("section_title") # For QSS targeting
|
||||
header_layout.addWidget(self.title)
|
||||
|
||||
header_layout.addStretch()
|
||||
@ -198,34 +164,11 @@ class AccountsOverviewView(QWidget):
|
||||
# Scroll Area für Accounts
|
||||
self.scroll = QScrollArea()
|
||||
self.scroll.setWidgetResizable(True)
|
||||
self.scroll.setStyleSheet("""
|
||||
QScrollArea {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
background-color: #F1F5F9;
|
||||
width: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background-color: #CBD5E0;
|
||||
min-height: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background-color: #A0AEC0;
|
||||
}
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
""")
|
||||
# No inline styles - handled by QSS
|
||||
|
||||
# Grid Container
|
||||
self.container = QWidget()
|
||||
self.container.setStyleSheet("background-color: transparent;")
|
||||
self.container.setObjectName("grid_container") # For QSS targeting
|
||||
self.grid_layout = QGridLayout(self.container)
|
||||
self.grid_layout.setSpacing(24) # Styleguide Grid-Gap
|
||||
self.grid_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@ -300,11 +243,7 @@ class AccountsOverviewView(QWidget):
|
||||
header_font = QFont("Poppins", 18)
|
||||
header_font.setWeight(QFont.DemiBold)
|
||||
header.setFont(header_font)
|
||||
header.setStyleSheet("""
|
||||
color: #1A365D;
|
||||
padding: 8px 0;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
header.setObjectName("platform_header") # For QSS targeting
|
||||
self.grid_layout.addWidget(header, row, 0, 1, 3)
|
||||
row += 1
|
||||
|
||||
@ -364,26 +303,8 @@ class AccountsOverviewView(QWidget):
|
||||
cancel_button = msg_box.addButton("Abbrechen", QMessageBox.NoRole)
|
||||
msg_box.setDefaultButton(cancel_button) # Abbrechen als Standard
|
||||
|
||||
# Explizites Styling für den Löschen-Button
|
||||
delete_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #F44336;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #D32F2F;
|
||||
border-radius: 4px;
|
||||
padding: 6px 20px;
|
||||
min-width: 80px;
|
||||
min-height: 26px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #D32F2F;
|
||||
border-color: #B71C1C;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #B71C1C;
|
||||
}
|
||||
""")
|
||||
# Set object name for QSS targeting
|
||||
delete_button.setObjectName("delete_confirm_button")
|
||||
|
||||
msg_box.exec_()
|
||||
|
||||
|
||||
@ -45,19 +45,11 @@ class PlatformGridView(QWidget):
|
||||
title_font.setBold(True)
|
||||
self.title_label.setFont(title_font)
|
||||
|
||||
self.title_label.setStyleSheet("""
|
||||
QLabel {
|
||||
color: #1A365D;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
""")
|
||||
|
||||
layout.addWidget(self.title_label)
|
||||
|
||||
# Container für Plattform-Grid
|
||||
platforms_container = QWidget()
|
||||
platforms_container.setStyleSheet("background: transparent;")
|
||||
platforms_container.setObjectName("platforms_container") # For QSS targeting
|
||||
grid_layout = QGridLayout(platforms_container)
|
||||
grid_layout.setSpacing(24) # Styleguide Grid-Gap
|
||||
|
||||
|
||||
@ -32,13 +32,8 @@ class TabNavigation(QWidget):
|
||||
# Feste Höhe nach Styleguide
|
||||
self.setFixedHeight(48)
|
||||
|
||||
# Basis-Styling
|
||||
self.setStyleSheet("""
|
||||
QWidget {
|
||||
background-color: #FFFFFF;
|
||||
border-bottom: 1px solid #E2E8F0;
|
||||
}
|
||||
""")
|
||||
# Set object name for QSS targeting - NO inline styles!
|
||||
self.setObjectName("tab_navigation")
|
||||
|
||||
# Layout
|
||||
layout = QHBoxLayout(self)
|
||||
@ -70,30 +65,7 @@ class TabNavigation(QWidget):
|
||||
font.setWeight(QFont.Medium)
|
||||
btn.setFont(font)
|
||||
|
||||
btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 12px 24px;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #4A5568;
|
||||
min-width: 100px;
|
||||
}
|
||||
QPushButton:checked {
|
||||
color: #1A365D;
|
||||
border-bottom-color: #3182CE;
|
||||
}
|
||||
QPushButton:hover:!checked {
|
||||
color: #2D3748;
|
||||
background-color: #F7FAFC;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
color: #1A365D;
|
||||
}
|
||||
""")
|
||||
# No inline styles - handled by QSS generator
|
||||
|
||||
return btn
|
||||
|
||||
|
||||
@ -27,7 +27,6 @@ class MainWindow(QMainWindow):
|
||||
# Signale
|
||||
platform_selected = pyqtSignal(str)
|
||||
back_to_selector_requested = pyqtSignal()
|
||||
theme_toggled = pyqtSignal()
|
||||
|
||||
def __init__(self, theme_manager=None, language_manager=None, db_manager=None):
|
||||
super().__init__()
|
||||
@ -143,32 +142,53 @@ class MainWindow(QMainWindow):
|
||||
self.add_platform_tabs(platform_controller)
|
||||
|
||||
def _create_menus(self):
|
||||
"""Erstellt die Menüeinträge."""
|
||||
"""Erstellt die Menüeinträge und Dark Mode Toggle."""
|
||||
# Erstelle ein Logo-Button anstelle des Text-Menüs
|
||||
logo_widget = QPushButton()
|
||||
logo_widget.setIcon(QIcon(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"resources", "icons", "intelsight-logo.svg")))
|
||||
logo_widget.setIconSize(QSize(120, 40))
|
||||
logo_widget.setFlat(True)
|
||||
logo_widget.setCursor(Qt.PointingHandCursor)
|
||||
logo_widget.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
""")
|
||||
logo_widget.clicked.connect(self._show_about_dialog)
|
||||
self.logo_widget = QPushButton() # Store as instance variable for easier access
|
||||
|
||||
# Add logo to menu bar
|
||||
self.menuBar().setCornerWidget(logo_widget, Qt.TopLeftCorner)
|
||||
# Get the correct logo based on current theme
|
||||
if self.theme_manager:
|
||||
logo_path = self.theme_manager.get_icon_path("intelsight-logo")
|
||||
else:
|
||||
# Fallback if no theme manager
|
||||
logo_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"resources", "icons", "intelsight-logo.svg")
|
||||
|
||||
self.logo_widget.setIcon(QIcon(logo_path))
|
||||
self.logo_widget.setIconSize(QSize(120, 40))
|
||||
self.logo_widget.setFlat(True)
|
||||
self.logo_widget.setCursor(Qt.PointingHandCursor)
|
||||
self.logo_widget.setObjectName("logo_button") # For QSS targeting
|
||||
self.logo_widget.clicked.connect(self._show_about_dialog)
|
||||
|
||||
# Add logo to menu bar (left side)
|
||||
self.menuBar().setCornerWidget(self.logo_widget, Qt.TopLeftCorner)
|
||||
|
||||
# Create container for dark mode toggle (right side)
|
||||
right_container = QWidget()
|
||||
right_container.setObjectName("menubar_right_container") # For QSS targeting
|
||||
right_layout = QHBoxLayout(right_container)
|
||||
right_layout.setContentsMargins(0, 5, 10, 5) # Add some right margin
|
||||
|
||||
# Import and create Dark Mode Toggle
|
||||
from views.widgets.dark_mode_toggle import DarkModeToggle
|
||||
self.dark_mode_toggle = DarkModeToggle(self)
|
||||
|
||||
# Set initial state based on current theme
|
||||
if self.theme_manager:
|
||||
initial_dark = self.theme_manager.is_dark_mode()
|
||||
self.dark_mode_toggle.setChecked(initial_dark)
|
||||
|
||||
# Connect toggle to theme manager
|
||||
self.dark_mode_toggle.toggled.connect(self._on_theme_toggled)
|
||||
|
||||
right_layout.addWidget(self.dark_mode_toggle)
|
||||
|
||||
# Add dark mode toggle to menu bar (right side)
|
||||
self.menuBar().setCornerWidget(right_container, Qt.TopRightCorner)
|
||||
|
||||
# Store reference for language updates
|
||||
self.about_action = logo_widget
|
||||
self.about_action = self.logo_widget
|
||||
|
||||
|
||||
def _show_about_dialog(self):
|
||||
@ -177,6 +197,17 @@ class MainWindow(QMainWindow):
|
||||
dialog.exec_()
|
||||
|
||||
|
||||
def _on_theme_toggled(self, is_dark):
|
||||
"""Handle theme toggle from the dark mode switch."""
|
||||
if self.theme_manager:
|
||||
if is_dark:
|
||||
self.theme_manager.apply_theme(self.theme_manager.DARK_THEME)
|
||||
else:
|
||||
self.theme_manager.apply_theme(self.theme_manager.LIGHT_THEME)
|
||||
|
||||
# Explicitly update logo after theme change
|
||||
self.update_logo()
|
||||
|
||||
def refresh_language_ui(self):
|
||||
"""
|
||||
Aktualisiert alle UI-Texte nach einem Sprachwechsel.
|
||||
@ -238,4 +269,43 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def add_log_widget(self, text_widget):
|
||||
"""Fügt einen GUI-Handler zum Logger hinzu."""
|
||||
add_gui_handler(logger, text_widget)
|
||||
add_gui_handler(logger, text_widget)
|
||||
|
||||
def update_logo(self, theme_name: str = None):
|
||||
"""
|
||||
Updates the logo based on the current theme.
|
||||
|
||||
Args:
|
||||
theme_name: Name of the theme ("light" or "dark") - not used, kept for compatibility
|
||||
"""
|
||||
try:
|
||||
# Use stored reference to logo widget
|
||||
if hasattr(self, 'logo_widget') and self.logo_widget and self.theme_manager:
|
||||
# Get the new logo path from theme manager based on current theme
|
||||
current_theme = self.theme_manager.get_current_theme()
|
||||
logo_path = self.theme_manager.get_icon_path("intelsight-logo")
|
||||
|
||||
print(f"DEBUG: Updating logo for theme '{current_theme}'")
|
||||
print(f"DEBUG: Logo path: {logo_path}")
|
||||
print(f"DEBUG: File exists: {os.path.exists(logo_path)}")
|
||||
|
||||
if os.path.exists(logo_path):
|
||||
icon = QIcon(logo_path)
|
||||
self.logo_widget.setIcon(icon)
|
||||
# Force update
|
||||
self.logo_widget.update()
|
||||
self.logo_widget.repaint()
|
||||
|
||||
logger.info(f"Logo updated to {logo_path} for theme {current_theme}")
|
||||
print(f"DEBUG: Logo icon set successfully")
|
||||
else:
|
||||
logger.warning(f"Logo file not found: {logo_path}")
|
||||
print(f"DEBUG: Logo file not found!")
|
||||
else:
|
||||
print(f"DEBUG: Cannot update logo - missing components:")
|
||||
print(f" - has logo_widget: {hasattr(self, 'logo_widget')}")
|
||||
print(f" - logo_widget exists: {hasattr(self, 'logo_widget') and self.logo_widget}")
|
||||
print(f" - theme_manager exists: {self.theme_manager is not None}")
|
||||
except Exception as e:
|
||||
logger.error(f"Could not update logo: {e}")
|
||||
print(f"DEBUG: Exception updating logo: {e}")
|
||||
@ -48,7 +48,7 @@ class PlatformSelector(QWidget):
|
||||
|
||||
# Content Container mit gestapelten Widgets
|
||||
self.content_stack = QStackedWidget()
|
||||
self.content_stack.setStyleSheet("background-color: #F8FAFC;")
|
||||
self.content_stack.setObjectName("content_stack") # For QSS targeting, no inline styles!
|
||||
|
||||
# Platform Grid View (Tab 0)
|
||||
self.platform_grid = PlatformGridView(self.language_manager)
|
||||
|
||||
@ -85,10 +85,7 @@ class AccountCard(QFrame):
|
||||
username_font = QFont("Poppins", 16)
|
||||
username_font.setWeight(QFont.DemiBold)
|
||||
username_label.setFont(username_font)
|
||||
username_label.setStyleSheet("""
|
||||
color: #1A365D;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
username_label.setObjectName("account_username") # For QSS targeting
|
||||
info_layout.addWidget(username_label)
|
||||
info_layout.addStretch()
|
||||
|
||||
@ -97,25 +94,7 @@ class AccountCard(QFrame):
|
||||
# Login Button
|
||||
self.login_btn = QPushButton("Login")
|
||||
self.login_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.login_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #3182CE;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 6px 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
min-width: 60px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #2563EB;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #1D4ED8;
|
||||
}
|
||||
""")
|
||||
self.login_btn.setObjectName("account_login_btn") # For QSS targeting
|
||||
self.login_btn.clicked.connect(lambda: self._on_login_clicked())
|
||||
header_layout.addWidget(self.login_btn)
|
||||
|
||||
@ -136,32 +115,14 @@ class AccountCard(QFrame):
|
||||
email_layout.setSpacing(8)
|
||||
|
||||
email_label = QLabel(self.account_data.get("email", ""))
|
||||
email_label.setStyleSheet("""
|
||||
color: #4A5568;
|
||||
font-size: 13px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
email_label.setObjectName("account_detail_text") # For QSS targeting
|
||||
email_layout.addWidget(email_label)
|
||||
|
||||
# Email Copy Button
|
||||
email_copy_btn = QPushButton()
|
||||
email_copy_btn.setToolTip("E-Mail kopieren")
|
||||
email_copy_btn.setCursor(Qt.PointingHandCursor)
|
||||
email_copy_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
min-width: 20px;
|
||||
max-width: 20px;
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #F7FAFC;
|
||||
border-radius: 4px;
|
||||
}
|
||||
""")
|
||||
email_copy_btn.setObjectName("account_icon_btn") # For QSS targeting
|
||||
self.copy_icon = IconFactory.get_icon("copy", size=16)
|
||||
self.check_icon = IconFactory.get_icon("check", size=16, color="#10B981")
|
||||
self.email_copy_btn = email_copy_btn
|
||||
@ -183,32 +144,14 @@ class AccountCard(QFrame):
|
||||
pass_layout.setSpacing(8)
|
||||
|
||||
self.password_label = QLabel("••••••••")
|
||||
self.password_label.setStyleSheet("""
|
||||
color: #4A5568;
|
||||
font-size: 13px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
self.password_label.setObjectName("account_detail_text") # For QSS targeting
|
||||
pass_layout.addWidget(self.password_label)
|
||||
|
||||
# Copy Button
|
||||
copy_btn = QPushButton()
|
||||
copy_btn.setToolTip("Passwort kopieren")
|
||||
copy_btn.setCursor(Qt.PointingHandCursor)
|
||||
copy_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
min-width: 20px;
|
||||
max-width: 20px;
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #F7FAFC;
|
||||
border-radius: 4px;
|
||||
}
|
||||
""")
|
||||
copy_btn.setObjectName("account_icon_btn") # For QSS targeting
|
||||
self.password_copy_btn = copy_btn
|
||||
self.password_copy_btn.setIcon(self.copy_icon)
|
||||
self.password_copy_btn.setIconSize(QSize(16, 16))
|
||||
@ -219,21 +162,7 @@ class AccountCard(QFrame):
|
||||
self.visibility_btn = QPushButton()
|
||||
self.visibility_btn.setToolTip("Passwort anzeigen")
|
||||
self.visibility_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.visibility_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
min-width: 20px;
|
||||
max-width: 20px;
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #F7FAFC;
|
||||
border-radius: 4px;
|
||||
}
|
||||
""")
|
||||
self.visibility_btn.setObjectName("account_icon_btn") # For QSS targeting
|
||||
self.eye_icon = IconFactory.get_icon("eye", size=16)
|
||||
self.eye_slash_icon = IconFactory.get_icon("eye-slash", size=16)
|
||||
self.visibility_btn.setIcon(self.eye_icon)
|
||||
@ -249,11 +178,7 @@ class AccountCard(QFrame):
|
||||
details_grid.addWidget(date_icon, 2, 0)
|
||||
|
||||
date_label = QLabel(self.account_data.get("created_at", ""))
|
||||
date_label.setStyleSheet("""
|
||||
color: #A0AEC0;
|
||||
font-size: 12px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
""")
|
||||
date_label.setObjectName("account_date_text") # For QSS targeting
|
||||
details_grid.addWidget(date_label, 2, 1)
|
||||
|
||||
layout.addLayout(details_grid)
|
||||
@ -265,27 +190,7 @@ class AccountCard(QFrame):
|
||||
# Export Button
|
||||
self.export_btn = QPushButton("Profil\nexportieren")
|
||||
self.export_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.export_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #10B981;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
min-width: 120px;
|
||||
min-height: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #059669;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #047857;
|
||||
}
|
||||
""")
|
||||
self.export_btn.setObjectName("account_export_btn") # For QSS targeting
|
||||
self.export_btn.clicked.connect(lambda: self.export_requested.emit(self.account_data))
|
||||
actions_layout.addWidget(self.export_btn)
|
||||
|
||||
@ -294,25 +199,7 @@ class AccountCard(QFrame):
|
||||
# Delete Button
|
||||
self.delete_btn = QPushButton("Löschen")
|
||||
self.delete_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.delete_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #DC2626;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
min-width: 90px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #B91C1C;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #991B1B;
|
||||
}
|
||||
""")
|
||||
self.delete_btn.setObjectName("account_delete_btn") # For QSS targeting
|
||||
self.delete_btn.clicked.connect(lambda: self.delete_requested.emit(self.account_data))
|
||||
actions_layout.addWidget(self.delete_btn)
|
||||
|
||||
@ -379,40 +266,14 @@ class AccountCard(QFrame):
|
||||
self.password_copy_timer.stop()
|
||||
|
||||
def _apply_status_styling(self):
|
||||
"""Wendet Status-basiertes Styling mit Pastel-Hintergrund und farbiger Umrandung an"""
|
||||
"""Wendet Status-basiertes Styling an"""
|
||||
# Status aus Account-Daten lesen - Standard ist "active" (grün)
|
||||
status = self.account_data.get("status", "active")
|
||||
|
||||
# Status-Farben definieren (nur Grün/Rot)
|
||||
status_styles = {
|
||||
"active": {
|
||||
"background": "#F0FDF4", # Sehr helles Mintgrün
|
||||
"border": "#10B981", # Kräftiges Grün
|
||||
"hover_border": "#059669" # Dunkleres Grün beim Hover
|
||||
},
|
||||
"inactive": {
|
||||
"background": "#FEF2F2", # Sehr helles Rosa
|
||||
"border": "#EF4444", # Kräftiges Rot
|
||||
"hover_border": "#DC2626" # Dunkleres Rot beim Hover
|
||||
}
|
||||
}
|
||||
|
||||
# Aktueller Status oder Fallback auf active (grün)
|
||||
current_style = status_styles.get(status, status_styles["active"])
|
||||
|
||||
# CSS-Styling anwenden
|
||||
self.setStyleSheet(f"""
|
||||
QFrame#accountCard {{
|
||||
background-color: {current_style["background"]};
|
||||
border: 2px solid {current_style["border"]};
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}}
|
||||
QFrame#accountCard:hover {{
|
||||
border: 2px solid {current_style["hover_border"]};
|
||||
background-color: {current_style["background"]};
|
||||
}}
|
||||
""")
|
||||
# Set a property that QSS can use for styling
|
||||
self.setProperty("status", status)
|
||||
# Force style refresh
|
||||
self.setStyle(self.style())
|
||||
|
||||
def update_status(self, new_status: str):
|
||||
"""Aktualisiert den Status der Account-Karte und das Styling"""
|
||||
|
||||
233
views/widgets/dark_mode_toggle.py
Normale Datei
233
views/widgets/dark_mode_toggle.py
Normale Datei
@ -0,0 +1,233 @@
|
||||
"""
|
||||
Dark Mode Toggle Widget for PyQt5
|
||||
Based on Corporate Design Guidelines with smooth animations
|
||||
"""
|
||||
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QPropertyAnimation, QEasingCurve, QRectF, pyqtProperty, QByteArray
|
||||
from PyQt5.QtGui import QPainter, QColor, QBrush, QPen
|
||||
from PyQt5.QtSvg import QSvgRenderer
|
||||
|
||||
|
||||
class DarkModeToggle(QWidget):
|
||||
"""
|
||||
Animated Toggle-Switch for Dark/Light Mode with embedded SVG Icons.
|
||||
|
||||
Features:
|
||||
- Smooth 200ms animation with InOutCubic easing
|
||||
- Embedded sun/moon icons (no external files needed)
|
||||
- Corporate design colors (#CBD5E0 for light, #00D4FF for dark)
|
||||
- Size: 60x30 pixels
|
||||
- PyQt5 compatible
|
||||
|
||||
Signals:
|
||||
toggled(bool): Emitted when toggle state changes (True = Dark Mode)
|
||||
"""
|
||||
|
||||
# Signal emitted when toggle state changes
|
||||
toggled = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, parent=None, initial_dark_mode=False):
|
||||
"""
|
||||
Initialize the Dark Mode Toggle.
|
||||
|
||||
Args:
|
||||
parent: Parent widget
|
||||
initial_dark_mode: Initial state (False = Light Mode, True = Dark Mode)
|
||||
"""
|
||||
super().__init__(parent)
|
||||
|
||||
# Fixed size as per design spec
|
||||
self.setFixedSize(60, 30)
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
|
||||
# State management
|
||||
self._checked = initial_dark_mode
|
||||
|
||||
# Animation property for smooth sliding
|
||||
self._handle_position = 27.0 if initial_dark_mode else 3.0
|
||||
|
||||
# Configure animation
|
||||
self._animation = QPropertyAnimation(self, b"handle_position")
|
||||
self._animation.setDuration(200) # 200ms as per spec
|
||||
self._animation.setEasingCurve(QEasingCurve.InOutCubic)
|
||||
|
||||
# Initialize SVG renderers
|
||||
self.sun_svg = QSvgRenderer()
|
||||
self.moon_svg = QSvgRenderer()
|
||||
|
||||
# Load embedded SVG content
|
||||
self._load_svg_icons()
|
||||
|
||||
# Tooltip for accessibility
|
||||
self._update_tooltip()
|
||||
|
||||
def _load_svg_icons(self):
|
||||
"""Load embedded SVG icons for sun and moon."""
|
||||
|
||||
# Sun icon for Light Mode (black strokes)
|
||||
sun_svg_content = b'''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 3V4M12 20V21M4 12H3M6.31412 6.31412L5.5 5.5M17.6859 6.31412L18.5 5.5M6.31412 17.69L5.5 18.5001M17.6859 17.69L18.5 18.5001M21 12H20M16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12C8 9.79086 9.79086 8 12 8C14.2091 8 16 9.79086 16 12Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>'''
|
||||
|
||||
# Moon icon for Dark Mode (dark blue strokes matching primary color)
|
||||
moon_svg_content = b'''<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.32031 11.6835C3.32031 16.6541 7.34975 20.6835 12.3203 20.6835C16.1075 20.6835 19.3483 18.3443 20.6768 15.032C19.6402 15.4486 18.5059 15.6834 17.3203 15.6834C12.3497 15.6834 8.32031 11.654 8.32031 6.68342C8.32031 5.50338 8.55165 4.36259 8.96453 3.32996C5.65605 4.66028 3.32031 7.89912 3.32031 11.6835Z" stroke="#232D53" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>'''
|
||||
|
||||
# Load SVG data into renderers
|
||||
self.sun_svg.load(QByteArray(sun_svg_content))
|
||||
self.moon_svg.load(QByteArray(moon_svg_content))
|
||||
|
||||
# Property for animation
|
||||
def get_handle_position(self):
|
||||
"""Get current handle position for animation."""
|
||||
return self._handle_position
|
||||
|
||||
def set_handle_position(self, pos):
|
||||
"""Set handle position and trigger repaint."""
|
||||
self._handle_position = pos
|
||||
self.update() # Trigger paintEvent
|
||||
|
||||
# Define property for QPropertyAnimation
|
||||
handle_position = pyqtProperty(float, get_handle_position, set_handle_position)
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""
|
||||
Custom paint event to draw the toggle switch.
|
||||
|
||||
Draws:
|
||||
1. Track (background pill shape)
|
||||
2. Handle (white circular button)
|
||||
3. Icon (sun or moon in the handle)
|
||||
"""
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
# Draw track (pill-shaped background)
|
||||
track_rect = QRectF(0, 0, self.width(), self.height())
|
||||
track_radius = self.height() / 2
|
||||
|
||||
# Track color based on state
|
||||
if self._checked:
|
||||
# Dark mode active - cyan color from corporate design
|
||||
track_color = QColor("#00D4FF")
|
||||
else:
|
||||
# Light mode active - gray color from design spec
|
||||
track_color = QColor("#CBD5E0")
|
||||
|
||||
painter.setBrush(QBrush(track_color))
|
||||
painter.setPen(QPen(Qt.NoPen))
|
||||
painter.drawRoundedRect(track_rect, track_radius, track_radius)
|
||||
|
||||
# Draw handle (white circle that slides)
|
||||
handle_diameter = self.height() - 6 # 24px (30 - 6)
|
||||
handle_rect = QRectF(
|
||||
self._handle_position, # Animated position
|
||||
3, # 3px from top
|
||||
handle_diameter,
|
||||
handle_diameter
|
||||
)
|
||||
|
||||
# White handle
|
||||
painter.setBrush(QBrush(QColor("#FFFFFF")))
|
||||
painter.setPen(QPen(Qt.NoPen))
|
||||
painter.drawEllipse(handle_rect)
|
||||
|
||||
# Draw icon inside handle
|
||||
icon_size = 16 # Icon size within the 24px handle
|
||||
icon_rect = QRectF(
|
||||
handle_rect.x() + (handle_diameter - icon_size) / 2,
|
||||
handle_rect.y() + (handle_diameter - icon_size) / 2,
|
||||
icon_size,
|
||||
icon_size
|
||||
)
|
||||
|
||||
# Render appropriate icon
|
||||
if self._checked:
|
||||
# Dark mode - show moon icon
|
||||
self.moon_svg.render(painter, icon_rect)
|
||||
else:
|
||||
# Light mode - show sun icon
|
||||
self.sun_svg.render(painter, icon_rect)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""
|
||||
Handle mouse click to toggle state.
|
||||
|
||||
Only responds to left mouse button clicks.
|
||||
"""
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.toggle()
|
||||
|
||||
def toggle(self):
|
||||
"""Toggle between Light and Dark mode."""
|
||||
self.setChecked(not self._checked)
|
||||
|
||||
def setChecked(self, checked):
|
||||
"""
|
||||
Set the toggle state programmatically.
|
||||
|
||||
Args:
|
||||
checked: True for Dark Mode, False for Light Mode
|
||||
"""
|
||||
# Only proceed if state actually changes
|
||||
if self._checked == checked:
|
||||
return
|
||||
|
||||
self._checked = checked
|
||||
|
||||
# Stop any running animation
|
||||
self._animation.stop()
|
||||
|
||||
# Set animation endpoints
|
||||
if checked:
|
||||
# Animate to dark mode position (right side)
|
||||
# Handle should be at: width - handle_diameter - 3px margin
|
||||
self._animation.setEndValue(self.width() - (self.height() - 6) - 3)
|
||||
else:
|
||||
# Animate to light mode position (left side)
|
||||
self._animation.setEndValue(3.0)
|
||||
|
||||
# Start animation
|
||||
self._animation.start()
|
||||
|
||||
# Update tooltip
|
||||
self._update_tooltip()
|
||||
|
||||
# Emit signal for theme change
|
||||
self.toggled.emit(checked)
|
||||
|
||||
def isChecked(self):
|
||||
"""
|
||||
Get current toggle state.
|
||||
|
||||
Returns:
|
||||
bool: True if Dark Mode is active, False for Light Mode
|
||||
"""
|
||||
return self._checked
|
||||
|
||||
def _update_tooltip(self):
|
||||
"""Update tooltip based on current state."""
|
||||
if self._checked:
|
||||
self.setToolTip("Zu Light Mode wechseln")
|
||||
else:
|
||||
self.setToolTip("Zu Dark Mode wechseln")
|
||||
|
||||
def isDarkMode(self):
|
||||
"""
|
||||
Convenience method to check if dark mode is active.
|
||||
|
||||
Returns:
|
||||
bool: True if Dark Mode is active
|
||||
"""
|
||||
return self._checked
|
||||
|
||||
def isLightMode(self):
|
||||
"""
|
||||
Convenience method to check if light mode is active.
|
||||
|
||||
Returns:
|
||||
bool: True if Light Mode is active
|
||||
"""
|
||||
return not self._checked
|
||||
@ -38,27 +38,8 @@ class PlatformButton(QWidget):
|
||||
self.icon_button.setIconSize(QSize(120, 120)) # Größeres Icon
|
||||
|
||||
self.icon_button.setMinimumSize(150, 150)
|
||||
# Platform button styling based on Styleguide
|
||||
self.icon_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #F5F7FF;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #E8EBFF;
|
||||
border: 1px solid #0099CC;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #DCE2FF;
|
||||
border: 1px solid #0099CC;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #F0F0F0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
""")
|
||||
# Set object name for QSS targeting
|
||||
self.icon_button.setObjectName("platform_icon_button")
|
||||
|
||||
# Button-Signal verbinden
|
||||
self.icon_button.clicked.connect(self.clicked)
|
||||
@ -70,15 +51,8 @@ class PlatformButton(QWidget):
|
||||
name_font.setPointSize(12)
|
||||
name_font.setBold(True)
|
||||
self.name_label.setFont(name_font)
|
||||
# Name label styling based on Styleguide
|
||||
self.name_label.setStyleSheet("""
|
||||
QLabel {
|
||||
color: #232D53;
|
||||
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
""")
|
||||
# Set object name for QSS targeting
|
||||
self.name_label.setObjectName("platform_name_label")
|
||||
|
||||
# Widgets zum Layout hinzufügen
|
||||
layout.addWidget(self.icon_button, 0, Qt.AlignCenter)
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren