1use component_gallery::Gallery;
4use family_finance::db::Database;
5use family_finance::seed;
6use family_finance::ui::App;
7use family_finance::update::Updater;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11use feature_center::seed::PASSWORD;
12use feature_center::{memory_database, watched};
13use ravenrs_app_ui::Session;
14use ravenrs_core::{AccessAction, Event, Key, Modifiers, Point, Role};
15use ravenrs_widgets::{AnyView, Date, Ui};
16
17use crate::{Ceiling, Class, PerfScene, Setup, Step, ceiling, hover_buttons, nothing, resize, scroll_at};
18
19const INTERACTIONS: &[&str] = &["hover", "scroll", "idle", "resize"];
20
21fn step(interaction: &str) -> Step {
22 match interaction {
23 "hover" => hover_buttons(),
24 "scroll" => scroll_at(Point::new(800.0, 400.0)),
25 "resize" => resize(),
26 _ => nothing(),
27 }
28}
29
30fn finance(page: usize, interaction: &str) -> Setup {
31 let Some(today) = Date::new(2026, 11, 15) else { panic!("a valid date") };
32 let Ok(database) = Database::in_memory() else { panic!("a database") };
33 if seed::load_demo(&database, today).is_err() {
34 panic!("the demo data");
35 }
36 let app = App::new(database, today, None, Updater::idle());
37 app.open_page(page);
38 Setup { root: Box::new(app), step: step(interaction) }
39}
40
41pub fn finance_tour() -> (AnyView, ravenrs_reactive::State<usize>) {
43 let Some(today) = Date::new(2026, 11, 15) else { panic!("a valid date") };
44 let Ok(database) = Database::in_memory() else { panic!("a database") };
45 if seed::load_demo(&database, today).is_err() {
46 panic!("the demo data");
47 }
48 let app = App::new(database, today, None, Updater::idle());
49 let page = app.page_state();
50 (Box::new(app), page)
51}
52
53pub fn feature_center() -> (AnyView, Rc<RefCell<Option<Session>>>) {
55 let Ok(database) = memory_database() else { panic!("a database") };
56 let session = Rc::new(RefCell::new(None));
57 let keep = session.clone();
58 let app = watched(move || database.space(), move |seen| *keep.borrow_mut() = Some(seen.clone()));
59 let Ok(root) = app.build() else { panic!("the app puts itself together") };
60 (Box::new(root), session)
61}
62
63fn act(ui: &mut Ui, role: Role, name: &str, action: AccessAction) {
64 ui.update();
65 let tree = ui.access_tree();
66 let found = tree
67 .nodes
68 .iter()
69 .find(|node| node.role == role && node.name.as_deref().is_some_and(|text| text.starts_with(name)));
70 let Some(id) = found.map(|node| node.id) else { panic!("nothing called {name} on screen") };
71 ui.perform_action(id, action);
72 ui.update();
73}
74
75pub fn sign_in(ui: &mut Ui) {
77 for (field, text) in [("Nome", "ana"), ("Senha", PASSWORD)] {
78 act(ui, Role::TextInput, field, AccessAction::Focus);
79 for character in text.chars() {
80 ui.handle_event(&Event::KeyDown {
81 key: Key::Character(character.to_string()),
82 modifiers: Modifiers::default(),
83 });
84 }
85 ui.update();
86 }
87 act(ui, Role::Button, "Entrar", AccessAction::Click);
88 ui.update();
89}
90
91pub const CENTER_LISTS: [&str; 8] = [
93 "ManyRows",
94 "EditorsDemo",
95 "ListEditorsDemo",
96 "VariantsDemo",
97 "StateDemo",
98 "RelationOwner",
99 "AnalyticsDashboard",
100 "SecurityAuditEntry",
101];
102
103fn center(list: Option<&'static str>, interaction: &str) -> Setup {
104 let (root, session) = feature_center();
105 let mut then = step(interaction);
106 let mut ready = false;
107 let step: Step = Box::new(move |ui, round| {
109 if !ready {
110 ready = true;
111 sign_in(ui);
112 if let (Some(list), Some(session)) = (list, session.borrow().as_ref()) {
113 session.open_view(&format!("{list}_ListView"));
114 }
115 ui.update();
116 return true;
117 }
118 then(ui, round)
119 });
120 Setup { root, step }
121}
122
123fn gallery(interaction: &str) -> Setup {
124 Setup { root: Box::new(Gallery::new()), step: step(interaction) }
125}
126
127const CEILINGS: &[Ceiling] = &[ceiling("idle", "frames", 0), ceiling("hover", "shapes", 0)];
128
129pub(super) fn scenes() -> Vec<PerfScene> {
130 let scene = |name, make| PerfScene {
131 name,
132 covers: &[],
133 class: Class::App,
134 interactions: INTERACTIONS,
135 make,
136 ceilings: CEILINGS,
137 };
138 vec![
139 scene("app-gallery", gallery),
140 scene("app-center-start", |interaction| center(None, interaction)),
141 scene("app-center-many-rows", |interaction| center(Some("ManyRows"), interaction)),
142 scene("app-center-editors", |interaction| center(Some("EditorsDemo"), interaction)),
143 scene("app-center-list-editors", |interaction| center(Some("ListEditorsDemo"), interaction)),
144 scene("app-finance-dashboard", |interaction| finance(0, interaction)),
145 scene("app-finance-entries", |interaction| finance(1, interaction)),
146 scene("app-finance-reports", |interaction| finance(5, interaction)),
147 ]
148}