Move placeholder titlebar render to collab_ui

This commit is contained in:
Conrad Irwin 2023-11-15 15:47:33 -07:00
parent 84bcbf1128
commit 793fa6e3a4
15 changed files with 7323 additions and 7316 deletions

1
Cargo.lock generated
View file

@ -1864,6 +1864,7 @@ dependencies = [
"theme2", "theme2",
"time", "time",
"tree-sitter-markdown", "tree-sitter-markdown",
"ui2",
"util", "util",
"workspace2", "workspace2",
"zed_actions2", "zed_actions2",

View file

@ -18,6 +18,7 @@ members = [
"crates/collab", "crates/collab",
"crates/collab2", "crates/collab2",
"crates/collab_ui", "crates/collab_ui",
"crates/collab_ui2",
"crates/collections", "crates/collections",
"crates/command_palette", "crates/command_palette",
"crates/command_palette2", "crates/command_palette2",

View file

@ -48,6 +48,7 @@ feature_flags = { package = "feature_flags2", path = "../feature_flags2"}
theme = { package = "theme2", path = "../theme2" } theme = { package = "theme2", path = "../theme2" }
# theme_selector = { path = "../theme_selector" } # theme_selector = { path = "../theme_selector" }
# vcs_menu = { path = "../vcs_menu" } # vcs_menu = { path = "../vcs_menu" }
ui = { package = "ui2", path = "../ui2" }
util = { path = "../util" } util = { path = "../util" }
workspace = { package = "workspace2", path = "../workspace2" } workspace = { package = "workspace2", path = "../workspace2" }
zed-actions = { package="zed_actions2", path = "../zed_actions2"} zed-actions = { package="zed_actions2", path = "../zed_actions2"}

View file

@ -1,454 +1,454 @@
use anyhow::{anyhow, Result}; // use anyhow::{anyhow, Result};
use call::report_call_event_for_channel; // use call::report_call_event_for_channel;
use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelId, ChannelStore}; // use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelId, ChannelStore};
use client::{ // use client::{
proto::{self, PeerId}, // proto::{self, PeerId},
Collaborator, ParticipantIndex, // Collaborator, ParticipantIndex,
}; // };
use collections::HashMap; // use collections::HashMap;
use editor::{CollaborationHub, Editor}; // use editor::{CollaborationHub, Editor};
use gpui::{ // use gpui::{
actions, // actions,
elements::{ChildView, Label}, // elements::{ChildView, Label},
geometry::vector::Vector2F, // geometry::vector::Vector2F,
AnyElement, AnyViewHandle, AppContext, Element, Entity, ModelHandle, Subscription, Task, View, // AnyElement, AnyViewHandle, AppContext, Element, Entity, ModelHandle, Subscription, Task, View,
ViewContext, ViewHandle, // ViewContext, ViewHandle,
}; // };
use project::Project; // use project::Project;
use smallvec::SmallVec; // use smallvec::SmallVec;
use std::{ // use std::{
any::{Any, TypeId}, // any::{Any, TypeId},
sync::Arc, // sync::Arc,
}; // };
use util::ResultExt; // use util::ResultExt;
use workspace::{ // use workspace::{
item::{FollowableItem, Item, ItemEvent, ItemHandle}, // item::{FollowableItem, Item, ItemEvent, ItemHandle},
register_followable_item, // register_followable_item,
searchable::SearchableItemHandle, // searchable::SearchableItemHandle,
ItemNavHistory, Pane, SaveIntent, ViewId, Workspace, WorkspaceId, // ItemNavHistory, Pane, SaveIntent, ViewId, Workspace, WorkspaceId,
}; // };
actions!(channel_view, [Deploy]); // actions!(channel_view, [Deploy]);
pub fn init(cx: &mut AppContext) { // pub fn init(cx: &mut AppContext) {
register_followable_item::<ChannelView>(cx) // register_followable_item::<ChannelView>(cx)
} // }
pub struct ChannelView { // pub struct ChannelView {
pub editor: ViewHandle<Editor>, // pub editor: ViewHandle<Editor>,
project: ModelHandle<Project>, // project: ModelHandle<Project>,
channel_store: ModelHandle<ChannelStore>, // channel_store: ModelHandle<ChannelStore>,
channel_buffer: ModelHandle<ChannelBuffer>, // channel_buffer: ModelHandle<ChannelBuffer>,
remote_id: Option<ViewId>, // remote_id: Option<ViewId>,
_editor_event_subscription: Subscription, // _editor_event_subscription: Subscription,
} // }
impl ChannelView { // impl ChannelView {
pub fn open( // pub fn open(
channel_id: ChannelId, // channel_id: ChannelId,
workspace: ViewHandle<Workspace>, // workspace: ViewHandle<Workspace>,
cx: &mut AppContext, // cx: &mut AppContext,
) -> Task<Result<ViewHandle<Self>>> { // ) -> Task<Result<ViewHandle<Self>>> {
let pane = workspace.read(cx).active_pane().clone(); // let pane = workspace.read(cx).active_pane().clone();
let channel_view = Self::open_in_pane(channel_id, pane.clone(), workspace.clone(), cx); // let channel_view = Self::open_in_pane(channel_id, pane.clone(), workspace.clone(), cx);
cx.spawn(|mut cx| async move { // cx.spawn(|mut cx| async move {
let channel_view = channel_view.await?; // let channel_view = channel_view.await?;
pane.update(&mut cx, |pane, cx| { // pane.update(&mut cx, |pane, cx| {
report_call_event_for_channel( // report_call_event_for_channel(
"open channel notes", // "open channel notes",
channel_id, // channel_id,
&workspace.read(cx).app_state().client, // &workspace.read(cx).app_state().client,
cx, // cx,
); // );
pane.add_item(Box::new(channel_view.clone()), true, true, None, cx); // pane.add_item(Box::new(channel_view.clone()), true, true, None, cx);
}); // });
anyhow::Ok(channel_view) // anyhow::Ok(channel_view)
}) // })
} // }
pub fn open_in_pane( // pub fn open_in_pane(
channel_id: ChannelId, // channel_id: ChannelId,
pane: ViewHandle<Pane>, // pane: ViewHandle<Pane>,
workspace: ViewHandle<Workspace>, // workspace: ViewHandle<Workspace>,
cx: &mut AppContext, // cx: &mut AppContext,
) -> Task<Result<ViewHandle<Self>>> { // ) -> Task<Result<ViewHandle<Self>>> {
let workspace = workspace.read(cx); // let workspace = workspace.read(cx);
let project = workspace.project().to_owned(); // let project = workspace.project().to_owned();
let channel_store = ChannelStore::global(cx); // let channel_store = ChannelStore::global(cx);
let language_registry = workspace.app_state().languages.clone(); // let language_registry = workspace.app_state().languages.clone();
let markdown = language_registry.language_for_name("Markdown"); // let markdown = language_registry.language_for_name("Markdown");
let channel_buffer = // let channel_buffer =
channel_store.update(cx, |store, cx| store.open_channel_buffer(channel_id, cx)); // channel_store.update(cx, |store, cx| store.open_channel_buffer(channel_id, cx));
cx.spawn(|mut cx| async move { // cx.spawn(|mut cx| async move {
let channel_buffer = channel_buffer.await?; // let channel_buffer = channel_buffer.await?;
let markdown = markdown.await.log_err(); // let markdown = markdown.await.log_err();
channel_buffer.update(&mut cx, |buffer, cx| { // channel_buffer.update(&mut cx, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| { // buffer.buffer().update(cx, |buffer, cx| {
buffer.set_language_registry(language_registry); // buffer.set_language_registry(language_registry);
if let Some(markdown) = markdown { // if let Some(markdown) = markdown {
buffer.set_language(Some(markdown), cx); // buffer.set_language(Some(markdown), cx);
} // }
}) // })
}); // });
pane.update(&mut cx, |pane, cx| { // pane.update(&mut cx, |pane, cx| {
let buffer_id = channel_buffer.read(cx).remote_id(cx); // let buffer_id = channel_buffer.read(cx).remote_id(cx);
let existing_view = pane // let existing_view = pane
.items_of_type::<Self>() // .items_of_type::<Self>()
.find(|view| view.read(cx).channel_buffer.read(cx).remote_id(cx) == buffer_id); // .find(|view| view.read(cx).channel_buffer.read(cx).remote_id(cx) == buffer_id);
// If this channel buffer is already open in this pane, just return it. // // If this channel buffer is already open in this pane, just return it.
if let Some(existing_view) = existing_view.clone() { // if let Some(existing_view) = existing_view.clone() {
if existing_view.read(cx).channel_buffer == channel_buffer { // if existing_view.read(cx).channel_buffer == channel_buffer {
return existing_view; // return existing_view;
} // }
} // }
let view = cx.add_view(|cx| { // let view = cx.add_view(|cx| {
let mut this = Self::new(project, channel_store, channel_buffer, cx); // let mut this = Self::new(project, channel_store, channel_buffer, cx);
this.acknowledge_buffer_version(cx); // this.acknowledge_buffer_version(cx);
this // this
}); // });
// If the pane contained a disconnected view for this channel buffer, // // If the pane contained a disconnected view for this channel buffer,
// replace that. // // replace that.
if let Some(existing_item) = existing_view { // if let Some(existing_item) = existing_view {
if let Some(ix) = pane.index_for_item(&existing_item) { // if let Some(ix) = pane.index_for_item(&existing_item) {
pane.close_item_by_id(existing_item.id(), SaveIntent::Skip, cx) // pane.close_item_by_id(existing_item.id(), SaveIntent::Skip, cx)
.detach(); // .detach();
pane.add_item(Box::new(view.clone()), true, true, Some(ix), cx); // pane.add_item(Box::new(view.clone()), true, true, Some(ix), cx);
} // }
} // }
view // view
}) // })
.ok_or_else(|| anyhow!("pane was dropped")) // .ok_or_else(|| anyhow!("pane was dropped"))
}) // })
} // }
pub fn new( // pub fn new(
project: ModelHandle<Project>, // project: ModelHandle<Project>,
channel_store: ModelHandle<ChannelStore>, // channel_store: ModelHandle<ChannelStore>,
channel_buffer: ModelHandle<ChannelBuffer>, // channel_buffer: ModelHandle<ChannelBuffer>,
cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
) -> Self { // ) -> Self {
let buffer = channel_buffer.read(cx).buffer(); // let buffer = channel_buffer.read(cx).buffer();
let editor = cx.add_view(|cx| { // let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, None, cx); // let mut editor = Editor::for_buffer(buffer, None, cx);
editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub( // editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
channel_buffer.clone(), // channel_buffer.clone(),
))); // )));
editor.set_read_only( // editor.set_read_only(
!channel_buffer // !channel_buffer
.read(cx) // .read(cx)
.channel(cx) // .channel(cx)
.is_some_and(|c| c.can_edit_notes()), // .is_some_and(|c| c.can_edit_notes()),
); // );
editor // editor
}); // });
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone())); // let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
cx.subscribe(&channel_buffer, Self::handle_channel_buffer_event) // cx.subscribe(&channel_buffer, Self::handle_channel_buffer_event)
.detach(); // .detach();
Self { // Self {
editor, // editor,
project, // project,
channel_store, // channel_store,
channel_buffer, // channel_buffer,
remote_id: None, // remote_id: None,
_editor_event_subscription, // _editor_event_subscription,
} // }
} // }
pub fn channel(&self, cx: &AppContext) -> Option<Arc<Channel>> { // pub fn channel(&self, cx: &AppContext) -> Option<Arc<Channel>> {
self.channel_buffer.read(cx).channel(cx) // self.channel_buffer.read(cx).channel(cx)
} // }
fn handle_channel_buffer_event( // fn handle_channel_buffer_event(
&mut self, // &mut self,
_: ModelHandle<ChannelBuffer>, // _: ModelHandle<ChannelBuffer>,
event: &ChannelBufferEvent, // event: &ChannelBufferEvent,
cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
) { // ) {
match event { // match event {
ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| { // ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| {
editor.set_read_only(true); // editor.set_read_only(true);
cx.notify(); // cx.notify();
}), // }),
ChannelBufferEvent::ChannelChanged => { // ChannelBufferEvent::ChannelChanged => {
self.editor.update(cx, |editor, cx| { // self.editor.update(cx, |editor, cx| {
editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes())); // editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes()));
cx.emit(editor::Event::TitleChanged); // cx.emit(editor::Event::TitleChanged);
cx.notify() // cx.notify()
}); // });
} // }
ChannelBufferEvent::BufferEdited => { // ChannelBufferEvent::BufferEdited => {
if cx.is_self_focused() || self.editor.is_focused(cx) { // if cx.is_self_focused() || self.editor.is_focused(cx) {
self.acknowledge_buffer_version(cx); // self.acknowledge_buffer_version(cx);
} else { // } else {
self.channel_store.update(cx, |store, cx| { // self.channel_store.update(cx, |store, cx| {
let channel_buffer = self.channel_buffer.read(cx); // let channel_buffer = self.channel_buffer.read(cx);
store.notes_changed( // store.notes_changed(
channel_buffer.channel_id, // channel_buffer.channel_id,
channel_buffer.epoch(), // channel_buffer.epoch(),
&channel_buffer.buffer().read(cx).version(), // &channel_buffer.buffer().read(cx).version(),
cx, // cx,
) // )
}); // });
} // }
} // }
ChannelBufferEvent::CollaboratorsChanged => {} // ChannelBufferEvent::CollaboratorsChanged => {}
} // }
} // }
fn acknowledge_buffer_version(&mut self, cx: &mut ViewContext<'_, '_, ChannelView>) { // fn acknowledge_buffer_version(&mut self, cx: &mut ViewContext<'_, '_, ChannelView>) {
self.channel_store.update(cx, |store, cx| { // self.channel_store.update(cx, |store, cx| {
let channel_buffer = self.channel_buffer.read(cx); // let channel_buffer = self.channel_buffer.read(cx);
store.acknowledge_notes_version( // store.acknowledge_notes_version(
channel_buffer.channel_id, // channel_buffer.channel_id,
channel_buffer.epoch(), // channel_buffer.epoch(),
&channel_buffer.buffer().read(cx).version(), // &channel_buffer.buffer().read(cx).version(),
cx, // cx,
) // )
}); // });
self.channel_buffer.update(cx, |buffer, cx| { // self.channel_buffer.update(cx, |buffer, cx| {
buffer.acknowledge_buffer_version(cx); // buffer.acknowledge_buffer_version(cx);
}); // });
} // }
} // }
impl Entity for ChannelView { // impl Entity for ChannelView {
type Event = editor::Event; // type Event = editor::Event;
} // }
impl View for ChannelView { // impl View for ChannelView {
fn ui_name() -> &'static str { // fn ui_name() -> &'static str {
"ChannelView" // "ChannelView"
} // }
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> { // fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
ChildView::new(self.editor.as_any(), cx).into_any() // ChildView::new(self.editor.as_any(), cx).into_any()
} // }
fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) { // fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
if cx.is_self_focused() { // if cx.is_self_focused() {
self.acknowledge_buffer_version(cx); // self.acknowledge_buffer_version(cx);
cx.focus(self.editor.as_any()) // cx.focus(self.editor.as_any())
} // }
} // }
} // }
impl Item for ChannelView { // impl Item for ChannelView {
fn act_as_type<'a>( // fn act_as_type<'a>(
&'a self, // &'a self,
type_id: TypeId, // type_id: TypeId,
self_handle: &'a ViewHandle<Self>, // self_handle: &'a ViewHandle<Self>,
_: &'a AppContext, // _: &'a AppContext,
) -> Option<&'a AnyViewHandle> { // ) -> Option<&'a AnyViewHandle> {
if type_id == TypeId::of::<Self>() { // if type_id == TypeId::of::<Self>() {
Some(self_handle) // Some(self_handle)
} else if type_id == TypeId::of::<Editor>() { // } else if type_id == TypeId::of::<Editor>() {
Some(&self.editor) // Some(&self.editor)
} else { // } else {
None // None
} // }
} // }
fn tab_content<V: 'static>( // fn tab_content<V: 'static>(
&self, // &self,
_: Option<usize>, // _: Option<usize>,
style: &theme::Tab, // style: &theme::Tab,
cx: &gpui::AppContext, // cx: &gpui::AppContext,
) -> AnyElement<V> { // ) -> AnyElement<V> {
let label = if let Some(channel) = self.channel(cx) { // let label = if let Some(channel) = self.channel(cx) {
match ( // match (
channel.can_edit_notes(), // channel.can_edit_notes(),
self.channel_buffer.read(cx).is_connected(), // self.channel_buffer.read(cx).is_connected(),
) { // ) {
(true, true) => format!("#{}", channel.name), // (true, true) => format!("#{}", channel.name),
(false, true) => format!("#{} (read-only)", channel.name), // (false, true) => format!("#{} (read-only)", channel.name),
(_, false) => format!("#{} (disconnected)", channel.name), // (_, false) => format!("#{} (disconnected)", channel.name),
} // }
} else { // } else {
format!("channel notes (disconnected)") // format!("channel notes (disconnected)")
}; // };
Label::new(label, style.label.to_owned()).into_any() // Label::new(label, style.label.to_owned()).into_any()
} // }
fn clone_on_split(&self, _: WorkspaceId, cx: &mut ViewContext<Self>) -> Option<Self> { // fn clone_on_split(&self, _: WorkspaceId, cx: &mut ViewContext<Self>) -> Option<Self> {
Some(Self::new( // Some(Self::new(
self.project.clone(), // self.project.clone(),
self.channel_store.clone(), // self.channel_store.clone(),
self.channel_buffer.clone(), // self.channel_buffer.clone(),
cx, // cx,
)) // ))
} // }
fn is_singleton(&self, _cx: &AppContext) -> bool { // fn is_singleton(&self, _cx: &AppContext) -> bool {
false // false
} // }
fn navigate(&mut self, data: Box<dyn Any>, cx: &mut ViewContext<Self>) -> bool { // fn navigate(&mut self, data: Box<dyn Any>, cx: &mut ViewContext<Self>) -> bool {
self.editor // self.editor
.update(cx, |editor, cx| editor.navigate(data, cx)) // .update(cx, |editor, cx| editor.navigate(data, cx))
} // }
fn deactivated(&mut self, cx: &mut ViewContext<Self>) { // fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
self.editor // self.editor
.update(cx, |editor, cx| Item::deactivated(editor, cx)) // .update(cx, |editor, cx| Item::deactivated(editor, cx))
} // }
fn set_nav_history(&mut self, history: ItemNavHistory, cx: &mut ViewContext<Self>) { // fn set_nav_history(&mut self, history: ItemNavHistory, cx: &mut ViewContext<Self>) {
self.editor // self.editor
.update(cx, |editor, cx| Item::set_nav_history(editor, history, cx)) // .update(cx, |editor, cx| Item::set_nav_history(editor, history, cx))
} // }
fn as_searchable(&self, _: &ViewHandle<Self>) -> Option<Box<dyn SearchableItemHandle>> { // fn as_searchable(&self, _: &ViewHandle<Self>) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(self.editor.clone())) // Some(Box::new(self.editor.clone()))
} // }
fn show_toolbar(&self) -> bool { // fn show_toolbar(&self) -> bool {
true // true
} // }
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Vector2F> { // fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Vector2F> {
self.editor.read(cx).pixel_position_of_cursor(cx) // self.editor.read(cx).pixel_position_of_cursor(cx)
} // }
fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { // fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
editor::Editor::to_item_events(event) // editor::Editor::to_item_events(event)
} // }
} // }
impl FollowableItem for ChannelView { // impl FollowableItem for ChannelView {
fn remote_id(&self) -> Option<workspace::ViewId> { // fn remote_id(&self) -> Option<workspace::ViewId> {
self.remote_id // self.remote_id
} // }
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant> { // fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant> {
let channel_buffer = self.channel_buffer.read(cx); // let channel_buffer = self.channel_buffer.read(cx);
if !channel_buffer.is_connected() { // if !channel_buffer.is_connected() {
return None; // return None;
} // }
Some(proto::view::Variant::ChannelView( // Some(proto::view::Variant::ChannelView(
proto::view::ChannelView { // proto::view::ChannelView {
channel_id: channel_buffer.channel_id, // channel_id: channel_buffer.channel_id,
editor: if let Some(proto::view::Variant::Editor(proto)) = // editor: if let Some(proto::view::Variant::Editor(proto)) =
self.editor.read(cx).to_state_proto(cx) // self.editor.read(cx).to_state_proto(cx)
{ // {
Some(proto) // Some(proto)
} else { // } else {
None // None
}, // },
}, // },
)) // ))
} // }
fn from_state_proto( // fn from_state_proto(
pane: ViewHandle<workspace::Pane>, // pane: ViewHandle<workspace::Pane>,
workspace: ViewHandle<workspace::Workspace>, // workspace: ViewHandle<workspace::Workspace>,
remote_id: workspace::ViewId, // remote_id: workspace::ViewId,
state: &mut Option<proto::view::Variant>, // state: &mut Option<proto::view::Variant>,
cx: &mut AppContext, // cx: &mut AppContext,
) -> Option<gpui::Task<anyhow::Result<ViewHandle<Self>>>> { // ) -> Option<gpui::Task<anyhow::Result<ViewHandle<Self>>>> {
let Some(proto::view::Variant::ChannelView(_)) = state else { // let Some(proto::view::Variant::ChannelView(_)) = state else {
return None; // return None;
}; // };
let Some(proto::view::Variant::ChannelView(state)) = state.take() else { // let Some(proto::view::Variant::ChannelView(state)) = state.take() else {
unreachable!() // unreachable!()
}; // };
let open = ChannelView::open_in_pane(state.channel_id, pane, workspace, cx); // let open = ChannelView::open_in_pane(state.channel_id, pane, workspace, cx);
Some(cx.spawn(|mut cx| async move { // Some(cx.spawn(|mut cx| async move {
let this = open.await?; // let this = open.await?;
let task = this // let task = this
.update(&mut cx, |this, cx| { // .update(&mut cx, |this, cx| {
this.remote_id = Some(remote_id); // this.remote_id = Some(remote_id);
if let Some(state) = state.editor { // if let Some(state) = state.editor {
Some(this.editor.update(cx, |editor, cx| { // Some(this.editor.update(cx, |editor, cx| {
editor.apply_update_proto( // editor.apply_update_proto(
&this.project, // &this.project,
proto::update_view::Variant::Editor(proto::update_view::Editor { // proto::update_view::Variant::Editor(proto::update_view::Editor {
selections: state.selections, // selections: state.selections,
pending_selection: state.pending_selection, // pending_selection: state.pending_selection,
scroll_top_anchor: state.scroll_top_anchor, // scroll_top_anchor: state.scroll_top_anchor,
scroll_x: state.scroll_x, // scroll_x: state.scroll_x,
scroll_y: state.scroll_y, // scroll_y: state.scroll_y,
..Default::default() // ..Default::default()
}), // }),
cx, // cx,
) // )
})) // }))
} else { // } else {
None // None
} // }
}) // })
.ok_or_else(|| anyhow!("window was closed"))?; // .ok_or_else(|| anyhow!("window was closed"))?;
if let Some(task) = task { // if let Some(task) = task {
task.await?; // task.await?;
} // }
Ok(this) // Ok(this)
})) // }))
} // }
fn add_event_to_update_proto( // fn add_event_to_update_proto(
&self, // &self,
event: &Self::Event, // event: &Self::Event,
update: &mut Option<proto::update_view::Variant>, // update: &mut Option<proto::update_view::Variant>,
cx: &AppContext, // cx: &AppContext,
) -> bool { // ) -> bool {
self.editor // self.editor
.read(cx) // .read(cx)
.add_event_to_update_proto(event, update, cx) // .add_event_to_update_proto(event, update, cx)
} // }
fn apply_update_proto( // fn apply_update_proto(
&mut self, // &mut self,
project: &ModelHandle<Project>, // project: &ModelHandle<Project>,
message: proto::update_view::Variant, // message: proto::update_view::Variant,
cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
) -> gpui::Task<anyhow::Result<()>> { // ) -> gpui::Task<anyhow::Result<()>> {
self.editor.update(cx, |editor, cx| { // self.editor.update(cx, |editor, cx| {
editor.apply_update_proto(project, message, cx) // editor.apply_update_proto(project, message, cx)
}) // })
} // }
fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) { // fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |editor, cx| { // self.editor.update(cx, |editor, cx| {
editor.set_leader_peer_id(leader_peer_id, cx) // editor.set_leader_peer_id(leader_peer_id, cx)
}) // })
} // }
fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool { // fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool {
Editor::should_unfollow_on_event(event, cx) // Editor::should_unfollow_on_event(event, cx)
} // }
fn is_project_item(&self, _cx: &AppContext) -> bool { // fn is_project_item(&self, _cx: &AppContext) -> bool {
false // false
} // }
} // }
struct ChannelBufferCollaborationHub(ModelHandle<ChannelBuffer>); // struct ChannelBufferCollaborationHub(ModelHandle<ChannelBuffer>);
impl CollaborationHub for ChannelBufferCollaborationHub { // impl CollaborationHub for ChannelBufferCollaborationHub {
fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> { // fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
self.0.read(cx).collaborators() // self.0.read(cx).collaborators()
} // }
fn user_participant_indices<'a>( // fn user_participant_indices<'a>(
&self, // &self,
cx: &'a AppContext, // cx: &'a AppContext,
) -> &'a HashMap<u64, ParticipantIndex> { // ) -> &'a HashMap<u64, ParticipantIndex> {
self.0.read(cx).user_store().read(cx).participant_indices() // self.0.read(cx).user_store().read(cx).participant_indices()
} // }
} // }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,159 +7,147 @@ pub mod notification_panel;
pub mod notifications; pub mod notifications;
mod panel_settings; mod panel_settings;
use call::{report_call_event_for_room, ActiveCall, Room}; use std::sync::Arc;
use feature_flags::{ChannelsAlpha, FeatureFlagAppExt};
use gpui::{
actions,
elements::{ContainerStyle, Empty, Image},
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
platform::{Screen, WindowBounds, WindowKind, WindowOptions},
AnyElement, AppContext, Element, ImageData, Task,
};
use std::{rc::Rc, sync::Arc};
use theme::AvatarStyle;
use util::ResultExt;
use workspace::AppState;
pub use collab_titlebar_item::CollabTitlebarItem; pub use collab_titlebar_item::CollabTitlebarItem;
use gpui::AppContext;
pub use panel_settings::{ pub use panel_settings::{
ChatPanelSettings, CollaborationPanelSettings, NotificationPanelSettings, ChatPanelSettings, CollaborationPanelSettings, NotificationPanelSettings,
}; };
use settings::Settings;
use workspace::AppState;
actions!( // actions!(
collab, // collab,
[ToggleScreenSharing, ToggleMute, ToggleDeafen, LeaveCall] // [ToggleScreenSharing, ToggleMute, ToggleDeafen, LeaveCall]
); // );
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) { pub fn init(_app_state: &Arc<AppState>, cx: &mut AppContext) {
settings::register::<CollaborationPanelSettings>(cx); CollaborationPanelSettings::register(cx);
settings::register::<ChatPanelSettings>(cx); ChatPanelSettings::register(cx);
settings::register::<NotificationPanelSettings>(cx); NotificationPanelSettings::register(cx);
vcs_menu::init(cx); // vcs_menu::init(cx);
collab_titlebar_item::init(cx); collab_titlebar_item::init(cx);
collab_panel::init(cx); // collab_panel::init(cx);
chat_panel::init(cx); // chat_panel::init(cx);
notifications::init(&app_state, cx); // notifications::init(&app_state, cx);
cx.add_global_action(toggle_screen_sharing); // cx.add_global_action(toggle_screen_sharing);
cx.add_global_action(toggle_mute); // cx.add_global_action(toggle_mute);
cx.add_global_action(toggle_deafen); // cx.add_global_action(toggle_deafen);
} }
pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { // pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
let call = ActiveCall::global(cx).read(cx); // let call = ActiveCall::global(cx).read(cx);
if let Some(room) = call.room().cloned() { // if let Some(room) = call.room().cloned() {
let client = call.client(); // let client = call.client();
let toggle_screen_sharing = room.update(cx, |room, cx| { // let toggle_screen_sharing = room.update(cx, |room, cx| {
if room.is_screen_sharing() { // if room.is_screen_sharing() {
report_call_event_for_room( // report_call_event_for_room(
"disable screen share", // "disable screen share",
room.id(), // room.id(),
room.channel_id(), // room.channel_id(),
&client, // &client,
cx, // cx,
); // );
Task::ready(room.unshare_screen(cx)) // Task::ready(room.unshare_screen(cx))
} else { // } else {
report_call_event_for_room( // report_call_event_for_room(
"enable screen share", // "enable screen share",
room.id(), // room.id(),
room.channel_id(), // room.channel_id(),
&client, // &client,
cx, // cx,
); // );
room.share_screen(cx) // room.share_screen(cx)
} // }
}); // });
toggle_screen_sharing.detach_and_log_err(cx); // toggle_screen_sharing.detach_and_log_err(cx);
} // }
} // }
pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { // pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) {
let call = ActiveCall::global(cx).read(cx); // let call = ActiveCall::global(cx).read(cx);
if let Some(room) = call.room().cloned() { // if let Some(room) = call.room().cloned() {
let client = call.client(); // let client = call.client();
room.update(cx, |room, cx| { // room.update(cx, |room, cx| {
let operation = if room.is_muted(cx) { // let operation = if room.is_muted(cx) {
"enable microphone" // "enable microphone"
} else { // } else {
"disable microphone" // "disable microphone"
}; // };
report_call_event_for_room(operation, room.id(), room.channel_id(), &client, cx); // report_call_event_for_room(operation, room.id(), room.channel_id(), &client, cx);
room.toggle_mute(cx) // room.toggle_mute(cx)
}) // })
.map(|task| task.detach_and_log_err(cx)) // .map(|task| task.detach_and_log_err(cx))
.log_err(); // .log_err();
} // }
} // }
pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { // pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) {
if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { // if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
room.update(cx, Room::toggle_deafen) // room.update(cx, Room::toggle_deafen)
.map(|task| task.detach_and_log_err(cx)) // .map(|task| task.detach_and_log_err(cx))
.log_err(); // .log_err();
} // }
} // }
fn notification_window_options( // fn notification_window_options(
screen: Rc<dyn Screen>, // screen: Rc<dyn Screen>,
window_size: Vector2F, // window_size: Vector2F,
) -> WindowOptions<'static> { // ) -> WindowOptions<'static> {
const NOTIFICATION_PADDING: f32 = 16.; // const NOTIFICATION_PADDING: f32 = 16.;
let screen_bounds = screen.content_bounds(); // let screen_bounds = screen.content_bounds();
WindowOptions { // WindowOptions {
bounds: WindowBounds::Fixed(RectF::new( // bounds: WindowBounds::Fixed(RectF::new(
screen_bounds.upper_right() // screen_bounds.upper_right()
+ vec2f( // + vec2f(
-NOTIFICATION_PADDING - window_size.x(), // -NOTIFICATION_PADDING - window_size.x(),
NOTIFICATION_PADDING, // NOTIFICATION_PADDING,
), // ),
window_size, // window_size,
)), // )),
titlebar: None, // titlebar: None,
center: false, // center: false,
focus: false, // focus: false,
show: true, // show: true,
kind: WindowKind::PopUp, // kind: WindowKind::PopUp,
is_movable: false, // is_movable: false,
screen: Some(screen), // screen: Some(screen),
} // }
} // }
fn render_avatar<T: 'static>( // fn render_avatar<T: 'static>(
avatar: Option<Arc<ImageData>>, // avatar: Option<Arc<ImageData>>,
avatar_style: &AvatarStyle, // avatar_style: &AvatarStyle,
container: ContainerStyle, // container: ContainerStyle,
) -> AnyElement<T> { // ) -> AnyElement<T> {
avatar // avatar
.map(|avatar| { // .map(|avatar| {
Image::from_data(avatar) // Image::from_data(avatar)
.with_style(avatar_style.image) // .with_style(avatar_style.image)
.aligned() // .aligned()
.contained() // .contained()
.with_corner_radius(avatar_style.outer_corner_radius) // .with_corner_radius(avatar_style.outer_corner_radius)
.constrained() // .constrained()
.with_width(avatar_style.outer_width) // .with_width(avatar_style.outer_width)
.with_height(avatar_style.outer_width) // .with_height(avatar_style.outer_width)
.into_any() // .into_any()
}) // })
.unwrap_or_else(|| { // .unwrap_or_else(|| {
Empty::new() // Empty::new()
.constrained() // .constrained()
.with_width(avatar_style.outer_width) // .with_width(avatar_style.outer_width)
.into_any() // .into_any()
}) // })
.contained() // .contained()
.with_style(container) // .with_style(container)
.into_any() // .into_any()
} // }
fn is_channels_feature_enabled(cx: &gpui::WindowContext<'_>) -> bool { // fn is_channels_feature_enabled(cx: &gpui::WindowContext<'_>) -> bool {
cx.is_staff() || cx.has_flag::<ChannelsAlpha>() // cx.is_staff() || cx.has_flag::<ChannelsAlpha>()
} // }

View file

@ -1,113 +1,113 @@
use std::ops::Range; // use std::ops::Range;
use gpui::{ // use gpui::{
geometry::{ // geometry::{
rect::RectF, // rect::RectF,
vector::{vec2f, Vector2F}, // vector::{vec2f, Vector2F},
}, // },
json::ToJson, // json::ToJson,
serde_json::{self, json}, // serde_json::{self, json},
AnyElement, Axis, Element, View, ViewContext, // AnyElement, Axis, Element, View, ViewContext,
}; // };
pub(crate) struct FacePile<V: View> { // pub(crate) struct FacePile<V: View> {
overlap: f32, // overlap: f32,
faces: Vec<AnyElement<V>>, // faces: Vec<AnyElement<V>>,
} // }
impl<V: View> FacePile<V> { // impl<V: View> FacePile<V> {
pub fn new(overlap: f32) -> Self { // pub fn new(overlap: f32) -> Self {
Self { // Self {
overlap, // overlap,
faces: Vec::new(), // faces: Vec::new(),
} // }
} // }
} // }
impl<V: View> Element<V> for FacePile<V> { // impl<V: View> Element<V> for FacePile<V> {
type LayoutState = (); // type LayoutState = ();
type PaintState = (); // type PaintState = ();
fn layout( // fn layout(
&mut self, // &mut self,
constraint: gpui::SizeConstraint, // constraint: gpui::SizeConstraint,
view: &mut V, // view: &mut V,
cx: &mut ViewContext<V>, // cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { // ) -> (Vector2F, Self::LayoutState) {
debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY); // debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY);
let mut width = 0.; // let mut width = 0.;
let mut max_height = 0.; // let mut max_height = 0.;
for face in &mut self.faces { // for face in &mut self.faces {
let layout = face.layout(constraint, view, cx); // let layout = face.layout(constraint, view, cx);
width += layout.x(); // width += layout.x();
max_height = f32::max(max_height, layout.y()); // max_height = f32::max(max_height, layout.y());
} // }
width -= self.overlap * self.faces.len().saturating_sub(1) as f32; // width -= self.overlap * self.faces.len().saturating_sub(1) as f32;
( // (
Vector2F::new(width, max_height.clamp(1., constraint.max.y())), // Vector2F::new(width, max_height.clamp(1., constraint.max.y())),
(), // (),
) // )
} // }
fn paint( // fn paint(
&mut self, // &mut self,
bounds: RectF, // bounds: RectF,
visible_bounds: RectF, // visible_bounds: RectF,
_layout: &mut Self::LayoutState, // _layout: &mut Self::LayoutState,
view: &mut V, // view: &mut V,
cx: &mut ViewContext<V>, // cx: &mut ViewContext<V>,
) -> Self::PaintState { // ) -> Self::PaintState {
let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); // let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
let origin_y = bounds.upper_right().y(); // let origin_y = bounds.upper_right().y();
let mut origin_x = bounds.upper_right().x(); // let mut origin_x = bounds.upper_right().x();
for face in self.faces.iter_mut().rev() { // for face in self.faces.iter_mut().rev() {
let size = face.size(); // let size = face.size();
origin_x -= size.x(); // origin_x -= size.x();
let origin_y = origin_y + (bounds.height() - size.y()) / 2.0; // let origin_y = origin_y + (bounds.height() - size.y()) / 2.0;
cx.scene().push_layer(None); // cx.scene().push_layer(None);
face.paint(vec2f(origin_x, origin_y), visible_bounds, view, cx); // face.paint(vec2f(origin_x, origin_y), visible_bounds, view, cx);
cx.scene().pop_layer(); // cx.scene().pop_layer();
origin_x += self.overlap; // origin_x += self.overlap;
} // }
() // ()
} // }
fn rect_for_text_range( // fn rect_for_text_range(
&self, // &self,
_: Range<usize>, // _: Range<usize>,
_: RectF, // _: RectF,
_: RectF, // _: RectF,
_: &Self::LayoutState, // _: &Self::LayoutState,
_: &Self::PaintState, // _: &Self::PaintState,
_: &V, // _: &V,
_: &ViewContext<V>, // _: &ViewContext<V>,
) -> Option<RectF> { // ) -> Option<RectF> {
None // None
} // }
fn debug( // fn debug(
&self, // &self,
bounds: RectF, // bounds: RectF,
_: &Self::LayoutState, // _: &Self::LayoutState,
_: &Self::PaintState, // _: &Self::PaintState,
_: &V, // _: &V,
_: &ViewContext<V>, // _: &ViewContext<V>,
) -> serde_json::Value { // ) -> serde_json::Value {
json!({ // json!({
"type": "FacePile", // "type": "FacePile",
"bounds": bounds.to_json() // "bounds": bounds.to_json()
}) // })
} // }
} // }
impl<V: View> Extend<AnyElement<V>> for FacePile<V> { // impl<V: View> Extend<AnyElement<V>> for FacePile<V> {
fn extend<T: IntoIterator<Item = AnyElement<V>>>(&mut self, children: T) { // fn extend<T: IntoIterator<Item = AnyElement<V>>>(&mut self, children: T) {
self.faces.extend(children); // self.faces.extend(children);
} // }
} // }

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
use gpui::AppContext; // use gpui::AppContext;
use std::sync::Arc; // use std::sync::Arc;
use workspace::AppState; // use workspace::AppState;
pub mod incoming_call_notification; // pub mod incoming_call_notification;
pub mod project_shared_notification; // pub mod project_shared_notification;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) { // pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
incoming_call_notification::init(app_state, cx); // incoming_call_notification::init(app_state, cx);
project_shared_notification::init(app_state, cx); // project_shared_notification::init(app_state, cx);
} // }

View file

@ -1,7 +1,7 @@
use anyhow; use anyhow;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use settings::Setting; use settings::Settings;
use workspace::dock::DockPosition; use workspace::dock::DockPosition;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -32,37 +32,37 @@ pub struct PanelSettingsContent {
pub default_width: Option<f32>, pub default_width: Option<f32>,
} }
impl Setting for CollaborationPanelSettings { impl Settings for CollaborationPanelSettings {
const KEY: Option<&'static str> = Some("collaboration_panel"); const KEY: Option<&'static str> = Some("collaboration_panel");
type FileContent = PanelSettingsContent; type FileContent = PanelSettingsContent;
fn load( fn load(
default_value: &Self::FileContent, default_value: &Self::FileContent,
user_values: &[&Self::FileContent], user_values: &[&Self::FileContent],
_: &gpui::AppContext, _: &mut gpui::AppContext,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values) Self::load_via_json_merge(default_value, user_values)
} }
} }
impl Setting for ChatPanelSettings { impl Settings for ChatPanelSettings {
const KEY: Option<&'static str> = Some("chat_panel"); const KEY: Option<&'static str> = Some("chat_panel");
type FileContent = PanelSettingsContent; type FileContent = PanelSettingsContent;
fn load( fn load(
default_value: &Self::FileContent, default_value: &Self::FileContent,
user_values: &[&Self::FileContent], user_values: &[&Self::FileContent],
_: &gpui::AppContext, _: &mut gpui::AppContext,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values) Self::load_via_json_merge(default_value, user_values)
} }
} }
impl Setting for NotificationPanelSettings { impl Settings for NotificationPanelSettings {
const KEY: Option<&'static str> = Some("notification_panel"); const KEY: Option<&'static str> = Some("notification_panel");
type FileContent = PanelSettingsContent; type FileContent = PanelSettingsContent;
fn load( fn load(
default_value: &Self::FileContent, default_value: &Self::FileContent,
user_values: &[&Self::FileContent], user_values: &[&Self::FileContent],
_: &gpui::AppContext, _: &mut gpui::AppContext,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values) Self::load_via_json_merge(default_value, user_values)
} }

View file

@ -36,11 +36,10 @@ use futures::{
Future, FutureExt, StreamExt, Future, FutureExt, StreamExt,
}; };
use gpui::{ use gpui::{
actions, div, point, prelude::*, rems, size, Action, AnyModel, AnyView, AnyWeakView, actions, div, point, prelude::*, size, Action, AnyModel, AnyView, AnyWeakView, AppContext,
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, AsyncAppContext, AsyncWindowContext, Bounds, Div, Entity, EntityId, EventEmitter, GlobalPixels,
EventEmitter, GlobalPixels, KeyContext, Model, ModelContext, ParentComponent, Point, Render, KeyContext, Model, ModelContext, ParentComponent, Point, Render, Size, Styled, Subscription,
Size, Styled, Subscription, Task, View, ViewContext, WeakView, WindowBounds, WindowContext, Task, View, ViewContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions,
WindowHandle, WindowOptions,
}; };
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools; use itertools::Itertools;
@ -68,8 +67,6 @@ use std::{
}; };
use theme2::{ActiveTheme, ThemeSettings}; use theme2::{ActiveTheme, ThemeSettings};
pub use toolbar::{ToolbarItemLocation, ToolbarItemView}; pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
use ui::TextColor;
use ui::{h_stack, Button, ButtonVariant, KeyBinding, Label, TextTooltip};
use util::ResultExt; use util::ResultExt;
use uuid::Uuid; use uuid::Uuid;
pub use workspace_settings::{AutosaveSetting, WorkspaceSettings}; pub use workspace_settings::{AutosaveSetting, WorkspaceSettings};
@ -447,7 +444,7 @@ pub struct Workspace {
last_active_view_id: Option<proto::ViewId>, last_active_view_id: Option<proto::ViewId>,
status_bar: View<StatusBar>, status_bar: View<StatusBar>,
modal_layer: View<ModalLayer>, modal_layer: View<ModalLayer>,
// titlebar_item: Option<AnyViewHandle>, titlebar_item: Option<AnyView>,
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>, notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Model<Project>, project: Model<Project>,
follower_states: HashMap<View<Pane>, FollowerState>, follower_states: HashMap<View<Pane>, FollowerState>,
@ -660,7 +657,7 @@ impl Workspace {
last_active_view_id: None, last_active_view_id: None,
status_bar, status_bar,
modal_layer, modal_layer,
// titlebar_item: None, titlebar_item: None,
notifications: Default::default(), notifications: Default::default(),
left_dock, left_dock,
bottom_dock, bottom_dock,
@ -1033,15 +1030,14 @@ impl Workspace {
&self.app_state.client &self.app_state.client
} }
// todo!() pub fn set_titlebar_item(&mut self, item: AnyView, cx: &mut ViewContext<Self>) {
// pub fn set_titlebar_item(&mut self, item: AnyViewHandle, cx: &mut ViewContext<Self>) { self.titlebar_item = Some(item);
// self.titlebar_item = Some(item); cx.notify();
// cx.notify(); }
// }
// pub fn titlebar_item(&self) -> Option<AnyViewHandle> { pub fn titlebar_item(&self) -> Option<AnyView> {
// self.titlebar_item.clone() self.titlebar_item.clone()
// } }
/// Call the given callback with a workspace whose project is local. /// Call the given callback with a workspace whose project is local.
/// ///
@ -2448,75 +2444,6 @@ impl Workspace {
// .any(|state| state.leader_id == peer_id) // .any(|state| state.leader_id == peer_id)
// } // }
fn render_titlebar(&self, cx: &mut ViewContext<Self>) -> impl Component<Self> {
h_stack()
.id("titlebar")
.justify_between()
.when(
!matches!(cx.window_bounds(), WindowBounds::Fullscreen),
|s| s.pl_20(),
)
.w_full()
.h(rems(1.75))
.bg(cx.theme().colors().title_bar_background)
.on_click(|_, event, cx| {
if event.up.click_count == 2 {
cx.zoom_window();
}
})
.child(
h_stack()
// TODO - Add player menu
.child(
div()
.id("project_owner_indicator")
.child(
Button::new("player")
.variant(ButtonVariant::Ghost)
.color(Some(TextColor::Player(0))),
)
.tooltip(move |_, cx| {
cx.build_view(|cx| TextTooltip::new("Toggle following"))
}),
)
// TODO - Add project menu
.child(
div()
.id("titlebar_project_menu_button")
.child(Button::new("project_name").variant(ButtonVariant::Ghost))
.tooltip(move |_, cx| {
cx.build_view(|cx| TextTooltip::new("Recent Projects"))
}),
)
// TODO - Add git menu
.child(
div()
.id("titlebar_git_menu_button")
.child(
Button::new("branch_name")
.variant(ButtonVariant::Ghost)
.color(Some(TextColor::Muted)),
)
.tooltip(move |_, cx| {
// todo!() Replace with real action.
#[gpui::action]
struct NoAction {}
cx.build_view(|cx| {
TextTooltip::new("Recent Branches")
.key_binding(KeyBinding::new(gpui::KeyBinding::new(
"cmd-b",
NoAction {},
None,
)))
.meta("Only local branches shown")
})
}),
),
) // self.titlebar_item
.child(h_stack().child(Label::new("Right side titlebar item")))
}
fn active_item_path_changed(&mut self, cx: &mut ViewContext<Self>) { fn active_item_path_changed(&mut self, cx: &mut ViewContext<Self>) {
let active_entry = self.active_project_path(cx); let active_entry = self.active_project_path(cx);
self.project self.project
@ -3719,7 +3646,7 @@ impl Render for Workspace {
.items_start() .items_start()
.text_color(cx.theme().colors().text) .text_color(cx.theme().colors().text)
.bg(cx.theme().colors().background) .bg(cx.theme().colors().background)
.child(self.render_titlebar(cx)) .children(self.titlebar_item.clone())
.child( .child(
// todo! should this be a component a view? // todo! should this be a component a view?
div() div()

View file

@ -207,7 +207,7 @@ fn main() {
// activity_indicator::init(cx); // activity_indicator::init(cx);
// language_tools::init(cx); // language_tools::init(cx);
call::init(app_state.client.clone(), app_state.user_store.clone(), cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
// collab_ui::init(&app_state, cx); collab_ui::init(&app_state, cx);
// feedback::init(cx); // feedback::init(cx);
// welcome::init(cx); // welcome::init(cx);
// zed::init(&app_state, cx); // zed::init(&app_state, cx);

View file

@ -341,10 +341,6 @@ pub fn initialize_workspace(
// workspace.active_pane().clone(), // workspace.active_pane().clone(),
// )); // ));
// let collab_titlebar_item =
// cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx));
// workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx);
// let copilot = // let copilot =
// cx.add_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx)); // cx.add_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
// let diagnostic_summary = // let diagnostic_summary =