1mod base_keymap_picker;
2
3use std::{borrow::Cow, sync::Arc};
4
5use db::kvp::KEY_VALUE_STORE;
6use gpui::{
7 elements::{Flex, Label, ParentElement},
8 AnyElement, AppContext, Element, Entity, Subscription, View, ViewContext, WeakViewHandle,
9};
10use settings::{settings_file::SettingsFile, Settings};
11
12use workspace::{
13 item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace,
14 WorkspaceId,
15};
16
17use crate::base_keymap_picker::ToggleBaseKeymapSelector;
18
19pub const FIRST_OPEN: &str = "first_open";
20
21pub fn init(cx: &mut AppContext) {
22 cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| {
23 let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx));
24 workspace.add_item(Box::new(welcome_page), cx)
25 });
26
27 base_keymap_picker::init(cx);
28}
29
30pub fn show_welcome_experience(app_state: &Arc<AppState>, cx: &mut AppContext) {
31 open_new(&app_state, cx, |workspace, cx| {
32 workspace.toggle_sidebar(SidebarSide::Left, cx);
33 let welcome_page = cx.add_view(|cx| WelcomePage::new(workspace, cx));
34 workspace.add_item_to_center(Box::new(welcome_page.clone()), cx);
35 cx.focus(&welcome_page);
36 cx.notify();
37 })
38 .detach();
39
40 db::write_and_log(cx, || {
41 KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string())
42 });
43}
44
45pub struct WelcomePage {
46 workspace: WeakViewHandle<Workspace>,
47 _settings_subscription: Subscription,
48}
49
50impl Entity for WelcomePage {
51 type Event = ();
52}
53
54impl View for WelcomePage {
55 fn ui_name() -> &'static str {
56 "WelcomePage"
57 }
58
59 fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> AnyElement<Self> {
60 let self_handle = cx.handle();
61 let settings = cx.global::<Settings>();
62 let theme = settings.theme.clone();
63
64 let width = theme.welcome.page_width;
65
66 let (diagnostics, metrics) = {
67 let telemetry = settings.telemetry();
68 (telemetry.diagnostics(), telemetry.metrics())
69 };
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_with_label::<Metrics, _, Self, _>(
151 Flex::column()
152 .with_child(
153 Label::new(
154 "Send anonymous usage data",
155 theme.welcome.checkbox.label.text.clone(),
156 )
157 .contained()
158 .with_style(theme.welcome.checkbox.label.container),
159 )
160 .with_child(
161 Label::new(
162 "Help > View Telemetry",
163 theme.welcome.usage_note.text.clone(),
164 )
165 .contained()
166 .with_style(theme.welcome.usage_note.container),
167 ),
168 &theme.welcome.checkbox,
169 metrics,
170 0,
171 cx,
172 |_, checked, cx| {
173 SettingsFile::update(cx, move |file| {
174 file.telemetry.set_metrics(checked)
175 })
176 },
177 )
178 .contained()
179 .with_style(theme.welcome.checkbox_container),
180 )
181 .with_child(
182 theme::ui::checkbox::<Diagnostics, Self, _>(
183 "Send crash reports",
184 &theme.welcome.checkbox,
185 diagnostics,
186 0,
187 cx,
188 |_, checked, cx| {
189 SettingsFile::update(cx, move |file| {
190 file.telemetry.set_diagnostics(checked)
191 })
192 },
193 )
194 .contained()
195 .with_style(theme.welcome.checkbox_container),
196 )
197 .contained()
198 .with_style(theme.welcome.checkbox_group)
199 .constrained()
200 .with_width(width),
201 )
202 .constrained()
203 .with_max_width(width)
204 .contained()
205 .with_uniform_padding(10.)
206 .aligned()
207 .into_any(),
208 )
209 .into_any_named("welcome page")
210 }
211}
212
213impl WelcomePage {
214 pub fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
215 WelcomePage {
216 workspace: workspace.weak_handle(),
217 _settings_subscription: cx.observe_global::<Settings, _>(move |_, cx| cx.notify()),
218 }
219 }
220}
221
222impl Item for WelcomePage {
223 fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
224 Some("Welcome to Zed!".into())
225 }
226
227 fn tab_content<T: View>(
228 &self,
229 _detail: Option<usize>,
230 style: &theme::Tab,
231 _cx: &gpui::AppContext,
232 ) -> AnyElement<T> {
233 Flex::row()
234 .with_child(
235 Label::new("Welcome to Zed!", style.label.clone())
236 .aligned()
237 .contained(),
238 )
239 .into_any()
240 }
241
242 fn show_toolbar(&self) -> bool {
243 false
244 }
245
246 fn clone_on_split(
247 &self,
248 _workspace_id: WorkspaceId,
249 cx: &mut ViewContext<Self>,
250 ) -> Option<Self> {
251 Some(WelcomePage {
252 workspace: self.workspace.clone(),
253 _settings_subscription: cx.observe_global::<Settings, _>(move |_, cx| cx.notify()),
254 })
255 }
256}