EU-Utility/plugins/dashboard/plugin.py

327 lines
11 KiB
Python

"""
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_panel']};
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_panel']};
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_panel']};
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()