mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-11 12:46:07 +00:00
183 lines
6.9 KiB
Rust
183 lines
6.9 KiB
Rust
use crate::{sidebar::Side, AppState, ToggleFollow, Workspace};
|
|
use anyhow::Result;
|
|
use client::{proto, Client, Contact};
|
|
use gpui::{
|
|
elements::*, ElementBox, Entity, ImageData, MutableAppContext, RenderContext, Task, View,
|
|
ViewContext,
|
|
};
|
|
use project::Project;
|
|
use settings::Settings;
|
|
use std::sync::Arc;
|
|
use util::ResultExt;
|
|
|
|
pub struct WaitingRoom {
|
|
project_id: u64,
|
|
avatar: Option<Arc<ImageData>>,
|
|
message: String,
|
|
waiting: bool,
|
|
client: Arc<Client>,
|
|
_join_task: Task<Result<()>>,
|
|
}
|
|
|
|
impl Entity for WaitingRoom {
|
|
type Event = ();
|
|
|
|
fn release(&mut self, _: &mut MutableAppContext) {
|
|
if self.waiting {
|
|
self.client
|
|
.send(proto::LeaveProject {
|
|
project_id: self.project_id,
|
|
})
|
|
.log_err();
|
|
}
|
|
}
|
|
}
|
|
|
|
impl View for WaitingRoom {
|
|
fn ui_name() -> &'static str {
|
|
"WaitingRoom"
|
|
}
|
|
|
|
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
|
let theme = &cx.global::<Settings>().theme.workspace;
|
|
|
|
Flex::column()
|
|
.with_children(self.avatar.clone().map(|avatar| {
|
|
Image::new(avatar)
|
|
.with_style(theme.joining_project_avatar)
|
|
.aligned()
|
|
.boxed()
|
|
}))
|
|
.with_child(
|
|
Text::new(
|
|
self.message.clone(),
|
|
theme.joining_project_message.text.clone(),
|
|
)
|
|
.contained()
|
|
.with_style(theme.joining_project_message.container)
|
|
.aligned()
|
|
.boxed(),
|
|
)
|
|
.aligned()
|
|
.contained()
|
|
.with_background_color(theme.background)
|
|
.boxed()
|
|
}
|
|
}
|
|
|
|
impl WaitingRoom {
|
|
pub fn new(
|
|
contact: Arc<Contact>,
|
|
project_index: usize,
|
|
app_state: Arc<AppState>,
|
|
cx: &mut ViewContext<Self>,
|
|
) -> Self {
|
|
let project_id = contact.projects[project_index].id;
|
|
let client = app_state.client.clone();
|
|
let _join_task =
|
|
cx.spawn_weak({
|
|
let contact = contact.clone();
|
|
|this, mut cx| async move {
|
|
let project = Project::remote(
|
|
project_id,
|
|
app_state.client.clone(),
|
|
app_state.user_store.clone(),
|
|
app_state.project_store.clone(),
|
|
app_state.languages.clone(),
|
|
app_state.fs.clone(),
|
|
cx.clone(),
|
|
)
|
|
.await;
|
|
|
|
if let Some(this) = this.upgrade(&cx) {
|
|
this.update(&mut cx, |this, cx| {
|
|
this.waiting = false;
|
|
match project {
|
|
Ok(project) => {
|
|
cx.replace_root_view(|cx| {
|
|
let mut workspace = Workspace::new(project, cx);
|
|
(app_state.initialize_workspace)(
|
|
&mut workspace,
|
|
&app_state,
|
|
cx,
|
|
);
|
|
workspace.toggle_sidebar(Side::Left, cx);
|
|
if let Some((host_peer_id, _)) =
|
|
workspace.project.read(cx).collaborators().iter().find(
|
|
|(_, collaborator)| collaborator.replica_id == 0,
|
|
)
|
|
{
|
|
if let Some(follow) = workspace
|
|
.toggle_follow(&ToggleFollow(*host_peer_id), cx)
|
|
{
|
|
follow.detach_and_log_err(cx);
|
|
}
|
|
}
|
|
workspace
|
|
});
|
|
}
|
|
Err(error @ _) => {
|
|
let login = &contact.user.github_login;
|
|
let message = match error {
|
|
project::JoinProjectError::HostDeclined => {
|
|
format!("@{} declined your request.", login)
|
|
}
|
|
project::JoinProjectError::HostClosedProject => {
|
|
format!(
|
|
"@{} closed their copy of {}.",
|
|
login,
|
|
humanize_list(
|
|
&contact.projects[project_index]
|
|
.visible_worktree_root_names
|
|
)
|
|
)
|
|
}
|
|
project::JoinProjectError::HostWentOffline => {
|
|
format!("@{} went offline.", login)
|
|
}
|
|
project::JoinProjectError::Other(error) => {
|
|
log::error!("error joining project: {}", error);
|
|
"An error occurred.".to_string()
|
|
}
|
|
};
|
|
this.message = message;
|
|
cx.notify();
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
});
|
|
|
|
Self {
|
|
project_id,
|
|
avatar: contact.user.avatar.clone(),
|
|
message: format!(
|
|
"Asking to join @{}'s copy of {}...",
|
|
contact.user.github_login,
|
|
humanize_list(&contact.projects[project_index].visible_worktree_root_names)
|
|
),
|
|
waiting: true,
|
|
client,
|
|
_join_task,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn humanize_list<'a>(items: impl IntoIterator<Item = &'a String>) -> String {
|
|
let mut list = String::new();
|
|
let mut items = items.into_iter().enumerate().peekable();
|
|
while let Some((ix, item)) = items.next() {
|
|
if ix > 0 {
|
|
list.push_str(", ");
|
|
if items.peek().is_none() {
|
|
list.push_str("and ");
|
|
}
|
|
}
|
|
|
|
list.push_str(item);
|
|
}
|
|
list
|
|
}
|