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,
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::ViewContext<Self>) -> AnyElement<Self> {
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_child(
77 Flex::column()
78 .with_child(
79 theme::ui::svg(&theme.welcome.logo)
80 .aligned()
81 .contained()
82 .aligned(),
83 )
84 .with_child(
85 Label::new(
86 "Code at the speed of thought",
87 theme.welcome.logo_subheading.text.clone(),
88 )
89 .aligned()
90 .contained()
91 .with_style(theme.welcome.logo_subheading.container),
92 )
93 .contained()
94 .with_style(theme.welcome.heading_group)
95 .constrained()
96 .with_width(width),
97 )
98 .with_child(
99 Flex::column()
100 .with_child(theme::ui::cta_button(
101 "Choose a theme",
102 theme_selector::Toggle,
103 width,
104 &theme.welcome.button,
105 cx,
106 ))
107 .with_child(theme::ui::cta_button(
108 "Choose a keymap",
109 ToggleBaseKeymapSelector,
110 width,
111 &theme.welcome.button,
112 cx,
113 ))
114 .with_child(theme::ui::cta_button(
115 "Install the CLI",
116 install_cli::Install,
117 width,
118 &theme.welcome.button,
119 cx,
120 ))
121 .contained()
122 .with_style(theme.welcome.button_group)
123 .constrained()
124 .with_width(width),
125 )
126 .with_child(
127 Flex::column()
128 .with_child(
129 theme::ui::checkbox_with_label::<Metrics, _, Self, _>(
130 Flex::column()
131 .with_child(
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 )
139 .with_child(
140 Label::new(
141 "Help > View Telemetry",
142 theme.welcome.usage_note.text.clone(),
143 )
144 .contained()
145 .with_style(theme.welcome.usage_note.container),
146 ),
147 &theme.welcome.checkbox,
148 metrics,
149 0,
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 )
160 .with_child(
161 theme::ui::checkbox::<Diagnostics, Self, _>(
162 "Send crash reports",
163 &theme.welcome.checkbox,
164 diagnostics,
165 0,
166 cx,
167 |_, checked, cx| {
168 SettingsFile::update(cx, move |file| {
169 file.telemetry.set_diagnostics(checked)
170 })
171 },
172 )
173 .contained()
174 .with_style(theme.welcome.checkbox_container),
175 )
176 .contained()
177 .with_style(theme.welcome.checkbox_group)
178 .constrained()
179 .with_width(width),
180 )
181 .constrained()
182 .with_max_width(width)
183 .contained()
184 .with_uniform_padding(10.)
185 .aligned()
186 .into_any(),
187 )
188 .into_any_named("welcome page")
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_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
202 Some("Welcome to Zed!".into())
203 }
204
205 fn tab_content<T: View>(
206 &self,
207 _detail: Option<usize>,
208 style: &theme::Tab,
209 _cx: &gpui::AppContext,
210 ) -> AnyElement<T> {
211 Flex::row()
212 .with_child(
213 Label::new("Welcome to Zed!", style.label.clone())
214 .aligned()
215 .contained(),
216 )
217 .into_any()
218 }
219
220 fn show_toolbar(&self) -> bool {
221 false
222 }
223 fn clone_on_split(
224 &self,
225 _workspace_id: WorkspaceId,
226 cx: &mut ViewContext<Self>,
227 ) -> Option<Self> {
228 Some(WelcomePage::new(cx))
229 }
230}