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 cx,
150 |checked, cx| {
151 SettingsFile::update(cx, move |file| {
152 file.telemetry.set_metrics(checked)
153 })
154 },
155 )
156 .contained()
157 .with_style(theme.welcome.checkbox_container),
158 )
159 .with_child(
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 )
174 .contained()
175 .with_style(theme.welcome.checkbox_group)
176 .constrained()
177 .with_width(width),
178 )
179 .constrained()
180 .with_max_width(width)
181 .contained()
182 .with_uniform_padding(10.)
183 .aligned()
184 .into_any(),
185 )
186 .into_any_named("welcome page")
187 }
188}
189
190impl WelcomePage {
191 pub fn new(cx: &mut ViewContext<Self>) -> Self {
192 WelcomePage {
193 _settings_subscription: cx.observe_global::<Settings, _>(move |_, cx| cx.notify()),
194 }
195 }
196}
197
198impl Item for WelcomePage {
199 fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
200 Some("Welcome to Zed!".into())
201 }
202
203 fn tab_content<T: View>(
204 &self,
205 _detail: Option<usize>,
206 style: &theme::Tab,
207 _cx: &gpui::AppContext,
208 ) -> AnyElement<T> {
209 Flex::row()
210 .with_child(
211 Label::new("Welcome to Zed!", style.label.clone())
212 .aligned()
213 .contained(),
214 )
215 .into_any()
216 }
217
218 fn show_toolbar(&self) -> bool {
219 false
220 }
221 fn clone_on_split(
222 &self,
223 _workspace_id: WorkspaceId,
224 cx: &mut ViewContext<Self>,
225 ) -> Option<Self> {
226 Some(WelcomePage::new(cx))
227 }
228}