1mod base_keymap_picker;
2mod base_keymap_setting;
3
4use crate::base_keymap_picker::ToggleBaseKeymapSelector;
5use client::TelemetrySettings;
6use db::kvp::KEY_VALUE_STORE;
7use gpui::{
8 elements::{Flex, Label, ParentElement},
9 AnyElement, AppContext, Element, Entity, Subscription, View, ViewContext, WeakViewHandle,
10};
11use settings::{update_settings_file, SettingsStore};
12use std::{borrow::Cow, sync::Arc};
13use vim::VimModeSetting;
14use workspace::{
15 dock::DockPosition, item::Item, open_new, AppState, PaneBackdrop, Welcome, Workspace,
16 WorkspaceId,
17};
18
19pub use base_keymap_setting::BaseKeymap;
20
21pub const FIRST_OPEN: &str = "first_open";
22
23pub fn init(cx: &mut AppContext) {
24 settings::register::<BaseKeymap>(cx);
25
26 cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| {
27 let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx));
28 workspace.add_item(Box::new(welcome_page), cx)
29 });
30
31 base_keymap_picker::init(cx);
32}
33
34pub fn show_welcome_experience(app_state: &Arc<AppState>, cx: &mut AppContext) {
35 open_new(&app_state, cx, |workspace, cx| {
36 workspace.toggle_dock(DockPosition::Left, cx);
37 let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx));
38 workspace.add_item_to_center(Box::new(welcome_page.clone()), cx);
39 cx.focus(&welcome_page);
40 cx.notify();
41 })
42 .detach();
43
44 db::write_and_log(cx, || {
45 KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string())
46 });
47}
48
49pub struct WelcomePage {
50 workspace: WeakViewHandle<Workspace>,
51 _settings_subscription: Subscription,
52}
53
54impl Entity for WelcomePage {
55 type Event = ();
56}
57
58impl View for WelcomePage {
59 fn ui_name() -> &'static str {
60 "WelcomePage"
61 }
62
63 fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> AnyElement<Self> {
64 let self_handle = cx.handle();
65 let theme = theme::current(cx);
66 let width = theme.welcome.page_width;
67
68 let telemetry_settings = *settings::get::<TelemetrySettings>(cx);
69 let vim_mode_setting = settings::get::<VimModeSetting>(cx).0;
70
71 enum Metrics {}
72 enum Diagnostics {}
73
74 PaneBackdrop::new(
75 self_handle.id(),
76 Flex::column()
77 .with_child(
78 Flex::column()
79 .with_child(
80 theme::ui::svg(&theme.welcome.logo)
81 .aligned()
82 .contained()
83 .aligned(),
84 )
85 .with_child(
86 Label::new(
87 "Code at the speed of thought",
88 theme.welcome.logo_subheading.text.clone(),
89 )
90 .aligned()
91 .contained()
92 .with_style(theme.welcome.logo_subheading.container),
93 )
94 .contained()
95 .with_style(theme.welcome.heading_group)
96 .constrained()
97 .with_width(width),
98 )
99 .with_child(
100 Flex::column()
101 .with_child(theme::ui::cta_button::<theme_selector::Toggle, _, _, _>(
102 "Choose a theme",
103 width,
104 &theme.welcome.button,
105 cx,
106 |_, this, cx| {
107 if let Some(workspace) = this.workspace.upgrade(cx) {
108 workspace.update(cx, |workspace, cx| {
109 theme_selector::toggle(workspace, &Default::default(), cx)
110 })
111 }
112 },
113 ))
114 .with_child(theme::ui::cta_button::<ToggleBaseKeymapSelector, _, _, _>(
115 "Choose a keymap",
116 width,
117 &theme.welcome.button,
118 cx,
119 |_, this, cx| {
120 if let Some(workspace) = this.workspace.upgrade(cx) {
121 workspace.update(cx, |workspace, cx| {
122 base_keymap_picker::toggle(
123 workspace,
124 &Default::default(),
125 cx,
126 )
127 })
128 }
129 },
130 ))
131 .with_child(theme::ui::cta_button::<install_cli::Install, _, _, _>(
132 "Install the CLI",
133 width,
134 &theme.welcome.button,
135 cx,
136 |_, _, cx| {
137 cx.app_context()
138 .spawn(|cx| async move { install_cli::install_cli(&cx).await })
139 .detach_and_log_err(cx);
140 },
141 ))
142 .contained()
143 .with_style(theme.welcome.button_group)
144 .constrained()
145 .with_width(width),
146 )
147 .with_child(
148 Flex::column()
149 .with_child(
150 theme::ui::checkbox::<Diagnostics, Self, _>(
151 "Enable vim mode",
152 &theme.welcome.checkbox,
153 vim_mode_setting,
154 0,
155 cx,
156 |this, checked, cx| {
157 if let Some(workspace) = this.workspace.upgrade(cx) {
158 let fs = workspace.read(cx).app_state().fs.clone();
159 update_settings_file::<VimModeSetting>(
160 fs,
161 cx,
162 move |setting| *setting = Some(checked),
163 )
164 }
165 },
166 )
167 .contained()
168 .with_style(theme.welcome.checkbox_container),
169 )
170 .with_child(
171 theme::ui::checkbox_with_label::<Metrics, _, Self, _>(
172 Flex::column()
173 .with_child(
174 Label::new(
175 "Send anonymous usage data",
176 theme.welcome.checkbox.label.text.clone(),
177 )
178 .contained()
179 .with_style(theme.welcome.checkbox.label.container),
180 )
181 .with_child(
182 Label::new(
183 "Help > View Telemetry",
184 theme.welcome.usage_note.text.clone(),
185 )
186 .contained()
187 .with_style(theme.welcome.usage_note.container),
188 ),
189 &theme.welcome.checkbox,
190 telemetry_settings.metrics,
191 0,
192 cx,
193 |this, checked, cx| {
194 if let Some(workspace) = this.workspace.upgrade(cx) {
195 let fs = workspace.read(cx).app_state().fs.clone();
196 update_settings_file::<TelemetrySettings>(
197 fs,
198 cx,
199 move |setting| setting.metrics = Some(checked),
200 )
201 }
202 },
203 )
204 .contained()
205 .with_style(theme.welcome.checkbox_container),
206 )
207 .with_child(
208 theme::ui::checkbox::<Diagnostics, Self, _>(
209 "Send crash reports",
210 &theme.welcome.checkbox,
211 telemetry_settings.diagnostics,
212 1,
213 cx,
214 |this, checked, cx| {
215 if let Some(workspace) = this.workspace.upgrade(cx) {
216 let fs = workspace.read(cx).app_state().fs.clone();
217 update_settings_file::<TelemetrySettings>(
218 fs,
219 cx,
220 move |setting| setting.diagnostics = Some(checked),
221 )
222 }
223 },
224 )
225 .contained()
226 .with_style(theme.welcome.checkbox_container),
227 )
228 .contained()
229 .with_style(theme.welcome.checkbox_group)
230 .constrained()
231 .with_width(width),
232 )
233 .constrained()
234 .with_max_width(width)
235 .contained()
236 .with_uniform_padding(10.)
237 .aligned()
238 .into_any(),
239 )
240 .into_any_named("welcome page")
241 }
242}
243
244impl WelcomePage {
245 pub fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
246 WelcomePage {
247 workspace: workspace.weak_handle(),
248 _settings_subscription: cx.observe_global::<SettingsStore, _>(move |_, cx| cx.notify()),
249 }
250 }
251}
252
253impl Item for WelcomePage {
254 fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
255 Some("Welcome to Zed!".into())
256 }
257
258 fn tab_content<T: 'static>(
259 &self,
260 _detail: Option<usize>,
261 style: &theme::Tab,
262 _cx: &gpui::AppContext,
263 ) -> AnyElement<T> {
264 Flex::row()
265 .with_child(
266 Label::new("Welcome to Zed!", style.label.clone())
267 .aligned()
268 .contained(),
269 )
270 .into_any()
271 }
272
273 fn show_toolbar(&self) -> bool {
274 false
275 }
276
277 fn clone_on_split(
278 &self,
279 _workspace_id: WorkspaceId,
280 cx: &mut ViewContext<Self>,
281 ) -> Option<Self> {
282 Some(WelcomePage {
283 workspace: self.workspace.clone(),
284 _settings_subscription: cx.observe_global::<SettingsStore, _>(move |_, cx| cx.notify()),
285 })
286 }
287}