Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
examples/modern_dashboard/src/app.rs
1use std::collections::HashMap;
2use strato_widgets::{
3 Widget, WidgetId, Row, Column, Container, Flex,
4};
5use strato_core::layout::{Constraints, Layout, Size};
6use strato_renderer::batch::RenderBatch;
7use strato_core::state::Signal;
8use crate::theme::AppTheme;
9use crate::components::{sidebar::Sidebar, header::Header};
10use crate::views::{
11 dashboard::DashboardView,
12 analytics::AnalyticsView,
13 users::UsersView,
14 settings::SettingsView,
15};
16 
17pub struct ModernDashboardApp {
18 root: Box<dyn Widget>,
19}
20 
21impl ModernDashboardApp {
22 pub fn new() -> Self {
23 let active_tab = Signal::new("dashboard".to_string());
24 let theme = AppTheme::dark();
25 
26 let sidebar = Sidebar::new(active_tab.clone()).build();
27 let header = Header::new().build();
28 
29 let view_switcher = ViewSwitcher::new(active_tab);
30 
31 let root = Container::new()
32 .background(theme.bg_primary)
33 .child(
34 Row::new()
35 .children(vec![
36 // Sidebar
37 sidebar,
38 
39 // Main Content Area
40 Box::new(Flex::new(
41 Box::new(Column::new()
42 .children(vec![
43 header,
44 Box::new(Flex::new(
45 Box::new(Container::new()
46 .padding(crate::theme::SPACING_LG)
47 .child(view_switcher)
48 )
49 ).flex(1.0)) as Box<dyn Widget>,
50 ])
51 )
52 ).flex(1.0)) as Box<dyn Widget>,
53 ])
54 );
55 
56 Self {
57 root: Box::new(root),
58 }
59 }
60 
61 pub fn build(self) -> Box<dyn Widget> {
62 self.root
63 }
64}
65 
66// Custom Widget to handle View Switching
67#[derive(Debug)]
68struct ViewSwitcher {
69 id: WidgetId,
70 active_tab: Signal<String>,
71 // We store factories or instances? Instances are easier but need to be careful about state.
72 // For this example, we just store instances.
73 views: HashMap<String, Box<dyn Widget>>,
74 last_tab: String,
75}
76 
77impl ViewSwitcher {
78 fn new(active_tab: Signal<String>) -> Self {
79 let mut views = HashMap::new();
80 views.insert("dashboard".to_string(), DashboardView::build());
81 views.insert("analytics".to_string(), AnalyticsView::build());
82 views.insert("users".to_string(), UsersView::build());
83 views.insert("settings".to_string(), SettingsView::build());
84 
85 Self {
86 id: strato_widgets::widget::generate_id(),
87 active_tab,
88 views,
89 last_tab: "dashboard".to_string(),
90 }
91 }
92}
93 
94impl Widget for ViewSwitcher {
95 fn id(&self) -> WidgetId {
96 self.id
97 }
98 
99 fn layout(&mut self, constraints: Constraints) -> Size {
100 let current_tab = self.active_tab.get();
101 if let Some(view) = self.views.get_mut(&current_tab) {
102 view.layout(constraints)
103 } else {
104 Size::zero()
105 }
106 }
107 
108 fn render(&self, batch: &mut RenderBatch, layout: Layout) {
109 let current_tab = self.active_tab.get();
110 if let Some(view) = self.views.get(&current_tab) {
111 view.render(batch, layout);
112 }
113 }
114 
115 fn handle_event(&mut self, event: &strato_core::event::Event) -> strato_core::event::EventResult {
116 let current_tab = self.active_tab.get();
117 if let Some(view) = self.views.get_mut(&current_tab) {
118 view.handle_event(event)
119 } else {
120 strato_core::event::EventResult::Ignored
121 }
122 }
123 
124 fn as_any(&self) -> &dyn std::any::Any {
125 self
126 }
127 
128 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
129 self
130 }
131 
132 fn clone_widget(&self) -> Box<dyn Widget> {
133 let mut new_views = HashMap::new();
134 for (k, v) in &self.views {
135 new_views.insert(k.clone(), v.clone_widget());
136 }
137 
138 Box::new(ViewSwitcher {
139 id: strato_widgets::widget::generate_id(),
140 active_tab: self.active_tab.clone(),
141 views: new_views,
142 last_tab: self.last_tab.clone(),
143 })
144 }
145 
146 fn children(&self) -> Vec<&(dyn Widget + '_)> {
147 let current_tab = self.active_tab.get();
148 if let Some(view) = self.views.get(&current_tab) {
149 vec![view.as_ref()]
150 } else {
151 vec![]
152 }
153 }
154 
155 fn children_mut(&mut self) -> Vec<&mut (dyn Widget + '_)> {
156 let current_tab = self.active_tab.get();
157 if let Some(view) = self.views.get_mut(&current_tab) {
158 vec![view.as_mut()]
159 } else {
160 vec![]
161 }
162 }
163}
164