1#![allow(dead_code, unused_imports)]
27
28use swiftui_native::{app, views, window, Color};
29
30static TAPS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
32
33fn on_tap() {
39 TAPS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
40 let s = switch_state();
41 s.set(!s.get());
42 refresh();
43}
44
45fn root_view() -> views::ViewHandle {
55 thread_local! {
56 static ROOT: std::cell::OnceCell<swiftui_native::state::StatefulView> =
57 const { std::cell::OnceCell::new() };
58 }
59 ROOT.with(|cell| {
60 let sv = cell.get_or_init(|| {
61 let sv = swiftui_native::state::StatefulView::new(0, |_generation| ui());
62 ROOT_ID.store(sv.id, std::sync::atomic::Ordering::Release);
63 sv
64 });
65 sv.as_view()
66 })
67}
68
69static ROOT_ID: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(-1);
70
71fn refresh() {
73 use std::sync::atomic::Ordering;
74 static GENERATION: std::sync::atomic::AtomicI64 = std::sync::atomic::AtomicI64::new(0);
75 let id = ROOT_ID.load(Ordering::Acquire);
76 if id >= 0 {
77 let n = GENERATION.fetch_add(1, Ordering::Relaxed) + 1;
78 swiftui_native::state::set_state(id, n);
79 }
80}
81
82fn slider_state() -> &'static views::BoundState<f64> {
84 static S: std::sync::OnceLock<views::BoundState<f64>> = std::sync::OnceLock::new();
85 S.get_or_init(|| views::BoundState::new(0.65))
86}
87
88fn stepper_state() -> &'static views::BoundState<f64> {
90 static S: std::sync::OnceLock<views::BoundState<f64>> = std::sync::OnceLock::new();
91 S.get_or_init(|| views::BoundState::new(3.0))
92}
93
94fn switch_state() -> &'static views::BoundState<bool> {
96 static S: std::sync::OnceLock<views::BoundState<bool>> = std::sync::OnceLock::new();
97 S.get_or_init(|| views::BoundState::new(false))
98}
99
100fn ui() -> views::ViewHandle {
101 views::zstack(&[
102 views::background_linear_gradient(
103 &views::color(0.0, 0.0, 0.0, 0.0),
104 &[Color::new(0.06, 0.07, 0.16, 1.0), Color::new(0.24, 0.07, 0.33, 1.0)],
105 (0.0, 0.0),
106 (1.0, 1.0),
107 ),
108 views::scroll(&views::padding(
109 &views::vstack_spacing(
110 &[
111 header(),
112 section("Typography", typography()),
113 section("Shapes", shapes()),
114 section("Controls", controls()),
115 section("Symbols", symbols()),
116 section("Effects", effects()),
117 section("Layout", layout()),
118 ],
119 18.0,
120 ),
121 16.0,
122 )),
123 ])
124}
125
126fn label_text(s: &str, size: f64, weight: Option<views::Weight>, alpha: f64) -> views::ViewHandle {
128 views::foreground_style_color(
129 &views::font_system(&views::text(s), size, weight, None),
130 1.0,
131 1.0,
132 1.0,
133 alpha,
134 )
135}
136
137fn header() -> views::ViewHandle {
138 views::vstack_spacing(
139 &[
140 label_text("SwiftUI from Rust", 30.0, Some(views::Weight::Bold), 1.0),
141 label_text(entry(), 13.0, None, 0.75),
142 label_text(
143 &format!("taps: {}", TAPS.load(std::sync::atomic::Ordering::Relaxed)),
144 13.0,
145 Some(views::Weight::Semibold),
146 0.9,
147 ),
148 ],
149 4.0,
150 )
151}
152
153fn section(title: &str, content: views::ViewHandle) -> views::ViewHandle {
155 views::vstack_spacing(
156 &[
157 label_text(title, 12.0, Some(views::Weight::Semibold), 0.55),
158 views::padding(
159 &views::corner_radius(
160 &views::background(&views::padding(&content, 12.0), 1.0, 1.0, 1.0, 0.07),
161 14.0,
162 ),
163 0.0,
164 ),
165 ],
166 6.0,
167 )
168}
169
170fn typography() -> views::ViewHandle {
171 views::vstack_spacing(
172 &[
173 views::hstack_spacing(
174 &[
175 views::font_text_style(&views::text("Title"), views::TextStyle::Title3),
176 views::italic(&views::text("Italic")),
177 views::monospaced(&views::text("mono")),
178 ],
179 14.0,
180 ),
181 views::kerning(&label_text("K E R N E D", 15.0, None, 0.9), 2.0),
182 views::foreground_style_linear_gradient(
183 &views::font_system(&views::text("Gradient fill"), 22.0, Some(views::Weight::Bold), None),
184 &[
185 views::color_value_of(Color::new(1.0, 0.55, 0.25, 1.0)),
186 views::color_value_of(Color::new(1.0, 0.25, 0.6, 1.0)),
187 ],
188 (0.0, 0.0),
189 (1.0, 0.0),
190 ),
191 ],
192 10.0,
193 )
194}
195
196fn shapes() -> views::ViewHandle {
197 let swatch = |shape: views::Shape, c: Color| {
198 views::frame(&shape.fill(views::color_value_of(c)), 58.0, 44.0)
199 };
200 views::hstack_spacing(
201 &[
202 swatch(views::Shape::circle(), Color::new(0.95, 0.35, 0.30, 1.0)),
203 swatch(views::Shape::capsule(), Color::new(0.98, 0.70, 0.20, 1.0)),
204 swatch(views::Shape::rounded_rectangle(10.0, true), Color::new(0.30, 0.65, 1.0, 1.0)),
205 swatch(views::Shape::ellipse(), Color::new(0.35, 0.85, 0.55, 1.0)),
206 ],
207 10.0,
208 )
209}
210
211fn controls() -> views::ViewHandle {
212 views::vstack_spacing(
213 &[
214 views::toggle_bound("Bound to Rust state", switch_state()),
218 views::toggle("Constant false", false),
219 views::hstack_spacing(
220 &[
221 label_text(&format!("{:.2}", slider_state().get()), 14.0, None, 0.9),
222 views::slider_bound(slider_state(), 0.0, 1.0),
223 ],
224 10.0,
225 ),
226 views::stepper_bound(
227 &format!("Stepper: {:.0}", stepper_state().get()),
228 stepper_state(),
229 0.0,
230 10.0,
231 1.0,
232 ),
233 views::progress(stepper_state().get(), 10.0),
238 views::hstack_spacing(
239 &[
240 views::button_style(
241 &views::button("Bordered", on_tap),
242 views::ButtonStyle::Bordered,
243 ),
244 views::button_style(
245 &views::button("Glass", on_tap),
246 views::ButtonStyle::Glass,
247 ),
248 ],
249 12.0,
250 ),
251 views::textfield("A text field", ""),
252 ],
253 12.0,
254 )
255}
256
257fn symbols() -> views::ViewHandle {
258 let icon = |name: &str, c: Color| {
259 views::foreground_style_color(
260 &views::font_system(&views::system_image(name), 24.0, None, None),
261 c.r, c.g, c.b, c.a,
262 )
263 };
264 views::hstack_spacing(
265 &[
266 icon("star.fill", Color::new(1.0, 0.8, 0.2, 1.0)),
267 icon("heart.fill", Color::new(1.0, 0.35, 0.45, 1.0)),
268 icon("bolt.fill", Color::new(0.55, 0.8, 1.0, 1.0)),
269 icon("cloud.sun.fill", Color::new(0.8, 0.85, 1.0, 1.0)),
270 icon("checkmark.seal.fill", Color::new(0.4, 0.9, 0.6, 1.0)),
271 ],
272 16.0,
273 )
274}
275
276fn effects() -> views::ViewHandle {
277 let tile = |c: Color| views::frame(&views::color(c.r, c.g, c.b, c.a), 48.0, 40.0);
278 views::hstack_spacing(
279 &[
280 views::blur(&tile(Color::new(0.95, 0.4, 0.3, 1.0)), 4.0),
281 views::shadow(
282 &tile(Color::new(0.3, 0.7, 1.0, 1.0)),
283 Color::new(0.0, 0.0, 0.0, 0.8),
284 8.0,
285 0.0,
286 4.0,
287 ),
288 views::opacity(&tile(Color::new(0.5, 0.9, 0.5, 1.0)), 0.35),
289 views::corner_radius(&tile(Color::new(0.9, 0.7, 0.2, 1.0)), 12.0),
290 views::border(&tile(Color::new(0.0, 0.0, 0.0, 0.0)), 1.0, 1.0, 1.0, 2.0),
291 ],
292 10.0,
293 )
294}
295
296fn layout() -> views::ViewHandle {
297 let chip = |s: &str, c: Color| {
298 views::corner_radius(
299 &views::background(&views::padding(&label_text(s, 13.0, None, 1.0), 8.0), c.r, c.g, c.b, c.a),
300 8.0,
301 )
302 };
303 views::vstack_spacing(
304 &[
305 views::hstack_spacing(
306 &[
307 chip("HStack", Color::new(0.35, 0.35, 0.8, 0.8)),
308 views::spacer(),
309 chip("Spacer", Color::new(0.8, 0.35, 0.5, 0.8)),
310 ],
311 8.0,
312 ),
313 views::divider(),
314 views::zstack(&[
315 views::frame(
316 &views::Shape::rounded_rectangle(8.0, true)
317 .fill(views::color_value_of(Color::new(0.2, 0.5, 0.9, 0.55))),
318 120.0,
319 34.0,
320 ),
321 label_text("ZStack", 13.0, Some(views::Weight::Semibold), 1.0),
322 ]),
323 ],
324 10.0,
325 )
326}
327
328fn entry() -> &'static str {
329 if uses_window() {
330 "UIApplicationMain, synthesised delegate"
331 } else {
332 "App.main(), synthesised conformance"
333 }
334}
335
336fn uses_window() -> bool {
337 std::env::args().any(|a| a == "window")
338}
339
340#[cfg(not(target_os = "macos"))]
345fn main() {
346 views::on_write(refresh);
348 #[cfg(feature = "uikit-entry")]
360 if uses_window() {
361 window::show_window(&root_view(), "RustUI", 0.0, 0.0);
364 }
365 app::run(root_view)
366}
367
368#[cfg(target_os = "macos")]
378#[path = "common/simulator.rs"]
379mod simulator;
380
381#[cfg(target_os = "macos")]
382fn main() {
383 simulator::main(&simulator::Bundle {
384 example: "ios_app",
385 bundle_id: "dev.rswift.RustUI",
386 executable: "RustUI",
387 display_name: "SwiftUI from Rust",
388 launch_args: if uses_window() { &["window"] } else { &[] },
389 });
390}