From b923f65a63c2536e66e82c90dd1aa65956fdfbc0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 25 Aug 2021 15:22:14 -0700 Subject: [PATCH] WIP --- Cargo.lock | 10 ++++ zed/Cargo.toml | 1 + zed/assets/themes/_base.toml | 6 +++ zed/src/channel.rs | 10 +++- zed/src/chat_panel.rs | 93 ++++++++++++++++++++++++++++++------ zed/src/theme.rs | 10 ++-- zed/src/theme_selector.rs | 1 + zed/src/workspace.rs | 4 +- 8 files changed, 114 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec4cfc74fe..9da817877e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5142,6 +5142,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "time" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0a10c9a9fb3a5dce8c2239ed670f1a2569fcf42da035f5face1b19860d52b0" +dependencies = [ + "libc", +] + [[package]] name = "time-macros" version = "0.1.1" @@ -5832,6 +5841,7 @@ dependencies = [ "smol", "surf", "tempdir", + "time 0.3.2", "tiny_http", "toml 0.5.8", "tree-sitter", diff --git a/zed/Cargo.toml b/zed/Cargo.toml index 13bc411e3b..a9cdb77675 100644 --- a/zed/Cargo.toml +++ b/zed/Cargo.toml @@ -48,6 +48,7 @@ smallvec = { version = "1.6", features = ["union"] } smol = "1.2.5" surf = "2.2" tempdir = { version = "0.3.7", optional = true } +time = { version = "0.3", features = ["local-offset"] } tiny_http = "0.8" toml = "0.5" tree-sitter = "0.19.5" diff --git a/zed/assets/themes/_base.toml b/zed/assets/themes/_base.toml index 6fed76f81a..fbd31f4d97 100644 --- a/zed/assets/themes/_base.toml +++ b/zed/assets/themes/_base.toml @@ -22,8 +22,14 @@ color = "$text.2" [workspace.active_sidebar_icon] color = "$text.0" +[chat_panel] +padding = { top = 10.0, bottom = 10.0, left = 10.0, right = 10.0 } + [chat_panel.message] body = "$text.0" +sender.margin.right = 10.0 +sender.text = { color = "#ff0000", weight = "bold", italic = true } +timestamp.text = "$text.2" [selector] background = "$surface.2" diff --git a/zed/src/channel.rs b/zed/src/channel.rs index 73eb015884..37d75a4c91 100644 --- a/zed/src/channel.rs +++ b/zed/src/channel.rs @@ -14,6 +14,7 @@ use std::{ ops::Range, sync::Arc, }; +use time::OffsetDateTime; use zrpc::{ proto::{self, ChannelMessageSent}, TypedEnvelope, @@ -47,6 +48,7 @@ pub struct Channel { pub struct ChannelMessage { pub id: u64, pub body: String, + pub timestamp: OffsetDateTime, pub sender: Arc, } @@ -261,14 +263,17 @@ impl Channel { this.insert_message( ChannelMessage { id: response.message_id, + timestamp: OffsetDateTime::from_unix_timestamp( + response.timestamp as i64, + )?, body, sender, }, cx, ); } - }); - Ok(()) + Ok(()) + }) } .log_err() }) @@ -363,6 +368,7 @@ impl ChannelMessage { Ok(ChannelMessage { id: message.id, body: message.body, + timestamp: OffsetDateTime::from_unix_timestamp(message.timestamp as i64)?, sender, }) } diff --git a/zed/src/chat_panel.rs b/zed/src/chat_panel.rs index 0c4fbd584f..582c5b436a 100644 --- a/zed/src/chat_panel.rs +++ b/zed/src/chat_panel.rs @@ -9,6 +9,7 @@ use gpui::{ Subscription, View, ViewContext, ViewHandle, }; use postage::watch; +use time::{OffsetDateTime, UtcOffset}; pub struct ChatPanel { channel_list: ModelHandle, @@ -75,12 +76,13 @@ impl ChatPanel { fn set_active_channel(&mut self, channel: ModelHandle, cx: &mut ViewContext) { if self.active_channel.as_ref().map(|e| &e.0) != Some(&channel) { let subscription = cx.subscribe(&channel, Self::channel_did_change); + let now = OffsetDateTime::now_utc(); self.messages = ListState::new( channel .read(cx) .messages() .cursor::<(), ()>() - .map(|m| self.render_message(m)) + .map(|m| self.render_message(m, now)) .collect(), Orientation::Bottom, ); @@ -99,12 +101,13 @@ impl ChatPanel { old_range, new_count, } => { + let now = OffsetDateTime::now_utc(); self.messages.splice( old_range.clone(), channel .read(cx) .messages_in_range(old_range.start..(old_range.start + new_count)) - .map(|message| self.render_message(message)), + .map(|message| self.render_message(message, now)), ); } } @@ -115,15 +118,50 @@ impl ChatPanel { Expanded::new(1., List::new(self.messages.clone()).boxed()).boxed() } - fn render_message(&self, message: &ChannelMessage) -> ElementBox { + fn render_message(&self, message: &ChannelMessage, now: OffsetDateTime) -> ElementBox { let settings = self.settings.borrow(); - Text::new( - message.body.clone(), - settings.ui_font_family, - settings.ui_font_size, - ) - .with_style(&settings.theme.chat_panel.message.body) - .boxed() + let theme = &settings.theme.chat_panel.message; + Flex::column() + .with_child( + Flex::row() + .with_child( + Container::new( + Label::new( + message.sender.github_login.clone(), + settings.ui_font_family, + settings.ui_font_size, + ) + .with_style(&theme.sender.label) + .boxed(), + ) + .with_style(&theme.sender.container) + .boxed(), + ) + .with_child( + Container::new( + Label::new( + format_timestamp(message.timestamp, now), + settings.ui_font_family, + settings.ui_font_size, + ) + .with_style(&theme.timestamp.label) + .boxed(), + ) + .with_style(&theme.timestamp.container) + .boxed(), + ) + .boxed(), + ) + .with_child( + Text::new( + message.body.clone(), + settings.ui_font_family, + settings.ui_font_size, + ) + .with_style(&theme.body) + .boxed(), + ) + .boxed() } fn render_input_box(&self) -> ElementBox { @@ -157,9 +195,36 @@ impl View for ChatPanel { } fn render(&self, _: &RenderContext) -> ElementBox { - Flex::column() - .with_child(self.render_active_channel_messages()) - .with_child(self.render_input_box()) - .boxed() + let theme = &self.settings.borrow().theme; + Container::new( + Flex::column() + .with_child(self.render_active_channel_messages()) + .with_child(self.render_input_box()) + .boxed(), + ) + .with_style(&theme.chat_panel.container) + .boxed() + } +} + +fn format_timestamp(mut timestamp: OffsetDateTime, mut now: OffsetDateTime) -> String { + let local_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC); + timestamp = timestamp.to_offset(local_offset); + now = now.to_offset(local_offset); + + let today = now.date(); + let date = timestamp.date(); + let mut hour = timestamp.hour(); + let mut part = "am"; + if hour > 12 { + hour -= 12; + part = "pm"; + } + if date == today { + format!("{}:{}{}", hour, timestamp.minute(), part) + } else if date.next_day() == Some(today) { + format!("yesterday at {}:{}{}", hour, timestamp.minute(), part) + } else { + format!("{}/{}/{}", date.month(), date.day(), date.year()) } } diff --git a/zed/src/theme.rs b/zed/src/theme.rs index 13fa534211..3a8430c4be 100644 --- a/zed/src/theme.rs +++ b/zed/src/theme.rs @@ -55,12 +55,16 @@ pub struct SidebarIcon { #[derive(Debug, Default, Deserialize)] pub struct ChatPanel { + #[serde(flatten)] + pub container: ContainerStyle, pub message: ChatMessage, } #[derive(Debug, Default, Deserialize)] pub struct ChatMessage { pub body: TextStyle, + pub sender: ContainedLabel, + pub timestamp: ContainedLabel, } #[derive(Debug, Default, Deserialize)] @@ -70,12 +74,12 @@ pub struct Selector { #[serde(flatten)] pub label: LabelStyle, - pub item: SelectorItem, - pub active_item: SelectorItem, + pub item: ContainedLabel, + pub active_item: ContainedLabel, } #[derive(Debug, Default, Deserialize)] -pub struct SelectorItem { +pub struct ContainedLabel { #[serde(flatten)] pub container: ContainerStyle, #[serde(flatten)] diff --git a/zed/src/theme_selector.rs b/zed/src/theme_selector.rs index eb062899c1..5dc3ae448a 100644 --- a/zed/src/theme_selector.rs +++ b/zed/src/theme_selector.rs @@ -99,6 +99,7 @@ impl ThemeSelector { Ok(theme) => { cx.notify_all(); action.0.settings_tx.lock().borrow_mut().theme = theme; + log::info!("reloaded theme {}", current_theme_name); } Err(error) => { log::error!("failed to load theme {}: {:?}", current_theme_name, error) diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 4013b068a3..e037460891 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -958,7 +958,7 @@ impl View for Workspace { if let Some(panel) = self.left_sidebar.active_item() { content.add_child( ConstrainedBox::new(ChildView::new(panel.id()).boxed()) - .with_width(200.0) + .with_width(300.0) .named("left panel"), ); } @@ -966,7 +966,7 @@ impl View for Workspace { if let Some(panel) = self.right_sidebar.active_item() { content.add_child( ConstrainedBox::new(ChildView::new(panel.id()).boxed()) - .with_width(200.0) + .with_width(300.0) .named("right panel"), ); }