First App
Build a complete counter application step by step.
Project Structure
counter-app/
├── Cargo.toml
├── src/
│ └── main.rs
└── tests/
└── counter_test.rs
Dependencies
[package]
name = "counter-app"
version = "0.1.0"
edition = "2021"
[dependencies]
presentar = "0.1"
[dev-dependencies]
presentar-test = "0.1"
The Counter Widget
use presentar::widgets::{Button, Column, Text};
use presentar::widgets::row::MainAxisAlignment;
use presentar::{Color, Constraints, Rect, Size, Widget, RecordingCanvas};
fn main() {
// Build the UI
let mut ui = Column::new()
.main_axis_alignment(MainAxisAlignment::Center)
.gap(16.0)
.child(Text::new("Counter: 0").font_size(24.0))
.child(Button::new("+1").with_test_id("increment"))
.child(Button::new("-1").with_test_id("decrement"));
// Measure
let constraints = Constraints::loose(Size::new(400.0, 300.0));
let size = ui.measure(constraints);
// Layout
ui.layout(Rect::new(0.0, 0.0, size.width, size.height));
// Paint
let mut canvas = RecordingCanvas::new();
ui.paint(&mut canvas);
println!("Drew {} commands", canvas.command_count());
}
Testing
#[test]
fn test_counter_ui() {
use presentar_test::Harness;
use presentar::widgets::{Button, Column, Text};
let ui = Column::new()
.child(Text::new("Counter: 0").with_test_id("count"))
.child(Button::new("+1").with_test_id("increment"));
let harness = Harness::new(ui);
harness
.assert_exists("[data-testid='count']")
.assert_exists("[data-testid='increment']");
}
Running
cargo run
cargo test
Next Steps
- Add state management for actual counting
- Style the buttons
- Add keyboard shortcuts
Verified Test
#[test]
fn test_first_app_builds() {
use presentar_widgets::{Button, Column, Text};
use presentar_core::{Constraints, Size, Widget};
let ui = Column::new()
.child(Text::new("Test"))
.child(Button::new("Click"));
let size = ui.measure(Constraints::loose(Size::new(400.0, 300.0)));
assert!(size.width > 0.0);
assert!(size.height > 0.0);
}