1use std::sync::Arc;
2
3use client::TelemetrySettings;
4use fs::Fs;
5use gpui::{App, IntoElement};
6use settings::{BaseKeymap, Settings, update_settings_file};
7use theme::{Appearance, SystemAppearance, ThemeMode, ThemeSettings};
8use ui::{
9 SwitchField, ThemePreviewTile, ToggleButtonGroup, ToggleButtonSimple, ToggleButtonWithIcon,
10 prelude::*,
11};
12use vim_mode_setting::VimModeSetting;
13
14use crate::Onboarding;
15
16fn read_theme_selection(cx: &App) -> (ThemeMode, SharedString) {
17 let settings = ThemeSettings::get_global(cx);
18 (
19 settings
20 .theme_selection
21 .as_ref()
22 .and_then(|selection| selection.mode())
23 .unwrap_or_default(),
24 settings.active_theme.name.clone(),
25 )
26}
27
28fn write_theme_selection(theme_mode: ThemeMode, cx: &App) {
29 let fs = <dyn Fs>::global(cx);
30
31 update_settings_file::<ThemeSettings>(fs, cx, move |settings, _| {
32 settings.set_mode(theme_mode);
33 });
34}
35
36fn write_keymap_base(keymap_base: BaseKeymap, cx: &App) {
37 let fs = <dyn Fs>::global(cx);
38
39 update_settings_file::<BaseKeymap>(fs, cx, move |setting, _| {
40 *setting = Some(keymap_base);
41 });
42}
43
44fn render_theme_section(theme_mode: ThemeMode) -> impl IntoElement {
45 h_flex().justify_between().child(Label::new("Theme")).child(
46 ToggleButtonGroup::single_row(
47 "theme-selector-onboarding",
48 [
49 ToggleButtonSimple::new("Light", |_, _, cx| {
50 write_theme_selection(ThemeMode::Light, cx)
51 }),
52 ToggleButtonSimple::new("Dark", |_, _, cx| {
53 write_theme_selection(ThemeMode::Dark, cx)
54 }),
55 ToggleButtonSimple::new("System", |_, _, cx| {
56 write_theme_selection(ThemeMode::System, cx)
57 }),
58 ],
59 )
60 .selected_index(match theme_mode {
61 ThemeMode::Light => 0,
62 ThemeMode::Dark => 1,
63 ThemeMode::System => 2,
64 })
65 .style(ui::ToggleButtonGroupStyle::Outlined)
66 .button_width(rems_from_px(64.)),
67 )
68}
69
70fn render_telemetry_section(fs: Arc<dyn Fs>, cx: &App) -> impl IntoElement {
71 v_flex()
72
73 .gap_4()
74 .child(Label::new("Telemetry").size(LabelSize::Large))
75 .child(SwitchField::new(
76 "onboarding-telemetry-metrics",
77 "Help Improve Zed",
78 "Sending anonymous usage data helps us build the right features and create the best experience.",
79 if TelemetrySettings::get_global(cx).metrics {
80 ui::ToggleState::Selected
81 } else {
82 ui::ToggleState::Unselected
83 },
84 {
85 let fs = fs.clone();
86 move |selection, _, cx| {
87 let enabled = match selection {
88 ToggleState::Selected => true,
89 ToggleState::Unselected => false,
90 ToggleState::Indeterminate => { return; },
91 };
92
93 update_settings_file::<TelemetrySettings>(
94 fs.clone(),
95 cx,
96 move |setting, _| setting.metrics = Some(enabled),
97 );
98 }},
99 ))
100 .child(SwitchField::new(
101 "onboarding-telemetry-crash-reports",
102 "Help Fix Zed",
103 "Send crash reports so we can fix critical issues fast.",
104 if TelemetrySettings::get_global(cx).diagnostics {
105 ui::ToggleState::Selected
106 } else {
107 ui::ToggleState::Unselected
108 },
109 {
110 let fs = fs.clone();
111 move |selection, _, cx| {
112 let enabled = match selection {
113 ToggleState::Selected => true,
114 ToggleState::Unselected => false,
115 ToggleState::Indeterminate => { return; },
116 };
117
118 update_settings_file::<TelemetrySettings>(
119 fs.clone(),
120 cx,
121 move |setting, _| setting.diagnostics = Some(enabled),
122 );
123 }
124 }
125 ))
126}
127
128pub(crate) fn render_basics_page(onboarding: &Onboarding, cx: &mut App) -> impl IntoElement {
129 let (theme_mode, active_theme_name) = read_theme_selection(cx);
130 let themes = match theme_mode {
131 ThemeMode::Dark => &onboarding.dark_themes,
132 ThemeMode::Light => &onboarding.light_themes,
133 ThemeMode::System => match SystemAppearance::global(cx).0 {
134 Appearance::Light => &onboarding.light_themes,
135 Appearance::Dark => &onboarding.dark_themes,
136 },
137 };
138
139 let base_keymap = match BaseKeymap::get_global(cx) {
140 BaseKeymap::VSCode => Some(0),
141 BaseKeymap::JetBrains => Some(1),
142 BaseKeymap::SublimeText => Some(2),
143 BaseKeymap::Atom => Some(3),
144 BaseKeymap::Emacs => Some(4),
145 BaseKeymap::Cursor => Some(5),
146 BaseKeymap::TextMate | BaseKeymap::None => None,
147 };
148
149 v_flex()
150 .gap_6()
151 .child(render_theme_section(theme_mode))
152 .child(h_flex().children(
153 themes.iter().map(|theme| {
154 ThemePreviewTile::new(theme.clone(), active_theme_name == theme.name, 0.48)
155 .on_click({
156 let theme_name = theme.name.clone();
157 let fs = onboarding.fs.clone();
158 move |_, _, cx| {
159 let theme_name = theme_name.clone();
160 update_settings_file::<ThemeSettings>(fs.clone(), cx, move |settings, cx| {
161 settings.set_theme(theme_name.to_string(), SystemAppearance::global(cx).0);
162 });
163 }
164 })
165 })
166 ))
167 .child(
168 v_flex().gap_2().child(Label::new("Base Keymap")).child(
169 ToggleButtonGroup::two_rows(
170 "multiple_row_test",
171 [
172 ToggleButtonWithIcon::new("VS Code", IconName::AiZed, |_, _, cx| {
173 write_keymap_base(BaseKeymap::VSCode, cx);
174 }),
175 ToggleButtonWithIcon::new("Jetbrains", IconName::AiZed, |_, _, cx| {
176 write_keymap_base(BaseKeymap::JetBrains, cx);
177 }),
178 ToggleButtonWithIcon::new("Sublime Text", IconName::AiZed, |_, _, cx| {
179 write_keymap_base(BaseKeymap::SublimeText, cx);
180 }),
181 ],
182 [
183 ToggleButtonWithIcon::new("Atom", IconName::AiZed, |_, _, cx| {
184 write_keymap_base(BaseKeymap::Atom, cx);
185 }),
186 ToggleButtonWithIcon::new("Emacs", IconName::AiZed, |_, _, cx| {
187 write_keymap_base(BaseKeymap::Emacs, cx);
188 }),
189 ToggleButtonWithIcon::new("Cursor (Beta)", IconName::AiZed, |_, _, cx| {
190 write_keymap_base(BaseKeymap::Cursor, cx);
191 }),
192 ],
193 )
194 .when_some(base_keymap, |this, base_keymap| this.selected_index(base_keymap))
195 .button_width(rems_from_px(230.))
196 .style(ui::ToggleButtonGroupStyle::Outlined)
197 ),
198 )
199 .child(v_flex().justify_center().child(div().h_0().child("hack").invisible()).child(SwitchField::new(
200 "onboarding-vim-mode",
201 "Vim Mode",
202 "Coming from Neovim? Zed's first-class implementation of Vim Mode has got your back.",
203 if VimModeSetting::get_global(cx).0 {
204 ui::ToggleState::Selected
205 } else {
206 ui::ToggleState::Unselected
207 },
208 {
209 let fs = onboarding.fs.clone();
210 move |selection, _, cx| {
211 let enabled = match selection {
212 ToggleState::Selected => true,
213 ToggleState::Unselected => false,
214 ToggleState::Indeterminate => { return; },
215 };
216
217 update_settings_file::<VimModeSetting>(
218 fs.clone(),
219 cx,
220 move |setting, _| *setting = Some(enabled),
221 );
222 }
223 },
224 )))
225 .child(render_telemetry_section(onboarding.fs.clone(), cx))
226}