1use std::sync::OnceLock;
13use swiftui_native::prelude::*;
14use swiftui_native::{state, views};
15
16struct Settings {
21 name: views::BoundState<String>,
22 notify: views::BoundState<bool>,
23 volume: views::BoundState<f64>,
24 theme: views::BoundState<i64>,
25 refresh: views::BoundState<f64>,
26 about: views::BoundState<bool>,
27}
28
29fn settings() -> &'static Settings {
30 static S: OnceLock<Settings> = OnceLock::new();
31 S.get_or_init(|| Settings {
32 name: views::BoundState::new("Ada".into()),
33 notify: views::BoundState::new(true),
34 volume: views::BoundState::new(0.6),
35 theme: views::BoundState::new(0),
36 refresh: views::BoundState::new(5.0),
37 about: views::BoundState::new(false),
38 })
39}
40
41const THEMES: [&str; 3] = ["System", "Light", "Dark"];
42
43fn body() -> View {
44 let s = settings();
45
46 form![
47 section![header: text("Account");
48 hstack![
49 text("Name"),
50 spacer(),
51 textfield_bound("Your name", &s.name).text_field_style(
52 views::TextFieldStyle::RoundedBorderTextFieldStyle,
53 ),
54 ],
55 toggle_bound("Notifications", &s.notify),
56 ],
57 section![header: text("Playback");
58 vstack_aligned(&[
59 hstack![
60 text("Volume"),
61 spacer(),
62 text!("{:.0}%", s.volume.get() * 100.0).fg_system(SystemColor::Gray),
63 ],
64 slider_bound(&s.volume, 0.0, 1.0),
65 ], HorizontalAlignment::Leading),
66 stepper_bound("Refresh every", &s.refresh, 1.0, 60.0, 1.0),
67 ],
68 section![header: text("Appearance");
69 picker_bound!(
70 "Theme",
71 &s.theme,
72 text(THEMES[0]).tag_int(0),
73 text(THEMES[1]).tag_int(1),
74 text(THEMES[2]).tag_int(2),
75 )
76 .picker_style(PickerStyle::InlinePickerStyle),
77 ],
78 section![
79 button("About", show_about)
80 .a11y_hint("Opens a panel describing this app"),
81 ],
82 ]
83 .form_style(FormStyle::GroupedFormStyle)
84 .sheet_bound(&s.about, about_panel())
85}
86
87fn about_panel() -> View {
90 let s = settings();
91 vstack_spacing(
92 &[
93 system_image("gearshape.fill")
94 .symbol_rendering_mode(Some(views::SymbolRenderingMode::Hierarchical))
95 .view()
96 .font_size(48.0)
97 .fg_system(SystemColor::Blue),
98 text("Settings").text_style(TextStyle::Title).bold(),
99 text!("Signed in as {}", s.name.get()).fg_system(SystemColor::Gray),
100 spacer(),
101 button("Done", hide_about).button_style(views::ButtonStyle::BorderedProminent),
102 ],
103 16.0,
104 )
105 .padding(24.0)
106 .presentation_detents(&[views::PresentationDetent::Medium])
107 .presentation_drag_indicator(Visibility::Visible)
108}
109
110fn show_about() {
111 settings().about.set(true);
112 state::refresh();
113}
114
115fn hide_about() {
116 settings().about.set(false);
117 state::refresh();
118}
119
120fn content_view() -> swiftui_native::ViewHandle {
121 state::root_view(|_| body().into_handle())
122}
123
124#[cfg(target_os = "macos")]
125#[path = "common/simulator.rs"]
126mod simulator;
127
128#[cfg(target_os = "macos")]
129fn main() {
130 if std::env::args().any(|a| a == "--sim" || a == "device") {
131 return simulator::main(&simulator::Bundle {
132 example: "settings",
133 bundle_id: "dev.rswift.Settings",
134 executable: "Settings",
135 display_name: "Settings",
136 launch_args: &[],
137 });
138 }
139 if std::env::args().any(|a| a == "--render") {
140 let out = concat!(env!("CARGO_MANIFEST_DIR"), "/../../target/settings.png");
141 swiftui_native::render::render(&content_view(), 420, 640).write_png(out);
142 eprintln!("wrote {out}");
143 return;
144 }
145 show_window(&content_view(), "Settings", 420.0, 640.0);
146}
147
148#[cfg(not(target_os = "macos"))]
149fn main() {
150 swiftui_native::app::run(content_view)
151}