1mod base_keymap_picker;
2
3use std::sync::Arc;
4
5use db::kvp::KEY_VALUE_STORE;
6use gpui::{
7 elements::{Flex, Label, ParentElement},
8 AppContext, Element, ElementBox, Entity, Subscription, View, ViewContext,
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(WelcomePage::new);
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(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 _settings_subscription: Subscription,
47}
48
49impl Entity for WelcomePage {
50 type Event = ();
51}
52
53impl View for WelcomePage {
54 fn ui_name() -> &'static str {
55 "WelcomePage"
56 }
57
58 fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
59 let self_handle = cx.handle();
60 let settings = cx.global::<Settings>();
61 let theme = settings.theme.clone();
62
63 let width = theme.welcome.page_width;
64
65 let (diagnostics, metrics) = {
66 let telemetry = settings.telemetry();
67 (telemetry.diagnostics(), telemetry.metrics())
68 };
69
70 enum Metrics {}
71 enum Diagnostics {}
72
73 PaneBackdrop::new(
74 self_handle.id(),
75 Flex::column()
76 .with_children([
77 Flex::column()
78 .with_children([
79 theme::ui::svg(&theme.welcome.logo)
80 .aligned()
81 .contained()
82 .aligned()
83 .boxed(),
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 .boxed(),
92 ])
93 .contained()
94 .with_style(theme.welcome.heading_group)
95 .constrained()
96 .with_width(width)
97 .boxed(),
98 Flex::column()
99 .with_children([
100 theme::ui::cta_button(
101 "Choose a theme",
102 theme_selector::Toggle,
103 width,
104 &theme.welcome.button,
105 cx,
106 ),
107 theme::ui::cta_button(
108 "Choose a keymap",
109 ToggleBaseKeymapSelector,
110 width,
111 &theme.welcome.button,
112 cx,
113 ),
114 theme::ui::cta_button(
115 "Install the CLI",
116 install_cli::Install,
117 width,
118 &theme.welcome.button,
119 cx,
120 ),
121 ])
122 .contained()
123 .with_style(theme.welcome.button_group)
124 .constrained()
125 .with_width(width)
126 .boxed(),
127 Flex::column()
128 .with_children([
129 theme::ui::checkbox_with_label::<Metrics, Self>(
130 Flex::column()
131 .with_children([
132 Label::new(
133 "Send anonymous usage data",
134 theme.welcome.checkbox.label.text.clone(),
135 )
136 .contained()
137 .with_style(theme.welcome.checkbox.label.container)
138 .boxed(),
139 Label::new(
140 "Help > View Telemetry",
141 theme.welcome.usage_note.text.clone(),
142 )
143 .contained()
144 .with_style(theme.welcome.usage_note.container)
145 .boxed(),
146 ])
147 .boxed(),
148 &theme.welcome.checkbox,
149 metrics,
150 cx,
151 |checked, cx| {
152 SettingsFile::update(cx, move |file| {
153 file.telemetry.set_metrics(checked)
154 })
155 },
156 )
157 .contained()
158 .with_style(theme.welcome.checkbox_container)
159 .boxed(),
160 theme::ui::checkbox::<Diagnostics, Self>(
161 "Send crash reports",
162 &theme.welcome.checkbox,
163 diagnostics,
164 cx,
165 |checked, cx| {
166 SettingsFile::update(cx, move |file| {
167 file.telemetry.set_diagnostics(checked)
168 })
169 },
170 )
171 .contained()
172 .with_style(theme.welcome.checkbox_container)
173 .boxed(),
174 ])
175 .contained()
176 .with_style(theme.welcome.checkbox_group)
177 .constrained()
178 .with_width(width)
179 .boxed(),
180 ])
181 .constrained()
182 .with_max_width(width)
183 .contained()
184 .with_uniform_padding(10.)
185 .aligned()
186 .boxed(),
187 )
188 .boxed()
189 }
190}
191
192impl WelcomePage {
193 pub fn new(cx: &mut ViewContext<Self>) -> Self {
194 WelcomePage {
195 _settings_subscription: cx.observe_global::<Settings, _>(move |_, cx| cx.notify()),
196 }
197 }
198}
199
200impl Item for WelcomePage {
201 fn tab_content(
202 &self,
203 _detail: Option<usize>,
204 style: &theme::Tab,
205 _cx: &gpui::AppContext,
206 ) -> gpui::ElementBox {
207 Flex::row()
208 .with_child(
209 Label::new("Welcome to Zed!", style.label.clone())
210 .aligned()
211 .contained()
212 .boxed(),
213 )
214 .boxed()
215 }
216
217 fn show_toolbar(&self) -> bool {
218 false
219 }
220 fn clone_on_split(
221 &self,
222 _workspace_id: WorkspaceId,
223 cx: &mut ViewContext<Self>,
224 ) -> Option<Self> {
225 Some(WelcomePage::new(cx))
226 }
227}