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