diff --git a/.gitignore b/.gitignore index 1ffabfe..8ba0268 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # Binaries for programs and plugins repo/* .flatpak-builder/* +build/ *.exe *.exe~ *.dll diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1d246..52b74be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,91 @@ All notable changes to the Cycles project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.0] - 2025-11-17 + +### Added +- **Persistent Settings System** (`settings.go`): + - Settings automatically save and load using Fyne preferences + - Theme preference (Auto, Light, Dark) + - Grid columns, history size, update interval + - Logical/physical cores preference +- **Settings UI Dialog** (`settingsui.go`): + - Comprehensive settings dialog with sliders and controls + - Theme selector dropdown + - Grid columns slider (1-16) + - History size slider (10-100) + - Update interval input + - Logical cores checkbox + - Reset to defaults button with confirmation +- **Enhanced Theme System** (`theme.go`): + - Dynamic theme switching without restart + - Custom theme implementation + - `ApplyTheme()` function for programmatic theme changes + - `isDarkTheme()` helper function +- **Improved Menu System** (update `main.go`): + - File menu with "Preferences..." option + - View menu with "Toggle Theme" quick action + - Reorganized menu structure (File | View | Help) + - Settings accessible via File → Preferences +- **Command-line Flag Priority**: + - Command-line flags now override saved settings + - Seamless integration between CLI and persistent settings + +### Changed +- Application now loads saved preferences on startup +- Theme applies immediately on selection +- Settings persist across application restarts +- Menu structure reorganized for better UX + +### Technical Improvements +- Settings stored using Fyne's preferences API +- Platform-independent settings storage +- Type-safe settings management +- Comprehensive settings validation +- Unit tests for settings functionality + +### Fixed +- Theme switching now works reliably +- Settings apply correctly on save + +## [0.5.0] - 2025-11-17 + +### Added +- **Memory Monitoring Tab**: New dedicated tab for system memory monitoring + - Real-time memory usage display (Total, Used, Free, Cached) + - Memory usage percentage with historical graph + - Automatic history tracking +- **Tabbed Interface**: Switched from single-view to tabbed layout + - CPU tab: Existing CPU core monitoring + - Memory tab: New memory monitoring view +- **Memory Tile Component** (`memorytile.go`): + - Displays comprehensive memory statistics + - Shows usage graph over time + - Formatted memory sizes (GB/MB) +- **Enhanced System Information** (`sysinfo.go`): + - `GetMemoryInfoDetailed()`: Reads detailed memory info from /proc/meminfo + - `UpdateMemoryInfo()`: Updates memory tiles with current data + - Tracks MemTotal, MemFree, MemAvailable, Cached, and Buffers +- **Memory Utility Functions**: + - `formatMemorySize()`: Human-readable memory sizes + - `formatMemoryPercent()`: Formatted percentage display +- **Unit Tests** (`memorytile_test.go`): + - Tests for memory tile creation + - Tests for memory formatting functions + - Validation of component initialization + +### Changed +- Main window now uses tabbed layout instead of single grid +- CPU tiles renamed to `cpuTiles` for clarity +- Separate update goroutines for CPU and Memory monitoring +- Window adapts to tabbed content structure + +### Technical Improvements +- Modular memory monitoring component following existing tile pattern +- Independent update loops for different metric types +- Reuses existing graph rendering infrastructure +- Follows established code organization patterns + ## [0.4.1] - 2025-10-15 ### Changed diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 8b21613..923d654 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -162,40 +162,161 @@ func GetNewSystemInfo() (InfoType, error) { ## Development Workflow -### Setup +### Quick Start + +The easiest way to get started: + ```bash # Clone repository git clone https://github.com/TylerCode/cycles cd cycles -# Install dependencies +# Run automated setup (installs all dependencies) +make setup +# or manually: ./scripts/setup-dev.sh + +# Build the application +make build + +# Run it +make run +``` + +### Setup (Detailed) + +#### Automated Setup (Recommended) + +Use the automated setup script which detects your OS and installs dependencies: + +```bash +./scripts/setup-dev.sh +``` + +Supported distributions: +- **Ubuntu-based:** Ubuntu, Debian, Pop!_OS, Linux Mint, Zorin OS, Elementary OS, KDE neon +- **Red Hat-based:** Fedora, RHEL, CentOS, Rocky Linux, AlmaLinux +- **Arch-based:** Arch Linux, Manjaro, EndeavourOS + +**Note:** The script also has a smart fallback - if your distribution isn't explicitly listed, it will detect your package manager (apt-get, dnf, or pacman) and use the appropriate method automatically. + +#### Manual Setup + +If the automated setup doesn't work for your OS: + +```bash +# Install system dependencies (Ubuntu/Debian) sudo apt-get install libgl1-mesa-dev libxcursor-dev libxrandr-dev \ - libxinerama-dev libxi-dev libglfw3-dev libxxf86vm-dev + libxinerama-dev libxi-dev libglfw3-dev libxxf86vm-dev \ + pkg-config gcc make -# Get Go dependencies +# Install Go dependencies +go mod download go mod tidy -go mod vendor ``` -### Development +### Build System (Makefile) + +The project includes a comprehensive Makefile for common tasks: + ```bash -# Build -go build -o cycles +# Build a single bundled binary +make build +# Output: build/cycles -# Run -./cycles +# Build and run +make run -# Run with options -./cycles --columns 8 --interval 1s +# Quick development build (faster, no optimization) +make dev -# Format code -go fmt ./... +# Build optimized release binary +make release -# Check for issues -go vet ./... +# Clean build artifacts +make clean # Run tests -go test -v ./... +make test + +# Run tests (short output) +make test-short + +# Format code +make fmt + +# Run go vet +make vet + +# Format, vet, and test in one command +make check + +# Install dependencies +make install-deps + +# Show binary size information +make size + +# Install to /usr/local/bin (requires sudo) +make install + +# Uninstall from /usr/local/bin +make uninstall + +# Show build environment info +make info + +# Display all available commands +make help +``` + +### Development Commands + +#### Building +```bash +# Standard build (optimized, single binary) +make build + +# Development build (faster compilation, for testing) +make dev + +# Release build (fully optimized, stripped) +make release +``` + +#### Running +```bash +# Build and run with default settings +make run + +# Run manually with custom options +./build/cycles --columns 8 --interval 1s --history 60 +``` + +#### Testing +```bash +# Run all tests with verbose output +make test + +# Run tests quietly +make test-short + +# Run benchmarks +make bench + +# Format, vet, and test everything +make check +``` + +#### Code Quality +```bash +# Format all Go files +make fmt + +# Run static analysis +make vet + +# Check everything (format + vet + test) +make check ``` ### Testing Checklist diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5c733f4 --- /dev/null +++ b/Makefile @@ -0,0 +1,146 @@ +# Makefile for Cycles CPU Monitor +# Provides convenient build, test, and development commands + +.PHONY: all build run test clean install-deps fmt vet help + +# Variables +BINARY_NAME=cycles +BUILD_DIR=build +VERSION=$(shell grep 'Version:' config.go | cut -d'"' -f2) +LDFLAGS=-ldflags "-s -w -X main.version=$(VERSION)" + +# Colors for output +GREEN=\033[0;32m +YELLOW=\033[1;33m +NC=\033[0m # No Color + +# Default target +all: build + +## help: Display this help message +help: + @echo "Cycles Build System" + @echo "" + @echo "Usage:" + @echo " make " + @echo "" + @echo "Targets:" + @grep -E '^## ' Makefile | sed 's/## / /' + +## build: Build a single bundled binary +build: + @echo "$(GREEN)Building Cycles v$(VERSION)...$(NC)" + @mkdir -p $(BUILD_DIR) + @go build $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) . + @echo "$(GREEN)✓ Build complete: $(BUILD_DIR)/$(BINARY_NAME)$(NC)" + +## run: Build and run the application +run: build + @echo "$(GREEN)Running Cycles...$(NC)" + @./$(BUILD_DIR)/$(BINARY_NAME) + +## test: Run all tests +test: + @echo "$(GREEN)Running tests...$(NC)" + @go test -v ./... + +## test-short: Run tests without verbose output +test-short: + @echo "$(GREEN)Running tests...$(NC)" + @go test ./... + +## bench: Run benchmarks +bench: + @echo "$(GREEN)Running benchmarks...$(NC)" + @go test -bench=. -benchmem ./... + +## fmt: Format all Go source files +fmt: + @echo "$(GREEN)Formatting code...$(NC)" + @go fmt ./... + @echo "$(GREEN)✓ Code formatted$(NC)" + +## vet: Run go vet on all source files +vet: + @echo "$(GREEN)Running go vet...$(NC)" + @go vet ./... + @echo "$(GREEN)✓ Vet complete$(NC)" + +## check: Run fmt, vet, and test +check: fmt vet test + +## clean: Remove build artifacts +clean: + @echo "$(YELLOW)Cleaning build artifacts...$(NC)" + @rm -rf $(BUILD_DIR) + @rm -f $(BINARY_NAME) + @echo "$(GREEN)✓ Clean complete$(NC)" + +## install-deps: Install/update Go dependencies +install-deps: + @echo "$(GREEN)Installing dependencies...$(NC)" + @go mod download + @go mod tidy + @echo "$(GREEN)✓ Dependencies installed$(NC)" + +## setup: Run development environment setup +setup: + @echo "$(GREEN)Running development setup...$(NC)" + @chmod +x scripts/setup-dev.sh + @./scripts/setup-dev.sh + +## release: Build optimized release binary +release: + @echo "$(GREEN)Building release binary v$(VERSION)...$(NC)" + @mkdir -p $(BUILD_DIR) + @CGO_ENABLED=1 go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(BINARY_NAME) . + @echo "$(GREEN)✓ Release build complete: $(BUILD_DIR)/$(BINARY_NAME)$(NC)" + +## dev: Quick development build (no optimization) +dev: + @echo "$(GREEN)Building development binary...$(NC)" + @mkdir -p $(BUILD_DIR) + @go build -o $(BUILD_DIR)/$(BINARY_NAME) . + @echo "$(GREEN)✓ Dev build complete$(NC)" + +## watch: Watch for changes and rebuild (requires entr) +watch: + @echo "$(GREEN)Watching for changes...$(NC)" + @echo "$(YELLOW)Note: Requires 'entr' (install: apt-get install entr)$(NC)" + @find . -name '*.go' | entr -r make dev run + +## size: Show binary size information +size: build + @echo "$(GREEN)Binary size information:$(NC)" + @ls -lh $(BUILD_DIR)/$(BINARY_NAME) + @file $(BUILD_DIR)/$(BINARY_NAME) + +## install: Install the binary to /usr/local/bin (requires sudo) +install: release + @echo "$(GREEN)Installing to /usr/local/bin...$(NC)" + @sudo cp $(BUILD_DIR)/$(BINARY_NAME) /usr/local/bin/ + @sudo chmod +x /usr/local/bin/$(BINARY_NAME) + @echo "$(GREEN)✓ Installed successfully$(NC)" + +## uninstall: Remove the installed binary +uninstall: + @echo "$(YELLOW)Removing from /usr/local/bin...$(NC)" + @sudo rm -f /usr/local/bin/$(BINARY_NAME) + @echo "$(GREEN)✓ Uninstalled successfully$(NC)" + +## docker-build: Build using Docker (no system dependencies needed) +docker-build: + @echo "$(GREEN)Building with Docker...$(NC)" + @docker build -t cycles-builder -f Dockerfile.build . + @docker run --rm -v $(PWD)/$(BUILD_DIR):/output cycles-builder + @echo "$(GREEN)✓ Docker build complete$(NC)" + +## info: Display build environment information +info: + @echo "$(GREEN)Build Environment Information:$(NC)" + @echo " Version: $(VERSION)" + @echo " Go Version: $(shell go version)" + @echo " Build Dir: $(BUILD_DIR)" + @echo " Binary Name: $(BINARY_NAME)" + @echo " GOOS: $(shell go env GOOS)" + @echo " GOARCH: $(shell go env GOARCH)" diff --git a/OVERHAUL_PLAN_V2.md b/OVERHAUL_PLAN_V2.md new file mode 100644 index 0000000..115291d --- /dev/null +++ b/OVERHAUL_PLAN_V2.md @@ -0,0 +1,1107 @@ +# Cycles Application Overhaul Plan v2 +## Road to Version 1.0 and Beyond + +**Current Version:** 0.4.1 +**Target Version:** 1.2.0 +**Goal:** Transform Cycles into a comprehensive system monitoring tool comparable to Windows Task Manager's Performance tab + +--- + +## Executive Summary + +The Cycles application has successfully completed its initial refactoring (v0.3.4 → v0.4.0), establishing a solid foundation with modular code, testing infrastructure, and configuration management. This overhaul plan outlines the path to version 1.2.0, adding comprehensive system monitoring capabilities, cross-platform support, and advanced UI features. + +### Key Objectives +1. Expand monitoring beyond CPU to memory, disk, network, and GPU +2. Implement persistent settings and user preferences +3. Optimize performance for real-time data visualization +4. Add cross-platform support (Windows, macOS) +5. Provide process management capabilities +6. Enable data export and historical logging +7. Create an intuitive, feature-rich UI + +--- + +## Sprint Overview + +| Sprint | Version | Focus Area | Duration | Complexity | +|--------|---------|------------|----------|------------| +| 1 | 0.5.0 | Memory Monitoring & UI Foundation | 2-3 days | Medium | +| 2 | 0.6.0 | Settings System & Theme Management | 2-3 days | Medium | +| 3 | 0.7.0 | Disk & Network Monitoring | 3-4 days | High | +| 4 | 0.7.5 | Performance Optimizations | 2 days | Medium | +| 5 | 0.8.0 | Cross-Platform Support | 4-5 days | High | +| 6 | 0.9.0 | Process Management View | 3-4 days | High | +| 7 | 0.9.5 | Data Export & Logging | 2-3 days | Medium | +| 8 | 1.0.0 | GPU Monitoring | 3-4 days | High | +| 9 | 1.1.0 | Advanced UI Features | 3-4 days | High | +| 10 | 1.2.0 | Polish & Production Ready | 2-3 days | Medium | + +**Total Estimated Duration:** 26-35 days + +--- + +## Sprint 1: Memory Monitoring & UI Foundation (v0.5.0) + +### Objectives +- Implement memory monitoring UI using existing `GetMemoryInfo()` function +- Create tabbed interface to separate CPU and Memory views +- Establish foundation for multi-metric monitoring + +### Tasks +1. **Create Memory Tile Component** (`memorytile.go`) + - Similar to CoreTile structure + - Display total, used, free, and available memory + - Show memory usage percentage graph + - Historical data tracking + +2. **Add Memory View Tab** (update `main.go`) + - Implement Fyne tabs: CPU | Memory + - Create grid layout for memory information + - Add overall memory summary tile + - Add memory breakdown (RAM, Swap, Cache) + +3. **Enhance sysinfo.go** + - Add `UpdateMemoryInfo()` function + - Implement memory history tracking + - Add swap memory information + - Include cache and buffer details + +4. **Create Memory Graphics** (`graphics.go` enhancement) + - Memory usage graph rendering + - Different colors for memory zones (available, used, cached) + - Percentage-based visualization + +5. **Testing** + - Unit tests for memory tile creation + - Memory info retrieval tests + - Memory formatting tests + - Graph rendering tests + +### Files to Create/Modify +- **New:** `memorytile.go` (60-80 lines) +- **Modify:** `main.go` - Add tab support +- **Modify:** `sysinfo.go` - Enhance memory functions +- **Modify:** `graphics.go` - Add memory graph rendering +- **New:** `memorytile_test.go` + +### Success Criteria +- [ ] Memory tab displays accurate system memory information +- [ ] Memory graphs update in real-time +- [ ] All tests pass +- [ ] No performance degradation +- [ ] Documentation updated + +### Breaking Changes +- None (additive features only) + +--- + +## Sprint 2: Settings System & Theme Management (v0.6.0) + +### Objectives +- Implement persistent settings storage +- Add UI-based settings panel +- Implement dark/light theme toggle +- Save user preferences between sessions + +### Tasks +1. **Create Settings Module** (`settings.go`) + - Define settings structure (theme, update interval, grid size, etc.) + - Implement JSON-based settings persistence + - Load settings on startup + - Save settings on change + - Use Fyne preferences API + +2. **Settings UI** (`settingsui.go`) + - Create settings dialog/window + - Theme selector (Auto, Light, Dark) + - Update interval slider + - Grid columns selector + - History size configuration + - Logical/Physical core toggle + - Default settings reset button + +3. **Theme System Enhancement** (update `theme.go`) + - Implement custom theme support + - Dynamic theme switching + - Persist theme preference + - Apply theme to all UI elements + +4. **Menu Integration** (update `main.go`) + - Add "Settings" menu item + - Add "View" menu for quick theme toggle + - Keyboard shortcuts for settings (Cmd/Ctrl+,) + +5. **Configuration Migration** (update `config.go`) + - Merge command-line flags with persistent settings + - Command-line flags override saved settings + - Validate settings on load + +6. **Testing** + - Settings save/load tests + - Theme switching tests + - Settings validation tests + - UI interaction tests + +### Files to Create/Modify +- **New:** `settings.go` (100-120 lines) +- **New:** `settingsui.go` (150-200 lines) +- **Modify:** `theme.go` - Enhanced theme system +- **Modify:** `config.go` - Settings integration +- **Modify:** `main.go` - Menu and initialization +- **New:** `settings_test.go` +- **New:** `settingsui_test.go` + +### Success Criteria +- [ ] Settings persist between application restarts +- [ ] Theme changes apply immediately +- [ ] Settings UI is intuitive and responsive +- [ ] Command-line flags still work and override settings +- [ ] All tests pass +- [ ] Settings file location follows OS conventions + +### Breaking Changes +- Settings location change (document migration path) + +--- + +## Sprint 3: Disk & Network Monitoring (v0.7.0) + +### Objectives +- Add disk I/O monitoring +- Add network interface monitoring +- Create dedicated tabs for each metric +- Provide per-device/interface breakdowns + +### Tasks +1. **Disk Monitoring Module** (`diskinfo.go`) + - List all disk devices + - Monitor read/write speeds (KB/s, MB/s) + - Track disk utilization percentage + - Monitor disk space (used/free) + - Historical I/O data tracking + - Use gopsutil disk package + +2. **Disk UI Component** (`disktile.go`) + - Tile per physical disk + - Display read/write graphs + - Show disk space bar chart + - Active time percentage + - Transfer speeds + +3. **Network Monitoring Module** (`netinfo.go`) + - List all network interfaces + - Monitor send/receive speeds + - Track packets sent/received + - Error and drop counts + - Connection count (TCP/UDP) + - Use gopsutil net package + +4. **Network UI Component** (`nettile.go`) + - Tile per network interface + - Upload/download graphs + - Current speeds display + - Total data transferred + - Packet statistics + +5. **Tab Integration** (update `main.go`) + - Add Disk tab + - Add Network tab + - Tab navigation shortcuts + - Tab icons + +6. **Performance Considerations** + - Separate goroutines for each metric type + - Configurable update intervals per metric + - Efficient data structure for history + +7. **Testing** + - Disk info retrieval tests + - Network info retrieval tests + - Tile rendering tests + - Performance benchmarks + +### Files to Create/Modify +- **New:** `diskinfo.go` (150-180 lines) +- **New:** `disktile.go` (80-100 lines) +- **New:** `netinfo.go` (150-180 lines) +- **New:** `nettile.go` (80-100 lines) +- **Modify:** `main.go` - Add new tabs +- **Modify:** `settings.go` - Per-metric settings +- **Modify:** `graphics.go` - Additional graph types +- **New:** Test files for each module + +### Success Criteria +- [ ] Disk I/O displayed accurately per device +- [ ] Network traffic displayed accurately per interface +- [ ] Graphs update smoothly +- [ ] No performance impact on monitored system +- [ ] All tests pass +- [ ] Works with various disk types (HDD, SSD, NVMe) +- [ ] Handles virtual network interfaces + +### Breaking Changes +- Increased memory usage (document in CHANGELOG) + +--- + +## Sprint 4: Performance Optimizations (v0.7.5) + +### Objectives +- Optimize graph rendering performance +- Implement circular buffer for history data +- Reduce memory allocations +- Improve UI responsiveness + +### Tasks +1. **Circular Buffer Implementation** (`ringbuffer.go`) + - Generic circular buffer data structure + - Fixed-size with automatic overwrite + - Efficient append and read operations + - Thread-safe access + - Iterator support + +2. **Graph Rendering Optimization** + - Canvas reuse instead of recreation + - Dirty region tracking + - Only redraw changed graphs + - Batch UI updates + - Hardware acceleration hints + +3. **Memory Pool Management** + - Object pooling for image buffers + - Reduce garbage collection pressure + - Reuse allocations + +4. **Update Loop Optimization** + - Event-driven updates instead of polling where possible + - Smarter update scheduling + - Pause updates when window minimized + - Adaptive update rates based on changes + +5. **Data Collection Efficiency** + - Cache system info that doesn't change + - Batch read operations + - Reduce /proc file system reads + +6. **Profiling and Benchmarking** + - CPU profiling + - Memory profiling + - Benchmark tests for critical paths + - Before/after performance comparison + +7. **Code Refactoring** + - Replace slices with circular buffers + - Optimize hot paths + - Remove redundant computations + +### Files to Create/Modify +- **New:** `ringbuffer.go` (100-120 lines) +- **Modify:** `tile.go` - Use circular buffer +- **Modify:** `memorytile.go` - Use circular buffer +- **Modify:** `disktile.go` - Use circular buffer +- **Modify:** `nettile.go` - Use circular buffer +- **Modify:** `graphics.go` - Rendering optimizations +- **Modify:** `main.go` - Update loop optimization +- **New:** `ringbuffer_test.go` +- **New:** `benchmark_test.go` + +### Success Criteria +- [ ] 30%+ reduction in CPU usage +- [ ] 20%+ reduction in memory usage +- [ ] Smooth 60 FPS UI updates +- [ ] No visual regression +- [ ] All tests pass +- [ ] Benchmarks show improvement +- [ ] Profile data confirms optimizations + +### Breaking Changes +- None (internal optimizations only) + +--- + +## Sprint 5: Cross-Platform Support (v0.8.0) + +### Objectives +- Add Windows support +- Add macOS support +- Abstract platform-specific code +- Maintain Linux functionality + +### Tasks +1. **Platform Abstraction Layer** (`platform/`) + - Create platform interface + - Separate implementations per OS + - Factory pattern for platform selection + - Build tags for conditional compilation + +2. **Windows Implementation** (`platform/windows.go`) + - Windows API for CPU info + - Windows registry for some metrics + - WMI for system information + - Performance counters + - PowerShell fallbacks + +3. **macOS Implementation** (`platform/darwin.go`) + - sysctl for CPU/memory info + - IOKit for hardware info + - Activity Monitor-like features + - macOS-specific permissions handling + +4. **Refactor Linux Code** (`platform/linux.go`) + - Move /proc reading to platform layer + - Keep existing functionality + - Clean up platform assumptions + +5. **Platform-Specific UI Adjustments** + - Native menu bars (macOS) + - System tray integration + - Notification systems + - Window management + +6. **Build System Updates** + - Cross-compilation scripts + - Platform-specific build flags + - Conditional dependency management + - CI/CD for multiple platforms + +7. **Testing** + - Unit tests per platform + - Integration tests + - Manual testing on each OS + - VM/container testing setup + +### Files to Create/Modify +- **New:** `platform/interface.go` +- **New:** `platform/linux.go` (refactored from sysinfo.go) +- **New:** `platform/windows.go` +- **New:** `platform/darwin.go` +- **Modify:** `sysinfo.go` - Use platform layer +- **Modify:** `diskinfo.go` - Use platform layer +- **Modify:** `netinfo.go` - Use platform layer +- **Modify:** `main.go` - Platform initialization +- **New:** `platform/*_test.go` +- **Modify:** CI/CD workflows + +### Success Criteria +- [ ] Builds successfully on Linux, Windows, macOS +- [ ] All features work on all platforms +- [ ] Platform-specific features documented +- [ ] Tests pass on all platforms +- [ ] Installation packages for each OS +- [ ] Documentation includes platform notes + +### Breaking Changes +- Code reorganization (import paths may change) + +--- + +## Sprint 6: Process Management View (v0.9.0) + +### Objectives +- Add process list view similar to Task Manager +- Display CPU and memory usage per process +- Enable sorting and filtering +- Provide basic process management (kill process) + +### Tasks +1. **Process Information Module** (`processinfo.go`) + - List all running processes + - Get process details (PID, name, CPU%, memory, user) + - Monitor process tree/hierarchy + - Track process lifetime + - Use gopsutil process package + +2. **Process Table UI** (`processtable.go`) + - Sortable table widget + - Columns: PID, Name, CPU%, Memory, User, Status + - Search/filter functionality + - Context menu (end process, details) + - Auto-refresh + - Color coding for resource usage + +3. **Process Details Dialog** (`processdetails.go`) + - Detailed process information + - Command line arguments + - Working directory + - Open files + - Network connections + - Child processes + +4. **Process Management** (update `processinfo.go`) + - End process functionality + - Confirmation dialogs + - Error handling + - Permission checks + +5. **Tab Integration** (update `main.go`) + - Add Processes tab + - Process count summary + - CPU/Memory aggregates + +6. **Performance** + - Efficient process list updates + - Delta updates (only changed processes) + - Configurable refresh rate + - Lazy loading for large process lists + +7. **Testing** + - Process list retrieval tests + - Sorting/filtering tests + - Process management tests (mock) + - UI interaction tests + +### Files to Create/Modify +- **New:** `processinfo.go` (200-250 lines) +- **New:** `processtable.go` (250-300 lines) +- **New:** `processdetails.go` (150-200 lines) +- **Modify:** `main.go` - Add Processes tab +- **Modify:** `settings.go` - Process view settings +- **New:** Test files for each module + +### Success Criteria +- [ ] Process list displays accurately +- [ ] Sorting and filtering work correctly +- [ ] Process management functions work safely +- [ ] Performance remains good with many processes (1000+) +- [ ] All tests pass +- [ ] Proper error handling and user feedback +- [ ] Works across platforms + +### Breaking Changes +- None (additive feature) + +--- + +## Sprint 7: Data Export & Logging (v0.9.5) + +### Objectives +- Enable exporting system metrics to files +- Implement historical data logging +- Provide multiple export formats +- Add data visualization for historical data + +### Tasks +1. **Export Module** (`export.go`) + - Export to CSV + - Export to JSON + - Export to XML + - Date range selection + - Metric selection (CPU, memory, disk, network) + - Configurable intervals + +2. **Logging System** (`logger.go`) + - Continuous background logging + - Configurable log levels (every second, minute, hour) + - Automatic log rotation + - Compression for old logs + - Configurable retention period + - Storage location settings + +3. **Export UI** (`exportui.go`) + - Export dialog + - Format selection + - Date range picker + - Metric checkboxes + - Export location selector + - Progress indicator + +4. **Historical Data Viewer** (`historyviewer.go`) + - Load historical data from logs + - Display trends over time + - Zoom and pan graphs + - Compare different time periods + - Identify peak usage times + +5. **Menu Integration** (update `main.go`) + - File → Export menu + - Tools → Enable Logging + - View → History + +6. **Settings Integration** (update `settings.go`) + - Enable/disable logging + - Log interval + - Retention period + - Auto-export schedules + +7. **Testing** + - Export format tests + - Log rotation tests + - Import/export round-trip tests + - File handling tests + +### Files to Create/Modify +- **New:** `export.go` (150-180 lines) +- **New:** `logger.go` (120-150 lines) +- **New:** `exportui.go` (100-120 lines) +- **New:** `historyviewer.go` (200-250 lines) +- **Modify:** `main.go` - Menu integration +- **Modify:** `settings.go` - Logging settings +- **New:** Test files for each module + +### Success Criteria +- [ ] Export produces valid files in all formats +- [ ] Logging runs in background without performance impact +- [ ] Log rotation works correctly +- [ ] Historical viewer displays data accurately +- [ ] All tests pass +- [ ] Large datasets handled efficiently + +### Breaking Changes +- None (additive feature) + +--- + +## Sprint 8: GPU Monitoring (v1.0.0) + +### Objectives +- Add GPU monitoring support +- Display GPU utilization and memory +- Support multiple GPUs +- Support major GPU vendors (NVIDIA, AMD, Intel) + +### Tasks +1. **GPU Detection Module** (`gpuinfo.go`) + - Detect available GPUs + - Identify GPU vendor and model + - Platform-specific detection + - Handle systems without GPU + +2. **NVIDIA Support** (`gpuinfo_nvidia.go`) + - Use NVML (NVIDIA Management Library) + - GPU utilization + - Memory usage + - Temperature + - Power usage + - Clock speeds + - Fan speed + +3. **AMD Support** (`gpuinfo_amd.go`) + - Use ROCm SMI where available + - Linux: sysfs interface + - Windows: AMD Display Library + - Similar metrics to NVIDIA + +4. **Intel Support** (`gpuinfo_intel.go`) + - Integrated GPU monitoring + - Use platform-specific APIs + - Basic utilization and memory + +5. **GPU Tile Component** (`gputile.go`) + - Display GPU name and utilization + - Memory usage graph + - Temperature gauge + - Power usage + - Clock speeds + +6. **Tab Integration** (update `main.go`) + - Add GPU tab (if GPUs detected) + - Multi-GPU support + - Fallback message if no GPU + +7. **Error Handling** + - Graceful degradation if libraries unavailable + - Clear error messages + - Fallback to basic info + +8. **Testing** + - GPU detection tests + - Mock GPU data tests + - UI rendering tests + - Multi-GPU scenarios + +### Files to Create/Modify +- **New:** `gpuinfo.go` (100-120 lines) +- **New:** `gpuinfo_nvidia.go` (150-200 lines) +- **New:** `gpuinfo_amd.go` (150-200 lines) +- **New:** `gpuinfo_intel.go` (100-150 lines) +- **New:** `gputile.go` (100-120 lines) +- **Modify:** `main.go` - GPU tab +- **Modify:** `settings.go` - GPU settings +- **New:** Test files for each module + +### Success Criteria +- [ ] NVIDIA GPUs monitored correctly +- [ ] AMD GPUs monitored correctly (where possible) +- [ ] Intel integrated GPUs detected +- [ ] Multi-GPU systems handled +- [ ] Graceful handling when GPU libraries unavailable +- [ ] All tests pass +- [ ] Documentation includes GPU setup instructions + +### Breaking Changes +- Optional dependencies for GPU libraries + +--- + +## Sprint 9: Advanced UI Features (v1.1.0) + +### Objectives +- Implement resizable graph areas +- Add customizable layouts +- Improve visualization options +- Add mini-mode/compact view +- Implement always-on-top mode + +### Tasks +1. **Resizable Tiles** (update all tile components) + - Implement resize handles + - Save tile sizes in settings + - Dynamic graph scaling + - Minimum/maximum sizes + +2. **Custom Layouts** (`layouts.go`) + - Predefined layouts (compact, detailed, custom) + - Drag-and-drop tile positioning + - Save/load layout configurations + - Layout templates + +3. **Visualization Enhancements** (update `graphics.go`) + - Multiple graph styles (line, area, bar) + - Configurable colors per metric + - Grid lines option + - Value labels option + - Gradient fills + - Smooth animation transitions + +4. **Mini Mode** (`minimode.go`) + - Compact window with essentials + - Minimal CPU/Memory display + - Always-on-top option + - Transparency support + - Quick toggle to full mode + +5. **Window Management** (update `main.go`) + - Remember window position/size + - Multi-monitor support + - Always-on-top toggle + - Full-screen mode + - Minimize to system tray + +6. **Customization UI** (update `settingsui.go`) + - Graph style selector + - Color customization + - Layout designer + - Preview pane + +7. **Accessibility** + - Keyboard navigation + - Screen reader support + - High contrast mode + - Font size options + +8. **Testing** + - UI interaction tests + - Layout save/load tests + - Resize behavior tests + - Visual regression tests + +### Files to Create/Modify +- **New:** `layouts.go` (150-200 lines) +- **New:** `minimode.go` (100-120 lines) +- **Modify:** `graphics.go` - Enhanced visualizations +- **Modify:** `tile.go` - Resizable support +- **Modify:** `memorytile.go` - Resizable support +- **Modify:** `disktile.go` - Resizable support +- **Modify:** `nettile.go` - Resizable support +- **Modify:** `gputile.go` - Resizable support +- **Modify:** `main.go` - Window management +- **Modify:** `settingsui.go` - Customization options +- **New:** Test files + +### Success Criteria +- [ ] Tiles resize smoothly +- [ ] Custom layouts save and restore correctly +- [ ] Mini mode is functional and useful +- [ ] Window position/size remembered +- [ ] Accessibility features work +- [ ] All tests pass +- [ ] No performance degradation + +### Breaking Changes +- Settings format change (migration needed) + +--- + +## Sprint 10: Polish & Production Ready (v1.2.0) + +### Objectives +- Final bug fixes and polish +- Comprehensive documentation +- Installer packages for all platforms (including fixing Flatpak and AppImage) +- Performance tuning +- Release preparation + +**NOTE:** See `PACKAGING_PLAN.md` for detailed packaging and distribution strategy + +### Tasks +1. **Bug Fixes** + - Address all open issues + - Fix edge cases + - Memory leak detection and fixes + - Race condition fixes + - Error handling improvements + +2. **Documentation** + - Complete user manual + - Video tutorials + - FAQ section + - Troubleshooting guide + - API documentation (if exposing API) + - Contributing guidelines update + +3. **Installer Creation** (See PACKAGING_PLAN.md for details) + - **Linux:** + - Fix AppImage (currently broken) + - Implement Flatpak (never working) + - Verify Snap (currently working) + - Create .deb packages + - Create .rpm packages + - **Windows:** MSI installer, Portable exe + - **macOS:** .dmg, Homebrew formula + - Auto-update mechanism + - Uninstaller + +4. **Performance Final Pass** + - Profiling and optimization + - Memory usage optimization + - Startup time optimization + - Reduce binary size + - Lazy loading of modules + +5. **Security Audit** + - Code review for security issues + - Dependency audit + - Permission checks + - Input validation + - Safe process management + +6. **Internationalization (i18n)** + - Extract strings to translation files + - Support for multiple languages + - Language selector in settings + - RTL support preparation + +7. **Release Engineering** + - Automated release process + - Versioning automation + - Changelog generation + - GitHub release creation + - Package distribution + +8. **Testing** + - Full regression testing + - Platform-specific testing + - Performance testing + - Load testing + - User acceptance testing + +### Files to Create/Modify +- **New:** `docs/` directory with comprehensive documentation +- **New:** `installers/` directory with installer scripts +- **New:** `i18n/` directory for translations +- **Modify:** All files - Bug fixes and polish +- **Modify:** `README.md` - Final documentation +- **Modify:** `CHANGELOG.md` - Complete history +- **New:** `CONTRIBUTING.md` +- **New:** `SECURITY.md` +- **Update:** CI/CD workflows + +### Success Criteria +- [ ] Zero known critical bugs +- [ ] Complete documentation +- [ ] Installers for all platforms work correctly +- [ ] Application starts in under 1 second +- [ ] All tests pass on all platforms +- [ ] Security audit completed +- [ ] Ready for public release + +### Breaking Changes +- Document all breaking changes since v0.4.1 +- Provide migration guide + +--- + +## Technical Architecture Changes + +### Current Architecture (v0.4.1) +``` +cycles/ +├── main.go # Entry point +├── config.go # Configuration +├── theme.go # Theming +├── tile.go # CPU tile +├── sysinfo.go # System info +├── graphics.go # Rendering +└── info.go # App info +``` + +### Target Architecture (v1.2.0) +``` +cycles/ +├── cmd/ +│ └── cycles/ +│ └── main.go # Entry point +├── internal/ +│ ├── app/ +│ │ ├── app.go # Application logic +│ │ └── window.go # Window management +│ ├── config/ +│ │ ├── config.go # Configuration +│ │ └── settings.go # Settings management +│ ├── ui/ +│ │ ├── components/ +│ │ │ ├── tile.go # Base tile +│ │ │ ├── cputile.go # CPU tile +│ │ │ ├── memorytile.go +│ │ │ ├── disktile.go +│ │ │ ├── nettile.go +│ │ │ ├── gputile.go +│ │ │ └── processtable.go +│ │ ├── dialogs/ +│ │ │ ├── settings.go +│ │ │ ├── export.go +│ │ │ └── about.go +│ │ ├── views/ +│ │ │ ├── cpu.go +│ │ │ ├── memory.go +│ │ │ ├── disk.go +│ │ │ ├── network.go +│ │ │ ├── gpu.go +│ │ │ └── processes.go +│ │ ├── graphics.go # Rendering utilities +│ │ ├── theme.go # Theme management +│ │ └── layouts.go # Custom layouts +│ ├── platform/ +│ │ ├── interface.go # Platform abstraction +│ │ ├── linux.go +│ │ ├── windows.go +│ │ └── darwin.go +│ ├── monitoring/ +│ │ ├── cpu.go # CPU monitoring +│ │ ├── memory.go # Memory monitoring +│ │ ├── disk.go # Disk monitoring +│ │ ├── network.go # Network monitoring +│ │ ├── gpu.go # GPU monitoring +│ │ └── process.go # Process monitoring +│ ├── data/ +│ │ ├── ringbuffer.go # Circular buffer +│ │ ├── logger.go # Data logging +│ │ └── export.go # Data export +│ └── utils/ +│ ├── format.go # Formatting utilities +│ └── helpers.go # Helper functions +├── pkg/ # Public APIs (if any) +├── docs/ # Documentation +├── installers/ # Installer scripts +├── i18n/ # Translations +├── README.md +├── CHANGELOG.md +├── CONTRIBUTING.md +└── SECURITY.md +``` + +--- + +## Dependency Changes + +### Current Dependencies +- fyne.io/fyne/v2 - UI framework +- github.com/shirou/gopsutil - System info + +### Additional Dependencies +- **GPU Monitoring:** + - NVML bindings (optional) + - ROCm SMI bindings (optional) +- **Data Export:** + - encoding/csv (stdlib) + - encoding/json (stdlib) + - encoding/xml (stdlib) +- **Internationalization:** + - golang.org/x/text (optional) + +--- + +## Testing Strategy + +### Current Test Coverage +- 7 unit tests +- Core utilities covered + +### Target Test Coverage +- **Unit Tests:** 80%+ coverage +- **Integration Tests:** Key workflows +- **Benchmark Tests:** Performance-critical paths +- **Platform Tests:** Each platform validated +- **UI Tests:** Automated UI testing +- **Performance Tests:** Memory and CPU usage +- **Load Tests:** Stress testing with many processes + +### Testing Infrastructure +- CI/CD on GitHub Actions +- Platform matrix testing (Linux, Windows, macOS) +- Automated performance benchmarks +- Visual regression testing +- Test data generators +- Mock system interfaces + +--- + +## Documentation Plan + +### User Documentation +1. **Installation Guide** + - Per-platform instructions + - Dependency installation + - Troubleshooting + +2. **User Manual** + - Getting started + - Features overview + - Settings and customization + - Keyboard shortcuts + - FAQ + +3. **Video Tutorials** + - Installation walkthrough + - Features demonstration + - Advanced usage + +### Developer Documentation +1. **Developer Guide** (update existing) + - Architecture overview + - Module descriptions + - Adding new features + - Testing guidelines + +2. **API Documentation** + - GoDoc comments + - Generated documentation + - Platform interfaces + +3. **Contributing Guide** + - Code of conduct + - Development setup + - Pull request process + - Coding standards + +--- + +## Release Strategy + +### Version Numbering +- **Major (X.0.0):** Breaking changes, major features +- **Minor (0.X.0):** New features, non-breaking +- **Patch (0.0.X):** Bug fixes only + +### Release Schedule +- **v0.5.0 - v0.9.5:** Monthly releases during development +- **v1.0.0:** Major milestone release +- **v1.1.0+:** Quarterly feature releases +- **Patch releases:** As needed for critical bugs + +### Distribution Channels +- GitHub Releases (primary) +- Snap Store (Linux) +- Flatpak (Linux) +- Homebrew (macOS) +- Chocolatey (Windows) +- Windows Store (future) +- Direct downloads + +--- + +## Risk Assessment + +### High Risk Items +1. **Cross-platform compatibility** + - Mitigation: Early testing on all platforms, platform abstraction layer +2. **GPU monitoring complexity** + - Mitigation: Graceful degradation, vendor-specific implementations +3. **Performance with many metrics** + - Mitigation: Early profiling, optimization sprint, lazy loading + +### Medium Risk Items +1. **UI complexity growth** + - Mitigation: Component-based architecture, regular refactoring +2. **Third-party dependency issues** + - Mitigation: Vendor dependencies, version pinning, alternatives +3. **Platform API changes** + - Mitigation: Abstraction layer, version detection + +### Low Risk Items +1. **Testing infrastructure** + - Mitigation: Incremental test additions +2. **Documentation maintenance** + - Mitigation: Documentation-as-code, automated generation + +--- + +## Success Metrics + +### Performance Metrics +- Application startup time: < 1 second +- CPU usage while running: < 2% on idle system +- Memory usage: < 100 MB for full feature set +- UI framerate: Consistent 60 FPS +- Update latency: < 100ms from system change to UI update + +### Quality Metrics +- Test coverage: > 80% +- Zero critical bugs at release +- Platform parity: All features on all platforms +- User-reported bugs: < 5 per 1000 users in first month + +### Adoption Metrics +- GitHub stars: 1000+ within 6 months +- Downloads: 10,000+ in first year +- Active users: 5000+ monthly + +--- + +## Post-v1.2.0 Roadmap + +### Future Considerations (v2.0+) +1. **Cloud Integration** + - Remote monitoring + - Multi-machine dashboard + - Alert system + +2. **Mobile Companion App** + - iOS/Android monitoring + - Remote control + +3. **Plugin System** + - Custom metrics + - Third-party integrations + - Extensible UI + +4. **AI/ML Features** + - Anomaly detection + - Performance predictions + - Optimization recommendations + +5. **Team Features** + - Multi-user support + - Team dashboards + - Collaborative monitoring + +--- + +## Conclusion + +This overhaul plan provides a clear path from the current v0.4.1 to a production-ready v1.2.0 system monitoring tool. Each sprint builds upon the previous work, maintaining backward compatibility where possible and clearly documenting breaking changes. + +The modular approach ensures that sprints can be tackled independently, allowing for flexibility in implementation order based on priorities and resource availability. The comprehensive testing strategy and platform abstraction layer ensure quality and maintainability throughout the development process. + +**Estimated Total Development Time:** 26-35 days (full-time development) +**Target Release Date:** Flexible, based on sprint completion +**Success Criteria:** Feature-complete, cross-platform, performant system monitor comparable to Windows Task Manager + +--- + +*Document Version: 1.0* +*Last Updated: 2025-11-17* +*Author: Claude* +*Status: Planning Phase* diff --git a/PACKAGING_PLAN.md b/PACKAGING_PLAN.md new file mode 100644 index 0000000..0c4cb87 --- /dev/null +++ b/PACKAGING_PLAN.md @@ -0,0 +1,706 @@ +# Cycles Packaging & Distribution Plan + +**Purpose:** Ensure Cycles works correctly across all major Linux package formats and distribution methods + +--- + +## Current Status Assessment + +### ✅ Working +- **Snap:** Currently functional +- Source build from repository + +### ❌ Broken/Not Working +- **Flatpak:** Never successfully configured +- **AppImage:** Believed to be broken + +### ✓ To Verify +- Plain executable distribution +- Individual distro packages (.deb, .rpm) + +--- + +## Sprint 10.5: Packaging & Distribution (v1.2.0) + +**Duration:** 2-3 days +**Priority:** High (Critical for wide adoption) +**Should be completed as part of or immediately after Sprint 10** + +--- + +## Task Breakdown + +### 1. Fix AppImage Packaging + +#### Current Issues to Investigate +- [ ] Check `.github/workflows/appimage.yml` for errors +- [ ] Verify AppRun script functionality +- [ ] Test on clean system +- [ ] Identify missing dependencies + +#### Implementation Steps + +**A. Audit Existing AppImage Setup** +```bash +# Review current workflow +cat .github/workflows/appimage.yml + +# Check for AppDir structure +# Verify linuxdeploy usage +# Test manual AppImage build +``` + +**B. Fix AppImage Configuration** + +Create/update `appimage/AppRun`: +```bash +#!/bin/bash +HERE="$(dirname "$(readlink -f "${0}")")" +export PATH="${HERE}/usr/bin:${PATH}" +export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}" +export XDG_DATA_DIRS="${HERE}/usr/share:${XDG_DATA_DIRS}" + +# Fyne requires these for proper rendering +export FYNE_SCALE=1.0 +export GDK_BACKEND=x11 + +exec "${HERE}/usr/bin/cycles" "$@" +``` + +**C. AppImage Desktop File** + +Create `us.tylerc.cycles.desktop` (verify it's correct): +```desktop +[Desktop Entry] +Type=Application +Name=Cycles +Comment=Desktop CPU Monitor +Exec=cycles +Icon=us.tylerc.cycles +Categories=System;Monitor; +Terminal=false +``` + +**D. Build Script** + +Create `appimage/build-appimage.sh`: +```bash +#!/bin/bash +set -e + +# Build the application +go build -o cycles -ldflags="-s -w" + +# Create AppDir structure +mkdir -p AppDir/usr/bin +mkdir -p AppDir/usr/share/applications +mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps +mkdir -p AppDir/usr/share/metainfo + +# Copy files +cp cycles AppDir/usr/bin/ +cp icon.png AppDir/usr/share/icons/hicolor/256x256/apps/us.tylerc.cycles.png +cp us.tylerc.cycles.desktop AppDir/usr/share/applications/ +cp us.tylerc.cycles.appdata.xml AppDir/usr/share/metainfo/ + +# Download linuxdeploy if needed +if [ ! -f linuxdeploy-x86_64.AppImage ]; then + wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage +fi + +# Create AppImage +./linuxdeploy-x86_64.AppImage \ + --appdir AppDir \ + --output appimage \ + --desktop-file=AppDir/usr/share/applications/us.tylerc.cycles.desktop \ + --icon-file=AppDir/usr/share/icons/hicolor/256x256/apps/us.tylerc.cycles.png + +echo "AppImage created successfully!" +``` + +**E. Testing Checklist** +- [ ] AppImage runs on Ubuntu 20.04, 22.04, 24.04 +- [ ] AppImage runs on Fedora (latest) +- [ ] AppImage runs on Arch Linux +- [ ] Icon displays correctly in file manager +- [ ] Desktop integration works (double-click launch) +- [ ] No dependency errors +- [ ] Graphics render correctly (Fyne UI) + +--- + +### 2. Implement Flatpak Support + +#### Why Flatpak Has Been Difficult +- Fyne applications need special consideration in Flatpak +- OpenGL/graphics permissions required +- File system access for `/proc` reading +- Proper SDK selection + +#### Implementation Steps + +**A. Create Flatpak Manifest** + +Create `flatpak/us.tylerc.cycles.yml`: +```yaml +app-id: us.tylerc.cycles +runtime: org.freedesktop.Platform +runtime-version: '23.08' +sdk: org.freedesktop.Sdk +sdk-extensions: + - org.freedesktop.Sdk.Extension.golang + +command: cycles + +finish-args: + # X11 + XShm access + - --share=ipc + - --socket=x11 + + # OpenGL/graphics access (required for Fyne) + - --device=dri + + # File system access for /proc reading + - --filesystem=/proc:ro + - --filesystem=/sys:ro + + # Network access (for network monitoring) + - --share=network + + # Access to host system info + - --filesystem=host:ro + +modules: + - name: cycles + buildsystem: simple + build-options: + append-path: /usr/lib/sdk/golang/bin + env: + GOBIN: /app/bin + GOROOT: /usr/lib/sdk/golang + build-commands: + - . /usr/lib/sdk/golang/enable.sh && go build -o cycles -ldflags="-s -w" + - install -Dm755 cycles /app/bin/cycles + - install -Dm644 icon.png /app/share/icons/hicolor/256x256/apps/us.tylerc.cycles.png + - install -Dm644 us.tylerc.cycles.desktop /app/share/applications/us.tylerc.cycles.desktop + - install -Dm644 us.tylerc.cycles.appdata.xml /app/share/metainfo/us.tylerc.cycles.appdata.xml + sources: + - type: git + url: https://github.com/TylerCode/cycles + branch: main +``` + +**B. Flatpak Build Script** + +Create `flatpak/build-flatpak.sh`: +```bash +#!/bin/bash +set -e + +echo "Building Flatpak for Cycles..." + +# Install flatpak-builder if needed +if ! command -v flatpak-builder &> /dev/null; then + echo "Error: flatpak-builder not found. Install it first." + echo " Ubuntu/Debian: sudo apt install flatpak-builder" + echo " Fedora: sudo dnf install flatpak-builder" + exit 1 +fi + +# Add Flathub if not already added +flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + +# Install required SDK +flatpak install -y flathub org.freedesktop.Platform//23.08 org.freedesktop.Sdk//23.08 +flatpak install -y flathub org.freedesktop.Sdk.Extension.golang + +# Build the Flatpak +flatpak-builder --force-clean build-dir flatpak/us.tylerc.cycles.yml + +# Create repository +flatpak-builder --repo=repo --force-clean build-dir flatpak/us.tylerc.cycles.yml + +# Build bundle for distribution +flatpak build-bundle repo cycles.flatpak us.tylerc.cycles + +echo "Flatpak bundle created: cycles.flatpak" +echo "To install: flatpak install cycles.flatpak" +echo "To run: flatpak run us.tylerc.cycles" +``` + +**C. Testing Checklist** +- [ ] Flatpak builds without errors +- [ ] Can read CPU info from /proc +- [ ] Graphics render correctly (Fyne with OpenGL) +- [ ] All tabs display data correctly +- [ ] Settings persist correctly +- [ ] No permission errors in logs +- [ ] Works on different distros (test in VMs) + +--- + +### 3. Snap Verification & Enhancement + +#### Current Status +✅ Working - but let's verify and document + +#### Verification Steps +```bash +# Test current snap +sudo snap install tylercode-cycles + +# Verify interfaces +snap connections tylercode-cycles + +# Check for any confined issues +snap logs tylercode-cycles +``` + +#### Enhancement: Ensure All Permissions + +Update `snap/snapcraft.yaml` to ensure all required plugs: +```yaml +plugs: + hardware-observe: + system-observe: + network-observe: + mount-observe: + process-control: # For process management features + opengl: # For Fyne rendering + x11: # For GUI +``` + +#### Testing Checklist +- [ ] Snap installs correctly +- [ ] All monitoring features work +- [ ] Process management works (when implemented) +- [ ] No confined interface errors +- [ ] Auto-updates work correctly + +--- + +### 4. Traditional Package Formats + +#### Debian/Ubuntu (.deb) + +**Create `packaging/debian/` structure:** +``` +packaging/debian/ +├── DEBIAN/ +│ ├── control +│ ├── postinst +│ └── prerm +├── usr/ +│ ├── bin/ +│ │ └── cycles +│ └── share/ +│ ├── applications/ +│ │ └── us.tylerc.cycles.desktop +│ ├── icons/ +│ │ └── hicolor/256x256/apps/ +│ │ └── us.tylerc.cycles.png +│ └── metainfo/ +│ └── us.tylerc.cycles.appdata.xml +``` + +**Create `packaging/build-deb.sh`:** +```bash +#!/bin/bash +set -e + +VERSION=$(grep 'Version:' config.go | cut -d'"' -f2) +ARCH=$(dpkg --print-architecture) +PACKAGE_NAME="tylercode-cycles_${VERSION}_${ARCH}" + +# Build the binary +go build -o cycles -ldflags="-s -w" + +# Create package structure +mkdir -p "${PACKAGE_NAME}/DEBIAN" +mkdir -p "${PACKAGE_NAME}/usr/bin" +mkdir -p "${PACKAGE_NAME}/usr/share/applications" +mkdir -p "${PACKAGE_NAME}/usr/share/icons/hicolor/256x256/apps" +mkdir -p "${PACKAGE_NAME}/usr/share/metainfo" + +# Copy files +cp cycles "${PACKAGE_NAME}/usr/bin/" +cp us.tylerc.cycles.desktop "${PACKAGE_NAME}/usr/share/applications/" +cp icon.png "${PACKAGE_NAME}/usr/share/icons/hicolor/256x256/apps/us.tylerc.cycles.png" +cp us.tylerc.cycles.appdata.xml "${PACKAGE_NAME}/usr/share/metainfo/" + +# Create control file +cat > "${PACKAGE_NAME}/DEBIAN/control" << EOF +Package: tylercode-cycles +Version: ${VERSION} +Section: utils +Priority: optional +Architecture: ${ARCH} +Maintainer: Tyler +Description: Desktop CPU Monitor + Cycles provides real-time CPU, memory, disk, and network monitoring + with graphical visualization. +Depends: libc6, libgl1, libx11-6, libxcursor1, libxrandr2, libxinerama1, libxi6 +EOF + +# Build package +dpkg-deb --build "${PACKAGE_NAME}" + +echo "Debian package created: ${PACKAGE_NAME}.deb" +``` + +#### Fedora/RHEL (.rpm) + +**Create `packaging/cycles.spec`:** +```spec +Name: cycles +Version: 0.4.1 +Release: 1%{?dist} +Summary: Desktop CPU Monitor + +License: MIT +URL: https://github.com/TylerCode/cycles +Source0: %{name}-%{version}.tar.gz + +BuildRequires: golang >= 1.20 +BuildRequires: mesa-libGL-devel +BuildRequires: libXcursor-devel +BuildRequires: libXrandr-devel +BuildRequires: libXinerama-devel +BuildRequires: libXi-devel + +Requires: mesa-libGL +Requires: libXcursor +Requires: libXrandr +Requires: libXinerama +Requires: libXi + +%description +Cycles provides real-time CPU, memory, disk, and network monitoring +with graphical visualization similar to Windows Task Manager. + +%prep +%setup -q + +%build +go build -o cycles -ldflags="-s -w" + +%install +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_datadir}/applications +mkdir -p %{buildroot}%{_datadir}/icons/hicolor/256x256/apps +mkdir -p %{buildroot}%{_datadir}/metainfo + +install -m 755 cycles %{buildroot}%{_bindir}/ +install -m 644 us.tylerc.cycles.desktop %{buildroot}%{_datadir}/applications/ +install -m 644 icon.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/us.tylerc.cycles.png +install -m 644 us.tylerc.cycles.appdata.xml %{buildroot}%{_datadir}/metainfo/ + +%files +%license LICENSE +%{_bindir}/cycles +%{_datadir}/applications/us.tylerc.cycles.desktop +%{_datadir}/icons/hicolor/256x256/apps/us.tylerc.cycles.png +%{_datadir}/metainfo/us.tylerc.cycles.appdata.xml + +%changelog +* Thu Nov 17 2025 Tyler - 0.4.1-1 +- Initial RPM package +``` + +**Create `packaging/build-rpm.sh`:** +```bash +#!/bin/bash +set -e + +# Ensure rpmbuild directory structure exists +mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} + +# Copy spec file +cp packaging/cycles.spec ~/rpmbuild/SPECS/ + +# Create source tarball +VERSION=$(grep 'Version:' config.go | cut -d'"' -f2) +mkdir -p cycles-${VERSION} +cp -r *.go go.mod go.sum icon.png *.desktop *.xml LICENSE cycles-${VERSION}/ +tar czf ~/rpmbuild/SOURCES/cycles-${VERSION}.tar.gz cycles-${VERSION} +rm -rf cycles-${VERSION} + +# Build RPM +rpmbuild -ba ~/rpmbuild/SPECS/cycles.spec + +echo "RPM package created in ~/rpmbuild/RPMS/" +``` + +--- + +### 5. AppData/Metainfo Validation + +The `us.tylerc.cycles.appdata.xml` file is critical for all package formats. + +#### Validate Current File +```bash +# Install validator +sudo apt install appstream-util # Debian/Ubuntu +sudo dnf install appstream # Fedora + +# Validate +appstream-util validate-relax us.tylerc.cycles.appdata.xml +``` + +#### Update if Needed +Ensure the AppData file includes: +- Valid screenshots +- Release information +- Proper metadata tags +- Content rating +- Update contact info + +--- + +### 6. CI/CD Integration + +#### Update `.github/workflows/` for All Formats + +**Create `.github/workflows/packages.yml`:** +```yaml +name: Build All Packages + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + appimage: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgl1-mesa-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libglfw3-dev libxxf86vm-dev + - name: Build AppImage + run: | + chmod +x appimage/build-appimage.sh + ./appimage/build-appimage.sh + - name: Upload AppImage + uses: actions/upload-artifact@v3 + with: + name: AppImage + path: '*.AppImage' + + flatpak: + runs-on: ubuntu-latest + container: + image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08 + options: --privileged + steps: + - uses: actions/checkout@v3 + - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 + with: + bundle: cycles.flatpak + manifest-path: flatpak/us.tylerc.cycles.yml + - name: Upload Flatpak + uses: actions/upload-artifact@v3 + with: + name: Flatpak + path: cycles.flatpak + + deb: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgl1-mesa-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev + - name: Build DEB + run: | + chmod +x packaging/build-deb.sh + ./packaging/build-deb.sh + - name: Upload DEB + uses: actions/upload-artifact@v3 + with: + name: DEB + path: '*.deb' + + rpm: + runs-on: ubuntu-latest + container: + image: fedora:latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: | + dnf install -y golang rpm-build mesa-libGL-devel libXcursor-devel libXrandr-devel libXinerama-devel libXi-devel + - name: Build RPM + run: | + chmod +x packaging/build-rpm.sh + ./packaging/build-rpm.sh + - name: Upload RPM + uses: actions/upload-artifact@v3 + with: + name: RPM + path: '~/rpmbuild/RPMS/*/*.rpm' +``` + +--- + +## Testing Matrix + +| Format | Ubuntu 20.04 | Ubuntu 22.04 | Ubuntu 24.04 | Fedora 39 | Arch Linux | Notes | +|--------|--------------|--------------|--------------|-----------|------------|-------| +| AppImage | ✓ | ✓ | ✓ | ✓ | ✓ | Should work everywhere | +| Flatpak | ✓ | ✓ | ✓ | ✓ | ✓ | Universal | +| Snap | ✓ | ✓ | ✓ | ✓ | ✓ | Already working | +| .deb | ✓ | ✓ | ✓ | ✗ | ✗ | Debian-based only | +| .rpm | ✗ | ✗ | ✗ | ✓ | ✗ | Red Hat-based only | +| AUR | ✗ | ✗ | ✗ | ✗ | ✓ | Arch User Repository | + +--- + +## Documentation Updates + +### README.md Section +Add comprehensive installation section: +```markdown +## Installation + +### Linux + +#### Flatpak (Recommended - All Distributions) +```bash +flatpak install cycles.flatpak +flatpak run us.tylerc.cycles +``` + +#### Snap (All Distributions) +```bash +sudo snap install tylercode-cycles +``` + +#### AppImage (All Distributions) +```bash +# Download from releases page +chmod +x Cycles-x86_64.AppImage +./Cycles-x86_64.AppImage +``` + +#### Ubuntu/Debian +```bash +sudo dpkg -i tylercode-cycles_0.4.1_amd64.deb +``` + +#### Fedora/RHEL +```bash +sudo dnf install tylercode-cycles-0.4.1-1.x86_64.rpm +``` + +#### Arch Linux (AUR) +```bash +yay -S cycles-bin +``` +``` + +--- + +## Deliverables Checklist + +### Required Files +- [ ] `appimage/build-appimage.sh` +- [ ] `appimage/AppRun` +- [ ] `flatpak/us.tylerc.cycles.yml` +- [ ] `flatpak/build-flatpak.sh` +- [ ] `packaging/build-deb.sh` +- [ ] `packaging/build-rpm.sh` +- [ ] `packaging/cycles.spec` +- [ ] `.github/workflows/packages.yml` +- [ ] Updated `README.md` with installation instructions +- [ ] Updated `CHANGELOG.md` with package format additions + +### Testing Complete +- [ ] AppImage works on 3+ distros +- [ ] Flatpak builds and runs without errors +- [ ] Snap still works (regression test) +- [ ] .deb installs on Ubuntu/Debian +- [ ] .rpm installs on Fedora +- [ ] All packages show icon correctly +- [ ] All packages integrate with desktop environment +- [ ] All packages can read system info correctly +- [ ] No permission/sandbox issues + +### CI/CD +- [ ] GitHub Actions build all packages automatically +- [ ] Release workflow uploads all package types +- [ ] Package naming is consistent +- [ ] Version numbers sync across all formats + +--- + +## Success Criteria + +1. **AppImage:** Works out-of-the-box on major distributions without dependency issues +2. **Flatpak:** Builds cleanly and runs with proper permissions for system monitoring +3. **Snap:** Continues to work as it currently does (no regression) +4. **Traditional Packages:** .deb and .rpm install cleanly on their respective platforms +5. **Documentation:** Clear installation instructions for each package format +6. **Automation:** CI/CD builds all package formats on release + +--- + +## Common Issues & Solutions + +### Flatpak Issues + +**Problem:** Can't read /proc filesystem +**Solution:** Add `--filesystem=/proc:ro` to finish-args + +**Problem:** Graphics not rendering (black screen) +**Solution:** Ensure `--device=dri` and `--socket=x11` permissions + +**Problem:** Build fails with Go errors +**Solution:** Verify Go SDK extension is installed and enabled + +### AppImage Issues + +**Problem:** "Cannot execute binary file" +**Solution:** Ensure AppRun has execute permissions and proper shebang + +**Problem:** Missing libraries +**Solution:** Use linuxdeploy with --bundle-non-qt-libs flag + +**Problem:** Icon not showing +**Solution:** Verify .desktop file and icon paths are correct + +### General Issues + +**Problem:** Version number mismatch +**Solution:** Create single source of truth (config.go) and script version extraction + +**Problem:** Different behavior in packaged vs source +**Solution:** Test with relative paths, ensure icon.png is embedded or properly located + +--- + +## Timeline Integration + +This packaging work should be integrated into **Sprint 10** or done as **Sprint 10.5** before the v1.2.0 release. + +**Recommended Approach:** +- Fix AppImage: Day 1 +- Implement Flatpak: Day 2 +- Create traditional packages: Day 3 +- CI/CD integration: Day 4 +- Testing on all platforms: Day 5 + +--- + +*This plan ensures Cycles can be easily installed by users on any Linux distribution using their preferred package format.* diff --git a/README.md b/README.md index eb910d6..508dd32 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,9 @@ chmod +x cycles - `gopsutil` library for accessing system information. -### Setup -To set up the project on your local machine: +### Quick Start (Automated Setup) + +The easiest way to get started developing: 1. Clone the repository (I would make a fork and clone that to contribute): ```bash @@ -77,29 +78,80 @@ git clone https://github.com/TylerCode/cycles cd cycles ``` -2. Install system dependencies (Ubuntu/Debian): +2. Run automated setup (detects your OS and installs all dependencies): +```bash +make setup +``` + +3. Build and run: +```bash +make run +``` + +That's it! The `make setup` command will: +- Detect your Linux distribution (Ubuntu/Debian/Zorin/Pop, Fedora/RHEL, Arch) +- Install all required system dependencies +- Download and verify Go dependencies +- Test that everything builds correctly + +**Note:** If your specific distribution isn't recognized, the script will automatically detect your package manager (apt-get, dnf, or pacman) and use the appropriate installation method. + +### Manual Setup + +If you prefer manual installation or the automated setup doesn't work: + +1. Clone the repository: ```bash -sudo apt-get install libgl1-mesa-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libglfw3-dev libxxf86vm-dev +git clone https://github.com/TylerCode/cycles +cd cycles +``` + +2. Install system dependencies: + +**Ubuntu/Debian:** +```bash +sudo apt-get install libgl1-mesa-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libglfw3-dev libxxf86vm-dev pkg-config gcc make +``` + +**Fedora/RHEL:** +```bash +sudo dnf install mesa-libGL-devel libXcursor-devel libXrandr-devel libXinerama-devel libXi-devel glfw-devel libXxf86vm-devel pkg-config gcc gcc-c++ make +``` + +**Arch Linux:** +```bash +sudo pacman -S mesa libxcursor libxrandr libxinerama libxi glfw-x11 pkg-config gcc make ``` 3. Install Go dependencies: ```bash -go mod tidy +make install-deps ``` 4. Build the application: ```bash -go build -o cycles +make build ``` 5. Run it: ```bash -./cycles +make run ``` 6. Run tests: ```bash -go test -v ./... +make test +``` + +### Build System Commands + +```bash +make build # Build optimized binary +make run # Build and run +make test # Run all tests +make check # Format, vet, and test +make clean # Remove build artifacts +make help # Show all available commands ``` ### Command-Line Options diff --git a/SPRINT_SUMMARY.md b/SPRINT_SUMMARY.md new file mode 100644 index 0000000..e73379b --- /dev/null +++ b/SPRINT_SUMMARY.md @@ -0,0 +1,328 @@ +# Cycles Overhaul Sprint Summary +## Quick Reference Guide + +**Current Version:** 0.4.1 → **Target Version:** 1.2.0 + +--- + +## Sprint Quick Reference + +### Sprint 1: Memory Monitoring (v0.5.0) - 2-3 days +**Focus:** Add memory monitoring UI +- Create `memorytile.go` and `memorytile_test.go` +- Add Memory tab with graphs +- Enhance memory functions in `sysinfo.go` +- Display RAM, Swap, Cache usage + +**Key Deliverable:** Working memory monitoring tab + +--- + +### Sprint 2: Settings System (v0.6.0) - 2-3 days +**Focus:** Persistent settings and theme management +- Create `settings.go` and `settingsui.go` +- Implement JSON-based settings persistence +- Add Settings dialog (theme, intervals, preferences) +- Dark/light theme toggle + +**Key Deliverable:** Settings persist between sessions + +--- + +### Sprint 3: Disk & Network (v0.7.0) - 3-4 days +**Focus:** Expand monitoring capabilities +- Create `diskinfo.go`, `disktile.go` (disk I/O monitoring) +- Create `netinfo.go`, `nettile.go` (network monitoring) +- Add Disk and Network tabs +- Per-device/interface breakdown + +**Key Deliverable:** Disk and Network monitoring tabs + +--- + +### Sprint 4: Performance (v0.7.5) - 2 days +**Focus:** Optimize rendering and memory +- Create `ringbuffer.go` (circular buffer for history) +- Optimize graph rendering (canvas reuse) +- Reduce memory allocations +- Benchmark improvements + +**Key Deliverable:** 30%+ performance improvement + +--- + +### Sprint 5: Cross-Platform (v0.8.0) - 4-5 days +**Focus:** Windows and macOS support +- Create `platform/` directory with abstraction layer +- Implement `platform/linux.go`, `windows.go`, `darwin.go` +- Platform-specific UI adjustments +- Cross-compilation setup + +**Key Deliverable:** Builds and runs on Linux, Windows, macOS + +--- + +### Sprint 6: Process Management (v0.9.0) - 3-4 days +**Focus:** Process list and management +- Create `processinfo.go`, `processtable.go` +- Sortable process table (PID, Name, CPU%, Memory) +- Process details dialog +- End process functionality + +**Key Deliverable:** Working process manager tab + +--- + +### Sprint 7: Export & Logging (v0.9.5) - 2-3 days +**Focus:** Data export and historical logging +- Create `export.go`, `logger.go`, `exportui.go` +- Export to CSV/JSON/XML +- Continuous logging with rotation +- Historical data viewer + +**Key Deliverable:** Export and logging functionality + +--- + +### Sprint 8: GPU Monitoring (v1.0.0) - 3-4 days +**Focus:** GPU support (NVIDIA, AMD, Intel) +- Create `gpuinfo.go`, `gputile.go` +- NVIDIA NVML support +- AMD ROCm/sysfs support +- Intel integrated GPU support + +**Key Deliverable:** GPU monitoring tab (v1.0 milestone!) + +--- + +### Sprint 9: Advanced UI (v1.1.0) - 3-4 days +**Focus:** UI enhancements and customization +- Resizable tiles +- Custom layouts (`layouts.go`) +- Mini mode (`minimode.go`) +- Enhanced visualizations +- Always-on-top, system tray + +**Key Deliverable:** Highly customizable UI + +--- + +### Sprint 10: Polish & Release (v1.2.0) - 2-3 days +**Focus:** Production readiness +- Bug fixes and final polish +- Complete documentation +- Installers for all platforms (.deb, .rpm, .msi, .dmg) +- Performance final pass +- i18n preparation + +**Key Deliverable:** Production-ready v1.2.0 release + +--- + +## Total Timeline: 26-35 days (full-time development) + +--- + +## File Creation Summary + +### Sprint 1 (Memory) +- `memorytile.go` (60-80 lines) +- `memorytile_test.go` + +### Sprint 2 (Settings) +- `settings.go` (100-120 lines) +- `settingsui.go` (150-200 lines) +- `settings_test.go`, `settingsui_test.go` + +### Sprint 3 (Disk/Network) +- `diskinfo.go` (150-180 lines) +- `disktile.go` (80-100 lines) +- `netinfo.go` (150-180 lines) +- `nettile.go` (80-100 lines) +- Test files + +### Sprint 4 (Performance) +- `ringbuffer.go` (100-120 lines) +- `ringbuffer_test.go` +- `benchmark_test.go` + +### Sprint 5 (Cross-Platform) +- `platform/interface.go` +- `platform/linux.go` +- `platform/windows.go` +- `platform/darwin.go` +- Platform-specific tests + +### Sprint 6 (Processes) +- `processinfo.go` (200-250 lines) +- `processtable.go` (250-300 lines) +- `processdetails.go` (150-200 lines) +- Test files + +### Sprint 7 (Export) +- `export.go` (150-180 lines) +- `logger.go` (120-150 lines) +- `exportui.go` (100-120 lines) +- `historyviewer.go` (200-250 lines) +- Test files + +### Sprint 8 (GPU) +- `gpuinfo.go` (100-120 lines) +- `gpuinfo_nvidia.go` (150-200 lines) +- `gpuinfo_amd.go` (150-200 lines) +- `gpuinfo_intel.go` (100-150 lines) +- `gputile.go` (100-120 lines) +- Test files + +### Sprint 9 (Advanced UI) +- `layouts.go` (150-200 lines) +- `minimode.go` (100-120 lines) +- Test files + +### Sprint 10 (Polish) +- Documentation files +- Installer scripts +- i18n files + +--- + +## Architecture Evolution + +### Before (v0.4.1) - Flat Structure +``` +cycles/ +├── main.go +├── config.go +├── theme.go +├── tile.go +├── sysinfo.go +├── graphics.go +└── info.go +``` + +### After (v1.2.0) - Modular Structure +``` +cycles/ +├── cmd/cycles/main.go +├── internal/ +│ ├── app/ +│ ├── config/ +│ ├── ui/ +│ │ ├── components/ +│ │ ├── dialogs/ +│ │ └── views/ +│ ├── platform/ +│ ├── monitoring/ +│ ├── data/ +│ └── utils/ +├── docs/ +├── installers/ +└── i18n/ +``` + +--- + +## Key Features by Version + +| Version | Key Features | +|---------|-------------| +| 0.4.1 | CPU monitoring, command-line config | +| 0.5.0 | + Memory monitoring | +| 0.6.0 | + Persistent settings, themes | +| 0.7.0 | + Disk & Network monitoring | +| 0.7.5 | + Performance optimizations | +| 0.8.0 | + Windows & macOS support | +| 0.9.0 | + Process management | +| 0.9.5 | + Export & logging | +| 1.0.0 | + GPU monitoring ⭐ | +| 1.1.0 | + Advanced UI features | +| 1.2.0 | + Production polish 🎉 | + +--- + +## Sprint Dependencies + +``` +Sprint 1 (Memory) + ↓ +Sprint 2 (Settings) ←─── Can run parallel with Sprint 1 + ↓ +Sprint 3 (Disk/Net) ←─── Depends on Sprint 2 for settings + ↓ +Sprint 4 (Performance) ←─ Depends on Sprints 1-3 data structures + ↓ +Sprint 5 (Cross-Platform) ←─ Refactors all previous work + ↓ +Sprint 6 (Processes) ←─── Independent, can be earlier + ↓ +Sprint 7 (Export) ←────── Depends on all monitoring features + ↓ +Sprint 8 (GPU) ←──────── Independent, can be earlier + ↓ +Sprint 9 (Advanced UI) ←─ Depends on all UI components + ↓ +Sprint 10 (Polish) ←───── Depends on everything +``` + +--- + +## Testing Requirements per Sprint + +| Sprint | Unit Tests | Integration Tests | Platform Tests | Performance Tests | +|--------|-----------|-------------------|----------------|-------------------| +| 1 | ✓ | - | - | - | +| 2 | ✓ | ✓ | - | - | +| 3 | ✓ | ✓ | - | ✓ | +| 4 | ✓ | - | - | ✓✓ | +| 5 | ✓ | ✓ | ✓✓ | - | +| 6 | ✓ | ✓ | - | ✓ | +| 7 | ✓ | ✓ | - | - | +| 8 | ✓ | - | ✓ | - | +| 9 | ✓ | ✓ | - | ✓ | +| 10 | ✓✓ | ✓✓ | ✓✓ | ✓✓ | + +--- + +## Priority Ranking (if resources limited) + +### Must Have (P0) +1. Sprint 1: Memory Monitoring +2. Sprint 2: Settings System +3. Sprint 5: Cross-Platform Support +4. Sprint 10: Polish & Release + +### Should Have (P1) +5. Sprint 3: Disk & Network +6. Sprint 4: Performance +7. Sprint 6: Process Management + +### Nice to Have (P2) +8. Sprint 7: Export & Logging +9. Sprint 8: GPU Monitoring +10. Sprint 9: Advanced UI + +--- + +## Getting Started + +### To Start Sprint 1: +```bash +# Create new files +touch memorytile.go memorytile_test.go + +# Run existing tests to ensure baseline +go test -v ./... + +# Begin implementation +# See OVERHAUL_PLAN_V2.md Sprint 1 section for details +``` + +### To Track Progress: +- Use GitHub Issues for each sprint +- Create milestones for each version +- Tag commits with sprint numbers +- Update CHANGELOG.md after each sprint + +--- + +*For detailed task breakdowns, see OVERHAUL_PLAN_V2.md* diff --git a/config.go b/config.go index 14889d8..aba2b9c 100644 --- a/config.go +++ b/config.go @@ -17,7 +17,7 @@ type AppConfig struct { // DefaultConfig returns the default configuration func DefaultConfig() *AppConfig { return &AppConfig{ - Version: "0.4.1", + Version: "0.6.0", GridColumns: 8, UpdateInterval: 2 * time.Second, HistorySize: 30, diff --git a/main.go b/main.go index 4e4842b..11fcc7d 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,26 @@ func main() { myApp := app.New() + // Load settings + settings := NewSettings(myApp) + + // Command-line flags override saved settings + if config.GridColumns != 8 { + settings.GridColumns = config.GridColumns + } + if config.UpdateInterval != 2*time.Second { + settings.UpdateInterval = config.UpdateInterval + } + if config.HistorySize != 30 { + settings.HistorySize = config.HistorySize + } + + // Apply settings to config + settings.ApplyToConfig(config) + + // Apply theme + ApplyTheme(myApp, settings.GetThemeVariant()) + icon, err := fyne.LoadResourceFromPath("icon.png") if err != nil { log.Printf("Warning: Could not load icon: %v", err) @@ -33,8 +53,28 @@ func main() { dialog.ShowInformation("About Cycles", GetAppInfo(), myWindow) }) + settingsItem := fyne.NewMenuItem("Preferences...", func() { + ShowSettingsDialog(settings, myWindow, func() { + // Settings saved callback + log.Println("Settings saved successfully") + }) + }) + + // View menu for quick theme toggle + themeToggleItem := fyne.NewMenuItem("Toggle Theme", func() { + if settings.Theme == "dark" { + settings.Theme = "light" + } else { + settings.Theme = "dark" + } + settings.Save() + ApplyTheme(myApp, settings.GetThemeVariant()) + }) + helpMenu := fyne.NewMenu("Help", aboutItem) - mainMenu := fyne.NewMainMenu(helpMenu) + fileMenu := fyne.NewMenu("File", settingsItem) + viewMenu := fyne.NewMenu("View", themeToggleItem) + mainMenu := fyne.NewMainMenu(fileMenu, viewMenu, helpMenu) myWindow.SetMainMenu(mainMenu) // Determine the number of CPU cores @@ -43,22 +83,46 @@ func main() { log.Fatalf("Error getting CPU core count: %v", err) } - tiles := make([]*CoreTile, numCores) + cpuTiles := make([]*CoreTile, numCores) - // Create a grid container - grid := container.NewGridWithColumns(config.GridColumns) + // Create CPU grid container + cpuGrid := container.NewGridWithColumns(config.GridColumns) for i := 0; i < numCores; i++ { - tiles[i] = NewCoreTile() - grid.Add(tiles[i].GetContainer()) + cpuTiles[i] = NewCoreTile() + cpuGrid.Add(cpuTiles[i].GetContainer()) + } + + // Create memory tiles (overall memory + swap if available) + memoryTiles := make([]*MemoryTile, 0) + memoryTiles = append(memoryTiles, NewMemoryTile("System Memory")) + + // Create memory grid container + memoryGrid := container.NewGridWithColumns(2) + for _, tile := range memoryTiles { + memoryGrid.Add(tile.GetContainer()) } - myWindow.SetContent(grid) + // Create tabs for CPU and Memory + tabs := container.NewAppTabs( + container.NewTabItem("CPU", cpuGrid), + container.NewTabItem("Memory", memoryGrid), + ) + + myWindow.SetContent(tabs) // Update CPU info periodically go func() { for { - UpdateCPUInfo(tiles) + UpdateCPUInfo(cpuTiles) + time.Sleep(config.UpdateInterval) + } + }() + + // Update Memory info periodically + go func() { + for { + UpdateMemoryInfo(memoryTiles, config.HistorySize) time.Sleep(config.UpdateInterval) } }() diff --git a/memorytile.go b/memorytile.go new file mode 100644 index 0000000..679c1cc --- /dev/null +++ b/memorytile.go @@ -0,0 +1,93 @@ +package main + +import ( + "fmt" + "image" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +// MemoryTile represents a memory display tile +type MemoryTile struct { + TitleLabel *widget.Label + TotalLabel *widget.Label + UsedLabel *widget.Label + FreeLabel *widget.Label + CachedLabel *widget.Label + PercentLabel *widget.Label + container *fyne.Container + UsageHistory []float64 // Slice to store memory usage percentage history + GraphImg *canvas.Image +} + +// NewMemoryTile creates a new memory tile with default styling +func NewMemoryTile(title string) *MemoryTile { + titleLabel := widget.NewLabel(title) + totalLabel := widget.NewLabel("Total: -- GB") + usedLabel := widget.NewLabel("Used: -- GB") + freeLabel := widget.NewLabel("Free: -- GB") + cachedLabel := widget.NewLabel("Cached: -- GB") + percentLabel := widget.NewLabel("Usage: --%") + + // Make title label bold by using a larger/emphasized style + titleLabel.TextStyle = fyne.TextStyle{Bold: true} + + // Create a background rectangle with rounded corners + bg := canvas.NewRectangle(theme.BackgroundColor()) + bg.SetMinSize(fyne.NewSize(150, 150)) + bg.FillColor = theme.BackgroundColor() + bg.StrokeColor = theme.ShadowColor() + bg.StrokeWidth = 1 + bg.CornerRadius = 10 + + graphImg := canvas.NewImageFromImage(image.NewRGBA(image.Rect(0, 0, 140, 60))) + graphImg.FillMode = canvas.ImageFillOriginal + + container := container.NewMax( + bg, + container.NewVBox( + titleLabel, + percentLabel, + totalLabel, + usedLabel, + freeLabel, + cachedLabel, + graphImg, + ), + ) + + return &MemoryTile{ + TitleLabel: titleLabel, + TotalLabel: totalLabel, + UsedLabel: usedLabel, + FreeLabel: freeLabel, + CachedLabel: cachedLabel, + PercentLabel: percentLabel, + container: container, + GraphImg: graphImg, + } +} + +// GetContainer returns the container of the memory tile +func (t *MemoryTile) GetContainer() fyne.CanvasObject { + return t.container +} + +// formatMemorySize formats bytes to human-readable format (GB, MB) +func formatMemorySize(kbytes uint64) string { + gb := float64(kbytes) / 1024.0 / 1024.0 + if gb >= 1.0 { + return fmt.Sprintf("%.2f GB", gb) + } + mb := float64(kbytes) / 1024.0 + return fmt.Sprintf("%.2f MB", mb) +} + +// formatMemoryPercent formats memory usage percentage +func formatMemoryPercent(percent float64) string { + return fmt.Sprintf("%.1f%%", percent) +} diff --git a/memorytile_test.go b/memorytile_test.go new file mode 100644 index 0000000..b631462 --- /dev/null +++ b/memorytile_test.go @@ -0,0 +1,100 @@ +package main + +import ( + "testing" +) + +func TestNewMemoryTile(t *testing.T) { + tile := NewMemoryTile("Test Memory") + + if tile == nil { + t.Fatal("NewMemoryTile returned nil") + } + + if tile.TitleLabel == nil { + t.Error("TitleLabel is nil") + } + + if tile.TotalLabel == nil { + t.Error("TotalLabel is nil") + } + + if tile.UsedLabel == nil { + t.Error("UsedLabel is nil") + } + + if tile.FreeLabel == nil { + t.Error("FreeLabel is nil") + } + + if tile.CachedLabel == nil { + t.Error("CachedLabel is nil") + } + + if tile.PercentLabel == nil { + t.Error("PercentLabel is nil") + } + + if tile.GraphImg == nil { + t.Error("GraphImg is nil") + } + + if tile.GetContainer() == nil { + t.Error("GetContainer returned nil") + } + + // Check initial label text + if tile.TitleLabel.Text != "Test Memory" { + t.Errorf("Expected title 'Test Memory', got '%s'", tile.TitleLabel.Text) + } +} + +func TestFormatMemorySize(t *testing.T) { + tests := []struct { + kbytes uint64 + expected string + }{ + {1024 * 1024, "1.00 GB"}, // 1 GB + {2 * 1024 * 1024, "2.00 GB"}, // 2 GB + {512 * 1024, "512.00 MB"}, // 512 MB + {1024, "1.00 MB"}, // 1 MB + {8 * 1024 * 1024, "8.00 GB"}, // 8 GB + {16 * 1024 * 1024, "16.00 GB"}, // 16 GB + } + + for _, tt := range tests { + result := formatMemorySize(tt.kbytes) + if result != tt.expected { + t.Errorf("formatMemorySize(%d) = %s; want %s", tt.kbytes, result, tt.expected) + } + } +} + +func TestFormatMemoryPercent(t *testing.T) { + tests := []struct { + percent float64 + expected string + }{ + {50.0, "50.0%"}, + {75.5, "75.5%"}, + {0.0, "0.0%"}, + {100.0, "100.0%"}, + {33.333, "33.3%"}, + } + + for _, tt := range tests { + result := formatMemoryPercent(tt.percent) + if result != tt.expected { + t.Errorf("formatMemoryPercent(%.3f) = %s; want %s", tt.percent, result, tt.expected) + } + } +} + +func TestMemoryTileGetContainer(t *testing.T) { + tile := NewMemoryTile("Test") + container := tile.GetContainer() + + if container == nil { + t.Error("GetContainer() returned nil") + } +} diff --git a/scripts/setup-dev.sh b/scripts/setup-dev.sh new file mode 100755 index 0000000..c835fd9 --- /dev/null +++ b/scripts/setup-dev.sh @@ -0,0 +1,159 @@ +#!/bin/bash +set -e + +# Cycles Development Environment Setup Script +# This script installs all necessary dependencies for building Cycles + +echo "=========================================" +echo "Cycles Development Environment Setup" +echo "=========================================" +echo "" + +# Detect OS +if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$ID + VER=$VERSION_ID +else + echo "Cannot detect OS. Please install dependencies manually." + exit 1 +fi + +echo "Detected OS: $OS $VER" +echo "" + +# Function to install dependencies on Ubuntu/Debian +install_ubuntu_deps() { + echo "Installing system dependencies for Ubuntu/Debian..." + sudo apt-get update + sudo apt-get install -y \ + libgl1-mesa-dev \ + libxcursor-dev \ + libxrandr-dev \ + libxinerama-dev \ + libxi-dev \ + libglfw3-dev \ + libxxf86vm-dev \ + pkg-config \ + gcc \ + g++ \ + make + echo "✓ System dependencies installed" +} + +# Function to install dependencies on Fedora/RHEL +install_fedora_deps() { + echo "Installing system dependencies for Fedora/RHEL..." + sudo dnf install -y \ + mesa-libGL-devel \ + libXcursor-devel \ + libXrandr-devel \ + libXinerama-devel \ + libXi-devel \ + glfw-devel \ + libXxf86vm-devel \ + pkg-config \ + gcc \ + gcc-c++ \ + make + echo "✓ System dependencies installed" +} + +# Function to install dependencies on Arch Linux +install_arch_deps() { + echo "Installing system dependencies for Arch Linux..." + sudo pacman -S --needed --noconfirm \ + mesa \ + libxcursor \ + libxrandr \ + libxinerama \ + libxi \ + glfw-x11 \ + pkg-config \ + gcc \ + make + echo "✓ System dependencies installed" +} + +# Install system dependencies based on OS +case "$OS" in + ubuntu|debian|pop|linuxmint|zorin|elementary|neon) + install_ubuntu_deps + ;; + fedora|rhel|centos|rocky|almalinux) + install_fedora_deps + ;; + arch|manjaro|endeavouros) + install_arch_deps + ;; + *) + # Check if it's a derivative of Ubuntu/Debian by checking for apt-get + if command -v apt-get &> /dev/null; then + echo "Detected Debian/Ubuntu-based system (using apt-get)" + install_ubuntu_deps + elif command -v dnf &> /dev/null; then + echo "Detected Red Hat-based system (using dnf)" + install_fedora_deps + elif command -v pacman &> /dev/null; then + echo "Detected Arch-based system (using pacman)" + install_arch_deps + else + echo "Unsupported OS: $OS" + echo "Please install dependencies manually:" + echo " - OpenGL development libraries" + echo " - X11 development libraries (Xcursor, Xrandr, Xinerama, Xi)" + echo " - GLFW development libraries" + echo " - pkg-config, gcc, make" + exit 1 + fi + ;; +esac + +echo "" + +# Check if Go is installed +if ! command -v go &> /dev/null; then + echo "Go is not installed!" + echo "Please install Go from https://golang.org/dl/" + echo "" + echo "Recommended installation:" + echo " wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz" + echo " sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz" + echo " export PATH=\$PATH:/usr/local/go/bin" + echo "" + exit 1 +fi + +GO_VERSION=$(go version | awk '{print $3}') +echo "✓ Go installed: $GO_VERSION" + +# Install Go dependencies +echo "" +echo "Installing Go dependencies..." +go mod download +go mod tidy +echo "✓ Go dependencies installed" + +# Verify build +echo "" +echo "Verifying build setup..." +if go build -o /tmp/cycles-test .; then + echo "✓ Build verification successful" + rm -f /tmp/cycles-test +else + echo "✗ Build verification failed" + exit 1 +fi + +echo "" +echo "=========================================" +echo "Setup Complete!" +echo "=========================================" +echo "" +echo "You can now:" +echo " make build - Build the application" +echo " make run - Build and run" +echo " make test - Run tests" +echo " make clean - Clean build artifacts" +echo "" +echo "For more information, see DEVELOPER_GUIDE.md" diff --git a/settings.go b/settings.go new file mode 100644 index 0000000..d05696b --- /dev/null +++ b/settings.go @@ -0,0 +1,104 @@ +package main + +import ( + "time" + + "fyne.io/fyne/v2" +) + +// Settings represents user preferences for the application +type Settings struct { + app fyne.App + + // Display settings + Theme string // "auto", "light", "dark" + GridColumns int + HistorySize int + LogicalCores bool + + // Update settings + UpdateInterval time.Duration +} + +// NewSettings creates a new Settings instance with the Fyne app +func NewSettings(app fyne.App) *Settings { + s := &Settings{ + app: app, + } + s.Load() + return s +} + +// Load loads settings from Fyne preferences +func (s *Settings) Load() { + prefs := s.app.Preferences() + + // Load theme setting (default: "auto") + s.Theme = prefs.StringWithFallback("theme", "auto") + + // Load grid columns (default: 8) + s.GridColumns = prefs.IntWithFallback("grid_columns", 8) + + // Load history size (default: 30) + s.HistorySize = prefs.IntWithFallback("history_size", 30) + + // Load logical cores setting (default: true) + s.LogicalCores = prefs.BoolWithFallback("logical_cores", true) + + // Load update interval in seconds (default: 2) + intervalSecs := prefs.IntWithFallback("update_interval_secs", 2) + s.UpdateInterval = time.Duration(intervalSecs) * time.Second +} + +// Save saves settings to Fyne preferences +func (s *Settings) Save() { + prefs := s.app.Preferences() + + prefs.SetString("theme", s.Theme) + prefs.SetInt("grid_columns", s.GridColumns) + prefs.SetInt("history_size", s.HistorySize) + prefs.SetBool("logical_cores", s.LogicalCores) + + // Store update interval as seconds + intervalSecs := int(s.UpdateInterval.Seconds()) + prefs.SetInt("update_interval_secs", intervalSecs) +} + +// Reset resets all settings to default values +func (s *Settings) Reset() { + s.Theme = "auto" + s.GridColumns = 8 + s.HistorySize = 30 + s.LogicalCores = true + s.UpdateInterval = 2 * time.Second + s.Save() +} + +// ApplyToConfig applies settings to an AppConfig +func (s *Settings) ApplyToConfig(config *AppConfig) { + config.GridColumns = s.GridColumns + config.HistorySize = s.HistorySize + config.LogicalCores = s.LogicalCores + config.UpdateInterval = s.UpdateInterval +} + +// LoadFromConfig loads settings from an AppConfig +// This is used to populate settings from command-line flags +func (s *Settings) LoadFromConfig(config *AppConfig) { + s.GridColumns = config.GridColumns + s.HistorySize = config.HistorySize + s.LogicalCores = config.LogicalCores + s.UpdateInterval = config.UpdateInterval +} + +// GetThemeVariant returns the Fyne theme variant based on settings +func (s *Settings) GetThemeVariant() fyne.ThemeVariant { + switch s.Theme { + case "light": + return fyne.VariantLight + case "dark": + return fyne.VariantDark + default: // "auto" + return fyne.VariantDark // Default to dark, can be enhanced to detect system theme + } +} diff --git a/settings_test.go b/settings_test.go new file mode 100644 index 0000000..71d749e --- /dev/null +++ b/settings_test.go @@ -0,0 +1,114 @@ +package main + +import ( + "testing" + "time" +) + +func TestSettingsDefaults(t *testing.T) { + // Create a test settings instance + // Note: In a real test, we'd mock the fyne.App + // For now, we're testing the Reset functionality + + tests := []struct { + name string + field string + expected interface{} + }{ + {"Default Theme", "Theme", "auto"}, + {"Default Grid Columns", "GridColumns", 8}, + {"Default History Size", "HistorySize", 30}, + {"Default Logical Cores", "LogicalCores", true}, + {"Default Update Interval", "UpdateInterval", 2 * time.Second}, + } + + // We can't easily test with a real Settings object without mocking fyne.App + // but we can test the logic + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // This test validates our expected defaults + // Actual testing would require fyne.App mock + }) + } +} + +func TestGetThemeVariant(t *testing.T) { + tests := []struct { + theme string + expected string // "light" or "dark" + }{ + {"light", "light"}, + {"dark", "dark"}, + {"auto", "dark"}, // Auto defaults to dark + {"", "dark"}, // Empty defaults to dark + } + + for _, tt := range tests { + t.Run(tt.theme, func(t *testing.T) { + // Create a settings object with the theme + s := &Settings{ + Theme: tt.theme, + } + + variant := s.GetThemeVariant() + + // Check if variant matches expected + if tt.expected == "light" && variant != 0 { + t.Errorf("Expected light theme variant for %s", tt.theme) + } + if tt.expected == "dark" && variant != 1 { + t.Errorf("Expected dark theme variant for %s", tt.theme) + } + }) + } +} + +func TestApplyToConfig(t *testing.T) { + s := &Settings{ + GridColumns: 12, + HistorySize: 50, + LogicalCores: false, + UpdateInterval: 3 * time.Second, + } + + config := DefaultConfig() + s.ApplyToConfig(config) + + if config.GridColumns != 12 { + t.Errorf("Expected GridColumns=12, got %d", config.GridColumns) + } + if config.HistorySize != 50 { + t.Errorf("Expected HistorySize=50, got %d", config.HistorySize) + } + if config.LogicalCores != false { + t.Errorf("Expected LogicalCores=false, got %v", config.LogicalCores) + } + if config.UpdateInterval != 3*time.Second { + t.Errorf("Expected UpdateInterval=3s, got %v", config.UpdateInterval) + } +} + +func TestLoadFromConfig(t *testing.T) { + config := &AppConfig{ + GridColumns: 16, + HistorySize: 100, + LogicalCores: true, + UpdateInterval: 5 * time.Second, + } + + s := &Settings{} + s.LoadFromConfig(config) + + if s.GridColumns != 16 { + t.Errorf("Expected GridColumns=16, got %d", s.GridColumns) + } + if s.HistorySize != 100 { + t.Errorf("Expected HistorySize=100, got %d", s.HistorySize) + } + if s.LogicalCores != true { + t.Errorf("Expected LogicalCores=true, got %v", s.LogicalCores) + } + if s.UpdateInterval != 5*time.Second { + t.Errorf("Expected UpdateInterval=5s, got %v", s.UpdateInterval) + } +} diff --git a/settingsui.go b/settingsui.go new file mode 100644 index 0000000..6dec349 --- /dev/null +++ b/settingsui.go @@ -0,0 +1,164 @@ +package main + +import ( + "fmt" + "strconv" + "time" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/widget" +) + +// ShowSettingsDialog displays the settings configuration dialog +func ShowSettingsDialog(settings *Settings, window fyne.Window, onSave func()) { + // Theme selection + themeSelect := widget.NewSelect([]string{"Auto", "Light", "Dark"}, func(value string) { + // Callback handled on save + }) + // Set current theme + switch settings.Theme { + case "light": + themeSelect.SetSelected("Light") + case "dark": + themeSelect.SetSelected("Dark") + default: + themeSelect.SetSelected("Auto") + } + + // Grid columns slider + columnsLabel := widget.NewLabel(fmt.Sprintf("Grid Columns: %d", settings.GridColumns)) + columnsSlider := widget.NewSlider(1, 16) + columnsSlider.SetValue(float64(settings.GridColumns)) + columnsSlider.OnChanged = func(value float64) { + columnsLabel.SetText(fmt.Sprintf("Grid Columns: %d", int(value))) + } + + // History size slider + historyLabel := widget.NewLabel(fmt.Sprintf("History Size: %d", settings.HistorySize)) + historySlider := widget.NewSlider(10, 100) + historySlider.SetValue(float64(settings.HistorySize)) + historySlider.OnChanged = func(value float64) { + historyLabel.SetText(fmt.Sprintf("History Size: %d", int(value))) + } + + // Update interval entry + intervalEntry := widget.NewEntry() + intervalEntry.SetText(fmt.Sprintf("%.0f", settings.UpdateInterval.Seconds())) + intervalEntry.SetPlaceHolder("Update interval in seconds") + + // Logical cores checkbox + logicalCoresCheck := widget.NewCheck("Show Logical Cores", nil) + logicalCoresCheck.SetChecked(settings.LogicalCores) + + // Create form + form := &widget.Form{ + Items: []*widget.FormItem{ + {Text: "Theme", Widget: themeSelect}, + {Text: "", Widget: columnsLabel}, + {Text: "", Widget: columnsSlider}, + {Text: "", Widget: historyLabel}, + {Text: "", Widget: historySlider}, + {Text: "Update Interval (seconds)", Widget: intervalEntry}, + {Text: "CPU Cores", Widget: logicalCoresCheck}, + }, + } + + // Reset button + resetButton := widget.NewButton("Reset to Defaults", func() { + confirm := dialog.NewConfirm("Reset Settings", + "Are you sure you want to reset all settings to default values?", + func(confirmed bool) { + if confirmed { + settings.Reset() + // Reload UI with default values + themeSelect.SetSelected("Auto") + columnsSlider.SetValue(8) + columnsLabel.SetText("Grid Columns: 8") + historySlider.SetValue(30) + historyLabel.SetText("History Size: 30") + intervalEntry.SetText("2") + logicalCoresCheck.SetChecked(true) + + if onSave != nil { + onSave() + } + } + }, window) + confirm.Show() + }) + + // Create dialog content with form and reset button + content := container.NewBorder( + nil, + container.NewHBox(resetButton), + nil, + nil, + form, + ) + + // Create dialog + settingsDialog := dialog.NewCustomConfirm("Settings", "Save", "Cancel", content, + func(save bool) { + if save { + // Apply settings from UI + switch themeSelect.Selected { + case "Light": + settings.Theme = "light" + case "Dark": + settings.Theme = "dark" + default: + settings.Theme = "auto" + } + + settings.GridColumns = int(columnsSlider.Value) + settings.HistorySize = int(historySlider.Value) + settings.LogicalCores = logicalCoresCheck.Checked + + // Parse update interval + if intervalSecs, err := strconv.ParseFloat(intervalEntry.Text, 64); err == nil && intervalSecs > 0 { + settings.UpdateInterval = time.Duration(intervalSecs) * time.Second + } + + // Save settings + settings.Save() + + // Apply theme immediately + fyne.CurrentApp().Settings().SetTheme(&CustomTheme{variant: settings.GetThemeVariant()}) + + // Show restart notification + dialog.ShowInformation("Settings Saved", + "Some settings (like Grid Columns and CPU Cores) will take effect after restarting the application.", + window) + + if onSave != nil { + onSave() + } + } + }, window) + + settingsDialog.Resize(fyne.NewSize(400, 500)) + settingsDialog.Show() +} + +// CustomTheme is a theme that wraps the default theme with custom variant +type CustomTheme struct { + variant fyne.ThemeVariant +} + +func (t *CustomTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) fyne.Color { + return fyne.CurrentApp().Settings().Theme().Color(name, t.variant) +} + +func (t *CustomTheme) Font(style fyne.TextStyle) fyne.Resource { + return fyne.CurrentApp().Settings().Theme().Font(style) +} + +func (t *CustomTheme) Icon(name fyne.ThemeIconName) fyne.Resource { + return fyne.CurrentApp().Settings().Theme().Icon(name) +} + +func (t *CustomTheme) Size(name fyne.ThemeSizeName) float32 { + return fyne.CurrentApp().Settings().Theme().Size(name) +} diff --git a/sysinfo.go b/sysinfo.go index 2cfebf8..1f73516 100644 --- a/sysinfo.go +++ b/sysinfo.go @@ -118,3 +118,90 @@ func UpdateCPUInfo(tiles []*CoreTile) { DrawGraph(tile.GraphImg, tile.UtilHistory) } } + +// GetMemoryInfoDetailed returns detailed memory information including cached memory +func GetMemoryInfoDetailed() (MemoryInfo, uint64, error) { + file, err := os.Open("/proc/meminfo") + if err != nil { + return MemoryInfo{}, 0, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var total, free, available, cached, buffers uint64 + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "MemTotal:") { + parts := strings.Fields(line) + if len(parts) == 3 { + total, _ = strconv.ParseUint(parts[1], 10, 64) + } + } else if strings.HasPrefix(line, "MemFree:") { + parts := strings.Fields(line) + if len(parts) == 3 { + free, _ = strconv.ParseUint(parts[1], 10, 64) + } + } else if strings.HasPrefix(line, "MemAvailable:") { + parts := strings.Fields(line) + if len(parts) == 3 { + available, _ = strconv.ParseUint(parts[1], 10, 64) + } + } else if strings.HasPrefix(line, "Cached:") { + parts := strings.Fields(line) + if len(parts) == 3 { + cached, _ = strconv.ParseUint(parts[1], 10, 64) + } + } else if strings.HasPrefix(line, "Buffers:") { + parts := strings.Fields(line) + if len(parts) == 3 { + buffers, _ = strconv.ParseUint(parts[1], 10, 64) + } + } + } + + if err := scanner.Err(); err != nil { + return MemoryInfo{}, 0, err + } + + // Calculate used memory (total - available gives a more accurate "used" value) + used := total - available + + return MemoryInfo{ + Total: total, + Used: used, + Free: free, + }, cached + buffers, nil +} + +// UpdateMemoryInfo updates the memory information for memory tiles +func UpdateMemoryInfo(tiles []*MemoryTile, historySize int) { + memInfo, cached, err := GetMemoryInfoDetailed() + if err != nil { + log.Printf("Error getting memory info: %v", err) + return + } + + for _, tile := range tiles { + // Calculate usage percentage + usagePercent := 0.0 + if memInfo.Total > 0 { + usagePercent = float64(memInfo.Used) / float64(memInfo.Total) * 100.0 + } + + // Update labels + tile.TotalLabel.SetText("Total: " + formatMemorySize(memInfo.Total)) + tile.UsedLabel.SetText("Used: " + formatMemorySize(memInfo.Used)) + tile.FreeLabel.SetText("Free: " + formatMemorySize(memInfo.Free)) + tile.CachedLabel.SetText("Cached: " + formatMemorySize(cached)) + tile.PercentLabel.SetText("Usage: " + formatMemoryPercent(usagePercent)) + + // Update usage history + tile.UsageHistory = append(tile.UsageHistory, usagePercent) + if len(tile.UsageHistory) > historySize { + tile.UsageHistory = tile.UsageHistory[1:] + } + + // Draw graph + DrawGraph(tile.GraphImg, tile.UsageHistory) + } +} diff --git a/theme.go b/theme.go index 5482b68..4413de6 100644 --- a/theme.go +++ b/theme.go @@ -18,15 +18,20 @@ var ( RedDark = color.RGBA{R: 252, G: 0, B: 13, A: 255} // Dark theme red ) -// GetGraphLineColor returns the appropriate color based on utilization status and theme -func GetGraphLineColor(status string) color.RGBA { +// isDarkTheme checks if the current theme variant is dark +func isDarkTheme() bool { currentTheme := fyne.CurrentApp().Settings().Theme() - isDark := true - // Check if the current theme is light if currentTheme == theme.LightTheme() { - isDark = false + return false } + // Default to dark for most themes + return true +} + +// GetGraphLineColor returns the appropriate color based on utilization status and theme +func GetGraphLineColor(status string) color.RGBA { + isDark := isDarkTheme() switch status { case "green": @@ -52,3 +57,8 @@ func GetGraphLineColor(status string) color.RGBA { } return GreenLight } + +// ApplyTheme applies the specified theme variant to the application +func ApplyTheme(app fyne.App, themeVariant fyne.ThemeVariant) { + app.Settings().SetTheme(&CustomTheme{variant: themeVariant}) +}