""" Notification Center Widget - Modern notification panel with filtering and management """ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QScrollArea, QFrame, QComboBox, QLineEdit, QCheckBox, QSizePolicy) from PySide6.QtCore import Qt, Signal, QTimer, QDateTime from PySide6.QtGui import QFont, QIcon class NotificationItem(QFrame): """Individual notification item with modern styling""" dismissed = Signal(object) # Emitted when notification is dismissed def __init__(self, message, level="info", timestamp=None, parent=None): super().__init__(parent) self.message = message self.level = level self.timestamp = timestamp or QDateTime.currentDateTime() self.setObjectName(f"notificationItem_{level}") self.setFrameStyle(QFrame.Box) self.setMaximumHeight(80) self._setup_ui() self._apply_style() # Auto-dismiss timer for info notifications if level == "info": QTimer.singleShot(10000, self._auto_dismiss) # 10 seconds def _setup_ui(self): """Setup the notification item UI""" layout = QHBoxLayout(self) layout.setContentsMargins(10, 8, 10, 8) # Level icon icon_label = QLabel() icon_label.setFixedSize(24, 24) icon_label.setAlignment(Qt.AlignCenter) icons = { 'info': '💡', 'warning': '⚠️', 'error': '❌', 'success': '✅' } icon_label.setText(icons.get(self.level, '📋')) icon_label.setStyleSheet("font-size: 16px;") layout.addWidget(icon_label) # Content area content_layout = QVBoxLayout() # Message message_label = QLabel(self.message) message_label.setWordWrap(True) message_label.setFont(QFont("Segoe UI", 9)) content_layout.addWidget(message_label) # Timestamp time_label = QLabel(self.timestamp.toString("hh:mm:ss")) time_label.setFont(QFont("Segoe UI", 8)) time_label.setStyleSheet("color: gray;") content_layout.addWidget(time_label) layout.addLayout(content_layout, 1) # Dismiss button dismiss_btn = QPushButton("×") dismiss_btn.setFixedSize(20, 20) dismiss_btn.setFont(QFont("Arial", 10, QFont.Bold)) dismiss_btn.clicked.connect(self._dismiss) layout.addWidget(dismiss_btn) def _apply_style(self): """Apply level-specific styling""" styles = { 'info': "border-left: 3px solid #3498db; background-color: rgba(52, 152, 219, 0.1);", 'warning': "border-left: 3px solid #f39c12; background-color: rgba(243, 156, 18, 0.1);", 'error': "border-left: 3px solid #e74c3c; background-color: rgba(231, 76, 60, 0.1);", 'success': "border-left: 3px solid #27ae60; background-color: rgba(39, 174, 96, 0.1);" } self.setStyleSheet(styles.get(self.level, styles['info'])) def _dismiss(self): """Dismiss this notification""" self.dismissed.emit(self) def _auto_dismiss(self): """Auto-dismiss for info notifications""" if self.level == "info": self._dismiss() class NotificationCenter(QWidget): """ Modern notification center with filtering and management capabilities """ def __init__(self, parent=None): super().__init__(parent) self.setFixedWidth(350) self.notifications = [] self.max_notifications = 50 self._setup_ui() print("✅ Notification Center initialized") def _setup_ui(self): """Setup the notification center UI""" layout = QVBoxLayout(self) layout.setContentsMargins(10, 10, 10, 10) layout.setSpacing(5) # Header header = self._create_header() layout.addWidget(header) # Filter controls filters = self._create_filters() layout.addWidget(filters) # Notification list self.scroll_area = QScrollArea() self.scroll_area.setWidgetResizable(True) self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarNever) self.notifications_widget = QWidget() self.notifications_layout = QVBoxLayout(self.notifications_widget) self.notifications_layout.setAlignment(Qt.AlignTop) self.scroll_area.setWidget(self.notifications_widget) layout.addWidget(self.scroll_area) # Footer with actions footer = self._create_footer() layout.addWidget(footer) def _create_header(self): """Create the header with title and controls""" header = QFrame() header.setFixedHeight(40) layout = QHBoxLayout(header) # Title title = QLabel("Notifications") title.setFont(QFont("Segoe UI", 11, QFont.Bold)) layout.addWidget(title) layout.addStretch() # Notification count self.count_label = QLabel("0") self.count_label.setFont(QFont("Segoe UI", 9)) self.count_label.setStyleSheet("color: gray;") layout.addWidget(self.count_label) return header def _create_filters(self): """Create filter controls""" filters = QFrame() filters.setFixedHeight(35) layout = QHBoxLayout(filters) layout.setContentsMargins(0, 0, 0, 0) # Level filter self.level_filter = QComboBox() self.level_filter.addItems(["All", "Info", "Warning", "Error", "Success"]) self.level_filter.currentTextChanged.connect(self._apply_filters) layout.addWidget(self.level_filter) # Search filter self.search_filter = QLineEdit() self.search_filter.setPlaceholderText("Search notifications...") self.search_filter.textChanged.connect(self._apply_filters) layout.addWidget(self.search_filter) return filters def _create_footer(self): """Create footer with action buttons""" footer = QFrame() footer.setFixedHeight(35) layout = QHBoxLayout(footer) # Clear all button clear_btn = QPushButton("Clear All") clear_btn.clicked.connect(self.clear_all) layout.addWidget(clear_btn) layout.addStretch() # Export button export_btn = QPushButton("Export") export_btn.clicked.connect(self._export_notifications) layout.addWidget(export_btn) return footer def add_notification(self, message, level="info"): """Add a new notification""" # Remove oldest notification if at limit if len(self.notifications) >= self.max_notifications: oldest = self.notifications[0] self._remove_notification(oldest) # Create new notification notification = NotificationItem(message, level) notification.dismissed.connect(self._remove_notification) # Add to list and layout self.notifications.append(notification) self.notifications_layout.insertWidget(0, notification) # Add to top # Update count self._update_count() # Scroll to top to show new notification self.scroll_area.verticalScrollBar().setValue(0) print(f"📝 Notification added: {level.upper()} - {message[:50]}...") def _remove_notification(self, notification): """Remove a notification""" if notification in self.notifications: self.notifications.remove(notification) notification.setParent(None) self._update_count() def _apply_filters(self): """Apply current filters to notifications""" level_filter = self.level_filter.currentText().lower() search_text = self.search_filter.text().lower() for notification in self.notifications: # Check level filter level_match = (level_filter == "all" or notification.level == level_filter) # Check search filter search_match = (not search_text or search_text in notification.message.lower()) # Show/hide notification notification.setVisible(level_match and search_match) def _update_count(self): """Update the notification count""" visible_count = sum(1 for n in self.notifications if n.isVisible()) total_count = len(self.notifications) self.count_label.setText(f"{visible_count}/{total_count}") def clear_all(self): """Clear all notifications""" for notification in self.notifications[:]: # Copy list to avoid modification during iteration self._remove_notification(notification) def _export_notifications(self): """Export notifications to file""" # Implementation for exporting notifications print("📤 Exporting notifications...") def get_notification_summary(self): """Get summary of current notifications""" summary = { 'total': len(self.notifications), 'by_level': {} } for notification in self.notifications: level = notification.level summary['by_level'][level] = summary['by_level'].get(level, 0) + 1 return summary