MovieMapper/Rust/RustUIPlan.md
Jarian Cottingham 68eb4d9f43 feat: Add Rust UI and backend implementation with project infrastructure
Adds the new Rust-based UI (iced), backend service, shared Swift models,
CI/CD workflows, build scripts, and project documentation.
2026-08-19 21:22:08 -05:00

536 lines
15 KiB
Markdown

# Rust UI Implementation Plan for MovieMapper
## Executive Summary
This plan outlines the architecture and implementation strategy for replacing the current Electron-based UI with a native Rust UI using a performant GUI framework. The plan maintains full compatibility with the existing Rust backend while providing a modern, responsive desktop application.
## Architecture Overview
### Current Architecture
```
Electron App (Renderer + Main)
├── index.html (UI)
├── renderer.js (UI logic)
└── main.js (IPC handlers → Rust backend)
```
### New Architecture
```
Native Desktop App
├── Rust UI Layer (iced/winit)
├── Rust Backend (existing)
└── IPC Bridge (optional: direct function calls)
```
## GUI Framework Selection
### Options Considered
#### 1. **Iced** (RECOMMENDED) ⭐
**Pros:**
- Modern, React-inspired API with Elm architecture
- Excellent performance (native rendering)
- Cross-platform (Windows, macOS, Linux)
- Active community and good documentation
- Async/await support built-in
- Small binary size (~5MB runtime)
- No WebKit dependencies
**Cons:**
- Less mature than some alternatives
- Smaller ecosystem
**Why Chosen:**
- Perfect for data-heavy applications like MovieMapper
- Similar state management to Electron/React
- Excellent performance characteristics
- Modern Rust ecosystem alignment
#### 2. **Dioxus**
**Pros:**
- React-inspired syntax (RSX)
- Web, desktop, and mobile support
- Strong community
**Cons:**
- Heavier runtime (~50MB+)
- Less mature for desktop apps
- More complex build process
#### 3. **Tauri** (Alternative)
**Pros:**
- Use existing HTML/CSS/JS
- Small binary size
- Native performance
**Cons:**
- Would keep web stack (defeats purpose)
- Additional WebView overhead
- Less "pure Rust" approach
#### 4. **Slint**
**Pros:**
- Declarative UI design
- Good performance
**Cons:**
- Learning curve for DSL
- Smaller community
- Less Rust-idiomatic
### Final Choice: **Iced**
## Project Structure
```
MovieMapper/
├── Cargo.toml # Workspace configuration
├── Cargo.lock
├── rust/
│ ├── Cargo.toml # Backend crate
│ ├── src/
│ │ ├── lib.rs
│ │ ├── main.rs
│ │ ├── error.rs
│ │ ├── types.rs
│ │ ├── scanner.rs
│ │ ├── ffmpeg.rs
│ │ ├── tvdb.rs
│ │ ├── file_manager.rs
│ │ └── mapper.rs
│ └── tests/
├── ui/ # NEW: Rust UI implementation
│ ├── Cargo.toml # UI crate configuration
│ ├── src/
│ │ ├── main.rs # Application entry point
│ │ ├── app.rs # Main app structure
│ │ ├── theme.rs # Styling and theming
│ │ ├── components/ # Reusable UI components
│ │ │ ├── mod.rs
│ │ │ ├── breadcrumb.rs # Navigation breadcrumbs
│ │ │ ├── file_list.rs # File listing component
│ │ │ ├── sidebar.rs # Search and show details
│ │ │ ├── progress.rs # Progress indicator
│ │ │ ├── tag_manager.rs # Tagging UI
│ │ │ ├── episode_editor.rs # Episode range editing
│ │ │ └── floating_action.rs # FAB component
│ │ ├── state.rs # Application state management
│ │ ├── messages.rs # UI messages/events
│ │ ├── backend.rs # Backend integration
│ │ ├── windows/
│ │ │ ├── mod.rs
│ │ │ ├── main.rs # Main window
│ │ │ └── video_preview.rs # Video preview modal
│ │ └── utils/
│ │ ├── mod.rs
│ │ ├── path.rs # Path utilities
│ │ ├── format.rs # Formatting helpers
│ │ └── ffmpeg.rs # FFmpeg helpers
│ └── assets/
│ ├── icons/
│ └── styles/
├── backend/ # Backend integration layer
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # Re-exports from rust/
│ └── bridge.rs # IPC/FFI bridge if needed
├── main.rs # Workspace entry point
├── index.html # Keep for reference/compatibility
├── renderer.js # Keep for reference
├── main.js # Keep for reference
└── package.json # Updated workspace config
```
## Implementation Phases
### Phase 1: Foundation (Week 1)
#### 1.1 Setup Rust UI Project
- [ ] Create `ui/` directory with `Cargo.toml`
- [ ] Configure workspace in root `Cargo.toml`
- [ ] Add `iced = "0.12"` dependency to `ui/Cargo.toml`
- [ ] Set up basic project structure
- [ ] Configure build for cross-platform
- [ ] Set up asset management (icons, styles)
#### 1.2 Backend Integration
- [ ] Create `backend/` crate for Rust backend access
- [ ] Implement direct function calls (no IPC overhead)
- [ ] Handle async operations with `tokio`
- [ ] Implement error propagation
- [ ] Create backend state management
#### 1.3 Core Application Structure
- [ ] Implement `iced::Application` trait
- [ ] Set up main window with `Settings`
- [ ] Implement state management with `Clone` + `Default`
- [ ] Create message enum for all UI events
- [ ] Set up logging with `tracing`
### Phase 2: UI Components (Week 2)
#### 2.1 Basic Layout
- [ ] Implement main layout (sidebar + content)
- [ ] Create breadcrumb navigation component
- [ ] Implement directory selector button
- [ ] Add progress indicator component
- [ ] Create file list container
#### 2.2 File List Component
- [ ] Implement file item rendering
- [ ] Add drag-and-drop support (using `iced_native::event::drag`)
- [ ] Create folder vs file visual distinction
- [ ] Implement file metadata display (duration, quality, FPS)
- [ ] Add episode number display with arrows
#### 2.3 Sidebar Components
- [ ] Search input with debouncing
- [ ] Search results dropdown
- [ ] Show details panel
- [ ] Season selector with episode list
- [ ] Episode hover highlighting
### Phase 3: Feature Implementation (Week 3)
#### 3.1 File Operations
- [ ] Implement directory scanning UI
- [ ] Add progress updates during scan
- [ ] Create file rename functionality
- [ ] Implement file tagging system
- [ ] Add play button for individual files
- [ ] Implement FAB for moving all tagged files
#### 3.2 Episode Mapping
- [ ] Create episode range editor component
- [ ] Implement arrow buttons for range adjustment
- [ ] Add visual feedback for episode matching
- [ ] Create "Begin Mapping" button and flow
- [ ] Implement mapping progress display
#### 3.3 Show/Season/Episode Selection
- [ ] Implement TVDB search
- [ ] Display search results
- [ ] Show details panel
- [ ] Season selector with episode counts
- [ ] Episode list with episode number matching
### Phase 4: Advanced Features (Week 4)
#### 4.1 Video Preview Modal
- [ ] Create modal window component
- [ ] Integrate with system video player
- [ ] Display file metadata
- [ ] Add close button and styling
#### 4.2 Breadcrumb Navigation
- [ ] Implement navigation stack
- [ ] Add back button functionality
- [ ] Display directory path history
- [ ] Handle folder navigation
#### 4.3 Audit Logging
- [ ] Implement audit event logging
- [ ] Display audit log in UI (optional)
- [ ] Export audit logs (optional)
#### 4.4 Performance Optimizations
- [ ] Virtual scrolling for large file lists
- [ ] Lazy loading for episode data
- [ ] Caching for TVDB results
- [ ] Background processing for large operations
- [ ] Memory usage monitoring
### Phase 5: Polish & Testing (Week 5)
#### 5.1 Theming
- [ ] Implement dark theme (match current design)
- [ ] Create reusable component styles
- [ ] Add hover states
- [ ] Implement focus states
- [ ] Support system theme detection (optional)
#### 5.2 Testing
- [ ] Unit tests for UI components
- [ ] Integration tests for workflows
- [ ] E2E tests with `iced_test` or similar
- [ ] Manual testing on all platforms
- [ ] Performance testing
#### 5.3 Documentation
- [ ] User documentation
- [ ] API documentation
- [ ] Architecture documentation
- [ ] Contribution guidelines
## Component Architecture
### State Management
```rust
#[derive(Debug, Clone, Default)]
pub struct AppState {
// Directory state
current_directory: Option<PathBuf>,
navigation_stack: Vec<PathBuf>,
// File state
files: Vec<FileMetadata>,
tagged_files: HashMap<PathBuf, TagType>,
// TVDB state
search_query: String,
search_results: Vec<Show>,
selected_show: Option<Show>,
selected_season: Option<Season>,
episodes: Vec<Episode>,
// Mapping state
is_mapping: bool,
mapping_progress: u32,
// UI state
progress_visible: bool,
progress_message: String,
}
```
### Messages (Events)
```rust
#[derive(Debug, Clone)]
pub enum Message {
// Navigation
SelectDirectory,
OpenDirectory(PathBuf),
NavigateBack,
// File operations
ScanDirectory(PathBuf),
FileScanned(FileMetadata),
ScanComplete(Vec<FileMetadata>),
// Tagging
TagFile(PathBuf, TagType),
UntagFile(PathBuf, TagType),
MoveTaggedFile(PathBuf, TagType),
MoveAllTaggedFiles,
// Episode editing
UpdateEpisodeRange(usize, u32, u32),
ShiftEpisodes(usize, i32),
// TVDB
SearchShows(String),
ShowsLoaded(Vec<Show>),
ShowSelected(Show),
SeasonsLoaded(Vec<Season>),
SeasonSelected(Season),
EpisodesLoaded(Vec<Episode>),
// Mapping
BeginMapping,
MappingComplete(Result<MappingResult, String>),
// UI updates
ProgressUpdate(u32, u32, String),
ShowProgress,
HideProgress,
// System
OpenVideoPreview(PathBuf),
OpenFileInPlayer(PathBuf),
LogAuditEvent(AuditEvent),
}
```
### Component Structure
```rust
// ui/src/components/file_list.rs
pub struct FileList {
files: Vec<FileMetadata>,
tagged_files: HashMap<PathBuf, TagType>,
on_file_click: Callback<PathBuf>,
on_tag: Callback<(PathBuf, TagType)>,
on_play: Callback<PathBuf>,
}
impl Component for FileList {
type Message = Message;
fn view(&self) -> Element<Message> {
// Render file list with tags, play buttons, etc.
}
}
// ui/src/components/sidebar.rs
pub struct Sidebar {
search_query: String,
search_results: Vec<Show>,
selected_show: Option<Show>,
on_search: Callback<String>,
on_show_select: Callback<Show>,
}
impl Component for Sidebar {
type Message = Message;
fn view(&self) -> Element<Message> {
// Render search and show details
}
}
```
## Backend Integration Strategy
### Direct Function Calls (Preferred)
Instead of IPC, use direct Rust function calls:
```rust
// ui/src/backend.rs
use movie_mapper_rust::{scan_directory, rename_file, move_to_folder};
pub async fn scan_directory_ui(path: &str) -> Result<Vec<FileMetadata>, String> {
scan_directory(path, Some(|current, total, filename| {
// Send progress updates to UI
Message::ProgressUpdate(current, total, filename.to_string())
})).await.map_err(|e| e.to_string())
}
```
### Benefits:
- Zero IPC overhead
- Type safety
- Better error handling
- Simpler code
- Easier debugging
### When IPC Might Be Needed:
- Long-running operations that could block UI
- When backend is in separate process for isolation
- For plugin architecture
## Performance Targets
- **Startup time**: < 1 second
- **Directory scan (100 files)**: < 500ms
- **File rendering**: Smooth 60fps
- **Memory usage**: < 100MB for typical workflow
- **Binary size**: < 15MB (with all dependencies)
## Cross-Platform Considerations
### macOS
- Native look and feel
- Touch Bar support (optional)
- Spotlight integration (optional)
### Windows
- Taskbar integration
- File association (optional)
- Aero effects
### Linux
- AppImage support
- Desktop file integration
- Theme compatibility
## Deployment
### Build Commands
```bash
# Development
cargo build --package ui --features debug
# Release
cargo build --package ui --release
# Cross-platform
cargo build --package ui --release --target x86_64-apple-darwin
cargo build --package ui --release --target x86_64-pc-windows-msvc
cargo build --package ui --release --target x86_64-unknown-linux-gnu
```
### Distribution
**Option 1: Standalone Binary**
- Single executable for each platform
- No runtime installation required
- Include FFmpeg binaries if needed
**Option 2: Installer**
- Platform-specific installers
- Automatic updates (using `taffy` or similar)
- Clean uninstall
**Option 3: Package Managers**
- macOS: Homebrew
- Windows: Scoop, MSI
- Linux: AppImage, Flatpak, Snap
## Risk Assessment
### Technical Risks
| Risk | Impact | Mitigation |
|------|--------|------------|
| Iced ecosystem maturity | Medium | Contribute back, use well-established features |
| Learning curve | Low | Team Rust expertise, documentation |
| Feature parity | Low | Phased implementation, testing |
### Schedule Risks
| Risk | Impact | Mitigation |
|------|--------|------------|
| Feature complexity | Medium | Break into small PRs, daily demos |
| Platform differences | Low | Test early on all platforms |
| Backend integration | Low | Direct calls, type safety |
## Success Criteria
- [ ] All existing features implemented
- [ ] Performance matches or exceeds Electron version
- [ ] UI looks native on all platforms
- [ ] No memory leaks (verified with `valgrind`/`ASAN`)
- [ ] All tests passing
- [ ] Documentation complete
- [ ] User testing successful
## Next Steps
1. **Approve plan** - Get stakeholder approval
2. **Setup repository** - Create `ui/` directory structure
3. **Build MVP** - Implement basic window with file list
4. **Weekly reviews** - Demo progress each week
5. **Iterate** - Add features incrementally
6. **Test** - Comprehensive testing on all platforms
7. **Release** - Beta release with user feedback
## Appendix: Alternative Approaches
### Hybrid Approach (Tauri + Rust UI)
If Tauri is preferred:
- Keep Tauri for window management
- Use Rust UI components (Dioxus or Slint)
- Keep some Electron features for compatibility
### Web UI with Rust Backend
If web stack is preferred:
- Keep HTML/CSS/JS for UI
- Use Rust backend via WASM
- Electron replaced with `tao`/`wry`
### Native Desktop with Different Framework
Other options:
- **egui**: Immediate mode GUI, very performant
- **slint**: Declarative, good for form-like apps
- **gtk-rs**: Mature, but heavier dependencies
## Conclusion
The recommended approach using **Iced** provides the best balance of performance, maintainability, and developer experience for a Rust-based MovieMapper UI. It maintains the performance benefits of the Rust backend while providing a modern, responsive user interface that feels native on all platforms.
This plan provides a clear roadmap for implementation while allowing flexibility for adjustments based on team feedback and technical discoveries during development.