Auto-sync: 2026-02-16 21:15
This commit is contained in:
parent
08e8da0f4c
commit
0e5a7148fd
|
|
@ -1,229 +0,0 @@
|
||||||
# EU-Utility Bug Fix Report
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
This document details all bugs, errors, and issues fixed in the EU-Utility codebase during the bug hunting session.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fixed Issues
|
|
||||||
|
|
||||||
### 1. **Missing QAction Import in activity_bar.py**
|
|
||||||
**File:** `core/activity_bar.py`
|
|
||||||
**Line:** 5
|
|
||||||
**Issue:** `QAction` was used in `_show_context_menu()` method but not imported from `PyQt6.QtGui`.
|
|
||||||
**Fix:** Added `QAction` to the imports from `PyQt6.QtGui`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Before:
|
|
||||||
from PyQt6.QtGui import QMouseEvent, QPainter, QColor, QFont, QIcon, QPixmap
|
|
||||||
|
|
||||||
# After:
|
|
||||||
from PyQt6.QtGui import QMouseEvent, QPainter, QColor, QFont, QIcon, QPixmap, QAction
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. **Invalid QPropertyAnimation Property (windowOpacity) in perfect_ux.py**
|
|
||||||
**File:** `core/perfect_ux.py`
|
|
||||||
**Line:** 904-930
|
|
||||||
**Issue:** The `_animate_transition()` method used `b"windowOpacity"` as a property for QPropertyAnimation, but `windowOpacity` is not a valid animatable property on QWidget in Qt6. This would cause runtime errors when switching views.
|
|
||||||
**Fix:** Added `QGraphicsOpacityEffect` and modified the animation to animate the `opacity` property of the effect instead of the widget directly.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Before:
|
|
||||||
fade_out = QPropertyAnimation(current, b"windowOpacity")
|
|
||||||
|
|
||||||
# After:
|
|
||||||
current._opacity_effect = QGraphicsOpacityEffect(current)
|
|
||||||
current.setGraphicsEffect(current._opacity_effect)
|
|
||||||
fade_out = QPropertyAnimation(current._opacity_effect, b"opacity")
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. **Invalid QPropertyAnimation Property (windowOpacity) in overlay_window.py**
|
|
||||||
**File:** `core/overlay_window.py`
|
|
||||||
**Line:** 527-540
|
|
||||||
**Issue:** Same issue as above - `windowOpacity` property cannot be animated directly on QWidget in Qt6.
|
|
||||||
**Fix:** Created a `QGraphicsOpacityEffect` for the window and animated its `opacity` property.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. **Missing show()/hide() Methods in TrayIcon**
|
|
||||||
**File:** `core/tray_icon.py`
|
|
||||||
**Line:** 61-79
|
|
||||||
**Issue:** The `TrayIcon` class inherited from `QWidget` but didn't implement `show()` and `hide()` methods that delegate to the internal `QSystemTrayIcon`. Other code expected these methods to exist.
|
|
||||||
**Fix:** Added `show()`, `hide()`, and `isVisible()` methods that properly delegate to the internal tray icon.
|
|
||||||
|
|
||||||
```python
|
|
||||||
def show(self):
|
|
||||||
"""Show the tray icon."""
|
|
||||||
if self.tray_icon:
|
|
||||||
self.tray_icon.show()
|
|
||||||
|
|
||||||
def hide(self):
|
|
||||||
"""Hide the tray icon."""
|
|
||||||
if self.tray_icon:
|
|
||||||
self.tray_icon.hide()
|
|
||||||
|
|
||||||
def isVisible(self):
|
|
||||||
"""Check if tray icon is visible."""
|
|
||||||
return self.tray_icon.isVisible() if self.tray_icon else False
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. **Qt6 AA_EnableHighDpiScaling Deprecation Warning**
|
|
||||||
**File:** `core/main.py`
|
|
||||||
**Line:** 81-86
|
|
||||||
**Issue:** The `Qt.AA_EnableHighDpiScaling` attribute is deprecated in Qt6 and always enabled by default. While the existing code didn't cause errors due to the `hasattr` check, it was unnecessary.
|
|
||||||
**Fix:** Added proper try/except handling and comments explaining the Qt6 compatibility.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Enable high DPI scaling (Qt6 has this enabled by default)
|
|
||||||
# This block is kept for backwards compatibility with Qt5 if ever needed
|
|
||||||
if hasattr(Qt, 'AA_EnableHighDpiScaling'):
|
|
||||||
try:
|
|
||||||
self.app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
|
||||||
except (AttributeError, TypeError):
|
|
||||||
pass # Qt6+ doesn't need this
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 6. **Unsafe Attribute Access in Activity Bar**
|
|
||||||
**File:** `core/activity_bar.py`
|
|
||||||
**Lines:** Multiple locations
|
|
||||||
**Issue:** Various methods accessed `plugin_class.name`, `self.drawer`, and other attributes without checking if they exist first. This could cause `AttributeError` exceptions.
|
|
||||||
**Fix:** Added `getattr()` calls with default values throughout:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Before:
|
|
||||||
plugin_name = plugin_class.name
|
|
||||||
|
|
||||||
# After:
|
|
||||||
plugin_name = getattr(plugin_class, 'name', plugin_id)
|
|
||||||
```
|
|
||||||
|
|
||||||
Also added `hasattr()` checks for `self.drawer` before accessing it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 7. **Missing Error Handling in Activity Bar Initialization**
|
|
||||||
**File:** `core/main.py`
|
|
||||||
**Line:** 127-139
|
|
||||||
**Issue:** Activity Bar initialization was not wrapped in try/except, so any error during creation would crash the entire application.
|
|
||||||
**Fix:** Wrapped the activity bar creation and initialization in a try/except block with proper error messages.
|
|
||||||
|
|
||||||
```python
|
|
||||||
try:
|
|
||||||
from core.activity_bar import get_activity_bar
|
|
||||||
self.activity_bar = get_activity_bar(self.plugin_manager)
|
|
||||||
if self.activity_bar:
|
|
||||||
if self.activity_bar.config.enabled:
|
|
||||||
# ... setup code ...
|
|
||||||
else:
|
|
||||||
print("[Core] Activity Bar disabled in config")
|
|
||||||
else:
|
|
||||||
print("[Core] Activity Bar not available")
|
|
||||||
self.activity_bar = None
|
|
||||||
except Exception as e:
|
|
||||||
print(f"[Core] Failed to create Activity Bar: {e}")
|
|
||||||
self.activity_bar = None
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 8. **Missing Error Handling in EU Focus Detection**
|
|
||||||
**File:** `core/main.py`
|
|
||||||
**Line:** 405-450
|
|
||||||
**Issue:** The `_check_eu_focus()` method had unsafe attribute access and could fail if `window_manager` or `activity_bar` were not properly initialized.
|
|
||||||
**Fix:** Added comprehensive error handling with `hasattr()` checks and try/except blocks around all UI operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 9. **Unsafe Attribute Access in Plugin Manager**
|
|
||||||
**File:** `core/plugin_manager.py`
|
|
||||||
**Lines:** Multiple locations
|
|
||||||
**Issue:** Plugin loading code accessed `plugin_class.name` and `plugin_class.__name__` without checking if these attributes exist, and didn't handle cases where plugin classes might be malformed.
|
|
||||||
**Fix:** Added safe attribute access with `getattr()` and `hasattr()` checks throughout the plugin loading pipeline.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Before:
|
|
||||||
print(f"[PluginManager] Skipping disabled plugin: {plugin_class.name}")
|
|
||||||
|
|
||||||
# After:
|
|
||||||
plugin_name = getattr(plugin_class, 'name', plugin_class.__name__ if hasattr(plugin_class, '__name__') else 'Unknown')
|
|
||||||
print(f"[PluginManager] Skipping disabled plugin: {plugin_name}")
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 10. **Missing Error Handling in _toggle_activity_bar**
|
|
||||||
**File:** `core/main.py`
|
|
||||||
**Line:** 390-403
|
|
||||||
**Issue:** The `_toggle_activity_bar()` method didn't check if `activity_bar` and `tray_icon` exist before calling methods on them.
|
|
||||||
**Fix:** Added `hasattr()` checks and try/except blocks.
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _toggle_activity_bar(self):
|
|
||||||
if hasattr(self, 'activity_bar') and self.activity_bar:
|
|
||||||
try:
|
|
||||||
if self.activity_bar.isVisible():
|
|
||||||
self.activity_bar.hide()
|
|
||||||
if hasattr(self, 'tray_icon') and self.tray_icon:
|
|
||||||
self.tray_icon.set_activity_bar_checked(False)
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 11. **Missing Error Handling in Drawer Methods**
|
|
||||||
**File:** `core/activity_bar.py`
|
|
||||||
**Lines:** 269-275, 373-377
|
|
||||||
**Issue:** The `_toggle_drawer()` and `_on_drawer_item_clicked()` methods didn't have error handling for drawer operations.
|
|
||||||
**Fix:** Added try/except blocks with error logging.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Recommendations
|
|
||||||
|
|
||||||
After applying these fixes, test the following critical paths:
|
|
||||||
|
|
||||||
1. **App Startup**
|
|
||||||
- Launch the application
|
|
||||||
- Verify no import errors occur
|
|
||||||
- Check that the dashboard opens correctly
|
|
||||||
|
|
||||||
2. **Dashboard Navigation**
|
|
||||||
- Click through all navigation items (Dashboard, Plugins, Widgets, Settings)
|
|
||||||
- Verify view transitions work without errors
|
|
||||||
|
|
||||||
3. **Activity Bar**
|
|
||||||
- Toggle activity bar visibility from tray menu
|
|
||||||
- Click on pinned plugins
|
|
||||||
- Open the drawer and click on plugins
|
|
||||||
- Test auto-hide functionality
|
|
||||||
|
|
||||||
4. **Tray Icon**
|
|
||||||
- Right-click tray icon to open menu
|
|
||||||
- Click "Dashboard" to toggle visibility
|
|
||||||
- Click "Quit" to exit the application
|
|
||||||
|
|
||||||
5. **Plugin Loading**
|
|
||||||
- Enable/disable plugins
|
|
||||||
- Verify plugins load without errors
|
|
||||||
- Check plugin UI displays correctly
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
All identified bugs have been fixed. The codebase now has:
|
|
||||||
- ✅ Proper Qt6 imports
|
|
||||||
- ✅ Safe attribute access throughout
|
|
||||||
- ✅ Comprehensive error handling
|
|
||||||
- ✅ Graceful degradation when services are unavailable
|
|
||||||
- ✅ No runtime errors in critical paths
|
|
||||||
|
|
||||||
The application should now be stable and ready for use.
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
# EU-Utility Bug Fix Report
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
- **Total Plugins Checked:** 24
|
|
||||||
- **Core Files Checked:** 39
|
|
||||||
- **Syntax Errors Found:** 0
|
|
||||||
- **Bugs Fixed:** 0 (No bugs were found - codebase is clean!)
|
|
||||||
- **Windows Compatibility Issues:** 0 (Properly handled)
|
|
||||||
|
|
||||||
## Detailed Analysis
|
|
||||||
|
|
||||||
### ✅ Syntax Check Results
|
|
||||||
All Python files compile successfully without syntax errors:
|
|
||||||
- All 24 plugins parse correctly
|
|
||||||
- All 39 core modules parse correctly
|
|
||||||
- No `SyntaxError` or `IndentationError` issues found
|
|
||||||
|
|
||||||
### ✅ Import Analysis
|
|
||||||
All imports are properly structured:
|
|
||||||
- No circular import issues detected
|
|
||||||
- All cross-module imports resolve correctly
|
|
||||||
- Optional dependencies have proper fallback handling
|
|
||||||
|
|
||||||
### ✅ Windows Compatibility Check
|
|
||||||
|
|
||||||
#### fcntl Module Handling
|
|
||||||
The `fcntl` module (Unix-only) is properly handled in:
|
|
||||||
- `core/data_store.py` - Lines 15-22: Wrapped in try/except with portalocker fallback
|
|
||||||
- `core/data_store_secure.py` - Lines 16-25: Wrapped in try/except with portalocker fallback
|
|
||||||
|
|
||||||
Both files implement cross-platform file locking with graceful fallback to threading locks.
|
|
||||||
|
|
||||||
#### Windows-Specific Code
|
|
||||||
All Windows-specific code is properly guarded:
|
|
||||||
- `core/window_manager.py` - Uses `IS_WINDOWS` and `WINDOWS_AVAILABLE` flags (lines 15, 18-26)
|
|
||||||
- `core/screenshot.py` - `capture_window()` method checks `self._platform != "windows"` before using win32gui
|
|
||||||
- `core/screenshot_secure.py` - Same platform checking as screenshot.py
|
|
||||||
- `plugins/spotify_controller/plugin.py` - Uses `platform.system()` checks before Windows-specific code
|
|
||||||
|
|
||||||
### ✅ Plugin Loading Verification
|
|
||||||
All 24 plugins load without errors:
|
|
||||||
1. ✅ auction_tracker
|
|
||||||
2. ✅ calculator
|
|
||||||
3. ✅ chat_logger
|
|
||||||
4. ✅ codex_tracker
|
|
||||||
5. ✅ crafting_calc
|
|
||||||
6. ✅ dashboard
|
|
||||||
7. ✅ dpp_calculator
|
|
||||||
8. ✅ enhancer_calc
|
|
||||||
9. ✅ event_bus_example
|
|
||||||
10. ✅ game_reader
|
|
||||||
11. ✅ global_tracker
|
|
||||||
12. ✅ inventory_manager
|
|
||||||
13. ✅ loot_tracker
|
|
||||||
14. ✅ mining_helper
|
|
||||||
15. ✅ mission_tracker
|
|
||||||
16. ✅ nexus_search
|
|
||||||
17. ✅ plugin_store_ui
|
|
||||||
18. ✅ profession_scanner
|
|
||||||
19. ✅ session_exporter
|
|
||||||
20. ✅ settings
|
|
||||||
21. ✅ skill_scanner
|
|
||||||
22. ✅ spotify_controller
|
|
||||||
23. ✅ tp_runner
|
|
||||||
24. ✅ universal_search
|
|
||||||
|
|
||||||
### ✅ Core Services Verified
|
|
||||||
All core services properly implemented:
|
|
||||||
- `main.py` - Entry point with proper dependency checking
|
|
||||||
- `plugin_manager.py` - Plugin discovery and lifecycle management
|
|
||||||
- `plugin_api.py` - Cross-plugin communication API
|
|
||||||
- `event_bus.py` - Typed event system with filtering
|
|
||||||
- `window_manager.py` - Windows window management with Linux fallback
|
|
||||||
- `screenshot.py` - Cross-platform screenshot capture
|
|
||||||
- `ocr_service.py` - OCR with multiple backend support
|
|
||||||
- `log_reader.py` - Game log monitoring
|
|
||||||
- `nexus_api.py` - Entropia Nexus API client
|
|
||||||
- `http_client.py` - Cached HTTP client
|
|
||||||
- `audio.py` - Cross-platform audio playback
|
|
||||||
- `clipboard.py` - Clipboard manager
|
|
||||||
- `tasks.py` - Background task execution
|
|
||||||
- `data_store.py` - Persistent data storage
|
|
||||||
- `security_utils.py` - Input validation and sanitization
|
|
||||||
|
|
||||||
### ✅ Code Quality Observations
|
|
||||||
|
|
||||||
#### Positive Findings:
|
|
||||||
1. **Proper Exception Handling:** All optional dependencies use try/except blocks
|
|
||||||
2. **Platform Detection:** `sys.platform` and `platform.system()` used correctly
|
|
||||||
3. **Singleton Pattern:** Properly implemented with thread-safety
|
|
||||||
4. **Type Hints:** Good use of type annotations throughout
|
|
||||||
5. **Documentation:** Comprehensive docstrings in all modules
|
|
||||||
|
|
||||||
#### Security Considerations (Already Implemented):
|
|
||||||
1. **Path Traversal Protection:** `data_store_secure.py` validates paths
|
|
||||||
2. **Input Sanitization:** `security_utils.py` provides validation functions
|
|
||||||
3. **Safe File Operations:** Atomic writes with temp files
|
|
||||||
|
|
||||||
## Files Noted but Not Issues:
|
|
||||||
|
|
||||||
### Vulnerable Test Files (Not Used in Production):
|
|
||||||
- `core/screenshot_vulnerable.py` - Not imported by any production code
|
|
||||||
- `core/data_store_vulnerable.py` - Not imported by any production code
|
|
||||||
|
|
||||||
These appear to be intentionally vulnerable versions for security testing/education.
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
**The EU-Utility codebase is well-structured and bug-free.** All potential issues that were checked for:
|
|
||||||
- ❌ Syntax errors - None found
|
|
||||||
- ❌ Missing imports - None found
|
|
||||||
- ❌ Undefined variables - None found
|
|
||||||
- ❌ Windows compatibility issues - Properly handled
|
|
||||||
- ❌ fcntl/Unix-specific problems - Properly guarded
|
|
||||||
- ❌ Plugin loading failures - All 24 plugins load correctly
|
|
||||||
|
|
||||||
The codebase demonstrates good software engineering practices with proper error handling, cross-platform compatibility, and clean architecture.
|
|
||||||
164
CHANGELOG.md
164
CHANGELOG.md
|
|
@ -7,46 +7,97 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Comprehensive documentation overhaul with new API.md and ARCHITECTURE.md
|
||||||
|
- Consolidated plugin development guides into single reference
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [2.1.0] - 2026-02-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Enhanced Dashboard Widgets** - Modular, draggable widgets with real-time data
|
||||||
|
- SystemStatusWidget - Monitor CPU, RAM, Disk usage
|
||||||
|
- QuickActionsWidget - One-click access to common actions
|
||||||
|
- RecentActivityWidget - Display recent system and plugin activity
|
||||||
|
- PluginGridWidget - Visual plugin status display
|
||||||
|
- **Activity Bar** - Windows 11-style taskbar with pinned plugins
|
||||||
|
- Start button with app drawer
|
||||||
|
- Drag-to-pin functionality
|
||||||
|
- Search box for quick plugin access
|
||||||
|
- Configurable auto-hide and position (top/bottom)
|
||||||
|
- **Plugin Store UI** - Browse, install, and manage community plugins
|
||||||
|
- **Widget Gallery** - Interface for adding and configuring dashboard widgets
|
||||||
|
- **SQLite Data Layer** - Thread-safe persistent storage for settings and states
|
||||||
|
- **Enhanced Settings Panel** - Full-featured settings with 6 organized tabs
|
||||||
|
- General settings
|
||||||
|
- Appearance (themes, colors, opacity)
|
||||||
|
- Plugin management
|
||||||
|
- Hotkey configuration
|
||||||
|
- Data & backup
|
||||||
|
- About section
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Improved UI responsiveness with animation batching
|
||||||
|
- Enhanced plugin loading with caching and error recovery
|
||||||
|
- Better error messages throughout the application
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Plugin loading race conditions during startup
|
||||||
|
- Memory leaks in overlay system
|
||||||
|
- Hotkey conflicts with some applications
|
||||||
|
- Settings persistence issues
|
||||||
|
- Activity bar visibility on multi-monitor setups
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Added path traversal protection in data store
|
||||||
|
- Secure file permissions for sensitive data
|
||||||
|
- Improved input sanitization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [2.0.0] - 2025-02-14
|
## [2.0.0] - 2025-02-14
|
||||||
|
|
||||||
### 🎉 Major Release
|
### 🎉 Major Release
|
||||||
|
|
||||||
This is a major release introducing the enhanced plugin architecture, improved UI, and comprehensive documentation.
|
This is a major release introducing the enhanced plugin architecture, improved UI, and comprehensive documentation.
|
||||||
|
|
||||||
### ✨ Added
|
### Added
|
||||||
|
|
||||||
#### Core Enhancements
|
#### Core Enhancements
|
||||||
- **Enhanced Plugin Manager** - Optimized plugin loading with caching and error recovery
|
- **Three-Tier API System** - PluginAPI, WidgetAPI, and ExternalAPI
|
||||||
- **Event Bus System** - Typed event system with filtering and persistence
|
- **Typed Event Bus** - Type-safe event system with filtering and persistence
|
||||||
- **Task Manager** - Thread pool-based background task execution
|
- **Task Manager** - Thread pool-based background task execution
|
||||||
- **Secure Data Store** - Encrypted data storage for sensitive information
|
- **Secure Data Store** - Encrypted data storage for sensitive information
|
||||||
- **Performance Optimizations** - Caching, lazy loading, and resource pooling
|
- **Performance Optimizations** - Caching, lazy loading, and resource pooling
|
||||||
- **UI Optimizations** - Responsive design, animation batching, style caching
|
- **UI Optimizations** - Responsive design, animation batching, style caching
|
||||||
- **Icon Manager** - Unified icon system with caching and scaling
|
- **Icon Manager** - Unified icon system with caching and scaling
|
||||||
|
|
||||||
#### New Plugins
|
#### New Plugins (25 Total)
|
||||||
- **Auction Tracker** - Track prices, markups, and market trends
|
|
||||||
- **Chat Logger** - Log, search, and filter chat messages with advanced features
|
|
||||||
- **Codex Tracker** - Track creature challenges and codex progress
|
|
||||||
- **Crafting Calculator** - Calculate crafting success rates and material costs
|
|
||||||
- **Dashboard** - Customizable start page with avatar statistics
|
- **Dashboard** - Customizable start page with avatar statistics
|
||||||
- **DPP Calculator** - Calculate Damage Per PEC and weapon efficiency
|
|
||||||
- **Enhancer Calculator** - Calculate enhancer break rates and costs
|
|
||||||
- **Event Bus Example** - Demonstrates Enhanced Event Bus features
|
|
||||||
- **Game Reader** - OCR scanner for in-game menus and text
|
|
||||||
- **Global Tracker** - Track globals, HOFs, and ATHs
|
|
||||||
- **Inventory Manager** - Track items, TT value, and weight
|
|
||||||
- **Loot Tracker** - Track hunting loot with stats and ROI analysis
|
|
||||||
- **Mining Helper** - Track mining finds, claims, and hotspots
|
|
||||||
- **Mission Tracker** - Track missions, challenges, and objectives
|
|
||||||
- **Nexus Search** - Search items, users, and market data via Nexus API
|
|
||||||
- **Plugin Store UI** - Community plugin marketplace interface
|
|
||||||
- **Profession Scanner** - Track profession ranks and progress
|
|
||||||
- **Settings** - Configure EU-Utility preferences
|
|
||||||
- **Skill Scanner** - Uses core OCR and Log services for skill tracking
|
|
||||||
- **Spotify Controller** - Control Spotify and view current track info
|
|
||||||
- **TP Runner** - Teleporter locations and route planner
|
|
||||||
- **Universal Search** - Search items, mobs, locations, blueprints, and more
|
- **Universal Search** - Search items, mobs, locations, blueprints, and more
|
||||||
|
- **Nexus Search** - Search items and market data via Nexus API
|
||||||
|
- **DPP Calculator** - Calculate Damage Per PEC and weapon efficiency
|
||||||
|
- **Crafting Calculator** - Calculate crafting success rates and material costs
|
||||||
|
- **Enhancer Calculator** - Calculate enhancer break rates and costs
|
||||||
|
- **Loot Tracker** - Track hunting loot with stats and ROI analysis
|
||||||
|
- **Skill Scanner** - OCR-based skill tracking
|
||||||
|
- **Codex Tracker** - Track creature challenges and codex progress
|
||||||
|
- **Mission Tracker** - Track missions, challenges, and objectives
|
||||||
|
- **Global Tracker** - Track globals, HOFs, and ATHs
|
||||||
|
- **Mining Helper** - Track mining finds, claims, and hotspots
|
||||||
|
- **Auction Tracker** - Track prices, markups, and market trends
|
||||||
|
- **Inventory Manager** - Track items, TT value, and weight
|
||||||
|
- **Profession Scanner** - Track profession ranks and progress
|
||||||
|
- **Game Reader** - OCR scanner for in-game menus and text
|
||||||
|
- **Chat Logger** - Log, search, and filter chat messages
|
||||||
|
- **TP Runner** - Teleporter locations and route planner
|
||||||
|
- **Spotify Controller** - Control Spotify and view current track info
|
||||||
|
- **Settings** - Configure EU-Utility preferences
|
||||||
|
- **Plugin Store UI** - Community plugin marketplace interface
|
||||||
|
- **Event Bus Example** - Demonstrates Enhanced Event Bus features
|
||||||
|
|
||||||
#### API & Services
|
#### API & Services
|
||||||
- **Nexus API Integration** - Full integration with Entropia Nexus API
|
- **Nexus API Integration** - Full integration with Entropia Nexus API
|
||||||
|
|
@ -94,24 +145,21 @@ This is a major release introducing the enhanced plugin architecture, improved U
|
||||||
- **Security Hardening Guide** - Security best practices
|
- **Security Hardening Guide** - Security best practices
|
||||||
- **Nexus API Reference** - Nexus integration documentation
|
- **Nexus API Reference** - Nexus integration documentation
|
||||||
|
|
||||||
### 🔧 Changed
|
### Changed
|
||||||
|
|
||||||
- **Plugin Architecture** - Complete rewrite for better modularity
|
- **Plugin Architecture** - Complete rewrite for better modularity
|
||||||
- **BasePlugin API** - Enhanced with more convenience methods
|
- **BasePlugin API** - Enhanced with more convenience methods
|
||||||
- **Settings System** - More robust with encryption support
|
- **Settings System** - More robust with encryption support
|
||||||
- **Data Store** - Improved with backup and recovery
|
- **Data Store** - Improved with backup and recovery
|
||||||
- **Hotkey System** - More reliable global hotkey handling
|
- **Hotkey System** - More reliable global hotkey handling
|
||||||
|
|
||||||
### ⚡ Improved
|
### Improved
|
||||||
|
|
||||||
- **Startup Time** - Faster plugin loading with caching
|
- **Startup Time** - Faster plugin loading with caching
|
||||||
- **Memory Usage** - Optimized resource management
|
- **Memory Usage** - Optimized resource management
|
||||||
- **UI Responsiveness** - Smoother interface interactions
|
- **UI Responsiveness** - Smoother interface interactions
|
||||||
- **Error Handling** - Better error reporting and recovery
|
- **Error Handling** - Better error reporting and recovery
|
||||||
- **Plugin Isolation** - Improved crash isolation between plugins
|
- **Plugin Isolation** - Improved crash isolation between plugins
|
||||||
|
|
||||||
### 🐛 Fixed
|
### Fixed
|
||||||
|
|
||||||
- Plugin loading race conditions
|
- Plugin loading race conditions
|
||||||
- Memory leaks in overlay system
|
- Memory leaks in overlay system
|
||||||
- Hotkey conflicts with other applications
|
- Hotkey conflicts with other applications
|
||||||
|
|
@ -119,29 +167,35 @@ This is a major release introducing the enhanced plugin architecture, improved U
|
||||||
- Data corruption during concurrent writes
|
- Data corruption during concurrent writes
|
||||||
- Settings not persisting properly
|
- Settings not persisting properly
|
||||||
|
|
||||||
### 🔒 Security
|
### Security
|
||||||
|
|
||||||
- Added data encryption for sensitive settings
|
- Added data encryption for sensitive settings
|
||||||
- Implemented secure file permissions
|
- Implemented secure file permissions
|
||||||
- Added input sanitization
|
- Added input sanitization
|
||||||
- Secure temporary file handling
|
- Secure temporary file handling
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Legacy plugin API (replaced with new three-tier system)
|
||||||
|
- Old settings storage format (migrated to encrypted storage)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## [1.1.0] - 2025-01-15
|
## [1.1.0] - 2025-01-15
|
||||||
|
|
||||||
### ✨ Added
|
### Added
|
||||||
- Spotify controller plugin
|
- Spotify controller plugin
|
||||||
- Skill scanner with OCR
|
- Skill scanner with OCR support
|
||||||
- Basic loot tracking
|
- Basic loot tracking functionality
|
||||||
|
- Nexus search integration improvements
|
||||||
|
|
||||||
### 🔧 Changed
|
### Changed
|
||||||
- Improved overlay styling
|
- Improved overlay styling with new theme
|
||||||
- Better error messages
|
- Better error messages throughout
|
||||||
|
- Enhanced calculator precision
|
||||||
|
|
||||||
### 🐛 Fixed
|
### Fixed
|
||||||
- Hotkey registration on Windows 11
|
- Hotkey registration on Windows 11
|
||||||
- Memory leak in screenshot service
|
- Memory leak in screenshot service
|
||||||
|
- Window detection edge cases
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -151,36 +205,39 @@ This is a major release introducing the enhanced plugin architecture, improved U
|
||||||
|
|
||||||
First public release of EU-Utility.
|
First public release of EU-Utility.
|
||||||
|
|
||||||
### ✨ Added
|
### Added
|
||||||
- Basic plugin system
|
- Basic plugin system with BasePlugin class
|
||||||
- Nexus search integration
|
- Nexus search integration
|
||||||
- DPP calculator
|
- DPP calculator
|
||||||
- Simple overlay UI
|
- Simple overlay UI
|
||||||
- Global hotkey support
|
- Global hotkey support
|
||||||
|
- Floating icon for quick access
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Release Notes Template
|
## Release Notes Template
|
||||||
|
|
||||||
|
When creating a new release, use this template:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## [X.Y.Z] - YYYY-MM-DD
|
## [X.Y.Z] - YYYY-MM-DD
|
||||||
|
|
||||||
### ✨ Added
|
### Added
|
||||||
- New features
|
- New features
|
||||||
|
|
||||||
### 🔧 Changed
|
### Changed
|
||||||
- Changes to existing functionality
|
- Changes to existing functionality
|
||||||
|
|
||||||
### 🗑️ Deprecated
|
### Deprecated
|
||||||
- Soon-to-be removed features
|
- Soon-to-be removed features
|
||||||
|
|
||||||
### 🗑️ Removed
|
### Removed
|
||||||
- Now removed features
|
- Now removed features
|
||||||
|
|
||||||
### 🐛 Fixed
|
### Fixed
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
|
|
||||||
### 🔒 Security
|
### Security
|
||||||
- Security improvements
|
- Security improvements
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -188,29 +245,32 @@ First public release of EU-Utility.
|
||||||
|
|
||||||
## Future Roadmap
|
## Future Roadmap
|
||||||
|
|
||||||
### Planned for 2.1.0
|
### Planned for 2.2.0
|
||||||
- [ ] Discord Rich Presence integration
|
- [ ] Discord Rich Presence integration
|
||||||
- [ ] Advanced crafting calculator with blueprint data
|
- [ ] Advanced crafting calculator with blueprint data
|
||||||
- [ ] Hunting efficiency analyzer
|
- [ ] Hunting efficiency analyzer
|
||||||
- [ ] Export to spreadsheet functionality
|
- [ ] Export to spreadsheet functionality
|
||||||
- [ ] Plugin auto-updater
|
- [ ] Plugin auto-updater
|
||||||
|
- [ ] Dark/Light theme toggle
|
||||||
|
|
||||||
### Planned for 2.2.0
|
### Planned for 2.3.0
|
||||||
- [ ] Web-based dashboard
|
- [ ] Web-based dashboard
|
||||||
- [ ] Mobile companion app
|
|
||||||
- [ ] Cloud sync for settings
|
- [ ] Cloud sync for settings
|
||||||
- [ ] Advanced analytics
|
- [ ] Advanced analytics
|
||||||
- [ ] Community plugin repository
|
- [ ] Community plugin repository
|
||||||
|
- [ ] Multi-language support
|
||||||
|
|
||||||
### Planned for 3.0.0
|
### Planned for 3.0.0
|
||||||
- [ ] Full plugin SDK
|
- [ ] Full plugin SDK
|
||||||
- [ ] Plugin marketplace
|
- [ ] Plugin marketplace
|
||||||
- [ ] Theme system
|
- [ ] Theme system with custom CSS
|
||||||
- [ ] Scripting support
|
- [ ] Scripting support (Python/Lua)
|
||||||
- [ ] Multi-account support
|
- [ ] Multi-account support
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/ImpulsiveFPS/EU-Utility/compare/v2.1.0...HEAD
|
||||||
|
[2.1.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v2.1.0
|
||||||
[2.0.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v2.0.0
|
[2.0.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v2.0.0
|
||||||
[1.1.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v1.1.0
|
[1.1.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v1.1.0
|
||||||
[1.0.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v1.0.0
|
[1.0.0]: https://github.com/ImpulsiveFPS/EU-Utility/releases/tag/v1.0.0
|
||||||
|
|
|
||||||
|
|
@ -1,197 +0,0 @@
|
||||||
# EU-Utility Code Cleanup Summary
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This document summarizes the code cleanup and refactoring performed on the EU-Utility codebase to improve code quality, maintainability, and type safety.
|
|
||||||
|
|
||||||
## Changes Made
|
|
||||||
|
|
||||||
### 1. Core Module (`core/`)
|
|
||||||
|
|
||||||
#### `__init__.py`
|
|
||||||
- Added comprehensive module-level docstring
|
|
||||||
- Updated exports with proper type annotations
|
|
||||||
- Added version constants (VERSION, API_VERSION)
|
|
||||||
- Organized imports by category
|
|
||||||
|
|
||||||
#### `base_plugin.py`
|
|
||||||
- Added comprehensive docstrings to all methods
|
|
||||||
- Added type hints to all methods and attributes
|
|
||||||
- Fixed return type annotations
|
|
||||||
- Improved method documentation with Args/Returns/Examples
|
|
||||||
- Maintained backward compatibility
|
|
||||||
|
|
||||||
#### `event_bus.py`
|
|
||||||
- Added module-level docstring with usage examples
|
|
||||||
- Added type hints to all classes and methods
|
|
||||||
- Fixed generic type annotations (TypeVar usage)
|
|
||||||
- Documented all event types with attributes
|
|
||||||
- Added comprehensive class and method docstrings
|
|
||||||
|
|
||||||
#### `settings.py`
|
|
||||||
- Added module-level documentation
|
|
||||||
- Added type hints throughout
|
|
||||||
- Added proper handling for Qt/non-Qt environments
|
|
||||||
- Documented all methods with Args/Returns
|
|
||||||
- Added DEFAULTS constant documentation
|
|
||||||
|
|
||||||
### 2. Plugin API (`core/api/`)
|
|
||||||
|
|
||||||
#### `__init__.py`
|
|
||||||
- Added comprehensive package documentation
|
|
||||||
- Organized exports by API tier
|
|
||||||
- Added version information
|
|
||||||
- Documented the three-tier API architecture
|
|
||||||
|
|
||||||
#### `plugin_api.py`
|
|
||||||
- Already well-documented
|
|
||||||
- Maintained backward compatibility
|
|
||||||
- Added to __all__ exports
|
|
||||||
|
|
||||||
### 3. Plugins Package (`plugins/`)
|
|
||||||
|
|
||||||
#### `__init__.py`
|
|
||||||
- Added comprehensive docstring
|
|
||||||
- Documented plugin structure
|
|
||||||
- Added usage example
|
|
||||||
- Linked to documentation
|
|
||||||
|
|
||||||
#### `base_plugin.py`
|
|
||||||
- Simplified to re-export only
|
|
||||||
- Added deprecation note for preferring core import
|
|
||||||
|
|
||||||
### 4. Documentation
|
|
||||||
|
|
||||||
#### `core/README.md` (New)
|
|
||||||
- Created comprehensive module documentation
|
|
||||||
- Documented module structure
|
|
||||||
- Added usage examples for all key components
|
|
||||||
- Created service architecture overview
|
|
||||||
- Added best practices section
|
|
||||||
- Included version history
|
|
||||||
|
|
||||||
## Code Quality Improvements
|
|
||||||
|
|
||||||
### Type Hints
|
|
||||||
- Added to all public methods
|
|
||||||
- Used proper generic types where appropriate
|
|
||||||
- Fixed Optional[] annotations
|
|
||||||
- Added return type annotations
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
- All modules have comprehensive docstrings
|
|
||||||
- All public methods documented with Args/Returns/Examples
|
|
||||||
- Added module-level usage examples
|
|
||||||
- Created README for core module
|
|
||||||
|
|
||||||
### Organization
|
|
||||||
- Consistent file structure
|
|
||||||
- Clear separation of concerns
|
|
||||||
- Proper import organization
|
|
||||||
- Removed dead code paths
|
|
||||||
|
|
||||||
### Standards Compliance
|
|
||||||
- PEP 8 formatting throughout
|
|
||||||
- Consistent naming conventions (snake_case)
|
|
||||||
- Proper import ordering (stdlib, third-party, local)
|
|
||||||
- Type-safe default values
|
|
||||||
|
|
||||||
## Backward Compatibility
|
|
||||||
|
|
||||||
All changes maintain full backward compatibility:
|
|
||||||
- No public API changes
|
|
||||||
- Existing plugins continue to work
|
|
||||||
- Re-exports maintained for compatibility
|
|
||||||
- Deprecation notes added where appropriate
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### Core Module
|
|
||||||
- `core/__init__.py` - Updated exports and documentation
|
|
||||||
- `core/base_plugin.py` - Added type hints and docs
|
|
||||||
- `core/event_bus.py` - Added type hints and docs
|
|
||||||
- `core/settings.py` - Added type hints and docs
|
|
||||||
|
|
||||||
### API Module
|
|
||||||
- `core/api/__init__.py` - Added documentation
|
|
||||||
|
|
||||||
### Plugin Package
|
|
||||||
- `plugins/__init__.py` - Added documentation
|
|
||||||
- `plugins/base_plugin.py` - Simplified re-export
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
- `core/README.md` - Created comprehensive guide
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
To verify the cleanup:
|
|
||||||
|
|
||||||
1. **Type checking** (if mypy available):
|
|
||||||
```bash
|
|
||||||
mypy core/ plugins/
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Import tests**:
|
|
||||||
```python
|
|
||||||
from core import get_event_bus, get_nexus_api
|
|
||||||
from core.base_plugin import BasePlugin
|
|
||||||
from core.api import get_api
|
|
||||||
from plugins import BasePlugin as PluginBase
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Documentation generation**:
|
|
||||||
```bash
|
|
||||||
pydoc core.base_plugin
|
|
||||||
pydoc core.event_bus
|
|
||||||
pydoc core.settings
|
|
||||||
```
|
|
||||||
|
|
||||||
## Recommendations for Future Work
|
|
||||||
|
|
||||||
1. **Add more type hints** to remaining core modules:
|
|
||||||
- `nexus_api.py`
|
|
||||||
- `http_client.py`
|
|
||||||
- `data_store.py`
|
|
||||||
- `log_reader.py`
|
|
||||||
|
|
||||||
2. **Create tests** for core functionality:
|
|
||||||
- Unit tests for EventBus
|
|
||||||
- Unit tests for Settings
|
|
||||||
- Mock tests for BasePlugin
|
|
||||||
|
|
||||||
3. **Add more documentation**:
|
|
||||||
- API usage guides
|
|
||||||
- Plugin development tutorials
|
|
||||||
- Architecture decision records
|
|
||||||
|
|
||||||
4. **Code cleanup** for remaining modules:
|
|
||||||
- Consolidate duplicate code
|
|
||||||
- Remove unused imports
|
|
||||||
- Optimize performance where needed
|
|
||||||
|
|
||||||
## Performance Notes
|
|
||||||
|
|
||||||
The cleanup focused on documentation and type safety without affecting runtime performance:
|
|
||||||
- No algorithmic changes
|
|
||||||
- Type hints are ignored at runtime
|
|
||||||
- Import structure maintained for lazy loading
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
- No security-sensitive code was modified
|
|
||||||
- Input validation preserved
|
|
||||||
- Security utilities in `security_utils.py` not affected
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
The codebase is now:
|
|
||||||
- ✅ Better documented with comprehensive docstrings
|
|
||||||
- ✅ Type-hinted for better IDE support and type checking
|
|
||||||
- ✅ Organized with clear module structure
|
|
||||||
- ✅ Standards-compliant (PEP 8)
|
|
||||||
- ✅ Fully backward compatible
|
|
||||||
- ✅ Ready for future development
|
|
||||||
|
|
||||||
Total files modified: 8
|
|
||||||
Lines of documentation added: ~500+
|
|
||||||
Type hints added: ~200+
|
|
||||||
|
|
@ -1,442 +0,0 @@
|
||||||
# EU-Utility Core Functionality
|
|
||||||
|
|
||||||
This document describes the core functionality implemented for EU-Utility v2.1.0.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The core functionality provides a complete, working foundation for EU-Utility including:
|
|
||||||
|
|
||||||
1. **Dashboard Widgets** - Modular, draggable widgets with real-time data
|
|
||||||
2. **Widget Gallery** - Interface for adding and configuring widgets
|
|
||||||
3. **Plugin Store** - Browse, install, and manage plugins
|
|
||||||
4. **Settings Panel** - Full-featured settings with persistence
|
|
||||||
5. **Activity Bar** - Windows 11-style taskbar with pinned plugins
|
|
||||||
6. **Data Layer** - SQLite-based persistent storage
|
|
||||||
|
|
||||||
## 1. Dashboard Widgets
|
|
||||||
|
|
||||||
### Implemented Widgets
|
|
||||||
|
|
||||||
#### SystemStatusWidget
|
|
||||||
- **Purpose**: Monitor system resources (CPU, RAM, Disk)
|
|
||||||
- **Features**:
|
|
||||||
- Real-time resource monitoring via `psutil`
|
|
||||||
- Service status indicators
|
|
||||||
- Auto-updating progress bars
|
|
||||||
- Configurable update intervals
|
|
||||||
- **Size**: 2 columns x 1 row
|
|
||||||
- **Persistence**: Settings saved to SQLite
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import SystemStatusWidget
|
|
||||||
|
|
||||||
widget = SystemStatusWidget(parent)
|
|
||||||
widget.set_service("Overlay", True) # Update service status
|
|
||||||
```
|
|
||||||
|
|
||||||
#### QuickActionsWidget
|
|
||||||
- **Purpose**: One-click access to common actions
|
|
||||||
- **Features**:
|
|
||||||
- Configurable action buttons
|
|
||||||
- Icon support via icon_manager
|
|
||||||
- Action signal emission
|
|
||||||
- Activity logging
|
|
||||||
- **Size**: 2 columns x 1 row
|
|
||||||
- **Default Actions**: Search, Screenshot, Settings, Plugins
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import QuickActionsWidget
|
|
||||||
|
|
||||||
widget = QuickActionsWidget(parent)
|
|
||||||
widget.set_actions([
|
|
||||||
{'id': 'custom', 'name': 'Custom Action', 'icon': 'star'},
|
|
||||||
])
|
|
||||||
widget.action_triggered.connect(handle_action)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### RecentActivityWidget
|
|
||||||
- **Purpose**: Display recent system and plugin activity
|
|
||||||
- **Features**:
|
|
||||||
- Auto-refresh from SQLite activity log
|
|
||||||
- Timestamp display
|
|
||||||
- Category icons
|
|
||||||
- Scrollable list
|
|
||||||
- **Size**: 1 column x 2 rows
|
|
||||||
- **Data Source**: `activity_log` table in SQLite
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import RecentActivityWidget
|
|
||||||
|
|
||||||
widget = RecentActivityWidget(parent)
|
|
||||||
# Auto-refreshes every 5 seconds
|
|
||||||
```
|
|
||||||
|
|
||||||
#### PluginGridWidget
|
|
||||||
- **Purpose**: Display installed plugins with status
|
|
||||||
- **Features**:
|
|
||||||
- Real-time plugin status
|
|
||||||
- Click to select
|
|
||||||
- Loaded/enabled indicators
|
|
||||||
- Scrollable grid layout
|
|
||||||
- **Size**: 2 columns x 2 rows
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import PluginGridWidget
|
|
||||||
|
|
||||||
widget = PluginGridWidget(plugin_manager, parent)
|
|
||||||
widget.plugin_clicked.connect(on_plugin_selected)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget Base Class
|
|
||||||
|
|
||||||
All widgets inherit from `DashboardWidget`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
class DashboardWidget(QFrame):
|
|
||||||
name = "Widget"
|
|
||||||
description = "Base widget"
|
|
||||||
icon_name = "target"
|
|
||||||
size = (1, 1) # (cols, rows)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. Widget Gallery
|
|
||||||
|
|
||||||
### WidgetGallery
|
|
||||||
|
|
||||||
A popup gallery for browsing and adding widgets:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import WidgetGallery
|
|
||||||
|
|
||||||
gallery = WidgetGallery(parent)
|
|
||||||
gallery.widget_added.connect(on_widget_added)
|
|
||||||
gallery.show()
|
|
||||||
```
|
|
||||||
|
|
||||||
### DashboardWidgetManager
|
|
||||||
|
|
||||||
Manages widget layout and persistence:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.widgets import DashboardWidgetManager
|
|
||||||
|
|
||||||
manager = DashboardWidgetManager(plugin_manager, parent)
|
|
||||||
manager.widget_created.connect(on_widget_created)
|
|
||||||
|
|
||||||
# Add widget
|
|
||||||
manager.add_widget('system_status', 'widget_1', {
|
|
||||||
'position': {'row': 0, 'col': 0},
|
|
||||||
'size': {'width': 2, 'height': 1}
|
|
||||||
})
|
|
||||||
|
|
||||||
# Widget configurations are automatically saved to SQLite
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. Plugin Store
|
|
||||||
|
|
||||||
### PluginStoreUI
|
|
||||||
|
|
||||||
Complete plugin store interface:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.plugin_store import PluginStoreUI
|
|
||||||
|
|
||||||
store = PluginStoreUI(plugin_manager, parent)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Browse available plugins from repository
|
|
||||||
- Category filtering
|
|
||||||
- Search functionality
|
|
||||||
- Dependency resolution
|
|
||||||
- Install/uninstall with confirmation
|
|
||||||
- Enable/disable installed plugins
|
|
||||||
|
|
||||||
**Implementation Details**:
|
|
||||||
- Fetches manifest from remote repository
|
|
||||||
- Downloads plugins via raw file access
|
|
||||||
- Stores plugins in `plugins/` directory
|
|
||||||
- Tracks installed/enabled state in SQLite
|
|
||||||
|
|
||||||
## 4. Settings Panel
|
|
||||||
|
|
||||||
### EnhancedSettingsPanel
|
|
||||||
|
|
||||||
Full-featured settings with SQLite persistence:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.ui.settings_panel import EnhancedSettingsPanel
|
|
||||||
|
|
||||||
settings = EnhancedSettingsPanel(overlay_window, parent)
|
|
||||||
settings.settings_changed.connect(on_setting_changed)
|
|
||||||
settings.theme_changed.connect(on_theme_changed)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tabs**:
|
|
||||||
1. **General**: Startup options, behavior settings, performance
|
|
||||||
2. **Appearance**: Theme selection, accent colors, opacity
|
|
||||||
3. **Plugins**: Enable/disable plugins, access plugin store
|
|
||||||
4. **Hotkeys**: Configure keyboard shortcuts
|
|
||||||
5. **Data & Backup**: Export/import, statistics, maintenance
|
|
||||||
6. **About**: Version info, system details, links
|
|
||||||
|
|
||||||
**Persistence**:
|
|
||||||
- All settings saved to SQLite via `user_preferences` table
|
|
||||||
- Hotkeys stored in `hotkeys` table
|
|
||||||
- Changes logged to `activity_log`
|
|
||||||
|
|
||||||
## 5. Activity Bar
|
|
||||||
|
|
||||||
### EnhancedActivityBar
|
|
||||||
|
|
||||||
Windows 11-style taskbar:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.activity_bar_enhanced import EnhancedActivityBar
|
|
||||||
|
|
||||||
bar = EnhancedActivityBar(plugin_manager, parent)
|
|
||||||
bar.plugin_requested.connect(on_plugin_requested)
|
|
||||||
bar.search_requested.connect(on_search)
|
|
||||||
bar.settings_requested.connect(show_settings)
|
|
||||||
bar.show()
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- **Start Button**: Opens app drawer
|
|
||||||
- **Search Box**: Quick plugin search
|
|
||||||
- **Pinned Plugins**: Drag-to-pin from app drawer
|
|
||||||
- **Clock**: Auto-updating time display
|
|
||||||
- **Settings Button**: Quick access to settings
|
|
||||||
- **Auto-hide**: Configurable auto-hide behavior
|
|
||||||
- **Position**: Top or bottom screen position
|
|
||||||
|
|
||||||
### AppDrawer
|
|
||||||
|
|
||||||
Start menu-style plugin launcher:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.activity_bar_enhanced import AppDrawer
|
|
||||||
|
|
||||||
drawer = AppDrawer(plugin_manager, parent)
|
|
||||||
drawer.plugin_launched.connect(on_plugin_launch)
|
|
||||||
drawer.plugin_pin_requested.connect(pin_plugin)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Grid of all plugins
|
|
||||||
- Real-time search filtering
|
|
||||||
- Context menu for pinning
|
|
||||||
- Frosted glass styling
|
|
||||||
|
|
||||||
## 6. Data Layer (SQLite)
|
|
||||||
|
|
||||||
### SQLiteDataStore
|
|
||||||
|
|
||||||
Thread-safe persistent storage:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from core.data import get_sqlite_store
|
|
||||||
|
|
||||||
store = get_sqlite_store()
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tables
|
|
||||||
|
|
||||||
#### plugin_states
|
|
||||||
```sql
|
|
||||||
CREATE TABLE plugin_states (
|
|
||||||
plugin_id TEXT PRIMARY KEY,
|
|
||||||
enabled INTEGER DEFAULT 0,
|
|
||||||
version TEXT,
|
|
||||||
settings TEXT, -- JSON
|
|
||||||
last_loaded TEXT,
|
|
||||||
load_count INTEGER DEFAULT 0,
|
|
||||||
error_count INTEGER DEFAULT 0,
|
|
||||||
created_at TEXT,
|
|
||||||
updated_at TEXT
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### user_preferences
|
|
||||||
```sql
|
|
||||||
CREATE TABLE user_preferences (
|
|
||||||
key TEXT PRIMARY KEY,
|
|
||||||
value TEXT, -- JSON
|
|
||||||
category TEXT DEFAULT 'general',
|
|
||||||
updated_at TEXT
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### sessions
|
|
||||||
```sql
|
|
||||||
CREATE TABLE sessions (
|
|
||||||
session_id TEXT PRIMARY KEY,
|
|
||||||
started_at TEXT,
|
|
||||||
ended_at TEXT,
|
|
||||||
plugin_stats TEXT, -- JSON
|
|
||||||
system_info TEXT -- JSON
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### activity_log
|
|
||||||
```sql
|
|
||||||
CREATE TABLE activity_log (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
category TEXT,
|
|
||||||
action TEXT,
|
|
||||||
details TEXT,
|
|
||||||
plugin_id TEXT
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### dashboard_widgets
|
|
||||||
```sql
|
|
||||||
CREATE TABLE dashboard_widgets (
|
|
||||||
widget_id TEXT PRIMARY KEY,
|
|
||||||
widget_type TEXT,
|
|
||||||
position_row INTEGER,
|
|
||||||
position_col INTEGER,
|
|
||||||
size_width INTEGER,
|
|
||||||
size_height INTEGER,
|
|
||||||
config TEXT, -- JSON
|
|
||||||
enabled INTEGER DEFAULT 1
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### hotkeys
|
|
||||||
```sql
|
|
||||||
CREATE TABLE hotkeys (
|
|
||||||
action TEXT PRIMARY KEY,
|
|
||||||
key_combo TEXT,
|
|
||||||
enabled INTEGER DEFAULT 1,
|
|
||||||
plugin_id TEXT
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### API Examples
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Plugin State
|
|
||||||
state = PluginState(
|
|
||||||
plugin_id='my_plugin',
|
|
||||||
enabled=True,
|
|
||||||
version='1.0.0',
|
|
||||||
settings={'key': 'value'}
|
|
||||||
)
|
|
||||||
store.save_plugin_state(state)
|
|
||||||
loaded_state = store.load_plugin_state('my_plugin')
|
|
||||||
|
|
||||||
# User Preferences
|
|
||||||
store.set_preference('theme', 'Dark Blue', category='appearance')
|
|
||||||
theme = store.get_preference('theme', default='Dark')
|
|
||||||
prefs = store.get_preferences_by_category('appearance')
|
|
||||||
|
|
||||||
# Activity Logging
|
|
||||||
store.log_activity('plugin', 'loaded', 'Plugin initialized', plugin_id='my_plugin')
|
|
||||||
recent = store.get_recent_activity(limit=50)
|
|
||||||
|
|
||||||
# Sessions
|
|
||||||
session_id = store.start_session()
|
|
||||||
store.end_session(session_id, plugin_stats={'loaded': 5})
|
|
||||||
|
|
||||||
# Widgets
|
|
||||||
store.save_widget_config(
|
|
||||||
widget_id='widget_1',
|
|
||||||
widget_type='system_status',
|
|
||||||
row=0, col=0,
|
|
||||||
width=2, height=1,
|
|
||||||
config={'update_interval': 1000}
|
|
||||||
)
|
|
||||||
widgets = store.load_widget_configs()
|
|
||||||
|
|
||||||
# Hotkeys
|
|
||||||
store.save_hotkey('toggle_overlay', 'Ctrl+Shift+U', enabled=True)
|
|
||||||
hotkeys = store.get_hotkeys()
|
|
||||||
|
|
||||||
# Maintenance
|
|
||||||
stats = store.get_stats()
|
|
||||||
store.vacuum() # Optimize database
|
|
||||||
```
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
core/
|
|
||||||
├── data/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ └── sqlite_store.py # SQLite data layer
|
|
||||||
├── widgets/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ ├── dashboard_widgets.py # Widget implementations
|
|
||||||
│ └── widget_gallery.py # Gallery and manager
|
|
||||||
├── ui/
|
|
||||||
│ ├── settings_panel.py # Enhanced settings
|
|
||||||
│ └── ...
|
|
||||||
├── dashboard_enhanced.py # Enhanced dashboard
|
|
||||||
├── activity_bar_enhanced.py # Enhanced activity bar
|
|
||||||
└── plugin_store.py # Plugin store
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running the Demo
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run the comprehensive demo
|
|
||||||
python core_functionality_demo.py
|
|
||||||
```
|
|
||||||
|
|
||||||
The demo showcases:
|
|
||||||
- All dashboard widgets
|
|
||||||
- Widget gallery functionality
|
|
||||||
- Activity bar features
|
|
||||||
- Settings panel with persistence
|
|
||||||
- Data layer statistics
|
|
||||||
|
|
||||||
## Integration Example
|
|
||||||
|
|
||||||
```python
|
|
||||||
from PyQt6.QtWidgets import QApplication, QMainWindow
|
|
||||||
|
|
||||||
from core.data import get_sqlite_store
|
|
||||||
from core.dashboard_enhanced import EnhancedDashboard
|
|
||||||
from core.activity_bar_enhanced import EnhancedActivityBar, get_activity_bar
|
|
||||||
from core.ui.settings_panel import EnhancedSettingsPanel
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
# Initialize data store
|
|
||||||
self.store = get_sqlite_store()
|
|
||||||
|
|
||||||
# Create dashboard
|
|
||||||
self.dashboard = EnhancedDashboard(plugin_manager=self.plugin_manager)
|
|
||||||
self.setCentralWidget(self.dashboard)
|
|
||||||
|
|
||||||
# Create activity bar
|
|
||||||
self.activity_bar = get_activity_bar(self.plugin_manager)
|
|
||||||
self.activity_bar.show()
|
|
||||||
|
|
||||||
# Settings panel (can be shown as overlay)
|
|
||||||
self.settings = EnhancedSettingsPanel(self)
|
|
||||||
|
|
||||||
# Log startup
|
|
||||||
self.store.log_activity('system', 'app_started')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = QApplication([])
|
|
||||||
window = MainWindow()
|
|
||||||
window.show()
|
|
||||||
app.exec()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
All critical tasks have been completed:
|
|
||||||
|
|
||||||
✅ **Dashboard Widgets**: System Status, Quick Actions, Recent Activity, Plugin Grid
|
|
||||||
✅ **Plugin Store**: Browse, install, uninstall, dependencies, versions
|
|
||||||
✅ **Settings Panel**: General, plugins, hotkeys, data/backup - all with persistence
|
|
||||||
✅ **Widget Gallery**: Browse, create, configure, position/size management
|
|
||||||
✅ **Activity Bar**: Pinned plugins, app drawer, search, drag-to-pin
|
|
||||||
✅ **Data Layer**: SQLite integration for settings, plugin state, preferences, sessions
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
# EU-Utility Feature Implementation Summary
|
|
||||||
|
|
||||||
**Date:** 2025-02-14
|
|
||||||
**Agent:** Feature Developer Agent
|
|
||||||
**Status:** ✅ COMPLETE
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implemented Features
|
|
||||||
|
|
||||||
### 1. 📊 Session Exporter (`plugins/session_exporter/`)
|
|
||||||
|
|
||||||
**Purpose:** Export hunting/mining sessions to CSV/JSON formats for analysis
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Real-time session tracking via Event Bus
|
|
||||||
- Captures: Loot, Skill Gains, Globals, HOFs, Damage
|
|
||||||
- Export formats: JSON (structured) and CSV (spreadsheet-friendly)
|
|
||||||
- Auto-export at configurable intervals
|
|
||||||
- Session statistics and summaries
|
|
||||||
- Hotkey: `Ctrl+Shift+E`
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- `plugins/session_exporter/__init__.py`
|
|
||||||
- `plugins/session_exporter/plugin.py` (23KB)
|
|
||||||
|
|
||||||
**Integration Points:**
|
|
||||||
- EventBus (subscribes to LootEvent, SkillGainEvent, GlobalEvent, DamageEvent)
|
|
||||||
- DataStore for settings persistence
|
|
||||||
- Notification service for user feedback
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. 🔔 Price Alert System (`plugins/price_alerts/`)
|
|
||||||
|
|
||||||
**Purpose:** Monitor Entropia Nexus API prices with smart alerts
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Search and monitor any Nexus item
|
|
||||||
- "Below" alerts for buy opportunities
|
|
||||||
- "Above" alerts for sell opportunities
|
|
||||||
- Auto-refresh at 1-60 minute intervals
|
|
||||||
- Price history tracking (7 days)
|
|
||||||
- Visual + sound notifications
|
|
||||||
- Hotkey: `Ctrl+Shift+P`
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- `plugins/price_alerts/__init__.py`
|
|
||||||
- `plugins/price_alerts/plugin.py` (25KB)
|
|
||||||
|
|
||||||
**Integration Points:**
|
|
||||||
- NexusAPI for market data
|
|
||||||
- DataStore for alerts and price history
|
|
||||||
- Background task service for non-blocking API calls
|
|
||||||
- Notification service for alerts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. 📸 Auto-Screenshot on Globals (`plugins/auto_screenshot/`)
|
|
||||||
|
|
||||||
**Purpose:** Automatically capture screenshots on Global/HOF and other events
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- Triggers: Global, HOF, ATH, Discovery, high-value loot, skill gains
|
|
||||||
- Configurable capture delay (to hide overlay)
|
|
||||||
- Custom filename patterns with variables
|
|
||||||
- Organized folder structure
|
|
||||||
- Notification and sound options
|
|
||||||
- Hotkey: `Ctrl+Shift+C` (manual capture)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- `plugins/auto_screenshot/__init__.py`
|
|
||||||
- `plugins/auto_screenshot/plugin.py` (29KB)
|
|
||||||
|
|
||||||
**Integration Points:**
|
|
||||||
- EventBus (subscribes to GlobalEvent, LootEvent, SkillGainEvent)
|
|
||||||
- ScreenshotService for capture
|
|
||||||
- DataStore for settings
|
|
||||||
- Notification + Audio services
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
**Created:** `docs/FEATURE_PACK.md` (7KB)
|
|
||||||
|
|
||||||
Comprehensive documentation including:
|
|
||||||
- Feature descriptions
|
|
||||||
- Usage instructions
|
|
||||||
- Configuration options
|
|
||||||
- File format specifications
|
|
||||||
- Troubleshooting guide
|
|
||||||
- Hotkey reference
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Compliance
|
|
||||||
|
|
||||||
All plugins follow EU-Utility architecture:
|
|
||||||
|
|
||||||
✅ Extend `BasePlugin`
|
|
||||||
✅ Use typed Event Bus subscriptions
|
|
||||||
✅ Integrate with PluginAPI services
|
|
||||||
✅ Persistent storage via DataStore
|
|
||||||
✅ Qt6 UI with consistent styling
|
|
||||||
✅ Hotkey support
|
|
||||||
✅ Notification integration
|
|
||||||
✅ Background task support (where applicable)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Code Quality
|
|
||||||
|
|
||||||
✅ All files pass Python syntax check
|
|
||||||
✅ Type hints used throughout
|
|
||||||
✅ Docstrings for all public methods
|
|
||||||
✅ Consistent error handling
|
|
||||||
✅ Resource cleanup on shutdown
|
|
||||||
✅ Thread-safe UI updates using signals
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
plugins/
|
|
||||||
├── session_exporter/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ └── plugin.py
|
|
||||||
├── price_alerts/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ └── plugin.py
|
|
||||||
└── auto_screenshot/
|
|
||||||
├── __init__.py
|
|
||||||
└── plugin.py
|
|
||||||
|
|
||||||
docs/
|
|
||||||
├── FEATURE_PACK.md
|
|
||||||
└── (existing docs...)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps (Optional Enhancements)
|
|
||||||
|
|
||||||
1. **Session Exporter:**
|
|
||||||
- Add PDF report generation
|
|
||||||
- Session comparison/analytics
|
|
||||||
- Export to Google Sheets
|
|
||||||
|
|
||||||
2. **Price Alerts:**
|
|
||||||
- Price trend graphs
|
|
||||||
- Bulk import/export of alerts
|
|
||||||
- Discord webhook integration
|
|
||||||
|
|
||||||
3. **Auto-Screenshot:**
|
|
||||||
- Video capture option
|
|
||||||
- Upload to cloud storage
|
|
||||||
- Social media sharing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deliverables Summary
|
|
||||||
|
|
||||||
| Deliverable | Status | Size |
|
|
||||||
|-------------|--------|------|
|
|
||||||
| Session Exporter Plugin | ✅ Complete | 23 KB |
|
|
||||||
| Price Alerts Plugin | ✅ Complete | 26 KB |
|
|
||||||
| Auto-Screenshot Plugin | ✅ Complete | 29 KB |
|
|
||||||
| Feature Documentation | ✅ Complete | 7 KB |
|
|
||||||
| Plugin `__init__.py` files | ✅ Complete | 3 files |
|
|
||||||
|
|
||||||
**Total Code:** ~78 KB
|
|
||||||
**Total Documentation:** ~7 KB
|
|
||||||
**All Requirements:** ✅ Met
|
|
||||||
|
|
@ -1,412 +0,0 @@
|
||||||
# EU-Utility Integration & Test Report
|
|
||||||
|
|
||||||
**Date:** 2024-02-15
|
|
||||||
**Engineer:** Integration & Test Engineer
|
|
||||||
**Project:** EU-Utility v2.0
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
I have completed a comprehensive test suite and documentation package for EU-Utility. This includes:
|
|
||||||
|
|
||||||
### Test Suite Deliverables
|
|
||||||
|
|
||||||
| Component | Status | Files | Test Count |
|
|
||||||
|-----------|--------|-------|------------|
|
|
||||||
| Unit Tests | ✅ Complete | 4 new + existing | 80+ |
|
|
||||||
| Integration Tests | ✅ Complete | 2 files | 20+ |
|
|
||||||
| UI Automation Tests | ✅ Complete | 1 file | 25+ |
|
|
||||||
| Performance Benchmarks | ✅ Complete | 1 file | 15+ |
|
|
||||||
| Test Runner | ✅ Complete | 1 script | - |
|
|
||||||
|
|
||||||
### Documentation Deliverables
|
|
||||||
|
|
||||||
| Document | Status | Pages |
|
|
||||||
|----------|--------|-------|
|
|
||||||
| User Guide | ✅ Complete | ~15 |
|
|
||||||
| Troubleshooting Guide | ✅ Complete | ~12 |
|
|
||||||
| API Documentation | ✅ Complete | ~18 |
|
|
||||||
| Setup Instructions | ✅ Complete | ~10 |
|
|
||||||
| Performance Report | ✅ Complete | ~8 |
|
|
||||||
| Test Suite README | ✅ Complete | ~6 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Test Suite Details
|
|
||||||
|
|
||||||
### 1. Unit Tests (`tests/unit/`)
|
|
||||||
|
|
||||||
#### New Test Files Created:
|
|
||||||
|
|
||||||
1. **`test_plugin_manager.py`** (250 lines)
|
|
||||||
- Plugin manager initialization
|
|
||||||
- Configuration loading
|
|
||||||
- Plugin enable/disable
|
|
||||||
- Discovery mechanisms
|
|
||||||
- Dependency management
|
|
||||||
|
|
||||||
2. **`test_window_manager.py`** (230 lines)
|
|
||||||
- Window manager singleton
|
|
||||||
- Window detection
|
|
||||||
- Focus tracking
|
|
||||||
- Multi-monitor support
|
|
||||||
- Activity bar functionality
|
|
||||||
|
|
||||||
3. **`test_api_integration.py`** (450 lines)
|
|
||||||
- Plugin API singleton
|
|
||||||
- All API methods
|
|
||||||
- Service registration
|
|
||||||
- Error handling
|
|
||||||
- Nexus API integration
|
|
||||||
- HTTP client
|
|
||||||
|
|
||||||
4. **`test_core_services.py`** (380 lines)
|
|
||||||
- Event bus
|
|
||||||
- Data store
|
|
||||||
- Settings
|
|
||||||
- Logger
|
|
||||||
- Hotkey manager
|
|
||||||
- Performance optimizations
|
|
||||||
|
|
||||||
**Existing Test Files Available:**
|
|
||||||
- test_audio.py
|
|
||||||
- test_clipboard.py
|
|
||||||
- test_data_store.py
|
|
||||||
- test_event_bus.py
|
|
||||||
- test_http_client.py
|
|
||||||
- test_log_reader.py
|
|
||||||
- test_nexus_api.py
|
|
||||||
- test_plugin_api.py
|
|
||||||
- test_security_utils.py
|
|
||||||
- test_settings.py
|
|
||||||
- test_tasks.py
|
|
||||||
|
|
||||||
### 2. Integration Tests (`tests/integration/`)
|
|
||||||
|
|
||||||
#### New Test Files Created:
|
|
||||||
|
|
||||||
1. **`test_plugin_workflows.py`** (500 lines)
|
|
||||||
- Plugin lifecycle tests
|
|
||||||
- Enable/disable workflow
|
|
||||||
- Settings persistence
|
|
||||||
- API workflows
|
|
||||||
- UI integration
|
|
||||||
- Error handling
|
|
||||||
|
|
||||||
**Existing Test Files Available:**
|
|
||||||
- test_plugin_lifecycle.py
|
|
||||||
|
|
||||||
### 3. UI Automation Tests (`tests/ui/`)
|
|
||||||
|
|
||||||
#### New Test Files Created:
|
|
||||||
|
|
||||||
1. **`test_ui_automation.py`** (380 lines)
|
|
||||||
- Dashboard UI tests
|
|
||||||
- Overlay window tests
|
|
||||||
- Activity bar tests
|
|
||||||
- Settings dialog tests
|
|
||||||
- Responsive UI tests
|
|
||||||
- Theme UI tests
|
|
||||||
- Accessibility tests
|
|
||||||
- Tray icon tests
|
|
||||||
|
|
||||||
### 4. Performance Tests (`tests/performance/`)
|
|
||||||
|
|
||||||
#### New Test Files Created:
|
|
||||||
|
|
||||||
1. **`test_benchmarks.py`** (320 lines)
|
|
||||||
- Plugin manager performance
|
|
||||||
- API performance
|
|
||||||
- UI performance
|
|
||||||
- Memory usage
|
|
||||||
- Startup performance
|
|
||||||
- Cache performance
|
|
||||||
- Concurrent operations
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation Details
|
|
||||||
|
|
||||||
### 1. User Guide (`docs/USER_GUIDE.md`)
|
|
||||||
- Getting started
|
|
||||||
- Installation instructions
|
|
||||||
- First launch guide
|
|
||||||
- Main interface overview
|
|
||||||
- Plugin usage
|
|
||||||
- Hotkey reference
|
|
||||||
- Settings configuration
|
|
||||||
- Tips & tricks
|
|
||||||
- FAQ
|
|
||||||
|
|
||||||
### 2. Troubleshooting Guide (`docs/TROUBLESHOOTING.md`)
|
|
||||||
- Installation issues
|
|
||||||
- Startup problems
|
|
||||||
- Hotkey troubleshooting
|
|
||||||
- Plugin issues
|
|
||||||
- UI problems
|
|
||||||
- Performance optimization
|
|
||||||
- OCR issues
|
|
||||||
- Network problems
|
|
||||||
- Debug procedures
|
|
||||||
|
|
||||||
### 3. API Documentation (`docs/API_DOCUMENTATION.md`)
|
|
||||||
- Plugin API reference
|
|
||||||
- Window Manager API
|
|
||||||
- Event Bus API
|
|
||||||
- Data Store API
|
|
||||||
- Nexus API
|
|
||||||
- HTTP Client API
|
|
||||||
- Plugin development guide
|
|
||||||
- Code examples
|
|
||||||
- Best practices
|
|
||||||
|
|
||||||
### 4. Setup Instructions (`docs/SETUP_INSTRUCTIONS.md`)
|
|
||||||
- Prerequisites
|
|
||||||
- Windows setup
|
|
||||||
- Linux setup
|
|
||||||
- Development setup
|
|
||||||
- Configuration guide
|
|
||||||
- Verification steps
|
|
||||||
- Troubleshooting
|
|
||||||
- Updating procedures
|
|
||||||
|
|
||||||
### 5. Performance Report (`docs/PERFORMANCE_REPORT.md`)
|
|
||||||
- Executive summary
|
|
||||||
- Benchmark results
|
|
||||||
- Resource utilization
|
|
||||||
- Scalability testing
|
|
||||||
- Stress testing
|
|
||||||
- Optimization recommendations
|
|
||||||
- Configuration tuning
|
|
||||||
- Comparison with v1.0
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Test Infrastructure
|
|
||||||
|
|
||||||
### Shared Fixtures (`tests/conftest.py`)
|
|
||||||
|
|
||||||
Comprehensive fixtures for:
|
|
||||||
- `temp_dir`: Temporary directories
|
|
||||||
- `mock_overlay`: Mock overlay window
|
|
||||||
- `mock_plugin_manager`: Mock plugin manager
|
|
||||||
- `mock_qt_app`: Mock Qt application
|
|
||||||
- `sample_config`: Sample configurations
|
|
||||||
- `mock_nexus_response`: Mock API responses
|
|
||||||
- `mock_window_info`: Mock window data
|
|
||||||
- `mock_ocr_result`: Mock OCR results
|
|
||||||
- `sample_log_lines`: Sample log data
|
|
||||||
- `event_bus`: Fresh event bus instances
|
|
||||||
- `data_store`: Temporary data stores
|
|
||||||
- `mock_http_client`: Mock HTTP client
|
|
||||||
- `test_logger`: Test logging
|
|
||||||
|
|
||||||
### Test Runner (`run_tests.py`)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- Run all or specific test categories
|
|
||||||
- Coverage reporting (terminal, HTML, XML)
|
|
||||||
- Verbose output option
|
|
||||||
- Fail-fast mode
|
|
||||||
- Marker display
|
|
||||||
- Summary reporting
|
|
||||||
|
|
||||||
### Development Dependencies (`requirements-dev.txt`)
|
|
||||||
|
|
||||||
```
|
|
||||||
pytest>=7.4.0
|
|
||||||
pytest-cov>=4.1.0
|
|
||||||
pytest-mock>=3.11.0
|
|
||||||
pytest-benchmark>=4.0.0
|
|
||||||
pytest-qt>=4.2.0
|
|
||||||
pytest-xvfb>=2.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Test Coverage Summary
|
|
||||||
|
|
||||||
### UI Integration Tests
|
|
||||||
✅ **Tested:**
|
|
||||||
- Dashboard opens correctly
|
|
||||||
- Navigation between tabs works
|
|
||||||
- Activity bar shows/hides properly
|
|
||||||
- Tray icon is responsive
|
|
||||||
- No UI freezing or blocking (responsive tests)
|
|
||||||
|
|
||||||
### Plugin System Tests
|
|
||||||
✅ **Tested:**
|
|
||||||
- Plugins load correctly
|
|
||||||
- Plugin enable/disable works
|
|
||||||
- Plugin settings persist
|
|
||||||
- Plugin store functions
|
|
||||||
- Dependency management
|
|
||||||
|
|
||||||
### API Integration Tests
|
|
||||||
✅ **Tested:**
|
|
||||||
- Plugin API singleton
|
|
||||||
- All service registrations
|
|
||||||
- Log reading
|
|
||||||
- Window operations
|
|
||||||
- OCR functionality
|
|
||||||
- Screenshot capture
|
|
||||||
- Nexus API integration
|
|
||||||
- HTTP client
|
|
||||||
- Audio/Notifications
|
|
||||||
- Clipboard operations
|
|
||||||
- Event bus
|
|
||||||
- Data store
|
|
||||||
- Background tasks
|
|
||||||
|
|
||||||
### Window Management Tests
|
|
||||||
✅ **Tested:**
|
|
||||||
- EU window detection
|
|
||||||
- Focus tracking
|
|
||||||
- Overlay positioning
|
|
||||||
- Multi-monitor support
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
EU-Utility/
|
|
||||||
├── tests/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ ├── conftest.py # Shared fixtures
|
|
||||||
│ ├── README.md # Test documentation
|
|
||||||
│ ├── unit/
|
|
||||||
│ │ ├── test_plugin_manager.py ✅ NEW
|
|
||||||
│ │ ├── test_window_manager.py ✅ NEW
|
|
||||||
│ │ ├── test_api_integration.py ✅ NEW
|
|
||||||
│ │ ├── test_core_services.py ✅ NEW
|
|
||||||
│ │ └── [existing test files...]
|
|
||||||
│ ├── integration/
|
|
||||||
│ │ ├── test_plugin_workflows.py ✅ NEW
|
|
||||||
│ │ └── [existing test files...]
|
|
||||||
│ ├── ui/
|
|
||||||
│ │ └── test_ui_automation.py ✅ NEW
|
|
||||||
│ └── performance/
|
|
||||||
│ └── test_benchmarks.py ✅ NEW
|
|
||||||
├── docs/
|
|
||||||
│ ├── USER_GUIDE.md ✅ NEW
|
|
||||||
│ ├── TROUBLESHOOTING.md ✅ NEW
|
|
||||||
│ ├── API_DOCUMENTATION.md ✅ NEW
|
|
||||||
│ ├── SETUP_INSTRUCTIONS.md ✅ NEW
|
|
||||||
│ └── PERFORMANCE_REPORT.md ✅ NEW
|
|
||||||
├── run_tests.py ✅ NEW (enhanced)
|
|
||||||
└── requirements-dev.txt ✅ NEW
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage Examples
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
python run_tests.py --all
|
|
||||||
|
|
||||||
# Run with coverage
|
|
||||||
python run_tests.py --all --coverage --html
|
|
||||||
|
|
||||||
# Run specific category
|
|
||||||
python run_tests.py --unit
|
|
||||||
python run_tests.py --integration
|
|
||||||
python run_tests.py --ui
|
|
||||||
python run_tests.py --performance
|
|
||||||
|
|
||||||
# Using pytest directly
|
|
||||||
python -m pytest tests/unit/ -v
|
|
||||||
python -m pytest tests/integration/ -v -m integration
|
|
||||||
python -m pytest tests/ui/ -v -m ui
|
|
||||||
python -m pytest tests/performance/ --benchmark-only
|
|
||||||
```
|
|
||||||
|
|
||||||
### Accessing Documentation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# User Guide
|
|
||||||
cat docs/USER_GUIDE.md
|
|
||||||
|
|
||||||
# Troubleshooting
|
|
||||||
cat docs/TROUBLESHOOTING.md
|
|
||||||
|
|
||||||
# API Reference
|
|
||||||
cat docs/API_DOCUMENTATION.md
|
|
||||||
|
|
||||||
# Setup Instructions
|
|
||||||
cat docs/SETUP_INSTRUCTIONS.md
|
|
||||||
|
|
||||||
# Performance Report
|
|
||||||
cat docs/PERFORMANCE_REPORT.md
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quality Metrics
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
- ✅ Consistent naming conventions
|
|
||||||
- ✅ Comprehensive docstrings
|
|
||||||
- ✅ Type hints where appropriate
|
|
||||||
- ✅ Error handling
|
|
||||||
- ✅ Mock usage for isolation
|
|
||||||
|
|
||||||
### Test Quality
|
|
||||||
- ✅ Descriptive test names
|
|
||||||
- ✅ Clear test structure
|
|
||||||
- ✅ Appropriate fixtures
|
|
||||||
- ✅ Good coverage of edge cases
|
|
||||||
- ✅ Performance benchmarks
|
|
||||||
|
|
||||||
### Documentation Quality
|
|
||||||
- ✅ Clear structure
|
|
||||||
- ✅ Comprehensive coverage
|
|
||||||
- ✅ Code examples
|
|
||||||
- ✅ Troubleshooting steps
|
|
||||||
- ✅ Easy to navigate
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommendations
|
|
||||||
|
|
||||||
### Immediate Actions
|
|
||||||
1. Install development dependencies: `pip install -r requirements-dev.txt`
|
|
||||||
2. Run unit tests to verify setup: `python run_tests.py --unit`
|
|
||||||
3. Review test coverage report
|
|
||||||
|
|
||||||
### Short Term
|
|
||||||
1. Integrate tests into CI/CD pipeline
|
|
||||||
2. Add more edge case tests
|
|
||||||
3. Expand UI automation coverage
|
|
||||||
|
|
||||||
### Long Term
|
|
||||||
1. Add visual regression tests
|
|
||||||
2. Implement load testing
|
|
||||||
3. Create automated release testing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
All deliverables have been successfully created:
|
|
||||||
|
|
||||||
✅ **Comprehensive test coverage** - 80+ unit tests, 20+ integration tests, 25+ UI tests, 15+ performance benchmarks
|
|
||||||
|
|
||||||
✅ **Working integration tests** - All major workflows tested
|
|
||||||
|
|
||||||
✅ **User documentation** - Complete user guide with examples
|
|
||||||
|
|
||||||
✅ **Troubleshooting guide** - Comprehensive problem-solving guide
|
|
||||||
|
|
||||||
✅ **Performance report** - Benchmarks and optimization recommendations
|
|
||||||
|
|
||||||
The test suite and documentation provide a solid foundation for maintaining EU-Utility quality and helping users get the most out of the application.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Report completed by Integration & Test Engineer*
|
|
||||||
*Date: 2024-02-15*
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 ImpulsiveFPS
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,226 @@
|
||||||
|
# EU-Utility Packaging Guide
|
||||||
|
|
||||||
|
This document describes the complete packaging setup for EU-Utility, designed for professional Python distribution and PyPI publication.
|
||||||
|
|
||||||
|
## 📦 Package Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
EU-Utility/
|
||||||
|
├── setup.py # Traditional setuptools configuration
|
||||||
|
├── pyproject.toml # Modern Python packaging (PEP 517/518)
|
||||||
|
├── MANIFEST.in # Source distribution file inclusion rules
|
||||||
|
├── Makefile # Development task automation
|
||||||
|
├── requirements.txt # Production dependencies
|
||||||
|
├── requirements-dev.txt # Development dependencies
|
||||||
|
├── LICENSE # MIT License
|
||||||
|
└── .github/
|
||||||
|
└── workflows/
|
||||||
|
└── ci.yml # GitHub Actions CI/CD pipeline
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Installation Methods
|
||||||
|
|
||||||
|
### For End Users
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install from PyPI (when published)
|
||||||
|
pip install eu-utility
|
||||||
|
|
||||||
|
# Install with all optional features
|
||||||
|
pip install "eu-utility[all]"
|
||||||
|
|
||||||
|
# Install with specific features
|
||||||
|
pip install "eu-utility[spotify]"
|
||||||
|
pip install "eu-utility[discord]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Developers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone https://github.com/ImpulsiveFPS/EU-Utility.git
|
||||||
|
cd EU-Utility
|
||||||
|
|
||||||
|
# Install in development mode with all dev dependencies
|
||||||
|
pip install -e ".[dev]"
|
||||||
|
|
||||||
|
# Or use the Makefile
|
||||||
|
make install-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ Development Commands (Makefile)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```bash
|
||||||
|
make install # Install production dependencies
|
||||||
|
make install-dev # Install development dependencies
|
||||||
|
make install-all # Install all dependencies including optional features
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
```bash
|
||||||
|
make test # Run all tests
|
||||||
|
make test-unit # Run unit tests only
|
||||||
|
make test-coverage # Run tests with coverage report
|
||||||
|
make test-fast # Run fast tests (excludes slow and UI tests)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
```bash
|
||||||
|
make lint # Run all linters (flake8, mypy)
|
||||||
|
make format # Format code with black and isort
|
||||||
|
make format-check # Check code formatting without modifying files
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security
|
||||||
|
```bash
|
||||||
|
make security # Run all security checks
|
||||||
|
make security-bandit # Run Bandit security analysis
|
||||||
|
make security-safety # Run Safety vulnerability check
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building and Distribution
|
||||||
|
```bash
|
||||||
|
make build # Build source and wheel distributions
|
||||||
|
make build-check # Check the built distributions
|
||||||
|
make upload-test # Upload to TestPyPI
|
||||||
|
make upload-prod # Upload to PyPI
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleanup
|
||||||
|
```bash
|
||||||
|
make clean # Remove build artifacts and cache files
|
||||||
|
make clean-all # Remove all generated files including virtual environments
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Tool Configurations (pyproject.toml)
|
||||||
|
|
||||||
|
### Black (Code Formatter)
|
||||||
|
- Line length: 100 characters
|
||||||
|
- Target Python versions: 3.11, 3.12
|
||||||
|
|
||||||
|
### isort (Import Sorting)
|
||||||
|
- Profile: black (compatible with black formatting)
|
||||||
|
- Known first-party packages: core, plugins
|
||||||
|
|
||||||
|
### flake8 (Linter)
|
||||||
|
- Max line length: 100
|
||||||
|
- Max complexity: 10
|
||||||
|
- Extends ignore: E203, E501, W503 (black compatibility)
|
||||||
|
|
||||||
|
### mypy (Type Checker)
|
||||||
|
- Python version: 3.11
|
||||||
|
- Strict mode enabled
|
||||||
|
- Missing imports ignored for certain modules (PyQt6, OCR libraries)
|
||||||
|
|
||||||
|
### pytest (Testing)
|
||||||
|
- Test directory: tests/
|
||||||
|
- Coverage minimum: 80%
|
||||||
|
- Coverage reports: terminal, HTML, XML
|
||||||
|
|
||||||
|
### Bandit (Security)
|
||||||
|
- Excludes: tests, venv directories
|
||||||
|
- Skips: B101 (assert_used), B311 (random)
|
||||||
|
|
||||||
|
## 📋 CI/CD Pipeline (GitHub Actions)
|
||||||
|
|
||||||
|
The CI/CD pipeline runs on every push and pull request:
|
||||||
|
|
||||||
|
1. **Lint and Format Check**: Verifies code style with black, isort, flake8, and mypy
|
||||||
|
2. **Security Analysis**: Runs Bandit and Safety checks
|
||||||
|
3. **Tests**: Runs tests on multiple Python versions (3.11, 3.12) and OS (Ubuntu, Windows)
|
||||||
|
4. **Build**: Creates source and wheel distributions
|
||||||
|
5. **Test Installation**: Verifies the package can be installed
|
||||||
|
6. **Release**: Creates GitHub releases for tagged versions
|
||||||
|
7. **Publish**: Publishes to PyPI (only for tagged releases, not dev builds)
|
||||||
|
|
||||||
|
### Release Process
|
||||||
|
|
||||||
|
1. Update version in `core/__init__.py`
|
||||||
|
2. Update `CHANGELOG.md`
|
||||||
|
3. Commit and push changes
|
||||||
|
4. Create a git tag: `git tag v2.1.0`
|
||||||
|
5. Push the tag: `git push origin v2.1.0`
|
||||||
|
6. The CI pipeline will automatically:
|
||||||
|
- Run all tests
|
||||||
|
- Build the package
|
||||||
|
- Create a GitHub release
|
||||||
|
- Publish to PyPI
|
||||||
|
|
||||||
|
## 📦 Dependencies
|
||||||
|
|
||||||
|
### Production Dependencies
|
||||||
|
|
||||||
|
| Package | Version | Purpose |
|
||||||
|
|---------|---------|---------|
|
||||||
|
| PyQt6 | >=6.4.0 | GUI framework |
|
||||||
|
| keyboard | >=0.13.5 | Global hotkeys |
|
||||||
|
| psutil | >=5.9.0 | System monitoring |
|
||||||
|
| easyocr | >=1.7.0 | OCR (text recognition) |
|
||||||
|
| pytesseract | >=0.3.10 | Alternative OCR backend |
|
||||||
|
| pyautogui | >=0.9.54 | Screen capture |
|
||||||
|
| pillow | >=10.0.0 | Image processing |
|
||||||
|
| requests | >=2.28.0 | HTTP client |
|
||||||
|
| numpy | >=1.21.0 | Data processing |
|
||||||
|
|
||||||
|
### Development Dependencies
|
||||||
|
|
||||||
|
| Package | Version | Purpose |
|
||||||
|
|---------|---------|---------|
|
||||||
|
| pytest | >=7.4.0 | Testing framework |
|
||||||
|
| pytest-cov | >=4.1.0 | Coverage reporting |
|
||||||
|
| pytest-qt | >=4.2.0 | Qt testing |
|
||||||
|
| black | >=23.0.0 | Code formatting |
|
||||||
|
| flake8 | >=6.0.0 | Linting |
|
||||||
|
| mypy | >=1.5.0 | Type checking |
|
||||||
|
| bandit | >=1.7.5 | Security analysis |
|
||||||
|
| safety | >=2.3.0 | Vulnerability scanning |
|
||||||
|
| sphinx | >=7.0.0 | Documentation |
|
||||||
|
| build | >=0.10.0 | Package building |
|
||||||
|
| twine | >=4.0.0 | PyPI publishing |
|
||||||
|
|
||||||
|
## 🔒 Security Considerations
|
||||||
|
|
||||||
|
1. **Vulnerable files excluded**: Files ending with `_vulnerable.py`, `_insecure.py` are excluded from distribution
|
||||||
|
2. **Sensitive files excluded**: `.env`, `secrets.json`, `credentials.json` are never included
|
||||||
|
3. **Security scanning**: Bandit runs on every CI build
|
||||||
|
4. **Dependency scanning**: Safety checks for known vulnerabilities
|
||||||
|
|
||||||
|
## 📄 Entry Points
|
||||||
|
|
||||||
|
The package provides the following CLI commands after installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
eu-utility # Main application entry point
|
||||||
|
eu-utility-secure # Secure/optimized version
|
||||||
|
eu-utility-gui # GUI entry point (Windows)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 Platform Support
|
||||||
|
|
||||||
|
- **Windows 10/11**: Full support with all features
|
||||||
|
- **Linux**: Core features supported (some Windows-specific features disabled)
|
||||||
|
- **macOS**: Not officially supported (contributions welcome)
|
||||||
|
|
||||||
|
## 📝 Publishing Checklist
|
||||||
|
|
||||||
|
Before publishing a new release:
|
||||||
|
|
||||||
|
- [ ] Version bumped in `core/__init__.py`
|
||||||
|
- [ ] `CHANGELOG.md` updated with release notes
|
||||||
|
- [ ] All tests passing locally (`make test`)
|
||||||
|
- [ ] Code formatted (`make format`)
|
||||||
|
- [ ] Linting passes (`make lint`)
|
||||||
|
- [ ] Security checks pass (`make security`)
|
||||||
|
- [ ] Build succeeds (`make build`)
|
||||||
|
- [ ] Package installs correctly (`make test-install`)
|
||||||
|
- [ ] Git tag created and pushed
|
||||||
|
- [ ] GitHub release notes prepared
|
||||||
|
|
||||||
|
## 🔗 Resources
|
||||||
|
|
||||||
|
- [Python Packaging User Guide](https://packaging.python.org/)
|
||||||
|
- [setuptools documentation](https://setuptools.pypa.io/)
|
||||||
|
- [pyproject.toml specification](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/)
|
||||||
|
- [GitHub Actions documentation](https://docs.github.com/en/actions)
|
||||||
|
- [PyPI publishing guide](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/)
|
||||||
|
|
@ -1,292 +0,0 @@
|
||||||
# EU-Utility Code Cleanup & Refactoring - Final Report
|
|
||||||
|
|
||||||
**Date:** 2026-02-15
|
|
||||||
**Scope:** Core modules and plugin architecture
|
|
||||||
**Status:** ✅ Complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
Successfully cleaned and refactored the EU-Utility codebase with focus on:
|
|
||||||
- **Code Organization:** Proper module structure with clear separation of concerns
|
|
||||||
- **Documentation:** Comprehensive docstrings for all public APIs
|
|
||||||
- **Type Safety:** Full type hints throughout core modules
|
|
||||||
- **Standards Compliance:** PEP 8 formatting and naming conventions
|
|
||||||
- **Backward Compatibility:** All changes are non-breaking
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Refactored
|
|
||||||
|
|
||||||
| File | Lines | Changes |
|
|
||||||
|------|-------|---------|
|
|
||||||
| `core/__init__.py` | 200 | Complete rewrite with exports and docs |
|
|
||||||
| `core/base_plugin.py` | 893 | Added type hints and comprehensive docs |
|
|
||||||
| `core/event_bus.py` | 831 | Added type hints and comprehensive docs |
|
|
||||||
| `core/settings.py` | 284 | Added type hints and comprehensive docs |
|
|
||||||
| `core/api/__init__.py` | 94 | Added package documentation |
|
|
||||||
| `plugins/__init__.py` | 42 | Added module documentation |
|
|
||||||
| `core/README.md` | 194 | Created comprehensive guide |
|
|
||||||
|
|
||||||
**Total:** 2,538 lines of cleaned, documented code
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Improvements by Category
|
|
||||||
|
|
||||||
### 1. Code Organization ✅
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
- Inconsistent module exports
|
|
||||||
- Mixed import styles
|
|
||||||
- Unclear module boundaries
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
- Clear module hierarchy
|
|
||||||
- Organized exports by category
|
|
||||||
- Consistent import patterns
|
|
||||||
- Well-defined module boundaries
|
|
||||||
|
|
||||||
### 2. Documentation ✅
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
- Minimal module-level docs
|
|
||||||
- Inconsistent docstring styles
|
|
||||||
- Missing examples
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
- Comprehensive module docstrings
|
|
||||||
- Google-style docstrings (Args, Returns, Examples)
|
|
||||||
- Usage examples in all key modules
|
|
||||||
- Created core/README.md with detailed guide
|
|
||||||
|
|
||||||
### 3. Type Hints ✅
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
- No type annotations
|
|
||||||
- No type safety
|
|
||||||
- IDE support limited
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
- Full type hints on all public methods
|
|
||||||
- Generic types (TypeVar) where appropriate
|
|
||||||
- Optional[] for nullable values
|
|
||||||
- Better IDE autocompletion
|
|
||||||
|
|
||||||
### 4. Standards Compliance ✅
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
- Inconsistent naming
|
|
||||||
- Mixed formatting styles
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
- PEP 8 compliant formatting
|
|
||||||
- Consistent snake_case naming
|
|
||||||
- Proper import organization
|
|
||||||
- Clean code structure
|
|
||||||
|
|
||||||
### 5. Performance ✅
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
- Potential import overhead
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
- TYPE_CHECKING for type-only imports
|
|
||||||
- Lazy loading maintained
|
|
||||||
- No runtime overhead from type hints
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key Features Added
|
|
||||||
|
|
||||||
### Event Bus System
|
|
||||||
- Typed events with dataclasses
|
|
||||||
- Event filtering (mob types, damage thresholds)
|
|
||||||
- Event persistence (configurable history)
|
|
||||||
- Async event handling
|
|
||||||
- Event statistics and metrics
|
|
||||||
|
|
||||||
### Plugin Base Class
|
|
||||||
- Comprehensive API integration
|
|
||||||
- Service access methods (OCR, screenshot, audio, etc.)
|
|
||||||
- Event subscription management
|
|
||||||
- Data persistence helpers
|
|
||||||
- Notification methods
|
|
||||||
|
|
||||||
### Settings Manager
|
|
||||||
- Type-safe configuration access
|
|
||||||
- Automatic persistence
|
|
||||||
- Signal-based change notifications
|
|
||||||
- Plugin enablement tracking
|
|
||||||
- Qt/non-Qt environment support
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Improvements
|
|
||||||
|
|
||||||
### Three-Tier API System
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ PluginAPI │ ← Core services
|
|
||||||
│ (Log, Window, OCR, Screenshot) │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ WidgetAPI │ ← UI management
|
|
||||||
│ (Widget creation, positioning) │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ ExternalAPI │ ← Integrations
|
|
||||||
│ (Webhooks, HTTP endpoints) │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Event System Architecture
|
|
||||||
```
|
|
||||||
Publisher → EventBus → [Filters] → Subscribers
|
|
||||||
↓
|
|
||||||
[History]
|
|
||||||
↓
|
|
||||||
Statistics
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backward Compatibility
|
|
||||||
|
|
||||||
All changes maintain 100% backward compatibility:
|
|
||||||
- ✅ No public API changes
|
|
||||||
- ✅ All existing imports work
|
|
||||||
- ✅ Re-exports maintained
|
|
||||||
- ✅ Default behavior unchanged
|
|
||||||
- ✅ Existing plugins unaffected
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing & Verification
|
|
||||||
|
|
||||||
### Syntax Validation
|
|
||||||
```bash
|
|
||||||
✓ python3 -m py_compile core/__init__.py
|
|
||||||
✓ python3 -m py_compile core/base_plugin.py
|
|
||||||
✓ python3 -m py_compile core/event_bus.py
|
|
||||||
✓ python3 -m py_compile core/settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Import Tests
|
|
||||||
```python
|
|
||||||
# Core imports
|
|
||||||
from core import get_event_bus, get_nexus_api, EventBus
|
|
||||||
from core.base_plugin import BasePlugin
|
|
||||||
from core.event_bus import LootEvent, DamageEvent
|
|
||||||
from core.settings import get_settings
|
|
||||||
|
|
||||||
# API imports
|
|
||||||
from core.api import get_api, get_widget_api, get_external_api
|
|
||||||
|
|
||||||
# Plugin imports
|
|
||||||
from plugins import BasePlugin
|
|
||||||
from plugins.base_plugin import BasePlugin
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation Created
|
|
||||||
|
|
||||||
### Core Module README
|
|
||||||
- Module structure overview
|
|
||||||
- Quick start guides
|
|
||||||
- Service architecture explanation
|
|
||||||
- Best practices
|
|
||||||
- Version history
|
|
||||||
|
|
||||||
### Docstrings Added
|
|
||||||
- Module-level docstrings: 8
|
|
||||||
- Class docstrings: 15+
|
|
||||||
- Method docstrings: 100+
|
|
||||||
- Total documentation lines: ~500+
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
| Metric | Value |
|
|
||||||
|--------|-------|
|
|
||||||
| Files modified | 8 |
|
|
||||||
| Total lines | 2,538 |
|
|
||||||
| Type hints added | 200+ |
|
|
||||||
| Docstrings added | 100+ |
|
|
||||||
| Documentation lines | 500+ |
|
|
||||||
| Backward compatibility | 100% |
|
|
||||||
| Syntax errors | 0 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommendations for Future
|
|
||||||
|
|
||||||
### Immediate (High Priority)
|
|
||||||
1. Add type hints to remaining core modules:
|
|
||||||
- `nexus_api.py` (~600 lines)
|
|
||||||
- `http_client.py` (~500 lines)
|
|
||||||
- `data_store.py` (~500 lines)
|
|
||||||
|
|
||||||
2. Create unit tests for:
|
|
||||||
- EventBus functionality
|
|
||||||
- Settings persistence
|
|
||||||
- BasePlugin lifecycle
|
|
||||||
|
|
||||||
### Short-term (Medium Priority)
|
|
||||||
3. Clean up duplicate files:
|
|
||||||
- Consolidate OCR service versions
|
|
||||||
- Remove *_vulnerable.py files
|
|
||||||
- Merge optimized versions
|
|
||||||
|
|
||||||
4. Create additional documentation:
|
|
||||||
- Plugin development guide
|
|
||||||
- API cookbook with examples
|
|
||||||
- Troubleshooting guide
|
|
||||||
|
|
||||||
### Long-term (Low Priority)
|
|
||||||
5. Performance optimizations:
|
|
||||||
- Profile critical paths
|
|
||||||
- Optimize hot loops
|
|
||||||
- Add caching where appropriate
|
|
||||||
|
|
||||||
6. Additional features:
|
|
||||||
- Plugin dependency resolution
|
|
||||||
- Hot-reload for plugins
|
|
||||||
- Plugin marketplace integration
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
The EU-Utility codebase has been successfully cleaned and refactored with:
|
|
||||||
- ✅ Comprehensive documentation
|
|
||||||
- ✅ Full type safety
|
|
||||||
- ✅ Clean architecture
|
|
||||||
- ✅ Standards compliance
|
|
||||||
- ✅ Backward compatibility
|
|
||||||
|
|
||||||
The codebase is now well-positioned for:
|
|
||||||
- Easier maintenance
|
|
||||||
- Better developer onboarding
|
|
||||||
- Improved IDE support
|
|
||||||
- Safer refactoring
|
|
||||||
- Future feature development
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deliverables Checklist
|
|
||||||
|
|
||||||
- [x] Clean, organized codebase
|
|
||||||
- [x] Well-documented modules
|
|
||||||
- [x] Type-hinted throughout
|
|
||||||
- [x] Optimized performance (no regressions)
|
|
||||||
- [x] Standards compliant
|
|
||||||
- [x] Backward compatible
|
|
||||||
- [x] Syntax validated
|
|
||||||
- [x] Documentation created
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Report Generated:** 2026-02-15
|
|
||||||
**Refactoring Complete:** ✅
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
# EU-Utility v2.1.0 Release Notes
|
|
||||||
|
|
||||||
**Release Date:** 2026-02-14
|
|
||||||
**Version:** 2.1.0
|
|
||||||
**Codename:** "Nexus"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 What's New
|
|
||||||
|
|
||||||
### 7 New Plugins
|
|
||||||
1. **Session Exporter** - Export hunting/mining sessions to CSV/JSON
|
|
||||||
2. **Price Alert System** - Monitor Nexus API prices with notifications
|
|
||||||
3. **Auto-Screenshot** - Capture screen on Global/HOF automatically
|
|
||||||
4. **Discord Rich Presence** - Show EU activity in Discord status
|
|
||||||
5. **Import/Export Tool** - Universal data backup and restore
|
|
||||||
6. **Analytics Dashboard** - Usage tracking and performance monitoring
|
|
||||||
7. **Auto-Updater** - Automatic update checking and installation
|
|
||||||
|
|
||||||
### New Core Systems
|
|
||||||
- **Theme System** - Dark, Light, and EU Classic themes
|
|
||||||
- **Logging System** - Structured logging with rotation
|
|
||||||
- **Security Hardening** - Path validation, input sanitization
|
|
||||||
- **CI/CD Pipeline** - GitHub Actions for testing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Statistics
|
|
||||||
|
|
||||||
- **Total Plugins:** 31 (24 + 7 new)
|
|
||||||
- **Core Services:** 12
|
|
||||||
- **Test Coverage:** 75%
|
|
||||||
- **Documentation:** 15 files
|
|
||||||
- **Lines of Code:** ~25,000
|
|
||||||
- **Git Commits:** 6 major
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔒 Security Improvements
|
|
||||||
|
|
||||||
- Path traversal vulnerabilities patched
|
|
||||||
- Input sanitization on all user inputs
|
|
||||||
- URL validation in HTTP client
|
|
||||||
- Clipboard size limits
|
|
||||||
- Plugin sandboxing improvements
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Performance Enhancements
|
|
||||||
|
|
||||||
- OCR lazy loading (faster startup)
|
|
||||||
- Database query optimization
|
|
||||||
- Memory leak fixes
|
|
||||||
- UI rendering improvements
|
|
||||||
- Background task efficiency
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Documentation
|
|
||||||
|
|
||||||
- Complete API Reference
|
|
||||||
- Plugin Development Guide
|
|
||||||
- User Manual
|
|
||||||
- Troubleshooting Guide
|
|
||||||
- FAQ (50+ questions)
|
|
||||||
- API Cookbook
|
|
||||||
- Migration Guide
|
|
||||||
- Security Hardening Guide
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Bug Fixes
|
|
||||||
|
|
||||||
- Windows compatibility improvements
|
|
||||||
- Cross-platform file locking
|
|
||||||
- Plugin loading reliability
|
|
||||||
- Error handling robustness
|
|
||||||
- Memory management fixes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Known Issues
|
|
||||||
|
|
||||||
1. **Linux:** Window manager features limited
|
|
||||||
2. **macOS:** Not officially supported
|
|
||||||
3. **OCR:** First run downloads models (slow)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Upgrade Notes
|
|
||||||
|
|
||||||
### From v2.0
|
|
||||||
1. Backup your data (automatic on update)
|
|
||||||
2. Run Auto-Updater or `git pull`
|
|
||||||
3. Install new dependencies: `pip install -r requirements.txt`
|
|
||||||
4. Restart EU-Utility
|
|
||||||
|
|
||||||
### From Other Tools
|
|
||||||
See [Migration Guide](docs/MIGRATION_GUIDE.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🙏 Contributors
|
|
||||||
|
|
||||||
- **LemonNexus** - Lead Developer
|
|
||||||
- **Community** - Testing and feedback
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📥 Download
|
|
||||||
|
|
||||||
- **Windows:** EU-Utility-Windows.zip
|
|
||||||
- **Linux:** EU-Utility-Linux.zip
|
|
||||||
- **Source:** `git clone https://github.com/ImpulsiveFPS/EU-Utility.git`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Full changelog available in CHANGELOG.md*
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
# EU-Utility Security Audit Report
|
|
||||||
|
|
||||||
**Date:** 2026-02-14
|
|
||||||
**Auditor:** Security Auditor Agent
|
|
||||||
**Scope:** `/home/impulsivefps/.openclaw/workspace/projects/EU-Utility/`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
The EU-Utility codebase contains **several security vulnerabilities**, primarily around **path traversal**, **insufficient input validation**, and **unsafe plugin loading**. A hardened version exists for some components (data_store_secure.py, screenshot_secure.py) but the original vulnerable versions are still in use.
|
|
||||||
|
|
||||||
**Overall Risk Level:** MEDIUM-HIGH
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
### 🔴 CRITICAL: Path Traversal in data_store.py
|
|
||||||
|
|
||||||
**File:** `core/data_store.py`
|
|
||||||
**Severity:** HIGH
|
|
||||||
**Status:** ⚠️ VULNERABLE (Secure version exists but unused)
|
|
||||||
|
|
||||||
**Issue:** The `_get_plugin_file()` method uses simple string replacement for sanitization:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _get_plugin_file(self, plugin_id: str) -> Path:
|
|
||||||
safe_name = plugin_id.replace(".", "_").replace("/", "_").replace("\\", "_")
|
|
||||||
return self.data_dir / f"{safe_name}.json"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Attack Vector:** A malicious plugin could use `plugin_id="../../../etc/passwd"` to escape the data directory.
|
|
||||||
|
|
||||||
**Fix:** Replace with `data_store_secure.py` which includes:
|
|
||||||
- Proper path validation using `PathValidator`
|
|
||||||
- Resolved path verification against base path
|
|
||||||
- Security error handling
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🔴 HIGH: Path Traversal in screenshot.py
|
|
||||||
|
|
||||||
**File:** `core/screenshot.py`
|
|
||||||
**Severity:** HIGH
|
|
||||||
**Status:** ⚠️ VULNERABLE (Secure version exists but unused)
|
|
||||||
|
|
||||||
**Issue:** The `save_screenshot()` method accepts arbitrary filenames without validation:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def save_screenshot(self, image: Image.Image, filename: Optional[str] = None) -> Path:
|
|
||||||
if filename is None:
|
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S_%f")[:-3]
|
|
||||||
filename = f"screenshot_{timestamp}.{self._format.lower()}"
|
|
||||||
|
|
||||||
# NO VALIDATION HERE
|
|
||||||
filepath = self._save_path / filename
|
|
||||||
image.save(filepath, ...)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Attack Vector:** A plugin could call `save_screenshot(image, "../../../malware.exe")` to write outside the screenshots directory.
|
|
||||||
|
|
||||||
**Fix:** Replace with `screenshot_secure.py` which includes:
|
|
||||||
- `PathValidator.sanitize_filename()` usage
|
|
||||||
- Resolved path verification
|
|
||||||
- Security error handling
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🟡 MEDIUM: Insufficient HTTP Client Security
|
|
||||||
|
|
||||||
**File:** `core/http_client.py`
|
|
||||||
**Severity:** MEDIUM
|
|
||||||
**Status:** ⚠️ PARTIALLY VULNERABLE
|
|
||||||
|
|
||||||
**Issues:**
|
|
||||||
1. No SSL certificate verification control
|
|
||||||
2. `post()` method allows caching of POST requests (unusual/unsafe)
|
|
||||||
3. No URL scheme validation (could allow `file://` protocol)
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
- Always verify SSL certificates
|
|
||||||
- Add URL scheme whitelist (`http://`, `https://`)
|
|
||||||
- Disable caching for POST by default
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🟡 MEDIUM: Unvalidated Clipboard Storage
|
|
||||||
|
|
||||||
**File:** `core/clipboard.py`
|
|
||||||
**Severity:** MEDIUM
|
|
||||||
**Status:** ⚠️ VULNERABLE
|
|
||||||
|
|
||||||
**Issues:**
|
|
||||||
1. No maximum length validation for clipboard text
|
|
||||||
2. No sanitization before saving to history file
|
|
||||||
3. History file stored without encryption
|
|
||||||
|
|
||||||
**Attack Vector:** A malicious actor could copy extremely large text (GBs) causing DoS via memory exhaustion.
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
- Add max length limits (e.g., 10KB per entry, 1000 entries max)
|
|
||||||
- Sanitize text before storage
|
|
||||||
- Consider encrypting sensitive clipboard history
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🟠 HIGH: Unsafe Plugin Loading
|
|
||||||
|
|
||||||
**File:** `core/plugin_manager.py`
|
|
||||||
**Severity:** HIGH
|
|
||||||
**Status:** ⚠️ VULNERABLE
|
|
||||||
|
|
||||||
**Issues:**
|
|
||||||
1. Uses `exec_module()` which executes arbitrary Python code
|
|
||||||
2. No signature verification for plugins
|
|
||||||
3. No sandboxing or permission system
|
|
||||||
4. No validation of plugin metadata
|
|
||||||
|
|
||||||
**Attack Vector:** A malicious plugin in the `user_plugins` directory could execute arbitrary code with user privileges.
|
|
||||||
|
|
||||||
**Recommendations:**
|
|
||||||
- Implement plugin signature verification
|
|
||||||
- Add permission manifest system for plugins
|
|
||||||
- Consider using restricted Python execution environment
|
|
||||||
- Validate plugin metadata against schema
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🟡 LOW: Subprocess Usage
|
|
||||||
|
|
||||||
**Files:** Multiple (window_manager.py, notifications.py, spotify_controller.py, game_reader.py)
|
|
||||||
**Severity:** LOW
|
|
||||||
**Status:** ✅ GENERALLY SAFE
|
|
||||||
|
|
||||||
**Analysis:** Subprocess usage found but:
|
|
||||||
- Uses hardcoded, safe commands
|
|
||||||
- No user input passed to shell commands
|
|
||||||
- Timeout protections in place
|
|
||||||
|
|
||||||
**No immediate action required** but continue to audit any new subprocess additions.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 🟢 LOW: No Hardcoded Credentials Found
|
|
||||||
|
|
||||||
**Status:** ✅ PASS
|
|
||||||
|
|
||||||
Searched for:
|
|
||||||
- API keys
|
|
||||||
- Passwords
|
|
||||||
- Authentication tokens
|
|
||||||
- Secret keys
|
|
||||||
|
|
||||||
None found in the codebase. Good security practice maintained.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Improvements Made
|
|
||||||
|
|
||||||
### 1. data_store_secure.py (EXISTS)
|
|
||||||
- Path traversal protection via `PathValidator`
|
|
||||||
- Input validation for plugin IDs and keys
|
|
||||||
- Data structure validation
|
|
||||||
- Secure backup path validation
|
|
||||||
|
|
||||||
### 2. screenshot_secure.py (EXISTS)
|
|
||||||
- Filename sanitization
|
|
||||||
- Path resolution validation
|
|
||||||
- Region coordinate validation
|
|
||||||
- Window handle validation
|
|
||||||
|
|
||||||
### 3. security_utils.py (EXISTS)
|
|
||||||
- `PathValidator` class for path sanitization
|
|
||||||
- `InputValidator` class for input validation
|
|
||||||
- `DataValidator` class for data structure validation
|
|
||||||
- `IntegrityChecker` for HMAC/hash operations
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommendations
|
|
||||||
|
|
||||||
### Immediate Actions (High Priority)
|
|
||||||
|
|
||||||
1. **Replace vulnerable modules with secure versions:**
|
|
||||||
```bash
|
|
||||||
mv core/data_store.py core/data_store_vulnerable.py
|
|
||||||
mv core/data_store_secure.py core/data_store.py
|
|
||||||
|
|
||||||
mv core/screenshot.py core/screenshot_vulnerable.py
|
|
||||||
mv core/screenshot_secure.py core/screenshot.py
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Add clipboard validation:**
|
|
||||||
- Implement max text length limits
|
|
||||||
- Sanitize clipboard content
|
|
||||||
|
|
||||||
3. **Implement plugin security:**
|
|
||||||
- Add plugin signature verification
|
|
||||||
- Create permission manifest system
|
|
||||||
|
|
||||||
### Medium Priority
|
|
||||||
|
|
||||||
4. **Enhance HTTP client:**
|
|
||||||
- Add URL scheme validation
|
|
||||||
- Enable SSL verification by default
|
|
||||||
- Add request/response size limits
|
|
||||||
|
|
||||||
5. **Add audit logging:**
|
|
||||||
- Log all file operations outside data directories
|
|
||||||
- Log plugin loading/unloading
|
|
||||||
- Log security violations
|
|
||||||
|
|
||||||
### Low Priority
|
|
||||||
|
|
||||||
6. **Implement data encryption:**
|
|
||||||
- Encrypt sensitive plugin data at rest
|
|
||||||
- Encrypt clipboard history
|
|
||||||
|
|
||||||
7. **Add rate limiting:**
|
|
||||||
- Rate limit screenshot captures
|
|
||||||
- Rate limit API calls per plugin
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Test Cases
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Test Path Traversal Protection
|
|
||||||
def test_path_traversal():
|
|
||||||
# Should raise SecurityError
|
|
||||||
try:
|
|
||||||
data_store._get_plugin_file("../../../etc/passwd")
|
|
||||||
assert False, "Path traversal not blocked!"
|
|
||||||
except SecurityError:
|
|
||||||
pass # Expected
|
|
||||||
|
|
||||||
# Test Filename Sanitization
|
|
||||||
def test_filename_sanitization():
|
|
||||||
# Should sanitize dangerous characters
|
|
||||||
safe = PathValidator.sanitize_filename("../../../test.txt")
|
|
||||||
assert ".." not in safe
|
|
||||||
assert "/" not in safe
|
|
||||||
|
|
||||||
# Test Input Validation
|
|
||||||
def test_clipboard_limits():
|
|
||||||
# Should reject oversized input
|
|
||||||
large_text = "x" * (10 * 1024 * 1024) # 10MB
|
|
||||||
result = clipboard_manager.copy(large_text)
|
|
||||||
assert result == False # Should fail
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
The EU-Utility project has a solid security foundation with `security_utils.py` providing comprehensive validation utilities. However, the **original vulnerable modules are still in use** instead of the hardened versions.
|
|
||||||
|
|
||||||
**Priority 1:** Switch to the secure versions of data_store and screenshot modules.
|
|
||||||
|
|
||||||
**Priority 2:** Implement plugin sandboxing and signature verification.
|
|
||||||
|
|
||||||
With these changes, the project risk level can be reduced from MEDIUM-HIGH to LOW-MEDIUM.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Report generated by Security Auditor Agent*
|
|
||||||
*EU-Utility Security Audit 2026*
|
|
||||||
|
|
@ -1,319 +0,0 @@
|
||||||
# EU-Utility Security Fixes Applied
|
|
||||||
|
|
||||||
**Date:** 2026-02-14
|
|
||||||
**Auditor:** Security Auditor Agent
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
This document details the security fixes applied during the security audit of EU-Utility.
|
|
||||||
|
|
||||||
**Modules Fixed:** 4
|
|
||||||
**Security Improvements:** 15+
|
|
||||||
**Risk Level Reduced:** MEDIUM-HIGH → LOW-MEDIUM
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fixes Applied
|
|
||||||
|
|
||||||
### 1. ✅ data_store.py - Path Traversal Protection
|
|
||||||
|
|
||||||
**Action:** Replaced vulnerable module with secure version
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- Backup created: `data_store_vulnerable.py`
|
|
||||||
- Active module now: `data_store_secure.py`
|
|
||||||
|
|
||||||
**Security Features Added:**
|
|
||||||
- Path validation using `PathValidator` class
|
|
||||||
- Resolved path verification against base directory
|
|
||||||
- Plugin ID validation (type checking, empty checks)
|
|
||||||
- Key validation against dangerous patterns
|
|
||||||
- Data structure validation before save
|
|
||||||
- Backup path traversal protection
|
|
||||||
|
|
||||||
**Code Example:**
|
|
||||||
```python
|
|
||||||
def _get_plugin_file(self, plugin_id: str) -> Path:
|
|
||||||
# Validate plugin_id
|
|
||||||
if not isinstance(plugin_id, str):
|
|
||||||
raise SecurityError("plugin_id must be a string")
|
|
||||||
|
|
||||||
# Sanitize and validate
|
|
||||||
safe_name = PathValidator.sanitize_filename(plugin_id, '_')
|
|
||||||
if '..' in safe_name or '/' in safe_name or '\\' in safe_name:
|
|
||||||
raise SecurityError(f"Invalid characters in plugin_id: {plugin_id}")
|
|
||||||
|
|
||||||
# Verify resolved path is within base directory
|
|
||||||
file_path = self.data_dir / f"{safe_name}.json"
|
|
||||||
resolved_path = file_path.resolve()
|
|
||||||
if not str(resolved_path).startswith(str(self._base_path)):
|
|
||||||
raise SecurityError(f"Path traversal detected: {plugin_id}")
|
|
||||||
|
|
||||||
return file_path
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. ✅ screenshot.py - Filename Sanitization & Path Validation
|
|
||||||
|
|
||||||
**Action:** Replaced vulnerable module with secure version
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- Backup created: `screenshot_vulnerable.py`
|
|
||||||
- Active module now: `screenshot_secure.py`
|
|
||||||
|
|
||||||
**Security Features Added:**
|
|
||||||
- Filename sanitization using `PathValidator.sanitize_filename()`
|
|
||||||
- Path resolution validation against base save path
|
|
||||||
- Region coordinate validation (prevent DoS via huge regions)
|
|
||||||
- Window handle validation (type and value checking)
|
|
||||||
- Dimension sanity checks
|
|
||||||
|
|
||||||
**Code Example:**
|
|
||||||
```python
|
|
||||||
def save_screenshot(self, image: Image.Image, filename: Optional[str] = None) -> Path:
|
|
||||||
# Sanitize filename
|
|
||||||
safe_filename = PathValidator.sanitize_filename(filename, '_')
|
|
||||||
|
|
||||||
filepath = self._save_path / safe_filename
|
|
||||||
|
|
||||||
# Security check: ensure resolved path is within save_path
|
|
||||||
try:
|
|
||||||
resolved_path = filepath.resolve()
|
|
||||||
if not str(resolved_path).startswith(str(self._base_save_path)):
|
|
||||||
raise SecurityError("Path traversal detected in filename")
|
|
||||||
except (OSError, ValueError) as e:
|
|
||||||
# Fallback to safe default
|
|
||||||
safe_filename = f"screenshot_{int(time.time())}.{self._format.lower()}"
|
|
||||||
filepath = self._save_path / safe_filename
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. ✅ clipboard.py - Input Validation & Size Limits
|
|
||||||
|
|
||||||
**Action:** Enhanced with security validation
|
|
||||||
|
|
||||||
**Security Features Added:**
|
|
||||||
- Maximum text length limit (10KB per entry)
|
|
||||||
- Maximum total storage limit (1MB)
|
|
||||||
- Null byte detection and rejection
|
|
||||||
- Text sanitization (control character removal)
|
|
||||||
- Source string length limiting
|
|
||||||
- Secure file permissions (0o600 - owner only)
|
|
||||||
- Temporary file atomic write pattern
|
|
||||||
|
|
||||||
**Code Example:**
|
|
||||||
```python
|
|
||||||
def _validate_text(self, text: str) -> tuple[bool, str]:
|
|
||||||
if not isinstance(text, str):
|
|
||||||
return False, "Text must be a string"
|
|
||||||
|
|
||||||
if '\x00' in text:
|
|
||||||
return False, "Text contains null bytes"
|
|
||||||
|
|
||||||
if len(text) > self._max_text_length:
|
|
||||||
return False, f"Text exceeds maximum length"
|
|
||||||
|
|
||||||
# Auto-cleanup to make room
|
|
||||||
current_size = sum(len(entry.text) for entry in self._history)
|
|
||||||
if current_size + len(text) > self._max_total_storage:
|
|
||||||
while self._history and current_size + len(text) > self._max_total_storage:
|
|
||||||
removed = self._history.popleft()
|
|
||||||
current_size -= len(removed.text)
|
|
||||||
|
|
||||||
return True, ""
|
|
||||||
|
|
||||||
def _save_history(self):
|
|
||||||
# Write with restricted permissions
|
|
||||||
temp_path = self._history_file.with_suffix('.tmp')
|
|
||||||
with open(temp_path, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(data, f, indent=2)
|
|
||||||
|
|
||||||
os.chmod(temp_path, 0o600) # Owner read/write only
|
|
||||||
temp_path.replace(self._history_file)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. ✅ http_client.py - URL Validation & SSRF Protection
|
|
||||||
|
|
||||||
**Action:** Enhanced with security validation
|
|
||||||
|
|
||||||
**Security Features Added:**
|
|
||||||
- URL scheme validation (only http:// and https:// allowed)
|
|
||||||
- Path traversal pattern detection (`..`, `@`, `\`, null bytes)
|
|
||||||
- SSRF protection (blocks private, loopback, reserved, link-local IPs)
|
|
||||||
- Custom exception classes for security errors
|
|
||||||
- URL validation on both GET and POST requests
|
|
||||||
|
|
||||||
**Code Example:**
|
|
||||||
```python
|
|
||||||
def _validate_url(self, url: str) -> str:
|
|
||||||
if not url:
|
|
||||||
raise URLSecurityError("URL cannot be empty")
|
|
||||||
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
parsed = urlparse(url)
|
|
||||||
|
|
||||||
# Check scheme
|
|
||||||
allowed_schemes = {'http', 'https'}
|
|
||||||
if parsed.scheme not in allowed_schemes:
|
|
||||||
raise URLSecurityError(f"URL scheme '{parsed.scheme}' not allowed")
|
|
||||||
|
|
||||||
# Check for dangerous patterns
|
|
||||||
dangerous_patterns = ['..', '@', '\\', '\x00']
|
|
||||||
for pattern in dangerous_patterns:
|
|
||||||
if pattern in url:
|
|
||||||
raise URLSecurityError(f"URL contains dangerous pattern")
|
|
||||||
|
|
||||||
# SSRF protection - block private IPs
|
|
||||||
hostname = parsed.hostname
|
|
||||||
if hostname:
|
|
||||||
try:
|
|
||||||
ip = ipaddress.ip_address(hostname)
|
|
||||||
if ip.is_private or ip.is_loopback or ip.is_reserved:
|
|
||||||
raise URLSecurityError(f"URL resolves to restricted IP")
|
|
||||||
except ValueError:
|
|
||||||
pass # Not an IP, it's a hostname
|
|
||||||
|
|
||||||
return url
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
| File | Action | Status |
|
|
||||||
|------|--------|--------|
|
|
||||||
| `core/data_store.py` | Replaced with secure version | ✅ Fixed |
|
|
||||||
| `core/data_store_vulnerable.py` | Backup created | ✅ Archived |
|
|
||||||
| `core/screenshot.py` | Replaced with secure version | ✅ Fixed |
|
|
||||||
| `core/screenshot_vulnerable.py` | Backup created | ✅ Archived |
|
|
||||||
| `core/clipboard.py` | Enhanced with validation | ✅ Fixed |
|
|
||||||
| `core/http_client.py` | Added URL validation | ✅ Fixed |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Remaining Recommendations
|
|
||||||
|
|
||||||
### Medium Priority (Not Yet Implemented)
|
|
||||||
|
|
||||||
1. **Plugin Manager Security**
|
|
||||||
- Implement plugin signature verification
|
|
||||||
- Add permission manifest system
|
|
||||||
- Consider sandboxed execution environment
|
|
||||||
|
|
||||||
2. **Audit Logging**
|
|
||||||
- Log all security violations
|
|
||||||
- Log plugin loading/unloading
|
|
||||||
- Log file operations outside data directories
|
|
||||||
|
|
||||||
### Low Priority (Future Enhancements)
|
|
||||||
|
|
||||||
3. **Data Encryption**
|
|
||||||
- Encrypt sensitive plugin data at rest
|
|
||||||
- Encrypt clipboard history with user password
|
|
||||||
|
|
||||||
4. **Rate Limiting**
|
|
||||||
- Per-plugin API rate limits
|
|
||||||
- Screenshot capture rate limiting
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Security Fixes
|
|
||||||
|
|
||||||
### Path Traversal Test
|
|
||||||
```python
|
|
||||||
from core.data_store import get_data_store
|
|
||||||
|
|
||||||
data_store = get_data_store()
|
|
||||||
|
|
||||||
# Should raise SecurityError
|
|
||||||
try:
|
|
||||||
data_store.save("../../../etc/passwd", "key", "data")
|
|
||||||
except SecurityError:
|
|
||||||
print("✅ Path traversal blocked in data_store")
|
|
||||||
|
|
||||||
# Should raise SecurityError
|
|
||||||
try:
|
|
||||||
from core.screenshot import get_screenshot_service
|
|
||||||
service = get_screenshot_service()
|
|
||||||
service.save_screenshot(image, "../../../malware.exe")
|
|
||||||
except SecurityError:
|
|
||||||
print("✅ Path traversal blocked in screenshot")
|
|
||||||
```
|
|
||||||
|
|
||||||
### URL Validation Test
|
|
||||||
```python
|
|
||||||
from core.http_client import HTTPClient, URLSecurityError
|
|
||||||
|
|
||||||
client = HTTPClient()
|
|
||||||
|
|
||||||
# Should raise URLSecurityError
|
|
||||||
try:
|
|
||||||
client.get("file:///etc/passwd")
|
|
||||||
except URLSecurityError:
|
|
||||||
print("✅ File protocol blocked")
|
|
||||||
|
|
||||||
try:
|
|
||||||
client.get("http://127.0.0.1/admin")
|
|
||||||
except URLSecurityError:
|
|
||||||
print("✅ Localhost blocked (SSRF protection)")
|
|
||||||
|
|
||||||
try:
|
|
||||||
client.get("http://192.168.1.1/admin")
|
|
||||||
except URLSecurityError:
|
|
||||||
print("✅ Private IP blocked (SSRF protection)")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clipboard Validation Test
|
|
||||||
```python
|
|
||||||
from core.clipboard import get_clipboard_manager
|
|
||||||
|
|
||||||
clipboard = get_clipboard_manager()
|
|
||||||
|
|
||||||
# Should fail - too large
|
|
||||||
result = clipboard.copy("x" * (11 * 1024)) # 11KB
|
|
||||||
assert result == False, "Should reject oversized text"
|
|
||||||
print("✅ Size limit enforced")
|
|
||||||
|
|
||||||
# Should sanitize null bytes
|
|
||||||
result = clipboard.copy("hello\x00world")
|
|
||||||
assert result == False, "Should reject null bytes"
|
|
||||||
print("✅ Null byte protection working")
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Checklist
|
|
||||||
|
|
||||||
- [x] Path traversal protection (data_store)
|
|
||||||
- [x] Path traversal protection (screenshot)
|
|
||||||
- [x] Filename sanitization
|
|
||||||
- [x] Input validation (clipboard)
|
|
||||||
- [x] Size limits (clipboard)
|
|
||||||
- [x] URL validation (http_client)
|
|
||||||
- [x] SSRF protection (http_client)
|
|
||||||
- [x] Secure file permissions
|
|
||||||
- [x] Atomic file writes
|
|
||||||
- [x] Data structure validation
|
|
||||||
- [ ] Plugin signature verification (future)
|
|
||||||
- [ ] Plugin sandboxing (future)
|
|
||||||
- [ ] Audit logging (future)
|
|
||||||
- [ ] Data encryption (future)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contact
|
|
||||||
|
|
||||||
For questions about these security fixes, refer to:
|
|
||||||
- `SECURITY_AUDIT_REPORT.md` - Full audit report
|
|
||||||
- `core/security_utils.py` - Security utility classes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Security fixes applied by Security Auditor Agent*
|
|
||||||
*EU-Utility Security Hardening 2026*
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
# UI/UX Excellence Transformation - Summary
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
Successfully transformed EU-Utility's UI to be professional, polished, and completely emoji-free.
|
|
||||||
|
|
||||||
## Changes Made
|
|
||||||
|
|
||||||
### 1. SVG Icons Created (assets/icons/)
|
|
||||||
- `dashboard.svg` - Grid-based dashboard icon
|
|
||||||
- `plugins.svg` - Monitor/plugins icon
|
|
||||||
- `widgets.svg` - Widget grid icon
|
|
||||||
- `settings.svg` - Gear/cog icon (Phosphor style)
|
|
||||||
- `search.svg` - Magnifying glass icon
|
|
||||||
- `clock.svg` - Clock/time icon
|
|
||||||
- `menu.svg` - Hamburger menu icon
|
|
||||||
- `close.svg` - X close icon
|
|
||||||
- `minimize.svg` - Minimize dash icon
|
|
||||||
- `pin.svg` - Star/pin icon
|
|
||||||
- `check.svg` - Checkmark icon
|
|
||||||
- `warning.svg` - Triangle warning icon
|
|
||||||
- `info.svg` - Information circle icon
|
|
||||||
- `more.svg` - Three dots/more icon
|
|
||||||
|
|
||||||
All icons are:
|
|
||||||
- 32px optimized SVG files
|
|
||||||
- Monochrome (white stroke)
|
|
||||||
- Phosphor Icons style
|
|
||||||
- Consistent 2px stroke width
|
|
||||||
- Clean, minimalist design
|
|
||||||
|
|
||||||
### 2. Files Updated - Emojis Removed
|
|
||||||
|
|
||||||
#### core/perfect_ux.py
|
|
||||||
- NavigationRail: Replaced text emojis (◆, 🔌, 🎨, ⚙️) with SVG icons
|
|
||||||
- Button: Added icon support via `icon` parameter
|
|
||||||
- Activity items: Replaced emoji status icons with SVG icons (check, info, more)
|
|
||||||
- Quick Actions: Replaced emoji buttons with SVG icons (camera, package, globe, bar-chart)
|
|
||||||
- Added glassmorphism effects to Surface component
|
|
||||||
- Orange left border (3px) on active navigation items
|
|
||||||
- EU color scheme: dark blue (#141f23), orange accent (#ff8c42)
|
|
||||||
|
|
||||||
#### core/activity_bar.py
|
|
||||||
- Start button: Replaced ⊞ emoji with grid SVG icon
|
|
||||||
- Plugin buttons: Now use icon_name attribute with SVG icons
|
|
||||||
- Clock: Added clock SVG icon next to time display
|
|
||||||
- Context menu: Removed emoji from "Settings" and "Hide" actions
|
|
||||||
- Drawer items: Now display plugin icons
|
|
||||||
|
|
||||||
#### core/ui/dashboard_view.py
|
|
||||||
- Header: Added dashboard SVG icon
|
|
||||||
- Plugin Store button: Replaced 🔌 emoji with shopping-bag SVG icon
|
|
||||||
- Plugin Widgets section: Removed 🔌 emoji from label
|
|
||||||
- Updated styling to match EU color palette
|
|
||||||
|
|
||||||
#### core/ui/search_view.py
|
|
||||||
- Header: Added search SVG icon, removed 🔍 emoji
|
|
||||||
- Hint text: Removed 💡 emoji
|
|
||||||
- Updated border colors to use EU orange accent
|
|
||||||
|
|
||||||
#### core/ui/settings_view.py
|
|
||||||
- Header: Added settings SVG icon, removed ⚙️ emoji
|
|
||||||
- Tab labels: Removed emojis (🔌, 📦, ⌨️, 💾, 🔄)
|
|
||||||
- Button labels: Removed emojis (📤, 📥, 🗑, 🔍)
|
|
||||||
- Updated styling to EU color palette
|
|
||||||
|
|
||||||
### 3. Design System Improvements
|
|
||||||
|
|
||||||
#### Color Palette
|
|
||||||
- Primary Background: #141f23 (EU dark blue)
|
|
||||||
- Accent Color: #ff8c42 (EU orange)
|
|
||||||
- Surface: rgba(20, 31, 35, 0.95) with glassmorphism
|
|
||||||
- Borders: rgba(255, 140, 66, 0.1) subtle orange tint
|
|
||||||
|
|
||||||
#### Spacing (8dp Grid)
|
|
||||||
- XS: 4px
|
|
||||||
- S: 8px
|
|
||||||
- M: 16px
|
|
||||||
- L: 24px
|
|
||||||
- XL: 32px
|
|
||||||
|
|
||||||
#### Active State Indicators
|
|
||||||
- Orange left border (3px) on active navigation items
|
|
||||||
- Background highlight on hover
|
|
||||||
- Smooth transitions (150-350ms)
|
|
||||||
|
|
||||||
### 4. Integration
|
|
||||||
- All UI components now use `icon_manager.get_icon()` and `icon_manager.get_pixmap()`
|
|
||||||
- Consistent 24px icon size in navigation
|
|
||||||
- Consistent 20px icon size in buttons
|
|
||||||
- Tooltips for all icon-only buttons
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
- All main UI files are now emoji-free
|
|
||||||
- 50 total SVG icons in assets/icons/
|
|
||||||
- Professional, consistent appearance throughout
|
|
||||||
- EU brand colors applied consistently
|
|
||||||
|
|
@ -0,0 +1,868 @@
|
||||||
|
"""
|
||||||
|
EU-Utility - Modern UI Design System
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
A beautiful, modern design system for EU-Utility featuring:
|
||||||
|
- Dark gaming aesthetic with EU orange accents
|
||||||
|
- Glassmorphism effects throughout
|
||||||
|
- Smooth 60fps animations
|
||||||
|
- Responsive layouts
|
||||||
|
- Professional iconography
|
||||||
|
|
||||||
|
Design Principles:
|
||||||
|
1. Visual Hierarchy - Clear distinction between elements
|
||||||
|
2. Consistency - Unified design language
|
||||||
|
3. Feedback - Clear interactive states
|
||||||
|
4. Performance - GPU-accelerated animations
|
||||||
|
5. Accessibility - WCAG compliant contrast ratios
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt6.QtCore import Qt, QPropertyAnimation, QEasingCurve, QParallelAnimationGroup, QTimer
|
||||||
|
from PyQt6.QtCore import pyqtSignal, QSize, QPoint, QRectF
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QWidget, QFrame, QPushButton, QLabel, QVBoxLayout, QHBoxLayout,
|
||||||
|
QGraphicsDropShadowEffect, QGraphicsOpacityEffect, QLineEdit,
|
||||||
|
QScrollArea, QStackedWidget, QProgressBar, QTextEdit, QComboBox
|
||||||
|
)
|
||||||
|
from PyQt6.QtGui import (
|
||||||
|
QColor, QPainter, QLinearGradient, QRadialGradient, QFont,
|
||||||
|
QFontDatabase, QIcon, QPixmap, QCursor, QPainterPath
|
||||||
|
)
|
||||||
|
from typing import Optional, Callable, List, Dict, Any
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# DESIGN TOKENS - Centralized Design System
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
class DesignTokens:
|
||||||
|
"""Central design tokens for consistent UI across the application."""
|
||||||
|
|
||||||
|
# Brand Colors
|
||||||
|
BRAND_ORANGE = "#FF6B35"
|
||||||
|
BRAND_ORANGE_LIGHT = "#FF8C5A"
|
||||||
|
BRAND_ORANGE_DARK = "#E55A2B"
|
||||||
|
BRAND_ORANGE_GLOW = "rgba(255, 107, 53, 0.4)"
|
||||||
|
|
||||||
|
# Extended Color Palette
|
||||||
|
COLORS = {
|
||||||
|
# Primary
|
||||||
|
'primary': '#FF6B35',
|
||||||
|
'primary_hover': '#FF8C5A',
|
||||||
|
'primary_pressed': '#E55A2B',
|
||||||
|
'primary_glow': 'rgba(255, 107, 53, 0.4)',
|
||||||
|
|
||||||
|
# Backgrounds - Deep space aesthetic
|
||||||
|
'bg_darkest': '#0A0C10',
|
||||||
|
'bg_dark': '#111318',
|
||||||
|
'bg_card': '#161920',
|
||||||
|
'bg_elevated': '#1D2129',
|
||||||
|
'bg_hover': '#252A33',
|
||||||
|
'bg_pressed': '#2D333D',
|
||||||
|
|
||||||
|
# Surfaces with glassmorphism
|
||||||
|
'surface': 'rgba(22, 25, 32, 0.85)',
|
||||||
|
'surface_hover': 'rgba(29, 33, 41, 0.9)',
|
||||||
|
'surface_active': 'rgba(37, 42, 51, 0.95)',
|
||||||
|
|
||||||
|
# Accents
|
||||||
|
'accent_teal': '#00D4AA',
|
||||||
|
'accent_blue': '#4D9CFF',
|
||||||
|
'accent_purple': '#A855F7',
|
||||||
|
'accent_yellow': '#FBBF24',
|
||||||
|
'accent_green': '#22C55E',
|
||||||
|
'accent_red': '#EF4444',
|
||||||
|
|
||||||
|
# Text
|
||||||
|
'text_primary': '#F0F4F8',
|
||||||
|
'text_secondary': '#9CA3AF',
|
||||||
|
'text_muted': '#6B7280',
|
||||||
|
'text_disabled': '#4B5563',
|
||||||
|
|
||||||
|
# Borders
|
||||||
|
'border_subtle': 'rgba(255, 255, 255, 0.06)',
|
||||||
|
'border_default': 'rgba(255, 255, 255, 0.1)',
|
||||||
|
'border_hover': 'rgba(255, 255, 255, 0.15)',
|
||||||
|
'border_focus': 'rgba(255, 107, 53, 0.5)',
|
||||||
|
'border_active': 'rgba(255, 107, 53, 0.8)',
|
||||||
|
|
||||||
|
# Status
|
||||||
|
'success': '#22C55E',
|
||||||
|
'warning': '#FBBF24',
|
||||||
|
'error': '#EF4444',
|
||||||
|
'info': '#4D9CFF',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Typography
|
||||||
|
TYPOGRAPHY = {
|
||||||
|
'font_family': '"Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont, sans-serif',
|
||||||
|
'font_mono': '"JetBrains Mono", "Fira Code", monospace',
|
||||||
|
|
||||||
|
'size_xs': 11,
|
||||||
|
'size_sm': 12,
|
||||||
|
'size_base': 13,
|
||||||
|
'size_md': 14,
|
||||||
|
'size_lg': 16,
|
||||||
|
'size_xl': 18,
|
||||||
|
'size_2xl': 20,
|
||||||
|
'size_3xl': 24,
|
||||||
|
'size_4xl': 30,
|
||||||
|
'size_5xl': 36,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Spacing (4px grid system)
|
||||||
|
SPACING = {
|
||||||
|
'0': 0,
|
||||||
|
'1': 4,
|
||||||
|
'2': 8,
|
||||||
|
'3': 12,
|
||||||
|
'4': 16,
|
||||||
|
'5': 20,
|
||||||
|
'6': 24,
|
||||||
|
'8': 32,
|
||||||
|
'10': 40,
|
||||||
|
'12': 48,
|
||||||
|
'16': 64,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Border Radius
|
||||||
|
RADIUS = {
|
||||||
|
'none': 0,
|
||||||
|
'sm': 4,
|
||||||
|
'md': 8,
|
||||||
|
'lg': 12,
|
||||||
|
'xl': 16,
|
||||||
|
'2xl': 20,
|
||||||
|
'3xl': 24,
|
||||||
|
'full': 9999,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Shadows
|
||||||
|
SHADOWS = {
|
||||||
|
'sm': '0 1px 2px rgba(0, 0, 0, 0.3)',
|
||||||
|
'md': '0 4px 6px rgba(0, 0, 0, 0.4)',
|
||||||
|
'lg': '0 10px 15px rgba(0, 0, 0, 0.5)',
|
||||||
|
'xl': '0 20px 25px rgba(0, 0, 0, 0.6)',
|
||||||
|
'glow': '0 0 20px rgba(255, 107, 53, 0.3)',
|
||||||
|
'glow_strong': '0 0 30px rgba(255, 107, 53, 0.5)',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Animation Durations (ms)
|
||||||
|
DURATION = {
|
||||||
|
'fast': 150,
|
||||||
|
'normal': 250,
|
||||||
|
'slow': 350,
|
||||||
|
'slower': 500,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Easing Curves
|
||||||
|
EASING = {
|
||||||
|
'default': QEasingCurve.Type.OutCubic,
|
||||||
|
'bounce': QEasingCurve.Type.OutBounce,
|
||||||
|
'elastic': QEasingCurve.Type.OutElastic,
|
||||||
|
'smooth': QEasingCurve.Type.InOutCubic,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def color(cls, name: str) -> str:
|
||||||
|
"""Get color by name."""
|
||||||
|
return cls.COLORS.get(name, '#FFFFFF')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def spacing(cls, name: str) -> int:
|
||||||
|
"""Get spacing value."""
|
||||||
|
return cls.SPACING.get(name, 0)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def radius(cls, name: str) -> int:
|
||||||
|
"""Get border radius value."""
|
||||||
|
return cls.RADIUS.get(name, 0)
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# ANIMATION UTILITIES
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
class AnimationManager:
|
||||||
|
"""Manages smooth GPU-accelerated animations."""
|
||||||
|
|
||||||
|
_active_animations: List[QPropertyAnimation] = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fade_in(cls, widget: QWidget, duration: int = 250) -> QPropertyAnimation:
|
||||||
|
"""Fade in a widget smoothly."""
|
||||||
|
effect = QGraphicsOpacityEffect(widget)
|
||||||
|
widget.setGraphicsEffect(effect)
|
||||||
|
|
||||||
|
anim = QPropertyAnimation(effect, b"opacity")
|
||||||
|
anim.setDuration(duration)
|
||||||
|
anim.setStartValue(0.0)
|
||||||
|
anim.setEndValue(1.0)
|
||||||
|
anim.setEasingCurve(QEasingCurve.Type.OutCubic)
|
||||||
|
|
||||||
|
cls._active_animations.append(anim)
|
||||||
|
anim.finished.connect(lambda: cls._cleanup_animation(anim))
|
||||||
|
|
||||||
|
return anim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fade_out(cls, widget: QWidget, duration: int = 200, on_finish: Optional[Callable] = None) -> QPropertyAnimation:
|
||||||
|
"""Fade out a widget smoothly."""
|
||||||
|
effect = widget.graphicsEffect()
|
||||||
|
if not isinstance(effect, QGraphicsOpacityEffect):
|
||||||
|
effect = QGraphicsOpacityEffect(widget)
|
||||||
|
widget.setGraphicsEffect(effect)
|
||||||
|
|
||||||
|
anim = QPropertyAnimation(effect, b"opacity")
|
||||||
|
anim.setDuration(duration)
|
||||||
|
anim.setStartValue(1.0)
|
||||||
|
anim.setEndValue(0.0)
|
||||||
|
anim.setEasingCurve(QEasingCurve.Type.InCubic)
|
||||||
|
|
||||||
|
if on_finish:
|
||||||
|
anim.finished.connect(on_finish)
|
||||||
|
|
||||||
|
cls._active_animations.append(anim)
|
||||||
|
anim.finished.connect(lambda: cls._cleanup_animation(anim))
|
||||||
|
|
||||||
|
return anim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def slide_in(cls, widget: QWidget, direction: str = "bottom", duration: int = 300) -> QPropertyAnimation:
|
||||||
|
"""Slide widget in from specified direction."""
|
||||||
|
anim = QPropertyAnimation(widget, b"pos")
|
||||||
|
anim.setDuration(duration)
|
||||||
|
anim.setEasingCurve(QEasingCurve.Type.OutCubic)
|
||||||
|
|
||||||
|
current_pos = widget.pos()
|
||||||
|
|
||||||
|
if direction == "left":
|
||||||
|
start_pos = current_pos - QPoint(widget.width() + 20, 0)
|
||||||
|
elif direction == "right":
|
||||||
|
start_pos = current_pos + QPoint(widget.width() + 20, 0)
|
||||||
|
elif direction == "top":
|
||||||
|
start_pos = current_pos - QPoint(0, widget.height() + 20)
|
||||||
|
else: # bottom
|
||||||
|
start_pos = current_pos + QPoint(0, widget.height() + 20)
|
||||||
|
|
||||||
|
anim.setStartValue(start_pos)
|
||||||
|
anim.setEndValue(current_pos)
|
||||||
|
|
||||||
|
cls._active_animations.append(anim)
|
||||||
|
anim.finished.connect(lambda: cls._cleanup_animation(anim))
|
||||||
|
|
||||||
|
return anim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def scale(cls, widget: QWidget, from_scale: float = 0.9, to_scale: float = 1.0, duration: int = 250) -> QPropertyAnimation:
|
||||||
|
"""Scale animation for widgets."""
|
||||||
|
anim = QPropertyAnimation(widget, b"minimumWidth")
|
||||||
|
anim.setDuration(duration)
|
||||||
|
anim.setEasingCurve(QEasingCurve.Type.OutBack)
|
||||||
|
|
||||||
|
base_width = widget.width()
|
||||||
|
anim.setStartValue(int(base_width * from_scale))
|
||||||
|
anim.setEndValue(int(base_width * to_scale))
|
||||||
|
|
||||||
|
cls._active_animations.append(anim)
|
||||||
|
anim.finished.connect(lambda: cls._cleanup_animation(anim))
|
||||||
|
|
||||||
|
return anim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def pulse_glow(cls, widget: QWidget, duration: int = 2000) -> QPropertyAnimation:
|
||||||
|
"""Create a pulsing glow effect."""
|
||||||
|
effect = QGraphicsDropShadowEffect(widget)
|
||||||
|
effect.setColor(QColor(255, 107, 53))
|
||||||
|
effect.setBlurRadius(20)
|
||||||
|
effect.setOffset(0, 0)
|
||||||
|
widget.setGraphicsEffect(effect)
|
||||||
|
|
||||||
|
anim = QPropertyAnimation(effect, b"blurRadius")
|
||||||
|
anim.setDuration(duration)
|
||||||
|
anim.setStartValue(20)
|
||||||
|
anim.setEndValue(40)
|
||||||
|
anim.setEasingCurve(QEasingCurve.Type.InOutSine)
|
||||||
|
anim.setLoopCount(-1)
|
||||||
|
|
||||||
|
return anim
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _cleanup_animation(cls, anim: QPropertyAnimation):
|
||||||
|
"""Remove completed animation from tracking."""
|
||||||
|
if anim in cls._active_animations:
|
||||||
|
cls._active_animations.remove(anim)
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# MODERN COMPONENTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
class GlassCard(QFrame):
|
||||||
|
"""Glassmorphism card with frosted glass effect."""
|
||||||
|
|
||||||
|
clicked = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None, elevation: int = 1, hover_lift: bool = True):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.elevation = elevation
|
||||||
|
self.hover_lift = hover_lift
|
||||||
|
self._hovered = False
|
||||||
|
|
||||||
|
self._setup_style()
|
||||||
|
self._setup_shadow()
|
||||||
|
|
||||||
|
if hover_lift:
|
||||||
|
self.setMouseTracking(True)
|
||||||
|
|
||||||
|
def _setup_style(self):
|
||||||
|
"""Apply glassmorphism styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
opacity = 0.85 + (self.elevation * 0.03)
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
GlassCard {{
|
||||||
|
background: rgba(22, 25, 32, {min(opacity, 0.95)});
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: {DesignTokens.radius('xl')}px;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
|
def _setup_shadow(self):
|
||||||
|
"""Apply elevation shadow."""
|
||||||
|
self._shadow = QGraphicsDropShadowEffect(self)
|
||||||
|
self._shadow.setBlurRadius(self.elevation * 15)
|
||||||
|
self._shadow.setColor(QColor(0, 0, 0, int(80 + self.elevation * 20)))
|
||||||
|
self._shadow.setOffset(0, self.elevation * 3)
|
||||||
|
self.setGraphicsEffect(self._shadow)
|
||||||
|
|
||||||
|
def enterEvent(self, event):
|
||||||
|
"""Hover effect."""
|
||||||
|
if self.hover_lift:
|
||||||
|
self._hovered = True
|
||||||
|
self._shadow.setBlurRadius((self.elevation + 1) * 15)
|
||||||
|
self._shadow.setColor(QColor(0, 0, 0, int(100 + (self.elevation + 1) * 20)))
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
GlassCard {{
|
||||||
|
background: rgba(29, 33, 41, 0.9);
|
||||||
|
border: 1px solid rgba(255, 107, 53, 0.2);
|
||||||
|
border-radius: {DesignTokens.radius('xl')}px;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
super().enterEvent(event)
|
||||||
|
|
||||||
|
def leaveEvent(self, event):
|
||||||
|
"""Reset hover effect."""
|
||||||
|
if self.hover_lift:
|
||||||
|
self._hovered = False
|
||||||
|
self._setup_shadow()
|
||||||
|
self._setup_style()
|
||||||
|
super().leaveEvent(event)
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
"""Handle click."""
|
||||||
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self.clicked.emit()
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class ModernButton(QPushButton):
|
||||||
|
"""Modern button with smooth animations and multiple variants."""
|
||||||
|
|
||||||
|
VARIANTS = ['primary', 'secondary', 'ghost', 'outline', 'danger', 'glass']
|
||||||
|
|
||||||
|
def __init__(self, text: str = "", variant: str = 'primary', icon: str = None, parent=None):
|
||||||
|
super().__init__(text, parent)
|
||||||
|
self.variant = variant
|
||||||
|
self.icon_text = icon
|
||||||
|
|
||||||
|
self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||||
|
self._apply_style()
|
||||||
|
self._setup_animations()
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply button styling based on variant."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
r = DesignTokens.radius('full')
|
||||||
|
|
||||||
|
styles = {
|
||||||
|
'primary': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||||
|
stop:0 {c['primary']}, stop:1 {c['primary_hover']});
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||||
|
stop:0 {c['primary_hover']}, stop:1 {c['primary']});
|
||||||
|
}}
|
||||||
|
ModernButton:pressed {{
|
||||||
|
background: {c['primary_pressed']};
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
'secondary': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 1px solid {c['border_default']};
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: {c['bg_hover']};
|
||||||
|
border-color: {c['border_hover']};
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
'ghost': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: transparent;
|
||||||
|
color: {c['text_secondary']};
|
||||||
|
border: none;
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 500;
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: {c['text_primary']};
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
'outline': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: transparent;
|
||||||
|
color: {c['primary']};
|
||||||
|
border: 2px solid {c['primary']};
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 10px 22px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: rgba(255, 107, 53, 0.1);
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
'danger': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: {c['error']};
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: #DC2626;
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
'glass': f"""
|
||||||
|
ModernButton {{
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
color: white;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}}
|
||||||
|
ModernButton:hover {{
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
border-color: rgba(255, 107, 53, 0.3);
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setStyleSheet(styles.get(self.variant, styles['primary']))
|
||||||
|
self.setFixedHeight(44)
|
||||||
|
|
||||||
|
def _setup_animations(self):
|
||||||
|
"""Setup press animation."""
|
||||||
|
self._press_anim = QPropertyAnimation(self, b"minimumHeight")
|
||||||
|
self._press_anim.setDuration(100)
|
||||||
|
self._press_anim.setEasingCurve(QEasingCurve.Type.OutQuad)
|
||||||
|
|
||||||
|
def enterEvent(self, event):
|
||||||
|
"""Hover animation."""
|
||||||
|
super().enterEvent(event)
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
"""Press animation."""
|
||||||
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self._press_anim.setStartValue(44)
|
||||||
|
self._press_anim.setEndValue(42)
|
||||||
|
self._press_anim.start()
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
def mouseReleaseEvent(self, event):
|
||||||
|
"""Release animation."""
|
||||||
|
self._press_anim.setStartValue(42)
|
||||||
|
self._press_anim.setEndValue(44)
|
||||||
|
self._press_anim.start()
|
||||||
|
super().mouseReleaseEvent(event)
|
||||||
|
|
||||||
|
|
||||||
|
class ModernInput(QLineEdit):
|
||||||
|
"""Modern input field with floating label and animations."""
|
||||||
|
|
||||||
|
def __init__(self, placeholder: str = "", parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setPlaceholderText(placeholder)
|
||||||
|
self._apply_style()
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply modern input styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
r = DesignTokens.radius('lg')
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
ModernInput {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 2px solid {c['border_default']};
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
selection-background-color: {c['primary']};
|
||||||
|
}}
|
||||||
|
ModernInput:hover {{
|
||||||
|
border-color: {c['border_hover']};
|
||||||
|
}}
|
||||||
|
ModernInput:focus {{
|
||||||
|
border-color: {c['primary']};
|
||||||
|
background: {c['bg_card']};
|
||||||
|
}}
|
||||||
|
ModernInput::placeholder {{
|
||||||
|
color: {c['text_muted']};
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
self.setFixedHeight(48)
|
||||||
|
|
||||||
|
|
||||||
|
class ModernComboBox(QComboBox):
|
||||||
|
"""Modern dropdown with custom styling."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._apply_style()
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply modern combobox styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
r = DesignTokens.radius('lg')
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
ModernComboBox {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 2px solid {c['border_default']};
|
||||||
|
border-radius: {r}px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_md']}px;
|
||||||
|
min-width: 150px;
|
||||||
|
}}
|
||||||
|
ModernComboBox:hover {{
|
||||||
|
border-color: {c['border_hover']};
|
||||||
|
}}
|
||||||
|
ModernComboBox:focus {{
|
||||||
|
border-color: {c['primary']};
|
||||||
|
}}
|
||||||
|
ModernComboBox::drop-down {{
|
||||||
|
border: none;
|
||||||
|
width: 30px;
|
||||||
|
}}
|
||||||
|
ModernComboBox::down-arrow {{
|
||||||
|
image: none;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-top: 5px solid {c['text_secondary']};
|
||||||
|
}}
|
||||||
|
ModernComboBox QAbstractItemView {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 1px solid {c['border_default']};
|
||||||
|
border-radius: {r}px;
|
||||||
|
selection-background-color: {c['bg_hover']};
|
||||||
|
selection-color: {c['text_primary']};
|
||||||
|
padding: 4px;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
self.setFixedHeight(48)
|
||||||
|
|
||||||
|
|
||||||
|
class Badge(QLabel):
|
||||||
|
"""Status badge with various styles."""
|
||||||
|
|
||||||
|
STYLES = ['default', 'success', 'warning', 'error', 'info', 'primary']
|
||||||
|
|
||||||
|
def __init__(self, text: str = "", style: str = 'default', parent=None):
|
||||||
|
super().__init__(text, parent)
|
||||||
|
self.badge_style = style
|
||||||
|
self._apply_style()
|
||||||
|
self.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply badge styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
'default': ('rgba(255,255,255,0.1)', c['text_secondary']),
|
||||||
|
'success': ('rgba(34, 197, 94, 0.2)', c['accent_green']),
|
||||||
|
'warning': ('rgba(251, 191, 36, 0.2)', c['accent_yellow']),
|
||||||
|
'error': ('rgba(239, 68, 68, 0.2)', c['accent_red']),
|
||||||
|
'info': ('rgba(77, 156, 255, 0.2)', c['accent_blue']),
|
||||||
|
'primary': ('rgba(255, 107, 53, 0.2)', c['primary']),
|
||||||
|
}
|
||||||
|
|
||||||
|
bg, fg = colors.get(self.badge_style, colors['default'])
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
Badge {{
|
||||||
|
background: {bg};
|
||||||
|
color: {fg};
|
||||||
|
border-radius: {DesignTokens.radius('full')}px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_xs']}px;
|
||||||
|
font-weight: 600;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Add subtle shadow
|
||||||
|
shadow = QGraphicsDropShadowEffect(self)
|
||||||
|
shadow.setBlurRadius(4)
|
||||||
|
shadow.setColor(QColor(0, 0, 0, 40))
|
||||||
|
shadow.setOffset(0, 1)
|
||||||
|
self.setGraphicsEffect(shadow)
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressIndicator(QProgressBar):
|
||||||
|
"""Modern progress indicator with gradient."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._apply_style()
|
||||||
|
self.setTextVisible(False)
|
||||||
|
self.setRange(0, 100)
|
||||||
|
self.setValue(0)
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply modern progress styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
ProgressIndicator {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
border: none;
|
||||||
|
border-radius: {DesignTokens.radius('full')}px;
|
||||||
|
height: 6px;
|
||||||
|
}}
|
||||||
|
ProgressIndicator::chunk {{
|
||||||
|
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||||
|
stop:0 {c['primary']}, stop:1 {c['primary_hover']});
|
||||||
|
border-radius: {DesignTokens.radius('full')}px;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
self.setFixedHeight(6)
|
||||||
|
|
||||||
|
|
||||||
|
class IconButton(QPushButton):
|
||||||
|
"""Circular icon button with hover effects."""
|
||||||
|
|
||||||
|
def __init__(self, icon_text: str = "", size: int = 40, tooltip: str = "", parent=None):
|
||||||
|
super().__init__(icon_text, parent)
|
||||||
|
self.setFixedSize(size, size)
|
||||||
|
self.setToolTip(tooltip)
|
||||||
|
self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||||
|
self._apply_style()
|
||||||
|
|
||||||
|
def _apply_style(self):
|
||||||
|
"""Apply icon button styling."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
size = self.width()
|
||||||
|
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
IconButton {{
|
||||||
|
background: transparent;
|
||||||
|
color: {c['text_secondary']};
|
||||||
|
border: none;
|
||||||
|
border-radius: {size // 2}px;
|
||||||
|
font-size: 16px;
|
||||||
|
}}
|
||||||
|
IconButton:hover {{
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
color: {c['text_primary']};
|
||||||
|
}}
|
||||||
|
IconButton:pressed {{
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# LAYOUT HELPERS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
def create_spacer(horizontal: bool = False, size: int = None):
|
||||||
|
"""Create a spacer item."""
|
||||||
|
from PyQt6.QtWidgets import QSpacerItem, QSizePolicy
|
||||||
|
|
||||||
|
if horizontal:
|
||||||
|
policy = QSizePolicy.Policy.Expanding
|
||||||
|
min_policy = QSizePolicy.Policy.Minimum
|
||||||
|
return QSpacerItem(size or 0, 0, policy, min_policy)
|
||||||
|
else:
|
||||||
|
policy = QSizePolicy.Policy.Expanding
|
||||||
|
min_policy = QSizePolicy.Policy.Minimum
|
||||||
|
return QSpacerItem(0, size or 0, min_policy, policy)
|
||||||
|
|
||||||
|
|
||||||
|
def create_separator(horizontal: bool = True):
|
||||||
|
"""Create a styled separator line."""
|
||||||
|
separator = QFrame()
|
||||||
|
if horizontal:
|
||||||
|
separator.setFrameShape(QFrame.Shape.HLine)
|
||||||
|
separator.setFixedHeight(1)
|
||||||
|
else:
|
||||||
|
separator.setFrameShape(QFrame.Shape.VLine)
|
||||||
|
separator.setFixedWidth(1)
|
||||||
|
|
||||||
|
separator.setStyleSheet(f"""
|
||||||
|
background: {DesignTokens.color('border_subtle')};
|
||||||
|
""")
|
||||||
|
return separator
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# GLOBAL STYLESHEET
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
def get_global_stylesheet() -> str:
|
||||||
|
"""Get complete global stylesheet for the application."""
|
||||||
|
c = DesignTokens.COLORS
|
||||||
|
|
||||||
|
return f"""
|
||||||
|
/* Base */
|
||||||
|
QWidget {{
|
||||||
|
font-family: {DesignTokens.TYPOGRAPHY['font_family']};
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_base']}px;
|
||||||
|
color: {c['text_primary']};
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Main Window */
|
||||||
|
QMainWindow {{
|
||||||
|
background: {c['bg_darkest']};
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Selection */
|
||||||
|
::selection {{
|
||||||
|
background: {c['primary']};
|
||||||
|
color: white;
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Scrollbars */
|
||||||
|
QScrollBar:vertical {{
|
||||||
|
background: transparent;
|
||||||
|
width: 8px;
|
||||||
|
margin: 0;
|
||||||
|
}}
|
||||||
|
QScrollBar::handle:vertical {{
|
||||||
|
background: {c['border_default']};
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: 40px;
|
||||||
|
}}
|
||||||
|
QScrollBar::handle:vertical:hover {{
|
||||||
|
background: {c['border_hover']};
|
||||||
|
}}
|
||||||
|
QScrollBar::add-line:vertical,
|
||||||
|
QScrollBar::sub-line:vertical {{
|
||||||
|
height: 0;
|
||||||
|
}}
|
||||||
|
|
||||||
|
QScrollBar:horizontal {{
|
||||||
|
background: transparent;
|
||||||
|
height: 8px;
|
||||||
|
margin: 0;
|
||||||
|
}}
|
||||||
|
QScrollBar::handle:horizontal {{
|
||||||
|
background: {c['border_default']};
|
||||||
|
border-radius: 4px;
|
||||||
|
min-width: 40px;
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Tooltips */
|
||||||
|
QToolTip {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 1px solid {c['border_default']};
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: {DesignTokens.TYPOGRAPHY['size_sm']}px;
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
QMenu {{
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
color: {c['text_primary']};
|
||||||
|
border: 1px solid {c['border_default']};
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 8px;
|
||||||
|
}}
|
||||||
|
QMenu::item {{
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}}
|
||||||
|
QMenu::item:selected {{
|
||||||
|
background: {c['bg_hover']};
|
||||||
|
}}
|
||||||
|
QMenu::separator {{
|
||||||
|
height: 1px;
|
||||||
|
background: {c['border_subtle']};
|
||||||
|
margin: 8px 0;
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Check Box */
|
||||||
|
QCheckBox {{
|
||||||
|
spacing: 8px;
|
||||||
|
}}
|
||||||
|
QCheckBox::indicator {{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border: 2px solid {c['border_default']};
|
||||||
|
border-radius: 6px;
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
}}
|
||||||
|
QCheckBox::indicator:hover {{
|
||||||
|
border-color: {c['border_hover']};
|
||||||
|
}}
|
||||||
|
QCheckBox::indicator:checked {{
|
||||||
|
background: {c['primary']};
|
||||||
|
border-color: {c['primary']};
|
||||||
|
}}
|
||||||
|
|
||||||
|
/* Slider */
|
||||||
|
QSlider::groove:horizontal {{
|
||||||
|
height: 4px;
|
||||||
|
background: {c['bg_elevated']};
|
||||||
|
border-radius: 2px;
|
||||||
|
}}
|
||||||
|
QSlider::handle:horizontal {{
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background: {c['primary']};
|
||||||
|
border-radius: 9px;
|
||||||
|
margin: -7px 0;
|
||||||
|
}}
|
||||||
|
QSlider::sub-page:horizontal {{
|
||||||
|
background: {c['primary']};
|
||||||
|
border-radius: 2px;
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
@ -1,6 +1,98 @@
|
||||||
pytest>=7.4.0
|
# EU-Utility - Development Dependencies
|
||||||
pytest-cov>=4.1.0
|
# ======================================
|
||||||
pytest-mock>=3.11.0
|
# These dependencies are required for development, testing, and CI/CD.
|
||||||
pytest-benchmark>=4.0.0
|
# They are NOT required for running EU-Utility in production.
|
||||||
pytest-qt>=4.2.0
|
#
|
||||||
pytest-xvfb>=2.0.0
|
# Install with: pip install -r requirements-dev.txt
|
||||||
|
# Or use: pip install -e ".[dev]"
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Testing Framework
|
||||||
|
# =============================================================================
|
||||||
|
# pytest is the main testing framework
|
||||||
|
pytest>=7.4.0,<8.0.0
|
||||||
|
|
||||||
|
# pytest-cov provides code coverage reporting
|
||||||
|
pytest-cov>=4.1.0,<5.0.0
|
||||||
|
|
||||||
|
# pytest-mock provides mocking utilities for pytest
|
||||||
|
pytest-mock>=3.11.0,<4.0.0
|
||||||
|
|
||||||
|
# pytest-benchmark provides performance benchmarking
|
||||||
|
pytest-benchmark>=4.0.0,<5.0.0
|
||||||
|
|
||||||
|
# pytest-qt provides Qt/PyQt6 testing support
|
||||||
|
pytest-qt>=4.2.0,<5.0.0
|
||||||
|
|
||||||
|
# pytest-xvfb allows running GUI tests headless on Linux
|
||||||
|
pytest-xvfb>=2.0.0,<3.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Code Quality and Linting
|
||||||
|
# =============================================================================
|
||||||
|
# black is the code formatter
|
||||||
|
black>=23.0.0,<24.0.0
|
||||||
|
|
||||||
|
# flake8 is the linter (style and error checking)
|
||||||
|
flake8>=6.0.0,<7.0.0
|
||||||
|
|
||||||
|
# mypy is the static type checker
|
||||||
|
mypy>=1.5.0,<2.0.0
|
||||||
|
|
||||||
|
# isort sorts imports automatically
|
||||||
|
isort>=5.12.0,<6.0.0
|
||||||
|
|
||||||
|
# pydocstyle checks docstring conventions
|
||||||
|
pydocstyle>=6.3.0,<7.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Security Analysis
|
||||||
|
# =============================================================================
|
||||||
|
# bandit finds common security issues in Python code
|
||||||
|
bandit>=1.7.5,<2.0.0
|
||||||
|
|
||||||
|
# safety checks for known security vulnerabilities in dependencies
|
||||||
|
safety>=2.3.0,<3.0.0
|
||||||
|
|
||||||
|
# pip-audit is an alternative to safety for vulnerability scanning
|
||||||
|
# pip-audit>=2.6.0,<3.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Documentation
|
||||||
|
# =============================================================================
|
||||||
|
# sphinx is the documentation generator
|
||||||
|
sphinx>=7.0.0,<8.0.0
|
||||||
|
|
||||||
|
# sphinx-rtd-theme is the Read the Docs theme
|
||||||
|
sphinx-rtd-theme>=1.3.0,<2.0.0
|
||||||
|
|
||||||
|
# myst-parser allows writing documentation in Markdown
|
||||||
|
myst-parser>=2.0.0,<3.0.0
|
||||||
|
|
||||||
|
# sphinx-autobuild provides live-reload for documentation development
|
||||||
|
# sphinx-autobuild>=2021.3.14,<2.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Build and Packaging
|
||||||
|
# =============================================================================
|
||||||
|
# build is the modern Python build frontend
|
||||||
|
build>=0.10.0,<1.0.0
|
||||||
|
|
||||||
|
# twine uploads packages to PyPI
|
||||||
|
twine>=4.0.0,<5.0.0
|
||||||
|
|
||||||
|
# wheel builds wheel distributions
|
||||||
|
wheel>=0.41.0,<1.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Development Tools
|
||||||
|
# =============================================================================
|
||||||
|
# pre-commit runs checks before commits
|
||||||
|
pre-commit>=3.4.0,<4.0.0
|
||||||
|
|
||||||
|
# bump2version manages version bumping
|
||||||
|
# bump2version>=1.0.1,<2.0.0
|
||||||
|
|
||||||
|
# pipdeptree shows dependency tree
|
||||||
|
# pipdeptree>=2.13.0,<3.0.0
|
||||||
|
|
|
||||||
105
requirements.txt
105
requirements.txt
|
|
@ -1,40 +1,73 @@
|
||||||
# Core dependencies
|
# EU-Utility - Production Dependencies
|
||||||
PyQt6>=6.4.0
|
# =====================================
|
||||||
keyboard>=0.13.5
|
# These are the minimum dependencies required to run EU-Utility.
|
||||||
|
# For development dependencies, see requirements-dev.txt
|
||||||
|
# For all optional features, install with: pip install "eu-utility[all]"
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
# OCR and Image Processing (for Game Reader and Skill Scanner)
|
# =============================================================================
|
||||||
easyocr>=1.7.0
|
# Core GUI Framework
|
||||||
pytesseract>=0.3.10 # Tesseract OCR wrapper
|
# =============================================================================
|
||||||
pyautogui>=0.9.54
|
# PyQt6 is the main GUI framework for EU-Utility.
|
||||||
pillow>=10.0.0
|
# Provides the overlay window, widgets, and theming system.
|
||||||
|
PyQt6>=6.4.0,<7.0.0
|
||||||
|
|
||||||
# Windows-specific (auto-installs only on Windows)
|
# =============================================================================
|
||||||
|
# System Integration
|
||||||
|
# =============================================================================
|
||||||
|
# keyboard provides global hotkey support for triggering the overlay
|
||||||
|
# from anywhere, even when the game is focused.
|
||||||
|
keyboard>=0.13.5,<1.0.0
|
||||||
|
|
||||||
|
# psutil is used for system monitoring in the Analytics plugin
|
||||||
|
# and for process management.
|
||||||
|
psutil>=5.9.0,<6.0.0
|
||||||
|
|
||||||
|
# pyperclip provides cross-platform clipboard access for copy/paste
|
||||||
|
# functionality in various plugins.
|
||||||
|
pyperclip>=1.8.2,<2.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# OCR and Image Processing
|
||||||
|
# =============================================================================
|
||||||
|
# easyocr is the recommended OCR engine for reading in-game text.
|
||||||
|
# It downloads models automatically on first use.
|
||||||
|
easyocr>=1.7.0,<2.0.0
|
||||||
|
|
||||||
|
# pytesseract provides an alternative OCR backend using Tesseract.
|
||||||
|
# Requires Tesseract OCR to be installed separately.
|
||||||
|
pytesseract>=0.3.10,<1.0.0
|
||||||
|
|
||||||
|
# pyautogui is used for screen capture and UI automation tasks.
|
||||||
|
pyautogui>=0.9.54,<1.0.0
|
||||||
|
|
||||||
|
# Pillow (PIL) is used for image processing in OCR and screenshot features.
|
||||||
|
pillow>=10.0.0,<11.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# HTTP and Networking
|
||||||
|
# =============================================================================
|
||||||
|
# requests is used for API calls to Entropia Nexus and other services.
|
||||||
|
requests>=2.28.0,<3.0.0
|
||||||
|
|
||||||
|
# urllib3 is a dependency of requests but pinned for security.
|
||||||
|
urllib3>=1.26.0,<3.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Data Processing
|
||||||
|
# =============================================================================
|
||||||
|
# numpy is required by easyocr and used for data processing in calculators
|
||||||
|
# and trackers.
|
||||||
|
numpy>=1.21.0,<2.0.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Windows-Specific Dependencies
|
||||||
|
# =============================================================================
|
||||||
|
# These are only installed on Windows systems.
|
||||||
|
# They provide Windows API access for advanced features.
|
||||||
|
|
||||||
|
# portalocker provides file locking for Windows
|
||||||
portalocker>=2.7.0; platform_system=="Windows"
|
portalocker>=2.7.0; platform_system=="Windows"
|
||||||
pywin32>=306; platform_system=="Windows" # Windows API access
|
|
||||||
|
|
||||||
# System monitoring (for Analytics plugin)
|
# pywin32 provides Windows API access for window management and system integration
|
||||||
psutil>=5.9.0
|
pywin32>=306; platform_system=="Windows"
|
||||||
|
|
||||||
# Clipboard support
|
|
||||||
pyperclip>=1.8.2
|
|
||||||
|
|
||||||
# HTTP requests
|
|
||||||
requests>=2.28.0
|
|
||||||
urllib3>=1.26.0
|
|
||||||
|
|
||||||
# Data processing
|
|
||||||
numpy>=1.21.0
|
|
||||||
|
|
||||||
# Optional plugin dependencies
|
|
||||||
# Uncomment if using specific plugins:
|
|
||||||
|
|
||||||
# For Spotify Controller (advanced features)
|
|
||||||
# spotipy>=2.23.0
|
|
||||||
# pycaw>=20230407; platform_system=="Windows"
|
|
||||||
|
|
||||||
# For Discord Rich Presence
|
|
||||||
# pypresence>=4.3.0
|
|
||||||
|
|
||||||
# Development
|
|
||||||
# pytest>=7.0.0
|
|
||||||
# black>=23.0.0
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue