""" EU-Utility - Dashboard Plugin with Customizable Widgets Customizable start page with avatar statistics. """ import json from pathlib import Path from datetime import datetime, timedelta from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout, QFrame, QScrollArea, QSizePolicy, QCheckBox, QDialog, QListWidget, QListWidgetItem, QDialogButtonBox ) from PyQt6.QtCore import Qt, QTimer from PyQt6.QtGui import QColor, QFont from core.eu_styles import EU_COLORS from plugins.base_plugin import BasePlugin class DashboardPlugin(BasePlugin): """Customizable dashboard with avatar statistics.""" name = "Dashboard" version = "2.0.0" author = "ImpulsiveFPS" description = "Customizable start page with avatar stats" hotkey = "ctrl+shift+home" # Available widgets AVAILABLE_WIDGETS = { 'ped_balance': {'name': 'PED Balance', 'icon': 'dollar-sign', 'default': True}, 'skill_count': {'name': 'Skills Tracked', 'icon': 'trending-up', 'default': True}, 'inventory_items': {'name': 'Inventory Items', 'icon': 'archive', 'default': True}, 'current_dpp': {'name': 'Current DPP', 'icon': 'crosshair', 'default': True}, 'total_gains_today': {'name': "Today's Skill Gains", 'icon': 'zap', 'default': True}, 'professions_count': {'name': 'Professions', 'icon': 'award', 'default': False}, 'missions_active': {'name': 'Active Missions', 'icon': 'map', 'default': False}, 'codex_progress': {'name': 'Codex Progress', 'icon': 'book', 'default': False}, 'globals_hofs': {'name': 'Globals/HOFs', 'icon': 'package', 'default': False}, 'play_time': {'name': 'Session Time', 'icon': 'clock', 'default': False}, } def initialize(self): """Setup dashboard.""" self.config_file = Path("data/dashboard_config.json") self.config_file.parent.mkdir(parents=True, exist_ok=True) self.enabled_widgets = [] self.widget_data = {} self._load_config() self._load_data() # Auto-refresh timer self.refresh_timer = QTimer() self.refresh_timer.timeout.connect(self._refresh_data) self.refresh_timer.start(5000) # Refresh every 5 seconds def _load_config(self): """Load widget configuration.""" if self.config_file.exists(): try: with open(self.config_file, 'r') as f: config = json.load(f) self.enabled_widgets = config.get('enabled', []) except: pass # Default: enable default widgets if not self.enabled_widgets: self.enabled_widgets = [ k for k, v in self.AVAILABLE_WIDGETS.items() if v['default'] ] def _save_config(self): """Save widget configuration.""" with open(self.config_file, 'w') as f: json.dump({'enabled': self.enabled_widgets}, f) def _load_data(self): """Load data from other plugins.""" # Try to get data from other plugin files data_dir = Path("data") # PED from inventory inv_file = data_dir / "inventory.json" if inv_file.exists(): try: with open(inv_file, 'r') as f: data = json.load(f) items = data.get('items', []) total_tt = sum(item.get('tt', 0) for item in items) self.widget_data['ped_balance'] = total_tt except: self.widget_data['ped_balance'] = 0 # Skills skills_file = data_dir / "skill_tracker.json" if skills_file.exists(): try: with open(skills_file, 'r') as f: data = json.load(f) self.widget_data['skill_count'] = len(data.get('skills', {})) self.widget_data['total_gains_today'] = len([ g for g in data.get('gains', []) if datetime.fromisoformat(g['time']).date() == datetime.now().date() ]) except: self.widget_data['skill_count'] = 0 self.widget_data['total_gains_today'] = 0 # Inventory count if inv_file.exists(): try: with open(inv_file, 'r') as f: data = json.load(f) self.widget_data['inventory_items'] = len(data.get('items', [])) except: self.widget_data['inventory_items'] = 0 # Professions prof_file = data_dir / "professions.json" if prof_file.exists(): try: with open(prof_file, 'r') as f: data = json.load(f) self.widget_data['professions_count'] = len(data.get('professions', {})) except: self.widget_data['professions_count'] = 0 def _refresh_data(self): """Refresh widget data.""" self._load_data() if hasattr(self, 'widgets_container'): self._update_widgets() def get_ui(self): """Create dashboard UI.""" widget = QWidget() layout = QVBoxLayout(widget) layout.setSpacing(15) layout.setContentsMargins(0, 0, 0, 0) # Header with customize button header = QHBoxLayout() title = QLabel("Dashboard") title.setStyleSheet("font-size: 20px; font-weight: bold; color: white;") header.addWidget(title) header.addStretch() customize_btn = QPushButton("Customize") customize_btn.setStyleSheet(f""" QPushButton {{ background-color: {EU_COLORS['bg_secondary']}; color: {EU_COLORS['text_secondary']}; border: 1px solid {EU_COLORS['border_subtle']}; border-radius: 4px; padding: 8px 16px; }} QPushButton:hover {{ background-color: {EU_COLORS['bg_hover']}; border-color: {EU_COLORS['accent_orange']}; }} """) customize_btn.clicked.connect(self._show_customize_dialog) header.addWidget(customize_btn) layout.addLayout(header) # Scroll area for widgets scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setFrameShape(QFrame.Shape.NoFrame) scroll.setStyleSheet("background: transparent; border: none;") self.widgets_container = QWidget() self.widgets_layout = QGridLayout(self.widgets_container) self.widgets_layout.setSpacing(15) self.widgets_layout.setContentsMargins(0, 0, 0, 0) self._update_widgets() scroll.setWidget(self.widgets_container) layout.addWidget(scroll) return widget def _update_widgets(self): """Update widget display.""" # Clear existing while self.widgets_layout.count(): item = self.widgets_layout.takeAt(0) if item.widget(): item.widget().deleteLater() # Add enabled widgets col = 0 row = 0 for widget_id in self.enabled_widgets: if widget_id in self.AVAILABLE_WIDGETS: widget_info = self.AVAILABLE_WIDGETS[widget_id] card = self._create_widget_card( widget_id, widget_info['name'], widget_info['icon'] ) self.widgets_layout.addWidget(card, row, col) col += 1 if col >= 2: # 2 columns col = 0 row += 1 def _create_widget_card(self, widget_id, name, icon_name): """Create a stat widget card.""" card = QFrame() card.setStyleSheet(f""" QFrame {{ background-color: {EU_COLORS['bg_secondary']}; border: 1px solid {EU_COLORS['border_subtle']}; border-radius: 8px; }} """) layout = QVBoxLayout(card) layout.setContentsMargins(15, 15, 15, 15) layout.setSpacing(8) # Title title = QLabel(name) title.setStyleSheet(f"color: {EU_COLORS['text_muted']}; font-size: 11px;") layout.addWidget(title) # Value value = self.widget_data.get(widget_id, 0) if widget_id == 'ped_balance': value_text = f"{value:.2f} PED" elif widget_id == 'play_time': value_text = "2h 34m" # Placeholder elif widget_id == 'current_dpp': value_text = "3.45" else: value_text = str(value) value_label = QLabel(value_text) value_label.setStyleSheet(f""" color: {EU_COLORS['accent_orange']}; font-size: 24px; font-weight: bold; """) layout.addWidget(value_label) layout.addStretch() return card def _show_customize_dialog(self): """Show widget customization dialog.""" dialog = QDialog() dialog.setWindowTitle("Customize Dashboard") dialog.setStyleSheet(f""" QDialog {{ background-color: {EU_COLORS['bg_dark']}; color: white; }} QLabel {{ color: white; }} """) layout = QVBoxLayout(dialog) # Instructions info = QLabel("Check widgets to display on dashboard:") info.setStyleSheet(f"color: {EU_COLORS['text_secondary']};") layout.addWidget(info) # Widget list list_widget = QListWidget() list_widget.setStyleSheet(f""" QListWidget {{ background-color: {EU_COLORS['bg_secondary']}; color: white; border: 1px solid {EU_COLORS['border_subtle']}; }} QListWidget::item {{ padding: 10px; }} """) for widget_id, widget_info in self.AVAILABLE_WIDGETS.items(): item = QListWidgetItem(widget_info['name']) item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable) item.setCheckState( Qt.CheckState.Checked if widget_id in self.enabled_widgets else Qt.CheckState.Unchecked ) item.setData(Qt.ItemDataRole.UserRole, widget_id) list_widget.addItem(item) layout.addWidget(list_widget) # Buttons buttons = QDialogButtonBox( QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel ) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.DialogCode.Accepted: # Save selection self.enabled_widgets = [] for i in range(list_widget.count()): item = list_widget.item(i) if item.checkState() == Qt.CheckState.Checked: self.enabled_widgets.append(item.data(Qt.ItemDataRole.UserRole)) self._save_config() self._update_widgets()