A little proc macro to make it easier to model data as items that can be used in the UI
(would definitely make it conditional on a flag)
I think this is a nice convenient macro that encourages a good separation of regular application data and data that is to be displayed in a UI but I'm on the fence about including this.
Example of how this would be used:
#[derive(Clone, floem::State)]
#[state_derives(Clone, Copy, Eq, Debug)]
/// There is a `Todo` struct that doesn't have any signals or anything to do with the UI and could be built and used separately from the UI.
pub struct Todo {
pub db_id: Option<i64>,
#[state_skip]
pub unique_id: u64,
pub done: bool,
pub description: String,
}
static UNIQUE_COUNTER: AtomicU64 = AtomicU64::new(0);
impl Todo {
pub fn new_from_db(db_id: i64, done: bool, description: impl Into<String>) -> Self {
Self {
db_id: Some(db_id),
unique_id: UNIQUE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
done,
description: description.into(),
}
}
pub fn new(done: bool, description: impl Into<String>) -> Self {
Self {
db_id: None,
unique_id: UNIQUE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
done,
description: description.into(),
}
}
}
/// The `TodoState` struct is generated and can be created by doing `todo.to_state()` and simply wraps the fields of `Todo` in signals and makes it easy to impl `IntoView`.
///
/// This really isn't incredibly useful but it is nice, encourages a good separation, and removes a tedious task of manually creating signals.
impl IntoView for TodoState {
type V = AnyView;
fn into_view(self) -> Self::V {
// At this point the `db_id`, `done`, and `description` are signals
// and are ready to be used for values that change over time in the UI.
debounce_action(self.done, 300.millis(), move || {
AppCommand::UpdateDone(self).execute()
});
debounce_action(self.description, 300.millis(), move || {
AppCommand::UpdateDescription(self).execute()
});
let state = todo_state();
let is_selected = create_memo(move |_| state.selected.with(|s| s.contains(&self)));
let is_active =
create_memo(move |_| state.active.with(|s| s.active.map_or(false, |v| v == self)));
let input_focused = Trigger::new();
let done_check = Checkbox::new_rw(self.done)
.style(|s| {
...
});
let input = todo_input(self).into_view();
let input_id = input.id();
let input = input
.disable_default_event(move || (EventListener::PointerDown, !is_active))
.style(move |s| {
...
});
let main_controls = (done_check, input)
.h_stack()
.debug_name("Todo Checkbox and text input (main controls)")
.style(|s| s.gap(10).width_full().items_center())
.container()
.style(|s| s.width_full().align_items(Some(AlignItems::FlexStart)));
let container = main_controls.container();
container
.style(move |s| {
...
})
.into_any()
}
}
A little proc macro to make it easier to model data as items that can be used in the UI
(would definitely make it conditional on a flag)
I think this is a nice convenient macro that encourages a good separation of regular application data and data that is to be displayed in a UI but I'm on the fence about including this.
Example of how this would be used: