// use crate::{
//     channel_view::ChannelView, is_channels_feature_enabled, render_avatar, ChatPanelSettings,
// };
// use anyhow::Result;
// use call::ActiveCall;
// use channel::{ChannelChat, ChannelChatEvent, ChannelMessageId, ChannelStore};
// use client::Client;
// use collections::HashMap;
// use db::kvp::KEY_VALUE_STORE;
// use editor::Editor;
// use gpui::{
//     actions,
//     elements::*,
//     platform::{CursorStyle, MouseButton},
//     serde_json,
//     views::{ItemType, Select, SelectStyle},
//     AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelHandle, Subscription, Task, View,
//     ViewContext, ViewHandle, WeakViewHandle,
// };
// use language::LanguageRegistry;
// use menu::Confirm;
// use message_editor::MessageEditor;
// use project::Fs;
// use rich_text::RichText;
// use serde::{Deserialize, Serialize};
// use settings::SettingsStore;
// use std::sync::Arc;
// use theme::{IconButton, Theme};
// use time::{OffsetDateTime, UtcOffset};
// use util::{ResultExt, TryFutureExt};
// use workspace::{
//     dock::{DockPosition, Panel},
//     Workspace,
// };

// mod message_editor;

// const MESSAGE_LOADING_THRESHOLD: usize = 50;
// const CHAT_PANEL_KEY: &'static str = "ChatPanel";

// pub struct ChatPanel {
//     client: Arc<Client>,
//     channel_store: ModelHandle<ChannelStore>,
//     languages: Arc<LanguageRegistry>,
//     active_chat: Option<(ModelHandle<ChannelChat>, Subscription)>,
//     message_list: ListState<ChatPanel>,
//     input_editor: ViewHandle<MessageEditor>,
//     channel_select: ViewHandle<Select>,
//     local_timezone: UtcOffset,
//     fs: Arc<dyn Fs>,
//     width: Option<f32>,
//     active: bool,
//     pending_serialization: Task<Option<()>>,
//     subscriptions: Vec<gpui::Subscription>,
//     workspace: WeakViewHandle<Workspace>,
//     is_scrolled_to_bottom: bool,
//     has_focus: bool,
//     markdown_data: HashMap<ChannelMessageId, RichText>,
// }

// #[derive(Serialize, Deserialize)]
// struct SerializedChatPanel {
//     width: Option<f32>,
// }

// #[derive(Debug)]
// pub enum Event {
//     DockPositionChanged,
//     Focus,
//     Dismissed,
// }

// actions!(
//     chat_panel,
//     [LoadMoreMessages, ToggleFocus, OpenChannelNotes, JoinCall]
// );

// pub fn init(cx: &mut AppContext) {
//     cx.add_action(ChatPanel::send);
//     cx.add_action(ChatPanel::load_more_messages);
//     cx.add_action(ChatPanel::open_notes);
//     cx.add_action(ChatPanel::join_call);
// }

// impl ChatPanel {
//     pub fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> ViewHandle<Self> {
//         let fs = workspace.app_state().fs.clone();
//         let client = workspace.app_state().client.clone();
//         let channel_store = ChannelStore::global(cx);
//         let languages = workspace.app_state().languages.clone();

//         let input_editor = cx.add_view(|cx| {
//             MessageEditor::new(
//                 languages.clone(),
//                 channel_store.clone(),
//                 cx.add_view(|cx| {
//                     Editor::auto_height(
//                         4,
//                         Some(Arc::new(|theme| theme.chat_panel.input_editor.clone())),
//                         cx,
//                     )
//                 }),
//                 cx,
//             )
//         });

//         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(
//                         &channel_store,
//                         ix,
//                         item_type,
//                         is_hovered,
//                         workspace,
//                         cx,
//                     )
//                 }
//             })
//             .with_style(move |cx| {
//                 let style = &theme::current(cx).chat_panel.channel_select;
//                 SelectStyle {
//                     header: Default::default(),
//                     menu: style.menu,
//                 }
//             })
//         });

//         let mut message_list =
//             ListState::<Self>::new(0, Orientation::Bottom, 10., move |this, ix, cx| {
//                 this.render_message(ix, cx)
//             });
//         message_list.set_scroll_handler(|visible_range, count, this, cx| {
//             if visible_range.start < MESSAGE_LOADING_THRESHOLD {
//                 this.load_more_messages(&LoadMoreMessages, cx);
//             }
//             this.is_scrolled_to_bottom = visible_range.end == count;
//         });

//         cx.add_view(|cx| {
//             let mut this = Self {
//                 fs,
//                 client,
//                 channel_store,
//                 languages,
//                 active_chat: Default::default(),
//                 pending_serialization: Task::ready(None),
//                 message_list,
//                 input_editor,
//                 channel_select,
//                 local_timezone: cx.platform().local_timezone(),
//                 has_focus: false,
//                 subscriptions: Vec::new(),
//                 workspace: workspace_handle,
//                 is_scrolled_to_bottom: true,
//                 active: false,
//                 width: None,
//                 markdown_data: Default::default(),
//             };

//             let mut old_dock_position = this.position(cx);
//             this.subscriptions
//                 .push(
//                     cx.observe_global::<SettingsStore, _>(move |this: &mut Self, cx| {
//                         let new_dock_position = this.position(cx);
//                         if new_dock_position != old_dock_position {
//                             old_dock_position = new_dock_position;
//                             cx.emit(Event::DockPositionChanged);
//                         }
//                         cx.notify();
//                     }),
//                 );

//             this.update_channel_count(cx);
//             cx.observe(&this.channel_store, |this, _, cx| {
//                 this.update_channel_count(cx)
//             })
//             .detach();

//             cx.observe(&this.channel_select, |this, channel_select, cx| {
//                 let selected_ix = channel_select.read(cx).selected_index();

//                 let selected_channel_id = this
//                     .channel_store
//                     .read(cx)
//                     .channel_at(selected_ix)
//                     .map(|e| e.id);
//                 if let Some(selected_channel_id) = selected_channel_id {
//                     this.select_channel(selected_channel_id, None, cx)
//                         .detach_and_log_err(cx);
//                 }
//             })
//             .detach();

//             this
//         })
//     }

//     pub fn is_scrolled_to_bottom(&self) -> bool {
//         self.is_scrolled_to_bottom
//     }

//     pub fn active_chat(&self) -> Option<ModelHandle<ChannelChat>> {
//         self.active_chat.as_ref().map(|(chat, _)| chat.clone())
//     }

//     pub fn load(
//         workspace: WeakViewHandle<Workspace>,
//         cx: AsyncAppContext,
//     ) -> Task<Result<ViewHandle<Self>>> {
//         cx.spawn(|mut cx| async move {
//             let serialized_panel = if let Some(panel) = cx
//                 .background()
//                 .spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
//                 .await
//                 .log_err()
//                 .flatten()
//             {
//                 Some(serde_json::from_str::<SerializedChatPanel>(&panel)?)
//             } else {
//                 None
//             };

//             workspace.update(&mut cx, |workspace, cx| {
//                 let panel = Self::new(workspace, cx);
//                 if let Some(serialized_panel) = serialized_panel {
//                     panel.update(cx, |panel, cx| {
//                         panel.width = serialized_panel.width;
//                         cx.notify();
//                     });
//                 }
//                 panel
//             })
//         })
//     }

//     fn serialize(&mut self, cx: &mut ViewContext<Self>) {
//         let width = self.width;
//         self.pending_serialization = cx.background().spawn(
//             async move {
//                 KEY_VALUE_STORE
//                     .write_kvp(
//                         CHAT_PANEL_KEY.into(),
//                         serde_json::to_string(&SerializedChatPanel { width })?,
//                     )
//                     .await?;
//                 anyhow::Ok(())
//             }
//             .log_err(),
//         );
//     }

//     fn update_channel_count(&mut self, cx: &mut ViewContext<Self>) {
//         let channel_count = self.channel_store.read(cx).channel_count();
//         self.channel_select.update(cx, |select, cx| {
//             select.set_item_count(channel_count, cx);
//         });
//     }

//     fn set_active_chat(&mut self, chat: ModelHandle<ChannelChat>, cx: &mut ViewContext<Self>) {
//         if self.active_chat.as_ref().map(|e| &e.0) != Some(&chat) {
//             let channel_id = chat.read(cx).channel_id;
//             {
//                 self.markdown_data.clear();
//                 let chat = chat.read(cx);
//                 self.message_list.reset(chat.message_count());

//                 let channel_name = chat.channel(cx).map(|channel| channel.name.clone());
//                 self.input_editor.update(cx, |editor, cx| {
//                     editor.set_channel(channel_id, channel_name, cx);
//                 });
//             };
//             let subscription = cx.subscribe(&chat, Self::channel_did_change);
//             self.active_chat = Some((chat, subscription));
//             self.acknowledge_last_message(cx);
//             self.channel_select.update(cx, |select, cx| {
//                 if let Some(ix) = self.channel_store.read(cx).index_of_channel(channel_id) {
//                     select.set_selected_index(ix, cx);
//                 }
//             });
//             cx.notify();
//         }
//     }

//     fn channel_did_change(
//         &mut self,
//         _: ModelHandle<ChannelChat>,
//         event: &ChannelChatEvent,
//         cx: &mut ViewContext<Self>,
//     ) {
//         match event {
//             ChannelChatEvent::MessagesUpdated {
//                 old_range,
//                 new_count,
//             } => {
//                 self.message_list.splice(old_range.clone(), *new_count);
//                 if self.active {
//                     self.acknowledge_last_message(cx);
//                 }
//             }
//             ChannelChatEvent::NewMessage {
//                 channel_id,
//                 message_id,
//             } => {
//                 if !self.active {
//                     self.channel_store.update(cx, |store, cx| {
//                         store.new_message(*channel_id, *message_id, cx)
//                     })
//                 }
//             }
//         }
//         cx.notify();
//     }

//     fn acknowledge_last_message(&mut self, cx: &mut ViewContext<'_, '_, ChatPanel>) {
//         if self.active && self.is_scrolled_to_bottom {
//             if let Some((chat, _)) = &self.active_chat {
//                 chat.update(cx, |chat, cx| {
//                     chat.acknowledge_last_message(cx);
//                 });
//             }
//         }
//     }

//     fn render_channel(&self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
//         let theme = theme::current(cx);
//         Flex::column()
//             .with_child(
//                 ChildView::new(&self.channel_select, cx)
//                     .contained()
//                     .with_style(theme.chat_panel.channel_select.container),
//             )
//             .with_child(self.render_active_channel_messages(&theme))
//             .with_child(self.render_input_box(&theme, cx))
//             .into_any()
//     }

//     fn render_active_channel_messages(&self, theme: &Arc<Theme>) -> AnyElement<Self> {
//         let messages = if self.active_chat.is_some() {
//             List::new(self.message_list.clone())
//                 .contained()
//                 .with_style(theme.chat_panel.list)
//                 .into_any()
//         } else {
//             Empty::new().into_any()
//         };

//         messages.flex(1., true).into_any()
//     }

//     fn render_message(&mut self, ix: usize, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
//         let (message, is_continuation, is_last, is_admin) = self
//             .active_chat
//             .as_ref()
//             .unwrap()
//             .0
//             .update(cx, |active_chat, cx| {
//                 let is_admin = self
//                     .channel_store
//                     .read(cx)
//                     .is_channel_admin(active_chat.channel_id);

//                 let last_message = active_chat.message(ix.saturating_sub(1));
//                 let this_message = active_chat.message(ix).clone();
//                 let is_continuation = last_message.id != this_message.id
//                     && this_message.sender.id == last_message.sender.id;

//                 if let ChannelMessageId::Saved(id) = this_message.id {
//                     if this_message
//                         .mentions
//                         .iter()
//                         .any(|(_, user_id)| Some(*user_id) == self.client.user_id())
//                     {
//                         active_chat.acknowledge_message(id);
//                     }
//                 }

//                 (
//                     this_message,
//                     is_continuation,
//                     active_chat.message_count() == ix + 1,
//                     is_admin,
//                 )
//             });

//         let is_pending = message.is_pending();
//         let theme = theme::current(cx);
//         let text = self.markdown_data.entry(message.id).or_insert_with(|| {
//             Self::render_markdown_with_mentions(&self.languages, self.client.id(), &message)
//         });

//         let now = OffsetDateTime::now_utc();

//         let style = if is_pending {
//             &theme.chat_panel.pending_message
//         } else if is_continuation {
//             &theme.chat_panel.continuation_message
//         } else {
//             &theme.chat_panel.message
//         };

//         let belongs_to_user = Some(message.sender.id) == self.client.user_id();
//         let message_id_to_remove = if let (ChannelMessageId::Saved(id), true) =
//             (message.id, belongs_to_user || is_admin)
//         {
//             Some(id)
//         } else {
//             None
//         };

//         enum MessageBackgroundHighlight {}
//         MouseEventHandler::new::<MessageBackgroundHighlight, _>(ix, cx, |state, cx| {
//             let container = style.style_for(state);
//             if is_continuation {
//                 Flex::row()
//                     .with_child(
//                         text.element(
//                             theme.editor.syntax.clone(),
//                             theme.chat_panel.rich_text.clone(),
//                             cx,
//                         )
//                         .flex(1., true),
//                     )
//                     .with_child(render_remove(message_id_to_remove, cx, &theme))
//                     .contained()
//                     .with_style(*container)
//                     .with_margin_bottom(if is_last {
//                         theme.chat_panel.last_message_bottom_spacing
//                     } else {
//                         0.
//                     })
//                     .into_any()
//             } else {
//                 Flex::column()
//                     .with_child(
//                         Flex::row()
//                             .with_child(
//                                 Flex::row()
//                                     .with_child(render_avatar(
//                                         message.sender.avatar.clone(),
//                                         &theme.chat_panel.avatar,
//                                         theme.chat_panel.avatar_container,
//                                     ))
//                                     .with_child(
//                                         Label::new(
//                                             message.sender.github_login.clone(),
//                                             theme.chat_panel.message_sender.text.clone(),
//                                         )
//                                         .contained()
//                                         .with_style(theme.chat_panel.message_sender.container),
//                                     )
//                                     .with_child(
//                                         Label::new(
//                                             format_timestamp(
//                                                 message.timestamp,
//                                                 now,
//                                                 self.local_timezone,
//                                             ),
//                                             theme.chat_panel.message_timestamp.text.clone(),
//                                         )
//                                         .contained()
//                                         .with_style(theme.chat_panel.message_timestamp.container),
//                                     )
//                                     .align_children_center()
//                                     .flex(1., true),
//                             )
//                             .with_child(render_remove(message_id_to_remove, cx, &theme))
//                             .align_children_center(),
//                     )
//                     .with_child(
//                         Flex::row()
//                             .with_child(
//                                 text.element(
//                                     theme.editor.syntax.clone(),
//                                     theme.chat_panel.rich_text.clone(),
//                                     cx,
//                                 )
//                                 .flex(1., true),
//                             )
//                             // Add a spacer to make everything line up
//                             .with_child(render_remove(None, cx, &theme)),
//                     )
//                     .contained()
//                     .with_style(*container)
//                     .with_margin_bottom(if is_last {
//                         theme.chat_panel.last_message_bottom_spacing
//                     } else {
//                         0.
//                     })
//                     .into_any()
//             }
//         })
//         .into_any()
//     }

//     fn render_markdown_with_mentions(
//         language_registry: &Arc<LanguageRegistry>,
//         current_user_id: u64,
//         message: &channel::ChannelMessage,
//     ) -> RichText {
//         let mentions = message
//             .mentions
//             .iter()
//             .map(|(range, user_id)| rich_text::Mention {
//                 range: range.clone(),
//                 is_self_mention: *user_id == current_user_id,
//             })
//             .collect::<Vec<_>>();

//         rich_text::render_markdown(message.body.clone(), &mentions, language_registry, None)
//     }

//     fn render_input_box(&self, theme: &Arc<Theme>, cx: &AppContext) -> AnyElement<Self> {
//         ChildView::new(&self.input_editor, cx)
//             .contained()
//             .with_style(theme.chat_panel.input_editor.container)
//             .into_any()
//     }

//     fn render_channel_name(
//         channel_store: &ModelHandle<ChannelStore>,
//         ix: usize,
//         item_type: ItemType,
//         is_hovered: bool,
//         workspace: WeakViewHandle<Workspace>,
//         cx: &mut ViewContext<Select>,
//     ) -> AnyElement<Select> {
//         let theme = theme::current(cx);
//         let tooltip_style = &theme.tooltip;
//         let theme = &theme.chat_panel;
//         let style = match (&item_type, is_hovered) {
//             (ItemType::Header, _) => &theme.channel_select.header,
//             (ItemType::Selected, _) => &theme.channel_select.active_item,
//             (ItemType::Unselected, false) => &theme.channel_select.item,
//             (ItemType::Unselected, true) => &theme.channel_select.hovered_item,
//         };

//         let channel = &channel_store.read(cx).channel_at(ix).unwrap();
//         let channel_id = channel.id;

//         let mut row = Flex::row()
//             .with_child(
//                 Label::new("#".to_string(), style.hash.text.clone())
//                     .contained()
//                     .with_style(style.hash.container),
//             )
//             .with_child(Label::new(channel.name.clone(), style.name.clone()));

//         if matches!(item_type, ItemType::Header) {
//             row.add_children([
//                 MouseEventHandler::new::<OpenChannelNotes, _>(0, cx, |mouse_state, _| {
//                     render_icon_button(theme.icon_button.style_for(mouse_state), "icons/file.svg")
//                 })
//                 .on_click(MouseButton::Left, move |_, _, cx| {
//                     if let Some(workspace) = workspace.upgrade(cx) {
//                         ChannelView::open(channel_id, workspace, cx).detach();
//                     }
//                 })
//                 .with_tooltip::<OpenChannelNotes>(
//                     channel_id as usize,
//                     "Open Notes",
//                     Some(Box::new(OpenChannelNotes)),
//                     tooltip_style.clone(),
//                     cx,
//                 )
//                 .flex_float(),
//                 MouseEventHandler::new::<ActiveCall, _>(0, cx, |mouse_state, _| {
//                     render_icon_button(
//                         theme.icon_button.style_for(mouse_state),
//                         "icons/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);
//                 })
//                 .with_tooltip::<ActiveCall>(
//                     channel_id as usize,
//                     "Join Call",
//                     Some(Box::new(JoinCall)),
//                     tooltip_style.clone(),
//                     cx,
//                 )
//                 .flex_float(),
//             ]);
//         }

//         row.align_children_center()
//             .contained()
//             .with_style(style.container)
//             .into_any()
//     }

//     fn render_sign_in_prompt(
//         &self,
//         theme: &Arc<Theme>,
//         cx: &mut ViewContext<Self>,
//     ) -> AnyElement<Self> {
//         enum SignInPromptLabel {}

//         MouseEventHandler::new::<SignInPromptLabel, _>(0, cx, |mouse_state, _| {
//             Label::new(
//                 "Sign in to use chat".to_string(),
//                 theme
//                     .chat_panel
//                     .sign_in_prompt
//                     .style_for(mouse_state)
//                     .clone(),
//             )
//         })
//         .with_cursor_style(CursorStyle::PointingHand)
//         .on_click(MouseButton::Left, move |_, this, cx| {
//             let client = this.client.clone();
//             cx.spawn(|this, mut cx| async move {
//                 if client
//                     .authenticate_and_connect(true, &cx)
//                     .log_err()
//                     .await
//                     .is_some()
//                 {
//                     this.update(&mut cx, |this, cx| {
//                         if cx.handle().is_focused(cx) {
//                             cx.focus(&this.input_editor);
//                         }
//                     })
//                     .ok();
//                 }
//             })
//             .detach();
//         })
//         .aligned()
//         .into_any()
//     }

//     fn send(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
//         if let Some((chat, _)) = self.active_chat.as_ref() {
//             let message = self
//                 .input_editor
//                 .update(cx, |editor, cx| editor.take_message(cx));

//             if let Some(task) = chat
//                 .update(cx, |chat, cx| chat.send_message(message, cx))
//                 .log_err()
//             {
//                 task.detach();
//             }
//         }
//     }

//     fn remove_message(&mut self, id: u64, cx: &mut ViewContext<Self>) {
//         if let Some((chat, _)) = self.active_chat.as_ref() {
//             chat.update(cx, |chat, cx| chat.remove_message(id, cx).detach())
//         }
//     }

//     fn load_more_messages(&mut self, _: &LoadMoreMessages, cx: &mut ViewContext<Self>) {
//         if let Some((chat, _)) = self.active_chat.as_ref() {
//             chat.update(cx, |channel, cx| {
//                 if let Some(task) = channel.load_more_messages(cx) {
//                     task.detach();
//                 }
//             })
//         }
//     }

//     pub fn select_channel(
//         &mut self,
//         selected_channel_id: u64,
//         scroll_to_message_id: Option<u64>,
//         cx: &mut ViewContext<ChatPanel>,
//     ) -> Task<Result<()>> {
//         let open_chat = self
//             .active_chat
//             .as_ref()
//             .and_then(|(chat, _)| {
//                 (chat.read(cx).channel_id == selected_channel_id)
//                     .then(|| Task::ready(anyhow::Ok(chat.clone())))
//             })
//             .unwrap_or_else(|| {
//                 self.channel_store.update(cx, |store, cx| {
//                     store.open_channel_chat(selected_channel_id, cx)
//                 })
//             });

//         cx.spawn(|this, mut cx| async move {
//             let chat = open_chat.await?;
//             this.update(&mut cx, |this, cx| {
//                 this.set_active_chat(chat.clone(), cx);
//             })?;

//             if let Some(message_id) = scroll_to_message_id {
//                 if let Some(item_ix) =
//                     ChannelChat::load_history_since_message(chat.clone(), message_id, cx.clone())
//                         .await
//                 {
//                     this.update(&mut cx, |this, cx| {
//                         if this.active_chat.as_ref().map_or(false, |(c, _)| *c == chat) {
//                             this.message_list.scroll_to(ListOffset {
//                                 item_ix,
//                                 offset_in_item: 0.,
//                             });
//                             cx.notify();
//                         }
//                     })?;
//                 }
//             }

//             Ok(())
//         })
//     }

//     fn open_notes(&mut self, _: &OpenChannelNotes, cx: &mut ViewContext<Self>) {
//         if let Some((chat, _)) = &self.active_chat {
//             let channel_id = chat.read(cx).channel_id;
//             if let Some(workspace) = self.workspace.upgrade(cx) {
//                 ChannelView::open(channel_id, workspace, cx).detach();
//             }
//         }
//     }

//     fn join_call(&mut self, _: &JoinCall, cx: &mut ViewContext<Self>) {
//         if let Some((chat, _)) = &self.active_chat {
//             let channel_id = chat.read(cx).channel_id;
//             ActiveCall::global(cx)
//                 .update(cx, |call, cx| call.join_channel(channel_id, cx))
//                 .detach_and_log_err(cx);
//         }
//     }
// }

// fn render_remove(
//     message_id_to_remove: Option<u64>,
//     cx: &mut ViewContext<'_, '_, ChatPanel>,
//     theme: &Arc<Theme>,
// ) -> AnyElement<ChatPanel> {
//     enum DeleteMessage {}

//     message_id_to_remove
//         .map(|id| {
//             MouseEventHandler::new::<DeleteMessage, _>(id as usize, cx, |mouse_state, _| {
//                 let button_style = theme.chat_panel.icon_button.style_for(mouse_state);
//                 render_icon_button(button_style, "icons/x.svg")
//                     .aligned()
//                     .into_any()
//             })
//             .with_padding(Padding::uniform(2.))
//             .with_cursor_style(CursorStyle::PointingHand)
//             .on_click(MouseButton::Left, move |_, this, cx| {
//                 this.remove_message(id, cx);
//             })
//             .flex_float()
//             .into_any()
//         })
//         .unwrap_or_else(|| {
//             let style = theme.chat_panel.icon_button.default;

//             Empty::new()
//                 .constrained()
//                 .with_width(style.icon_width)
//                 .aligned()
//                 .constrained()
//                 .with_width(style.button_width)
//                 .with_height(style.button_width)
//                 .contained()
//                 .with_uniform_padding(2.)
//                 .flex_float()
//                 .into_any()
//         })
// }

// impl Entity for ChatPanel {
//     type Event = Event;
// }

// impl View for ChatPanel {
//     fn ui_name() -> &'static str {
//         "ChatPanel"
//     }

//     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
//         let theme = theme::current(cx);
//         let element = if self.client.user_id().is_some() {
//             self.render_channel(cx)
//         } else {
//             self.render_sign_in_prompt(&theme, cx)
//         };
//         element
//             .contained()
//             .with_style(theme.chat_panel.container)
//             .constrained()
//             .with_min_width(150.)
//             .into_any()
//     }

//     fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
//         self.has_focus = true;
//         if matches!(
//             *self.client.status().borrow(),
//             client::Status::Connected { .. }
//         ) {
//             let editor = self.input_editor.read(cx).editor.clone();
//             cx.focus(&editor);
//         }
//     }

//     fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {
//         self.has_focus = false;
//     }
// }

// impl Panel for ChatPanel {
//     fn position(&self, cx: &gpui::WindowContext) -> DockPosition {
//         settings::get::<ChatPanelSettings>(cx).dock
//     }

//     fn position_is_valid(&self, position: DockPosition) -> bool {
//         matches!(position, DockPosition::Left | DockPosition::Right)
//     }

//     fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>) {
//         settings::update_settings_file::<ChatPanelSettings>(self.fs.clone(), cx, move |settings| {
//             settings.dock = Some(position)
//         });
//     }

//     fn size(&self, cx: &gpui::WindowContext) -> f32 {
//         self.width
//             .unwrap_or_else(|| settings::get::<ChatPanelSettings>(cx).default_width)
//     }

//     fn set_size(&mut self, size: Option<f32>, cx: &mut ViewContext<Self>) {
//         self.width = size;
//         self.serialize(cx);
//         cx.notify();
//     }

//     fn set_active(&mut self, active: bool, cx: &mut ViewContext<Self>) {
//         self.active = active;
//         if active {
//             self.acknowledge_last_message(cx);
//             if !is_channels_feature_enabled(cx) {
//                 cx.emit(Event::Dismissed);
//             }
//         }
//     }

//     fn icon_path(&self, cx: &gpui::WindowContext) -> Option<&'static str> {
//         (settings::get::<ChatPanelSettings>(cx).button && is_channels_feature_enabled(cx))
//             .then(|| "icons/conversations.svg")
//     }

//     fn icon_tooltip(&self) -> (String, Option<Box<dyn gpui::Action>>) {
//         ("Chat Panel".to_string(), Some(Box::new(ToggleFocus)))
//     }

//     fn should_change_position_on_event(event: &Self::Event) -> bool {
//         matches!(event, Event::DockPositionChanged)
//     }

//     fn should_close_on_event(event: &Self::Event) -> bool {
//         matches!(event, Event::Dismissed)
//     }

//     fn has_focus(&self, _cx: &gpui::WindowContext) -> bool {
//         self.has_focus
//     }

//     fn is_focus_event(event: &Self::Event) -> bool {
//         matches!(event, Event::Focus)
//     }
// }

// fn format_timestamp(
//     mut timestamp: OffsetDateTime,
//     mut now: OffsetDateTime,
//     local_timezone: UtcOffset,
// ) -> String {
//     timestamp = timestamp.to_offset(local_timezone);
//     now = now.to_offset(local_timezone);

//     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!("{:02}:{:02}{}", hour, timestamp.minute(), part)
//     } else if date.next_day() == Some(today) {
//         format!("yesterday at {:02}:{:02}{}", hour, timestamp.minute(), part)
//     } else {
//         format!("{:02}/{}/{}", date.month() as u32, date.day(), date.year())
//     }
// }

// fn render_icon_button<V: View>(style: &IconButton, svg_path: &'static str) -> impl Element<V> {
//     Svg::new(svg_path)
//         .with_color(style.color)
//         .constrained()
//         .with_width(style.icon_width)
//         .aligned()
//         .constrained()
//         .with_width(style.button_width)
//         .with_height(style.button_width)
//         .contained()
//         .with_style(style.container)
// }

// #[cfg(test)]
// mod tests {
//     use super::*;
//     use gpui::fonts::HighlightStyle;
//     use pretty_assertions::assert_eq;
//     use rich_text::{BackgroundKind, Highlight, RenderedRegion};
//     use util::test::marked_text_ranges;

//     #[gpui::test]
//     fn test_render_markdown_with_mentions() {
//         let language_registry = Arc::new(LanguageRegistry::test());
//         let (body, ranges) = marked_text_ranges("*hi*, «@abc», let's **call** «@fgh»", false);
//         let message = channel::ChannelMessage {
//             id: ChannelMessageId::Saved(0),
//             body,
//             timestamp: OffsetDateTime::now_utc(),
//             sender: Arc::new(client::User {
//                 github_login: "fgh".into(),
//                 avatar: None,
//                 id: 103,
//             }),
//             nonce: 5,
//             mentions: vec![(ranges[0].clone(), 101), (ranges[1].clone(), 102)],
//         };

//         let message = ChatPanel::render_markdown_with_mentions(&language_registry, 102, &message);

//         // Note that the "'" was replaced with ’ due to smart punctuation.
//         let (body, ranges) = marked_text_ranges("«hi», «@abc», let’s «call» «@fgh»", false);
//         assert_eq!(message.text, body);
//         assert_eq!(
//             message.highlights,
//             vec![
//                 (
//                     ranges[0].clone(),
//                     HighlightStyle {
//                         italic: Some(true),
//                         ..Default::default()
//                     }
//                     .into()
//                 ),
//                 (ranges[1].clone(), Highlight::Mention),
//                 (
//                     ranges[2].clone(),
//                     HighlightStyle {
//                         weight: Some(gpui::fonts::Weight::BOLD),
//                         ..Default::default()
//                     }
//                     .into()
//                 ),
//                 (ranges[3].clone(), Highlight::SelfMention)
//             ]
//         );
//         assert_eq!(
//             message.regions,
//             vec![
//                 RenderedRegion {
//                     background_kind: Some(BackgroundKind::Mention),
//                     link_url: None
//                 },
//                 RenderedRegion {
//                     background_kind: Some(BackgroundKind::SelfMention),
//                     link_url: None
//                 },
//             ]
//         );
//     }
// }
