History

Refine messages on waiting to join screen and include host avatar

Nathan Sobo committed 4 years ago

Commit 7c3eebf1 parent 91257f313 files · +125 −29Browse files

Unified · Split

13 files
  1. assets/themes/cave-dark.json +4 −0
  2. assets/themes/cave-light.json +4 −0
  3. assets/themes/dark.json +4 −0
  4. assets/themes/light.json +4 −0
  5. assets/themes/solarized-dark.json +4 −0
  6. assets/themes/solarized-light.json +4 −0
  7. assets/themes/sulphurpool-dark.json +4 −0
  8. assets/themes/sulphurpool-light.json +4 −0
  9. crates/contacts_panel/src/contacts_panel.rs +9 −8
  10. crates/theme/src/theme.rs +1 −0
  11. crates/workspace/src/workspace.rs +72 −21
  12. script/watch-themes +7 −0
  13. styles/src/styleTree/workspace.ts +4 −0
assets/themes/cave-dark.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#26232a",92 "background": "#26232a",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/cave-light.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#e2dfe7",92 "background": "#e2dfe7",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/dark.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#1c1c1c",92 "background": "#1c1c1c",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/light.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#f8f8f8",92 "background": "#f8f8f8",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/solarized-dark.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#073642",92 "background": "#073642",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/solarized-light.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#eee8d5",92 "background": "#eee8d5",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/sulphurpool-dark.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#293256",92 "background": "#293256",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
assets/themes/sulphurpool-light.json+4−0
@@ -90,6 +90,10 @@ · 89 unmodified lines
90 },90 },
91 "workspace": {91 "workspace": {
92 "background": "#dfe2f1",92 "background": "#dfe2f1",
93 "joining_project_avatar": {
94 "corner_radius": 40,
95 "width": 80
96 },
93 "joining_project_message": {97 "joining_project_message": {
94 "padding": 12,98 "padding": 12,
95 "family": "Zed Sans",99 "family": "Zed Sans",
crates/contacts_panel/src/contacts_panel.rs+9−8
@@ -336,14 +336,14 @@ impl ContactsPanel { · 335 unmodified lines
336 fn render_contact_project(336 fn render_contact_project(
337 contact: Arc<Contact>,337 contact: Arc<Contact>,
338 current_user_id: Option<u64>,338 current_user_id: Option<u64>,
339 project_ix: usize,339 project_index: usize,
340 app_state: Arc<AppState>,340 app_state: Arc<AppState>,
341 theme: &theme::ContactsPanel,341 theme: &theme::ContactsPanel,
342 is_last_project: bool,342 is_last_project: bool,
343 is_selected: bool,343 is_selected: bool,
344 cx: &mut LayoutContext,344 cx: &mut LayoutContext,
345 ) -> ElementBox {345 ) -> ElementBox {
346 let project = &contact.projects[project_ix];346 let project = &contact.projects[project_index];
347 let project_id = project.id;347 let project_id = project.id;
348 let is_host = Some(contact.user.id) == current_user_id;348 let is_host = Some(contact.user.id) == current_user_id;
349 let is_guest = !is_host349 let is_guest = !is_host
@@ -445,7 +445,8 @@ impl ContactsPanel { · 95 unmodified lines
445 .on_click(move |_, cx| {445 .on_click(move |_, cx| {
446 if !is_host && !is_guest {446 if !is_host && !is_guest {
447 cx.dispatch_global_action(JoinProject {447 cx.dispatch_global_action(JoinProject {
448 project_id,448 contact: contact.clone(),
449 project_index,
449 app_state: app_state.clone(),450 app_state: app_state.clone(),
450 });451 });
451 }452 }
@@ -768,12 +769,12 @@ impl ContactsPanel { · 316 unmodified lines
768 let section = *section;769 let section = *section;
769 self.toggle_expanded(&ToggleExpanded(section), cx);770 self.toggle_expanded(&ToggleExpanded(section), cx);
770 }771 }
771 ContactEntry::ContactProject(contact, project_ix) => {772 ContactEntry::ContactProject(contact, project_index) => cx
772 cx.dispatch_global_action(JoinProject {773 .dispatch_global_action(JoinProject {
773 project_id: contact.projects[*project_ix].id,774 contact: contact.clone(),
775 project_index: *project_index,
774 app_state: self.app_state.clone(),776 app_state: self.app_state.clone(),
775 })777 }),
776 }
777 _ => {}778 _ => {}
778 }779 }
779 }780 }
crates/theme/src/theme.rs+1−0
@@ -48,6 +48,7 @@ pub struct Workspace { · 47 unmodified lines
48 pub modal: ContainerStyle,48 pub modal: ContainerStyle,
49 pub notification: ContainerStyle,49 pub notification: ContainerStyle,
50 pub notifications: Notifications,50 pub notifications: Notifications,
51 pub joining_project_avatar: ImageStyle,
51 pub joining_project_message: ContainedText,52 pub joining_project_message: ContainedText,
52}53}
53 54
crates/workspace/src/workspace.rs+72−21
@@ -8,7 +8,8 @@ mod toolbar; · 7 unmodified lines
8 8
9use anyhow::{anyhow, Context, Result};9use anyhow::{anyhow, Context, Result};
10use client::{10use client::{
11 proto, Authenticate, ChannelList, Client, PeerId, Subscription, TypedEnvelope, User, UserStore,11 proto, Authenticate, ChannelList, Client, Contact, PeerId, Subscription, TypedEnvelope, User,
12 UserStore,
12};13};
13use clock::ReplicaId;14use clock::ReplicaId;
14use collections::{hash_map, HashMap, HashSet};15use collections::{hash_map, HashMap, HashSet};
@@ -97,7 +98,8 @@ pub struct ToggleFollow(pub PeerId); · 82 unmodified lines
97 98
98#[derive(Clone)]99#[derive(Clone)]
99pub struct JoinProject {100pub struct JoinProject {
100 pub project_id: u64,101 pub contact: Arc<Contact>,
102 pub project_index: usize,
101 pub app_state: Arc<AppState>,103 pub app_state: Arc<AppState>,
102}104}
103 105
@@ -117,7 +119,13 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) { · 13 unmodified lines
117 open_new(&action.0, cx)119 open_new(&action.0, cx)
118 });120 });
119 cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| {121 cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| {
120 join_project(action.project_id, &action.app_state, cx).detach();122 join_project(
123 action.contact.clone(),
124 action.project_index,
125 &action.app_state,
126 cx,
127 )
128 .detach();
121 });129 });
122 130
123 cx.add_async_action(Workspace::toggle_follow);131 cx.add_async_action(Workspace::toggle_follow);
@@ -2268,12 +2276,16 @@ pub fn open_paths( · 2144 unmodified lines
2268}2276}
2269 2277
2270pub fn join_project(2278pub fn join_project(
2271 project_id: u64,2279 contact: Arc<Contact>,
2280 project_index: usize,
2272 app_state: &Arc<AppState>,2281 app_state: &Arc<AppState>,
2273 cx: &mut MutableAppContext,2282 cx: &mut MutableAppContext,
2274) -> Task<Result<ViewHandle<Workspace>>> {2283) -> Task<Result<ViewHandle<Workspace>>> {
2284 let project_id = contact.projects[project_index].id;
2285
2275 struct JoiningNotice {2286 struct JoiningNotice {
2276 message: &'static str,2287 avatar: Option<Arc<ImageData>>,
2288 message: String,
2277 }2289 }
2278 2290
2279 impl Entity for JoiningNotice {2291 impl Entity for JoiningNotice {
@@ -2287,16 +2299,28 @@ pub fn join_project( · 7 unmodified lines
2287 2299
2288 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {2300 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
2289 let theme = &cx.global::<Settings>().theme.workspace;2301 let theme = &cx.global::<Settings>().theme.workspace;
2290 Text::new(2302
2291 self.message.to_string(),2303 Flex::column()
2292 theme.joining_project_message.text.clone(),2304 .with_children(self.avatar.clone().map(|avatar| {
2293 )2305 Image::new(avatar)
2294 .contained()2306 .with_style(theme.joining_project_avatar)
2295 .with_style(theme.joining_project_message.container)2307 .aligned()
2296 .aligned()2308 .boxed()
2297 .contained()2309 }))
2298 .with_background_color(theme.background)2310 .with_child(
2299 .boxed()2311 Text::new(
2312 self.message.clone(),
2313 theme.joining_project_message.text.clone(),
2314 )
2315 .contained()
2316 .with_style(theme.joining_project_message.container)
2317 .aligned()
2318 .boxed(),
2319 )
2320 .aligned()
2321 .contained()
2322 .with_background_color(theme.background)
2323 .boxed()
2300 }2324 }
2301 }2325 }
2302 2326
@@ -2312,7 +2336,12 @@ pub fn join_project( · 9 unmodified lines
2312 cx.spawn(|mut cx| async move {2336 cx.spawn(|mut cx| async move {
2313 let (window, joining_notice) = cx.update(|cx| {2337 let (window, joining_notice) = cx.update(|cx| {
2314 cx.add_window((app_state.build_window_options)(), |_| JoiningNotice {2338 cx.add_window((app_state.build_window_options)(), |_| JoiningNotice {
2315 message: "Loading remote project...",2339 avatar: contact.user.avatar.clone(),
2340 message: format!(
2341 "Asking to join @{}'s copy of {}...",
2342 contact.user.github_login,
2343 humanize_list(&contact.projects[project_index].worktree_root_names)
2344 ),
2316 })2345 })
2317 });2346 });
2318 let project = Project::remote(2347 let project = Project::remote(
@@ -2338,15 +2367,22 @@ pub fn join_project( · 19 unmodified lines
2338 workspace2367 workspace
2339 })),2368 })),
2340 Err(error @ _) => {2369 Err(error @ _) => {
2370 let login = &contact.user.github_login;
2341 let message = match error {2371 let message = match error {
2342 project::JoinProjectError::HostDeclined => {2372 project::JoinProjectError::HostDeclined => {
2343 "The host declined your request to join."2373 format!("@{} declined your request.", login)
2374 }
2375 project::JoinProjectError::HostClosedProject => {
2376 format!(
2377 "@{} closed their copy of {}.",
2378 login,
2379 humanize_list(&contact.projects[project_index].worktree_root_names)
2380 )
2344 }2381 }
2345 project::JoinProjectError::HostClosedProject => "The host closed the project.",2382 project::JoinProjectError::HostWentOffline => {
2346 project::JoinProjectError::HostWentOffline => "The host went offline.",2383 format!("@{} went offline.", login)
2347 project::JoinProjectError::Other(_) => {
2348 "An error occurred when attempting to join the project."
2349 }2384 }
2385 project::JoinProjectError::Other(_) => "An error occurred.".to_string(),
2350 };2386 };
2351 joining_notice.update(cx, |notice, cx| {2387 joining_notice.update(cx, |notice, cx| {
2352 notice.message = message;2388 notice.message = message;
@@ -2372,3 +2408,18 @@ fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) { · 19 unmodified lines
2372 });2408 });
2373 cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone()));2409 cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone()));
2374}2410}
2411
2412fn humanize_list<'a>(items: impl IntoIterator<Item = &'a String>) -> String {
2413 let mut list = String::new();
2414 let mut items = items.into_iter().enumerate().peekable();
2415 while let Some((ix, item)) = items.next() {
2416 if ix > 0 {
2417 list.push_str(", ");
2418 }
2419 if items.peek().is_none() {
2420 list.push_str("and ");
2421 }
2422 list.push_str(item);
2423 }
2424 list
2425}
script/watch-themes+7−0
@@ -0,0 +1,7 @@
1#!/bin/bash
2
3set -e
4
5cd styles
6npm install
7npm run watch
styles/src/styleTree/workspace.ts+4−0
@@ -41,6 +41,10 @@ export default function workspace(theme: Theme) { · 40 unmodified lines
41 41
42 return {42 return {
43 background: backgroundColor(theme, 300),43 background: backgroundColor(theme, 300),
44 joiningProjectAvatar: {
45 cornerRadius: 40,
46 width: 80,
47 },
44 joiningProjectMessage: {48 joiningProjectMessage: {
45 padding: 12,49 padding: 12,
46 ...text(theme, "sans", "primary", { size: "lg" })50 ...text(theme, "sans", "primary", { size: "lg" })