Refine messages on waiting to join screen and include host avatar

This commit is contained in:
Nathan Sobo 2022-05-16 16:52:31 -06:00
parent 91257f308e
commit 7c3eebf93e
13 changed files with 125 additions and 29 deletions

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#26232a", "background": "#26232a",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#e2dfe7", "background": "#e2dfe7",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#1c1c1c", "background": "#1c1c1c",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#f8f8f8", "background": "#f8f8f8",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#073642", "background": "#073642",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#eee8d5", "background": "#eee8d5",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#293256", "background": "#293256",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -90,6 +90,10 @@
}, },
"workspace": { "workspace": {
"background": "#dfe2f1", "background": "#dfe2f1",
"joining_project_avatar": {
"corner_radius": 40,
"width": 80
},
"joining_project_message": { "joining_project_message": {
"padding": 12, "padding": 12,
"family": "Zed Sans", "family": "Zed Sans",

View file

@ -336,14 +336,14 @@ impl ContactsPanel {
fn render_contact_project( fn render_contact_project(
contact: Arc<Contact>, contact: Arc<Contact>,
current_user_id: Option<u64>, current_user_id: Option<u64>,
project_ix: usize, project_index: usize,
app_state: Arc<AppState>, app_state: Arc<AppState>,
theme: &theme::ContactsPanel, theme: &theme::ContactsPanel,
is_last_project: bool, is_last_project: bool,
is_selected: bool, is_selected: bool,
cx: &mut LayoutContext, cx: &mut LayoutContext,
) -> ElementBox { ) -> ElementBox {
let project = &contact.projects[project_ix]; let project = &contact.projects[project_index];
let project_id = project.id; let project_id = project.id;
let is_host = Some(contact.user.id) == current_user_id; let is_host = Some(contact.user.id) == current_user_id;
let is_guest = !is_host let is_guest = !is_host
@ -445,7 +445,8 @@ impl ContactsPanel {
.on_click(move |_, cx| { .on_click(move |_, cx| {
if !is_host && !is_guest { if !is_host && !is_guest {
cx.dispatch_global_action(JoinProject { cx.dispatch_global_action(JoinProject {
project_id, contact: contact.clone(),
project_index,
app_state: app_state.clone(), app_state: app_state.clone(),
}); });
} }
@ -768,12 +769,12 @@ impl ContactsPanel {
let section = *section; let section = *section;
self.toggle_expanded(&ToggleExpanded(section), cx); self.toggle_expanded(&ToggleExpanded(section), cx);
} }
ContactEntry::ContactProject(contact, project_ix) => { ContactEntry::ContactProject(contact, project_index) => cx
cx.dispatch_global_action(JoinProject { .dispatch_global_action(JoinProject {
project_id: contact.projects[*project_ix].id, contact: contact.clone(),
project_index: *project_index,
app_state: self.app_state.clone(), app_state: self.app_state.clone(),
}) }),
}
_ => {} _ => {}
} }
} }

View file

@ -48,6 +48,7 @@ pub struct Workspace {
pub modal: ContainerStyle, pub modal: ContainerStyle,
pub notification: ContainerStyle, pub notification: ContainerStyle,
pub notifications: Notifications, pub notifications: Notifications,
pub joining_project_avatar: ImageStyle,
pub joining_project_message: ContainedText, pub joining_project_message: ContainedText,
} }

View file

@ -8,7 +8,8 @@ mod toolbar;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use client::{ use client::{
proto, Authenticate, ChannelList, Client, PeerId, Subscription, TypedEnvelope, User, UserStore, proto, Authenticate, ChannelList, Client, Contact, PeerId, Subscription, TypedEnvelope, User,
UserStore,
}; };
use clock::ReplicaId; use clock::ReplicaId;
use collections::{hash_map, HashMap, HashSet}; use collections::{hash_map, HashMap, HashSet};
@ -97,7 +98,8 @@ pub struct ToggleFollow(pub PeerId);
#[derive(Clone)] #[derive(Clone)]
pub struct JoinProject { pub struct JoinProject {
pub project_id: u64, pub contact: Arc<Contact>,
pub project_index: usize,
pub app_state: Arc<AppState>, pub app_state: Arc<AppState>,
} }
@ -117,7 +119,13 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
open_new(&action.0, cx) open_new(&action.0, cx)
}); });
cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| { cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| {
join_project(action.project_id, &action.app_state, cx).detach(); join_project(
action.contact.clone(),
action.project_index,
&action.app_state,
cx,
)
.detach();
}); });
cx.add_async_action(Workspace::toggle_follow); cx.add_async_action(Workspace::toggle_follow);
@ -2268,12 +2276,16 @@ pub fn open_paths(
} }
pub fn join_project( pub fn join_project(
project_id: u64, contact: Arc<Contact>,
project_index: usize,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) -> Task<Result<ViewHandle<Workspace>>> { ) -> Task<Result<ViewHandle<Workspace>>> {
let project_id = contact.projects[project_index].id;
struct JoiningNotice { struct JoiningNotice {
message: &'static str, avatar: Option<Arc<ImageData>>,
message: String,
} }
impl Entity for JoiningNotice { impl Entity for JoiningNotice {
@ -2287,16 +2299,28 @@ pub fn join_project(
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox { fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = &cx.global::<Settings>().theme.workspace; let theme = &cx.global::<Settings>().theme.workspace;
Text::new(
self.message.to_string(), Flex::column()
theme.joining_project_message.text.clone(), .with_children(self.avatar.clone().map(|avatar| {
) Image::new(avatar)
.contained() .with_style(theme.joining_project_avatar)
.with_style(theme.joining_project_message.container) .aligned()
.aligned() .boxed()
.contained() }))
.with_background_color(theme.background) .with_child(
.boxed() 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()
} }
} }
@ -2312,7 +2336,12 @@ pub fn join_project(
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let (window, joining_notice) = cx.update(|cx| { let (window, joining_notice) = cx.update(|cx| {
cx.add_window((app_state.build_window_options)(), |_| JoiningNotice { cx.add_window((app_state.build_window_options)(), |_| JoiningNotice {
message: "Loading remote project...", avatar: contact.user.avatar.clone(),
message: format!(
"Asking to join @{}'s copy of {}...",
contact.user.github_login,
humanize_list(&contact.projects[project_index].worktree_root_names)
),
}) })
}); });
let project = Project::remote( let project = Project::remote(
@ -2338,15 +2367,22 @@ pub fn join_project(
workspace workspace
})), })),
Err(error @ _) => { Err(error @ _) => {
let login = &contact.user.github_login;
let message = match error { let message = match error {
project::JoinProjectError::HostDeclined => { project::JoinProjectError::HostDeclined => {
"The host declined your request to join." format!("@{} declined your request.", login)
} }
project::JoinProjectError::HostClosedProject => "The host closed the project.", project::JoinProjectError::HostClosedProject => {
project::JoinProjectError::HostWentOffline => "The host went offline.", format!(
project::JoinProjectError::Other(_) => { "@{} closed their copy of {}.",
"An error occurred when attempting to join the project." login,
humanize_list(&contact.projects[project_index].worktree_root_names)
)
} }
project::JoinProjectError::HostWentOffline => {
format!("@{} went offline.", login)
}
project::JoinProjectError::Other(_) => "An error occurred.".to_string(),
}; };
joining_notice.update(cx, |notice, cx| { joining_notice.update(cx, |notice, cx| {
notice.message = message; notice.message = message;
@ -2372,3 +2408,18 @@ fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
}); });
cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone())); cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone()));
} }
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
}

7
script/watch-themes Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
set -e
cd styles
npm install
npm run watch

View file

@ -41,6 +41,10 @@ export default function workspace(theme: Theme) {
return { return {
background: backgroundColor(theme, 300), background: backgroundColor(theme, 300),
joiningProjectAvatar: {
cornerRadius: 40,
width: 80,
},
joiningProjectMessage: { joiningProjectMessage: {
padding: 12, padding: 12,
...text(theme, "sans", "primary", { size: "lg" }) ...text(theme, "sans", "primary", { size: "lg" })