| Crates.io | flashkraft |
| lib.rs | flashkraft |
| version | 0.3.2 |
| created_at | 2025-10-24 21:33:44.101345+00 |
| updated_at | 2025-10-30 18:09:45.258982+00 |
| description | An OS Imager app similar to Balena-Etcher written in Rust with the Iced UI Framework |
| homepage | |
| repository | https://github.com/sorinirimies/flashkraft |
| max_upload_size | |
| id | 1899285 |
| size | 3,054,353 |
A lightning fast, lightweight app size and memory footprint, no Electron bloat, OS Imager application built with Rust and the Iced GUI framework.
Working Rust examples demonstrating FlashKraft's architecture and patterns:
cargo run --example basic_usage # Full FlashKraft application
cargo run --example custom_theme # Theme system showcase
See examples/README.md for more details.
FlashKraft is built using The Elm Architecture (TEA), which Iced embraces as the natural approach for building interactive applications. This architecture provides a simple, scalable pattern for managing application state and side effects.
The Elm Architecture consists of four main components:
The Model represents the complete state of the application at any given moment:
struct FlashKraft {
selected_image: Option<ImageInfo>, // Currently selected image file
selected_target: Option<DriveInfo>, // Currently selected target drive
available_drives: Vec<DriveInfo>, // List of detected drives
flash_progress: Option<f32>, // Flash progress (0.0 to 1.0)
error_message: Option<String>, // Error message if any
}
The state is immutable and only changes through the update function. This makes the application predictable and easy to reason about.
Messages represent all possible events that can occur in the application:
enum Message {
// User interactions
SelectImageClicked,
RefreshDrivesClicked,
TargetDriveClicked(DriveInfo),
FlashClicked,
ResetClicked,
CancelClicked,
// Async results
ImageSelected(Option<PathBuf>),
DrivesRefreshed(Vec<DriveInfo>),
FlashProgress(f32),
FlashCompleted(Result<(), String>),
}
Messages are the only way to trigger state changes. They can come from:
The update function is the heart of the application. It's a pure function that:
Command for side effectsfn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::SelectImageClicked => {
// Trigger async file selection
Command::perform(select_image_file(), Message::ImageSelected)
}
Message::ImageSelected(maybe_path) => {
// Update state with selected image
self.selected_image = maybe_path.map(ImageInfo::from_path);
Command::none()
}
// ... handle other messages
}
}
This separation ensures:
The view function is a pure function that:
fn view(&self) -> Element<'_, Message> {
if let Some(progress) = self.flash_progress {
view_flashing(progress)
} else if let Some(error) = &self.error_message {
view_error(error)
} else {
view_main(self)
}
}
The view is declarative - you describe what the UI should look like based on state, not how to update it.
update, making it easy to log and debug┌─────────────────────────────────────────────────────────┐
│ │
│ User Interaction → Message → Update → State │
│ ↓ │
│ Command │
│ ↓ │
│ Async Result → Message → Update → State │
│ │
│ State → View → UI │
│ │
└─────────────────────────────────────────────────────────┘
# Clone the repository
git clone https://github.com/yourusername/flashkraft.git
cd flashkraft
# Build the project
cargo build --release
# Run the application
cargo run --release
# Run in debug mode (faster compilation, slower runtime)
cargo run
# Check code without building
cargo check
# Run with backtrace on errors
RUST_BACKTRACE=1 cargo run
flashkraft/
├── src/
│ ├── main.rs # Application entry point
│ ├── view.rs # View orchestration
│ ├── core/ # Core application logic (Elm Architecture)
│ │ ├── mod.rs
│ │ ├── state.rs # Application state (Model)
│ │ ├── message.rs # Message definitions
│ │ ├── update.rs # Update logic
│ │ ├── storage.rs # Persistent storage
│ │ ├── flash_subscription.rs # Flash operation monitoring
│ │ └── commands/ # Async commands (side effects)
│ │ ├── mod.rs
│ │ ├── file_selection.rs
│ │ └── drive_detection.rs
│ ├── domain/ # Domain models (business entities)
│ │ ├── mod.rs
│ │ ├── drive_info.rs
│ │ └── image_info.rs
│ ├── components/ # UI components
│ │ ├── mod.rs
│ │ ├── animated_progress.rs
│ │ ├── device_selector.rs
│ │ ├── header.rs
│ │ ├── progress_line.rs
│ │ ├── selection_panels.rs
│ │ ├── status_views.rs
│ │ ├── step_indicators.rs
│ │ └── theme_selector.rs
│ └── utils/ # Utility modules
│ ├── mod.rs
│ ├── icons_bootstrap_mapper.rs
│ └── logger.rs
├── .github/
│ └── workflows/
│ ├── ci.yml # Continuous Integration
│ └── release.yml # Release automation
├── Cargo.toml # Rust dependencies and project metadata
├── README.md # This file
└── LICENSE # MIT License
Contributions are welcome! Please feel free to submit a Pull Request. When contributing, please:
This project is licensed under the MIT License - see the LICENSE file for details.