Start on welcome experience settings
This commit is contained in:
parent
a0637a769c
commit
416c793076
9 changed files with 326 additions and 66 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -8018,6 +8018,7 @@ name = "welcome"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"editor",
|
||||||
"gpui",
|
"gpui",
|
||||||
"log",
|
"log",
|
||||||
"project",
|
"project",
|
||||||
|
|
|
@ -5086,7 +5086,7 @@ impl<T: Entity> From<WeakModelHandle<T>> for AnyWeakModelHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy)]
|
||||||
pub struct WeakViewHandle<T> {
|
pub struct WeakViewHandle<T> {
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
view_id: usize,
|
view_id: usize,
|
||||||
|
|
|
@ -66,9 +66,18 @@ impl TelemetrySettings {
|
||||||
pub fn metrics(&self) -> bool {
|
pub fn metrics(&self) -> bool {
|
||||||
self.metrics.unwrap()
|
self.metrics.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diagnostics(&self) -> bool {
|
pub fn diagnostics(&self) -> bool {
|
||||||
self.diagnostics.unwrap()
|
self.diagnostics.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_metrics(&mut self, value: bool) {
|
||||||
|
self.metrics = Some(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_diagnostics(&mut self, value: bool) {
|
||||||
|
self.diagnostics = Some(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
|
@ -679,7 +688,7 @@ pub fn settings_file_json_schema(
|
||||||
|
|
||||||
/// Expects the key to be unquoted, and the value to be valid JSON
|
/// Expects the key to be unquoted, and the value to be valid JSON
|
||||||
/// (e.g. values should be unquoted for numbers and bools, quoted for strings)
|
/// (e.g. values should be unquoted for numbers and bools, quoted for strings)
|
||||||
pub fn write_top_level_setting(
|
pub fn write_settings_key(
|
||||||
mut settings_content: String,
|
mut settings_content: String,
|
||||||
top_level_key: &str,
|
top_level_key: &str,
|
||||||
new_val: &str,
|
new_val: &str,
|
||||||
|
@ -786,11 +795,160 @@ pub fn parse_json_with_comments<T: DeserializeOwned>(content: &str) -> Result<T>
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_settings_file(
|
||||||
|
old_text: String,
|
||||||
|
old_file_content: SettingsFileContent,
|
||||||
|
update: impl FnOnce(&mut SettingsFileContent),
|
||||||
|
) -> String {
|
||||||
|
let mut new_file_content = old_file_content.clone();
|
||||||
|
update(&mut new_file_content);
|
||||||
|
|
||||||
|
let old_json = to_json_object(old_file_content);
|
||||||
|
let new_json = to_json_object(new_file_content);
|
||||||
|
|
||||||
|
// Find changed fields
|
||||||
|
let mut diffs = vec![];
|
||||||
|
for (key, old_value) in old_json.iter() {
|
||||||
|
let new_value = new_json.get(key).unwrap();
|
||||||
|
if old_value != new_value {
|
||||||
|
if matches!(
|
||||||
|
new_value,
|
||||||
|
&Value::Null | &Value::Object(_) | &Value::Array(_)
|
||||||
|
) {
|
||||||
|
unimplemented!("We only support updating basic values at the top level");
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_json = serde_json::to_string_pretty(new_value)
|
||||||
|
.expect("Could not serialize new json field to string");
|
||||||
|
|
||||||
|
diffs.push((key, new_json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_text = old_text;
|
||||||
|
for (key, new_value) in diffs {
|
||||||
|
new_text = write_settings_key(new_text, key, &new_value)
|
||||||
|
}
|
||||||
|
new_text
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json_object(settings_file: SettingsFileContent) -> serde_json::Map<String, Value> {
|
||||||
|
let tmp = serde_json::to_value(settings_file).unwrap();
|
||||||
|
match tmp {
|
||||||
|
Value::Object(map) => map,
|
||||||
|
_ => unreachable!("SettingsFileContent represents a JSON map"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::write_top_level_setting;
|
use super::*;
|
||||||
use unindent::Unindent;
|
use unindent::Unindent;
|
||||||
|
|
||||||
|
fn assert_new_settings<S1: Into<String>, S2: Into<String>>(
|
||||||
|
old_json: S1,
|
||||||
|
update: fn(&mut SettingsFileContent),
|
||||||
|
expected_new_json: S2,
|
||||||
|
) {
|
||||||
|
let old_json = old_json.into();
|
||||||
|
let old_content: SettingsFileContent = serde_json::from_str(&old_json).unwrap();
|
||||||
|
let new_json = update_settings_file(old_json, old_content, update);
|
||||||
|
assert_eq!(new_json, expected_new_json.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_telemetry_setting_multiple_fields() {
|
||||||
|
assert_new_settings(
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"metrics": false,
|
||||||
|
"diagnostics": false
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
|settings| {
|
||||||
|
settings.telemetry.set_diagnostics(true);
|
||||||
|
settings.telemetry.set_metrics(true);
|
||||||
|
},
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"metrics": true,
|
||||||
|
"diagnostics": true
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_telemetry_setting_weird_formatting() {
|
||||||
|
assert_new_settings(
|
||||||
|
r#"{
|
||||||
|
"telemetry": { "metrics": false, "diagnostics": true }
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
|settings| settings.telemetry.set_diagnostics(false),
|
||||||
|
r#"{
|
||||||
|
"telemetry": { "metrics": false, "diagnostics": false }
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_telemetry_setting_other_fields() {
|
||||||
|
assert_new_settings(
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"metrics": false,
|
||||||
|
"diagnostics": true
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
|settings| settings.telemetry.set_diagnostics(false),
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"metrics": false,
|
||||||
|
"diagnostics": false
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_telemetry_setting_pre_existing() {
|
||||||
|
assert_new_settings(
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"diagnostics": true
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
|settings| settings.telemetry.set_diagnostics(false),
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"diagnostics": false
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_telemetry_setting() {
|
||||||
|
assert_new_settings(
|
||||||
|
"{}",
|
||||||
|
|settings| settings.telemetry.set_diagnostics(true),
|
||||||
|
r#"{
|
||||||
|
"telemetry": {
|
||||||
|
"diagnostics": true
|
||||||
|
}
|
||||||
|
}"#
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_write_theme_into_settings_with_theme() {
|
fn test_write_theme_into_settings_with_theme() {
|
||||||
let settings = r#"
|
let settings = r#"
|
||||||
|
@ -807,8 +965,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
@ -828,8 +985,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
@ -845,8 +1001,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
@ -856,8 +1011,7 @@ mod tests {
|
||||||
let settings = r#"{ "a": "", "ok": true }"#.to_string();
|
let settings = r#"{ "a": "", "ok": true }"#.to_string();
|
||||||
let new_settings = r#"{ "theme": "summerfruit-light", "a": "", "ok": true }"#;
|
let new_settings = r#"{ "theme": "summerfruit-light", "a": "", "ok": true }"#;
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
@ -867,8 +1021,7 @@ mod tests {
|
||||||
let settings = r#" { "a": "", "ok": true }"#.to_string();
|
let settings = r#" { "a": "", "ok": true }"#.to_string();
|
||||||
let new_settings = r#" { "theme": "summerfruit-light", "a": "", "ok": true }"#;
|
let new_settings = r#" { "theme": "summerfruit-light", "a": "", "ok": true }"#;
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
@ -890,8 +1043,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
let settings_after_theme =
|
let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\"");
|
||||||
write_top_level_setting(settings, "theme", "\"summerfruit-light\"");
|
|
||||||
|
|
||||||
assert_eq!(settings_after_theme, new_settings)
|
assert_eq!(settings_after_theme, new_settings)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use crate::{watched_json::WatchedJsonFile, write_top_level_setting, SettingsFileContent};
|
use crate::{update_settings_file, watched_json::WatchedJsonFile, SettingsFileContent};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use gpui::MutableAppContext;
|
use gpui::MutableAppContext;
|
||||||
use serde_json::Value;
|
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
// TODO: Switch SettingsFile to open a worktree and buffer for synchronization
|
// TODO: Switch SettingsFile to open a worktree and buffer for synchronization
|
||||||
|
@ -27,57 +26,24 @@ impl SettingsFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(cx: &mut MutableAppContext, update: impl FnOnce(&mut SettingsFileContent)) {
|
pub fn update(
|
||||||
|
cx: &mut MutableAppContext,
|
||||||
|
update: impl 'static + Send + FnOnce(&mut SettingsFileContent),
|
||||||
|
) {
|
||||||
let this = cx.global::<SettingsFile>();
|
let this = cx.global::<SettingsFile>();
|
||||||
|
|
||||||
let current_file_content = this.settings_file_content.current();
|
let current_file_content = this.settings_file_content.current();
|
||||||
let mut new_file_content = current_file_content.clone();
|
|
||||||
|
|
||||||
update(&mut new_file_content);
|
|
||||||
|
|
||||||
let fs = this.fs.clone();
|
let fs = this.fs.clone();
|
||||||
let path = this.path.clone();
|
let path = this.path.clone();
|
||||||
|
|
||||||
cx.background()
|
cx.background()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
// Unwrap safety: These values are all guarnteed to be well formed, and we know
|
let old_text = fs.load(path).await?;
|
||||||
// that they will deserialize to our settings object. All of the following unwraps
|
|
||||||
// are therefore safe.
|
|
||||||
let tmp = serde_json::to_value(current_file_content).unwrap();
|
|
||||||
let old_json = tmp.as_object().unwrap();
|
|
||||||
|
|
||||||
let new_tmp = serde_json::to_value(new_file_content).unwrap();
|
let new_text = update_settings_file(old_text, current_file_content, update);
|
||||||
let new_json = new_tmp.as_object().unwrap();
|
|
||||||
|
|
||||||
// Find changed fields
|
fs.atomic_write(path.to_path_buf(), new_text).await?;
|
||||||
let mut diffs = vec![];
|
|
||||||
for (key, old_value) in old_json.iter() {
|
|
||||||
let new_value = new_json.get(key).unwrap();
|
|
||||||
if old_value != new_value {
|
|
||||||
if matches!(
|
|
||||||
new_value,
|
|
||||||
&Value::Null | &Value::Object(_) | &Value::Array(_)
|
|
||||||
) {
|
|
||||||
unimplemented!(
|
|
||||||
"We only support updating basic values at the top level"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_json = serde_json::to_string_pretty(new_value)
|
|
||||||
.expect("Could not serialize new json field to string");
|
|
||||||
|
|
||||||
diffs.push((key, new_json));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Have diffs, rewrite the settings file now.
|
|
||||||
let mut content = fs.load(path).await?;
|
|
||||||
|
|
||||||
for (key, new_value) in diffs {
|
|
||||||
content = write_top_level_setting(content, key, &new_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.atomic_write(path.to_path_buf(), content).await?;
|
|
||||||
|
|
||||||
Ok(()) as Result<()>
|
Ok(()) as Result<()>
|
||||||
})
|
})
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub struct Theme {
|
||||||
pub tooltip: TooltipStyle,
|
pub tooltip: TooltipStyle,
|
||||||
pub terminal: TerminalStyle,
|
pub terminal: TerminalStyle,
|
||||||
pub feedback: FeedbackStyle,
|
pub feedback: FeedbackStyle,
|
||||||
|
pub welcome: WelcomeStyle,
|
||||||
pub color_scheme: ColorScheme,
|
pub color_scheme: ColorScheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,6 +851,20 @@ pub struct FeedbackStyle {
|
||||||
pub link_text_hover: ContainedText,
|
pub link_text_hover: ContainedText,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
pub struct WelcomeStyle {
|
||||||
|
pub checkbox: CheckboxStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
pub struct CheckboxStyle {
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
|
pub unchecked: ContainerStyle,
|
||||||
|
pub checked: ContainerStyle,
|
||||||
|
pub hovered: ContainerStyle,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Default)]
|
#[derive(Clone, Deserialize, Default)]
|
||||||
pub struct ColorScheme {
|
pub struct ColorScheme {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
@ -13,6 +13,7 @@ test-support = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
editor = { path = "../editor" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
project = { path = "../project" }
|
project = { path = "../project" }
|
||||||
settings = { path = "../settings" }
|
settings = { path = "../settings" }
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
elements::{Flex, Label, ParentElement, Svg},
|
elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg},
|
||||||
Element, Entity, MutableAppContext, View,
|
Element, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext,
|
||||||
};
|
};
|
||||||
use settings::Settings;
|
use settings::{settings_file::SettingsFile, Settings, SettingsFileContent};
|
||||||
|
use theme::CheckboxStyle;
|
||||||
use workspace::{item::Item, Welcome, Workspace};
|
use workspace::{item::Item, Welcome, Workspace};
|
||||||
|
|
||||||
pub fn init(cx: &mut MutableAppContext) {
|
pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| {
|
cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| {
|
||||||
let welcome_page = cx.add_view(|_cx| WelcomePage);
|
let welcome_page = cx.add_view(WelcomePage::new);
|
||||||
workspace.add_item(Box::new(welcome_page), cx)
|
workspace.add_item(Box::new(welcome_page), cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WelcomePage;
|
struct WelcomePage {
|
||||||
|
_settings_subscription: Subscription,
|
||||||
|
}
|
||||||
|
|
||||||
impl Entity for WelcomePage {
|
impl Entity for WelcomePage {
|
||||||
type Event = ();
|
type Event = ();
|
||||||
|
@ -24,12 +27,21 @@ impl View for WelcomePage {
|
||||||
"WelcomePage"
|
"WelcomePage"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
|
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
|
||||||
let theme = &cx.global::<Settings>().theme;
|
let settings = cx.global::<Settings>();
|
||||||
|
let theme = settings.theme.clone();
|
||||||
|
|
||||||
Flex::new(gpui::Axis::Vertical)
|
let (diagnostics, metrics) = {
|
||||||
|
let telemetry = settings.telemetry();
|
||||||
|
(telemetry.diagnostics(), telemetry.metrics())
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Metrics {}
|
||||||
|
enum Diagnostics {}
|
||||||
|
|
||||||
|
Flex::column()
|
||||||
.with_children([
|
.with_children([
|
||||||
Flex::new(gpui::Axis::Horizontal)
|
Flex::row()
|
||||||
.with_children([
|
.with_children([
|
||||||
Svg::new("icons/terminal_16.svg")
|
Svg::new("icons/terminal_16.svg")
|
||||||
.with_color(Color::red())
|
.with_color(Color::red())
|
||||||
|
@ -47,11 +59,88 @@ impl View for WelcomePage {
|
||||||
theme.editor.hover_popover.prose.clone(),
|
theme.editor.hover_popover.prose.clone(),
|
||||||
)
|
)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
Flex::row()
|
||||||
|
.with_children([
|
||||||
|
self.render_settings_checkbox::<Metrics>(
|
||||||
|
&theme.welcome.checkbox,
|
||||||
|
metrics,
|
||||||
|
cx,
|
||||||
|
|content, checked| {
|
||||||
|
content.telemetry.set_metrics(checked);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Label::new(
|
||||||
|
"Do you want to send telemetry?",
|
||||||
|
theme.editor.hover_popover.prose.clone(),
|
||||||
|
)
|
||||||
|
.boxed(),
|
||||||
|
])
|
||||||
|
.boxed(),
|
||||||
|
Flex::row()
|
||||||
|
.with_children([
|
||||||
|
self.render_settings_checkbox::<Diagnostics>(
|
||||||
|
&theme.welcome.checkbox,
|
||||||
|
diagnostics,
|
||||||
|
cx,
|
||||||
|
|content, checked| content.telemetry.set_diagnostics(checked),
|
||||||
|
),
|
||||||
|
Label::new(
|
||||||
|
"Send crash reports",
|
||||||
|
theme.editor.hover_popover.prose.clone(),
|
||||||
|
)
|
||||||
|
.boxed(),
|
||||||
|
])
|
||||||
|
.boxed(),
|
||||||
])
|
])
|
||||||
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WelcomePage {
|
||||||
|
fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
|
let handle = cx.weak_handle();
|
||||||
|
|
||||||
|
let settings_subscription = cx.observe_global::<Settings, _>(move |cx| {
|
||||||
|
if let Some(handle) = handle.upgrade(cx) {
|
||||||
|
handle.update(cx, |_, cx| cx.notify())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
WelcomePage {
|
||||||
|
_settings_subscription: settings_subscription,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_settings_checkbox<T: 'static>(
|
||||||
|
&self,
|
||||||
|
style: &CheckboxStyle,
|
||||||
|
checked: bool,
|
||||||
|
cx: &mut RenderContext<Self>,
|
||||||
|
set_value: fn(&mut SettingsFileContent, checked: bool) -> (),
|
||||||
|
) -> ElementBox {
|
||||||
|
MouseEventHandler::<T>::new(0, cx, |state, _| {
|
||||||
|
Empty::new()
|
||||||
|
.constrained()
|
||||||
|
.with_width(style.width)
|
||||||
|
.with_height(style.height)
|
||||||
|
.contained()
|
||||||
|
.with_style(if checked {
|
||||||
|
style.checked
|
||||||
|
} else if state.hovered() {
|
||||||
|
style.hovered
|
||||||
|
} else {
|
||||||
|
style.unchecked
|
||||||
|
})
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.on_click(gpui::MouseButton::Left, move |_, cx| {
|
||||||
|
SettingsFile::update(cx, move |content| set_value(content, !checked))
|
||||||
|
})
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Item for WelcomePage {
|
impl Item for WelcomePage {
|
||||||
fn tab_content(
|
fn tab_content(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import contactList from "./contactList"
|
||||||
import incomingCallNotification from "./incomingCallNotification"
|
import incomingCallNotification from "./incomingCallNotification"
|
||||||
import { ColorScheme } from "../themes/common/colorScheme"
|
import { ColorScheme } from "../themes/common/colorScheme"
|
||||||
import feedback from "./feedback"
|
import feedback from "./feedback"
|
||||||
|
import welcome from "./welcome"
|
||||||
|
|
||||||
export default function app(colorScheme: ColorScheme): Object {
|
export default function app(colorScheme: ColorScheme): Object {
|
||||||
return {
|
return {
|
||||||
|
@ -33,6 +34,7 @@ export default function app(colorScheme: ColorScheme): Object {
|
||||||
incomingCallNotification: incomingCallNotification(colorScheme),
|
incomingCallNotification: incomingCallNotification(colorScheme),
|
||||||
picker: picker(colorScheme),
|
picker: picker(colorScheme),
|
||||||
workspace: workspace(colorScheme),
|
workspace: workspace(colorScheme),
|
||||||
|
welcome: welcome(colorScheme),
|
||||||
contextMenu: contextMenu(colorScheme),
|
contextMenu: contextMenu(colorScheme),
|
||||||
editor: editor(colorScheme),
|
editor: editor(colorScheme),
|
||||||
projectDiagnostics: projectDiagnostics(colorScheme),
|
projectDiagnostics: projectDiagnostics(colorScheme),
|
||||||
|
|
34
styles/src/styleTree/welcome.ts
Normal file
34
styles/src/styleTree/welcome.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
import { ColorScheme } from "../themes/common/colorScheme";
|
||||||
|
import { border } from "./components";
|
||||||
|
|
||||||
|
export default function welcome(colorScheme: ColorScheme) {
|
||||||
|
let layer = colorScheme.highest;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
let checkbox_base = {
|
||||||
|
background: colorScheme.ramps.red(0.5).hex(),
|
||||||
|
cornerRadius: 8,
|
||||||
|
padding: {
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
top: 4,
|
||||||
|
bottom: 4,
|
||||||
|
},
|
||||||
|
shadow: colorScheme.popoverShadow,
|
||||||
|
border: border(layer),
|
||||||
|
margin: {
|
||||||
|
left: -8,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
checkbox: {
|
||||||
|
width: 9,
|
||||||
|
height: 9,
|
||||||
|
unchecked: checkbox_base,
|
||||||
|
checked: checkbox_base,
|
||||||
|
hovered: checkbox_base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue