diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index 8bcfad68b3b2eceb8db69f2ec9863c94eb9f5b67..c6f32cecd271fea3e61101c4cc0d8104ad2329d3 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Result}; +use call::ActiveCall; use channel::{ChannelBuffer, ChannelBufferEvent, ChannelId}; use client::proto; use clock::ReplicaId; @@ -35,6 +36,30 @@ pub struct ChannelView { } impl ChannelView { + pub fn deploy(channel_id: ChannelId, workspace: ViewHandle, cx: &mut AppContext) { + let pane = workspace.read(cx).active_pane().clone(); + let channel_view = Self::open(channel_id, pane.clone(), workspace.clone(), cx); + cx.spawn(|mut cx| async move { + let channel_view = channel_view.await?; + pane.update(&mut cx, |pane, cx| { + let room_id = ActiveCall::global(cx) + .read(cx) + .room() + .map(|room| room.read(cx).id()); + ActiveCall::report_call_event_for_room( + "open channel notes", + room_id, + Some(channel_id), + &workspace.read(cx).app_state().client, + cx, + ); + pane.add_item(Box::new(channel_view), true, true, None, cx); + }); + anyhow::Ok(()) + }) + .detach(); + } + pub fn open( channel_id: ChannelId, pane: ViewHandle, diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index afd293422f59ce205438a88d927a7b09033d0342..8e4148bd9baa3f99537868f6dbfe755e402228f7 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -1,5 +1,6 @@ -use crate::ChatPanelSettings; +use crate::{channel_view::ChannelView, ChatPanelSettings}; use anyhow::Result; +use call::ActiveCall; use channel::{ChannelChat, ChannelChatEvent, ChannelMessageId, ChannelStore}; use client::Client; use db::kvp::KEY_VALUE_STORE; @@ -80,8 +81,11 @@ impl ChatPanel { editor }); + let workspace_handle = workspace.weak_handle(); + let channel_select = cx.add_view(|cx| { let channel_store = channel_store.clone(); + let workspace = workspace_handle.clone(); Select::new(0, cx, { move |ix, item_type, is_hovered, cx| { Self::render_channel_name( @@ -89,7 +93,8 @@ impl ChatPanel { ix, item_type, is_hovered, - &theme::current(cx).chat_panel.channel_select, + &theme::current(cx).chat_panel, + workspace, cx, ) } @@ -334,7 +339,7 @@ impl ChatPanel { cx, |mouse_state, _| { let button_style = - theme.collab_panel.contact_button.style_for(mouse_state); + theme.chat_panel.icon_button.style_for(mouse_state); render_icon_button(button_style, "icons/x.svg") .aligned() .into_any() @@ -366,28 +371,62 @@ impl ChatPanel { ix: usize, item_type: ItemType, is_hovered: bool, - theme: &theme::ChannelSelect, - cx: &AppContext, + theme: &theme::ChatPanel, + workspace: WeakViewHandle, + cx: &mut ViewContext { + enum ChannelNotes {} + enum JoinCall {} + let channel = &channel_store.read(cx).channel_at_index(ix).unwrap().1; - let theme = match (item_type, is_hovered) { - (ItemType::Header, _) => &theme.header, - (ItemType::Selected, false) => &theme.active_item, - (ItemType::Selected, true) => &theme.hovered_active_item, - (ItemType::Unselected, false) => &theme.item, - (ItemType::Unselected, true) => &theme.hovered_item, + let channel_id = channel.id; + let style = &theme.channel_select; + let style = match (&item_type, is_hovered) { + (ItemType::Header, _) => &style.header, + (ItemType::Selected, _) => &style.active_item, + (ItemType::Unselected, false) => &style.item, + (ItemType::Unselected, true) => &style.hovered_item, }; - Flex::row() + let mut row = Flex::row() .with_child( - Label::new("#".to_string(), theme.hash.text.clone()) + Label::new("#".to_string(), style.hash.text.clone()) .contained() - .with_style(theme.hash.container), + .with_style(style.hash.container), ) - .with_child(Label::new(channel.name.clone(), theme.name.clone())) - .aligned() - .left() + .with_child(Label::new(channel.name.clone(), style.name.clone())); + + if matches!(item_type, ItemType::Header) { + row.add_children([ + MouseEventHandler::new::(0, cx, |mouse_state, _| { + render_icon_button( + theme.icon_button.style_for(mouse_state), + "icons/radix/file.svg", + ) + }) + .on_click(MouseButton::Left, move |_, _, cx| { + if let Some(workspace) = workspace.upgrade(cx) { + ChannelView::deploy(channel_id, workspace, cx); + } + }) + .flex_float(), + MouseEventHandler::new::(0, cx, |mouse_state, _| { + render_icon_button( + theme.icon_button.style_for(mouse_state), + "icons/radix/speaker-loud.svg", + ) + }) + .on_click(MouseButton::Left, move |_, _, cx| { + ActiveCall::global(cx) + .update(cx, |call, cx| call.join_channel(channel_id, cx)) + .detach_and_log_err(cx); + }) + .flex_float(), + ]); + } + + row.align_children_center() .contained() - .with_style(theme.container) + .with_style(style.container) .into_any() } @@ -511,6 +550,7 @@ impl View for ChatPanel { } fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + self.has_focus = true; if matches!( *self.client.status().borrow(), client::Status::Connected { .. } @@ -518,6 +558,10 @@ impl View for ChatPanel { cx.focus(&self.input_editor); } } + + fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) { + self.has_focus = false; + } } impl Panel for ChatPanel { @@ -594,7 +638,7 @@ fn format_timestamp( } } -fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { +fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { Svg::new(svg_path) .with_color(style.color) .constrained() diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index ad1c2a0037176615ca6911df5db6e5eec1a26ae2..437eaad3fed05ceff753d9f7880070c8cb5107d0 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -2252,29 +2252,7 @@ impl CollabPanel { fn open_channel_notes(&mut self, action: &OpenChannelNotes, cx: &mut ViewContext) { if let Some(workspace) = self.workspace.upgrade(cx) { - let pane = workspace.read(cx).active_pane().clone(); - let channel_id = action.channel_id; - let channel_view = ChannelView::open(channel_id, pane.clone(), workspace, cx); - cx.spawn(|_, mut cx| async move { - let channel_view = channel_view.await?; - pane.update(&mut cx, |pane, cx| { - pane.add_item(Box::new(channel_view), true, true, None, cx) - }); - anyhow::Ok(()) - }) - .detach(); - let room_id = ActiveCall::global(cx) - .read(cx) - .room() - .map(|room| room.read(cx).id()); - - ActiveCall::report_call_event_for_room( - "open channel notes", - room_id, - Some(channel_id), - &self.client, - cx, - ); + ChannelView::deploy(action.channel_id, workspace, cx); } } @@ -2436,8 +2414,6 @@ impl CollabPanel { } fn join_channel_chat(&mut self, channel_id: u64, cx: &mut ViewContext) { - self.open_channel_notes(&OpenChannelNotes { channel_id }, cx); - if let Some(workspace) = self.workspace.upgrade(cx) { cx.app_context().defer(move |cx| { workspace.update(cx, |workspace, cx| { diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index 0d57630c244d2e112158c9c9468b76cbb4e5eaa9..bad65ccfc8e0d9bf583847ac12058d3e08ad2865 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -6,7 +6,7 @@ use crate::{ pub struct Select { handle: WeakViewHandle, - render_item: Box AnyElement>, + render_item: Box) -> AnyElement>, selected_item_ix: usize, item_count: usize, is_open: bool, @@ -29,7 +29,9 @@ pub enum ItemType { pub enum Event {} impl Select { - pub fn new AnyElement>( + pub fn new< + F: 'static + Fn(usize, ItemType, bool, &mut ViewContext) -> AnyElement, + >( item_count: usize, cx: &mut ViewContext, render_item: F, diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 613c88d5cc8ae174a02531aa3210345107b965c7..5ea5ce877829e2c3dae5f622b08ec35e0c283e34 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -635,6 +635,7 @@ pub struct ChatPanel { pub message: ChatMessage, pub pending_message: ChatMessage, pub sign_in_prompt: Interactive, + pub icon_button: Interactive, } #[derive(Deserialize, Default, JsonSchema)] @@ -654,7 +655,6 @@ pub struct ChannelSelect { pub item: ChannelName, pub active_item: ChannelName, pub hovered_item: ChannelName, - pub hovered_active_item: ChannelName, pub menu: ContainerStyle, } diff --git a/styles/src/style_tree/chat_panel.ts b/styles/src/style_tree/chat_panel.ts index d0e5d3c2499a376a7df98cf7bf6c54b48c4a195b..9efa0844569103036c6b19de7a71f3708bdd8cc2 100644 --- a/styles/src/style_tree/chat_panel.ts +++ b/styles/src/style_tree/chat_panel.ts @@ -3,6 +3,7 @@ import { border, text, } from "./components" +import { icon_button } from "../component/icon_button" import { useTheme } from "../theme" export default function chat_panel(): any { @@ -46,15 +47,16 @@ export default function chat_panel(): any { ...channel_name, background: background(layer, "on", "hovered"), }, - hovered_active_item: { - ...channel_name, - background: background(layer, "on", "active"), - }, menu: { background: background(layer, "on"), border: border(layer, { bottom: true }) } }, + icon_button: icon_button({ + variant: "ghost", + color: "variant", + size: "sm", + }), input_editor: { background: background(layer, "on"), corner_radius: 6,