From 44d40625fee03966164352ac5874526de6153b71 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 12 Dec 2023 11:26:37 -0500 Subject: [PATCH] Start changing Avatar to use URI Co-Authored-By: Antonio Scandurra --- crates/channel2/src/channel_store_tests.rs | 2 +- crates/client2/src/test.rs | 4 +- crates/client2/src/user.rs | 32 ++--- crates/collab2/src/tests/integration_tests.rs | 4 +- crates/collab2/src/tests/test_server.rs | 2 +- crates/collab_ui2/src/chat_panel.rs | 10 +- .../src/chat_panel/message_editor.rs | 6 +- crates/collab_ui2/src/collab_panel.rs | 85 ++++++------- .../src/collab_panel/contact_finder.rs | 4 +- crates/collab_ui2/src/collab_titlebar_item.rs | 112 ++++++++---------- crates/collab_ui2/src/face_pile.rs | 13 +- crates/collab_ui2/src/notification_panel.rs | 83 +++++++------ crates/project2/src/project2.rs | 2 +- crates/ui2/src/components/avatar.rs | 12 +- crates/ui2/src/components/list/list_item.rs | 2 +- crates/ui2/src/components/stories/avatar.rs | 8 +- crates/workspace2/src/workspace2.rs | 2 +- crates/zed2/src/main.rs | 2 +- crates/zed2/src/zed2.rs | 8 +- 19 files changed, 190 insertions(+), 203 deletions(-) diff --git a/crates/channel2/src/channel_store_tests.rs b/crates/channel2/src/channel_store_tests.rs index e193917b76ea6db80554fe10d82364492fe8cc7c..7f392032cdfbfbaf5ac597746e08efd4afbfde56 100644 --- a/crates/channel2/src/channel_store_tests.rs +++ b/crates/channel2/src/channel_store_tests.rs @@ -345,7 +345,7 @@ async fn test_channel_messages(cx: &mut TestAppContext) { fn init_test(cx: &mut AppContext) -> Model { let http = FakeHttpClient::with_404_response(); let client = Client::new(http.clone(), cx); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); diff --git a/crates/client2/src/test.rs b/crates/client2/src/test.rs index 086cbd570ec0f8d9d5108dc889a589b0b41572e0..ce3ea740b66edaf12590bddcc414af9579da9db1 100644 --- a/crates/client2/src/test.rs +++ b/crates/client2/src/test.rs @@ -8,7 +8,6 @@ use rpc::{ ConnectionId, Peer, Receipt, TypedEnvelope, }; use std::sync::Arc; -use util::http::FakeHttpClient; pub struct FakeServer { peer: Arc, @@ -195,8 +194,7 @@ impl FakeServer { client: Arc, cx: &mut TestAppContext, ) -> Model { - let http_client = FakeHttpClient::with_404_response(); - let user_store = cx.build_model(|cx| UserStore::new(client, http_client, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client, cx)); assert_eq!( self.receive::() .await diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index a5dba03d2da59e8277ed5f36a71d92fe51c63162..766861fbf8e7e6106cf148cbaff6b2fa8a4608c7 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -2,8 +2,8 @@ use super::{proto, Client, Status, TypedEnvelope}; use anyhow::{anyhow, Context, Result}; use collections::{hash_map::Entry, HashMap, HashSet}; use feature_flags::FeatureFlagAppExt; -use futures::{channel::mpsc, future, AsyncReadExt, Future, StreamExt}; -use gpui::{AsyncAppContext, EventEmitter, ImageData, Model, ModelContext, Task}; +use futures::{channel::mpsc, AsyncReadExt, Future, StreamExt}; +use gpui::{AsyncAppContext, EventEmitter, ImageData, Model, ModelContext, SharedString, Task}; use postage::{sink::Sink, watch}; use rpc::proto::{RequestMessage, UsersResponse}; use std::sync::{Arc, Weak}; @@ -20,7 +20,7 @@ pub struct ParticipantIndex(pub u32); pub struct User { pub id: UserId, pub github_login: String, - pub avatar: Option>, + pub avatar_uri: SharedString, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -76,7 +76,6 @@ pub struct UserStore { pending_contact_requests: HashMap, invite_info: Option, client: Weak, - http: Arc, _maintain_contacts: Task<()>, _maintain_current_user: Task>, } @@ -114,7 +113,6 @@ enum UpdateContacts { impl UserStore { pub fn new( client: Arc, - http: Arc, cx: &mut ModelContext, ) -> Self { let (mut current_user_tx, current_user_rx) = watch::channel(); @@ -134,7 +132,6 @@ impl UserStore { invite_info: None, client: Arc::downgrade(&client), update_contacts_tx, - http, _maintain_contacts: cx.spawn(|this, mut cx| async move { let _subscriptions = rpc_subscriptions; while let Some(message) = update_contacts_rx.next().await { @@ -445,6 +442,12 @@ impl UserStore { self.perform_contact_request(user_id, proto::RemoveContact { user_id }, cx) } + pub fn has_incoming_contact_request(&self, user_id: u64) -> bool { + self.incoming_contact_requests + .iter() + .any(|user| user.id == user_id) + } + pub fn respond_to_contact_request( &mut self, requester_id: u64, @@ -616,17 +619,14 @@ impl UserStore { cx: &mut ModelContext, ) -> Task>>> { let client = self.client.clone(); - let http = self.http.clone(); cx.spawn(|this, mut cx| async move { if let Some(rpc) = client.upgrade() { let response = rpc.request(request).await.context("error loading users")?; - let users = future::join_all( - response - .users - .into_iter() - .map(|user| User::new(user, http.as_ref())), - ) - .await; + let users = response + .users + .into_iter() + .map(|user| User::new(user)) + .collect::>(); this.update(&mut cx, |this, _| { for user in &users { @@ -659,11 +659,11 @@ impl UserStore { } impl User { - async fn new(message: proto::User, http: &dyn HttpClient) -> Arc { + fn new(message: proto::User) -> Arc { Arc::new(User { id: message.id, github_login: message.github_login, - avatar: fetch_avatar(http, &message.avatar_url).warn_on_err().await, + avatar_uri: message.avatar_url.into(), }) } } diff --git a/crates/collab2/src/tests/integration_tests.rs b/crates/collab2/src/tests/integration_tests.rs index 823c8e9045eb02fe67fa605bc1cf2d21fb88a670..201ba07dbb319663cb2c6f1810c50faa87a077ab 100644 --- a/crates/collab2/src/tests/integration_tests.rs +++ b/crates/collab2/src/tests/integration_tests.rs @@ -1823,7 +1823,7 @@ async fn test_active_call_events( owner: Arc::new(User { id: client_a.user_id().unwrap(), github_login: "user_a".to_string(), - avatar: None, + avatar_uri: "avatar_a".into(), }), project_id: project_a_id, worktree_root_names: vec!["a".to_string()], @@ -1841,7 +1841,7 @@ async fn test_active_call_events( owner: Arc::new(User { id: client_b.user_id().unwrap(), github_login: "user_b".to_string(), - avatar: None, + avatar_uri: "avatar_b".into(), }), project_id: project_b_id, worktree_root_names: vec!["b".to_string()] diff --git a/crates/collab2/src/tests/test_server.rs b/crates/collab2/src/tests/test_server.rs index f7517369711d6fc53fc5c53041122134af797e72..cfecb4880d1c226daef22a9233568bdace832296 100644 --- a/crates/collab2/src/tests/test_server.rs +++ b/crates/collab2/src/tests/test_server.rs @@ -209,7 +209,7 @@ impl TestServer { }); let fs = FakeFs::new(cx.executor()); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let workspace_store = cx.build_model(|cx| WorkspaceStore::new(client.clone(), cx)); let mut language_registry = LanguageRegistry::test(); language_registry.set_executor(cx.executor()); diff --git a/crates/collab_ui2/src/chat_panel.rs b/crates/collab_ui2/src/chat_panel.rs index c484016aae61a51d287f705ab531533bdba47042..6715ddf5138d2fcca6a0059e7d9219b2bee85229 100644 --- a/crates/collab_ui2/src/chat_panel.rs +++ b/crates/collab_ui2/src/chat_panel.rs @@ -364,13 +364,7 @@ impl ChatPanel { if !is_continuation { result = result.child( h_stack() - .children( - message - .sender - .avatar - .clone() - .map(|avatar| Avatar::data(avatar)), - ) + .child(Avatar::new(message.sender.avatar_uri.clone())) .child(Label::new(message.sender.github_login.clone())) .child(Label::new(format_timestamp( message.timestamp, @@ -659,7 +653,7 @@ mod tests { timestamp: OffsetDateTime::now_utc(), sender: Arc::new(client::User { github_login: "fgh".into(), - avatar: None, + avatar_uri: "avatar_fgh".into(), id: 103, }), nonce: 5, diff --git a/crates/collab_ui2/src/chat_panel/message_editor.rs b/crates/collab_ui2/src/chat_panel/message_editor.rs index 61e621525fa44a956b8c7197e00f1d9aab804d35..0b9d0be0b40b6db762f468b7d21f479fde1ea548 100644 --- a/crates/collab_ui2/src/chat_panel/message_editor.rs +++ b/crates/collab_ui2/src/chat_panel/message_editor.rs @@ -234,7 +234,7 @@ mod tests { user: Arc::new(User { github_login: "a-b".into(), id: 101, - avatar: None, + avatar_uri: "avatar_a-b".into(), }), kind: proto::channel_member::Kind::Member, role: proto::ChannelRole::Member, @@ -243,7 +243,7 @@ mod tests { user: Arc::new(User { github_login: "C_D".into(), id: 102, - avatar: None, + avatar_uri: "avatar_C_D".into(), }), kind: proto::channel_member::Kind::Member, role: proto::ChannelRole::Member, @@ -275,7 +275,7 @@ mod tests { cx.update(|cx| { let http = FakeHttpClient::with_404_response(); let client = Client::new(http.clone(), cx); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let settings = SettingsStore::test(cx); cx.set_global(settings); theme::init(theme::LoadThemes::JustBase, cx); diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 0b917d72b0beb4bf797641836e0f0989c0c7327f..bae1779d74acd6ef4e0292813ad9e3b1089db207 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -1155,7 +1155,7 @@ impl CollabPanel { let tooltip = format!("Follow {}", user.github_login); ListItem::new(SharedString::from(user.github_login.clone())) - .left_child(Avatar::data(user.avatar.clone().unwrap())) + .left_child(Avatar::new(user.avatar_uri.clone())) .child( h_stack() .w_full() @@ -2365,44 +2365,45 @@ impl CollabPanel { let busy = contact.busy || calling; let user_id = contact.user.id; let github_login = SharedString::from(contact.user.github_login.clone()); - let mut item = ListItem::new(github_login.clone()) - .on_click(cx.listener(move |this, _, cx| this.call(user_id, cx))) - .child( - h_stack() - .w_full() - .justify_between() - .child(Label::new(github_login.clone())) - .when(calling, |el| { - el.child(Label::new("Calling").color(Color::Muted)) - }) - .when(!calling, |el| { - el.child( - div() - .id("remove_contact") - .invisible() - .group_hover("", |style| style.visible()) - .child( - IconButton::new("remove_contact", Icon::Close) - .icon_color(Color::Muted) - .tooltip(|cx| Tooltip::text("Remove Contact", cx)) - .on_click(cx.listener({ - let github_login = github_login.clone(); - move |this, _, cx| { - this.remove_contact(user_id, &github_login, cx); - } - })), - ), - ) - }), - ) - .left_child( - // todo!() handle contacts with no avatar - Avatar::data(contact.user.avatar.clone().unwrap()) - .availability_indicator(if online { Some(!busy) } else { None }), - ) - .when(online && !busy, |el| { - el.on_click(cx.listener(move |this, _, cx| this.call(user_id, cx))) - }); + let mut item = + ListItem::new(github_login.clone()) + .on_click(cx.listener(move |this, _, cx| this.call(user_id, cx))) + .child( + h_stack() + .w_full() + .justify_between() + .child(Label::new(github_login.clone())) + .when(calling, |el| { + el.child(Label::new("Calling").color(Color::Muted)) + }) + .when(!calling, |el| { + el.child( + div() + .id("remove_contact") + .invisible() + .group_hover("", |style| style.visible()) + .child( + IconButton::new("remove_contact", Icon::Close) + .icon_color(Color::Muted) + .tooltip(|cx| Tooltip::text("Remove Contact", cx)) + .on_click(cx.listener({ + let github_login = github_login.clone(); + move |this, _, cx| { + this.remove_contact(user_id, &github_login, cx); + } + })), + ), + ) + }), + ) + .left_child( + // todo!() handle contacts with no avatar + Avatar::new(contact.user.avatar_uri.clone()) + .availability_indicator(if online { Some(!busy) } else { None }), + ) + .when(online && !busy, |el| { + el.on_click(cx.listener(move |this, _, cx| this.call(user_id, cx))) + }); div() .id(github_login.clone()) @@ -2474,7 +2475,7 @@ impl CollabPanel { .child(Label::new(github_login.clone())) .child(h_stack().children(controls)), ) - .when_some(user.avatar.clone(), |el, avatar| el.left_avatar(avatar)) + .left_avatar(user.avatar_uri.clone()) } fn render_contact_placeholder( @@ -2532,7 +2533,9 @@ impl CollabPanel { let result = FacePile { faces: participants .iter() - .filter_map(|user| Some(Avatar::data(user.avatar.clone()?).into_any_element())) + .filter_map(|user| { + Some(Avatar::new(user.avatar_uri.clone()).into_any_element()) + }) .take(FACEPILE_LIMIT) .chain(if extra_count > 0 { // todo!() @nate - this label looks wrong. diff --git a/crates/collab_ui2/src/collab_panel/contact_finder.rs b/crates/collab_ui2/src/collab_panel/contact_finder.rs index 742c25d148604dbbd195c1b17124f0e64b7ffc72..bd0c5d4b074beef1e8a433c03eec71df4a2d2c7c 100644 --- a/crates/collab_ui2/src/collab_panel/contact_finder.rs +++ b/crates/collab_ui2/src/collab_panel/contact_finder.rs @@ -7,7 +7,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use std::sync::Arc; use theme::ActiveTheme as _; -use ui::prelude::*; +use ui::{prelude::*, Avatar}; use util::{ResultExt as _, TryFutureExt}; use workspace::ModalView; @@ -187,7 +187,7 @@ impl PickerDelegate for ContactFinderDelegate { div() .flex_1() .justify_between() - .children(user.avatar.clone().map(|avatar| img(avatar))) + .child(Avatar::new(user.avatar_uri.clone())) .child(Label::new(user.github_login.clone())) .children(icon_path.map(|icon_path| svg().path(icon_path))), ) diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 4940893a6cc1462ad9a3dbf1e91137912329a595..8c2d112f0947c8f1012da555a2dfe8a5f855b7eb 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -232,43 +232,41 @@ impl Render for CollabTitlebarItem { }) .child(h_stack().px_1p5().map(|this| { if let Some(user) = current_user { - this.when_some(user.avatar.clone(), |this, avatar| { - // TODO: Finish implementing user menu popover - // - this.child( - popover_menu("user-menu") - .menu(|cx| { - ContextMenu::build(cx, |menu, _| menu.header("ADADA")) - }) - .trigger( - ButtonLike::new("user-menu") - .child( - h_stack() - .gap_0p5() - .child(Avatar::data(avatar)) - .child( - IconElement::new(Icon::ChevronDown) - .color(Color::Muted), - ), - ) - .style(ButtonStyle::Subtle) - .tooltip(move |cx| { - Tooltip::text("Toggle User Menu", cx) - }), - ) - .anchor(gpui::AnchorCorner::TopRight), - ) - // this.child( - // ButtonLike::new("user-menu") - // .child( - // h_stack().gap_0p5().child(Avatar::data(avatar)).child( - // IconElement::new(Icon::ChevronDown).color(Color::Muted), - // ), - // ) - // .style(ButtonStyle::Subtle) - // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), - // ) - }) + // TODO: Finish implementing user menu popover + // + this.child( + popover_menu("user-menu") + .menu(|cx| { + ContextMenu::build(cx, |menu, _| menu.header("ADADA")) + }) + .trigger( + ButtonLike::new("user-menu") + .child( + h_stack() + .gap_0p5() + .child(Avatar::new(user.avatar_uri.clone())) + .child( + IconElement::new(Icon::ChevronDown) + .color(Color::Muted), + ), + ) + .style(ButtonStyle::Subtle) + .tooltip(move |cx| { + Tooltip::text("Toggle User Menu", cx) + }), + ) + .anchor(gpui::AnchorCorner::TopRight), + ) + // this.child( + // ButtonLike::new("user-menu") + // .child( + // h_stack().gap_0p5().child(Avatar::data(avatar)).child( + // IconElement::new(Icon::ChevronDown).color(Color::Muted), + // ), + // ) + // .style(ButtonStyle::Subtle) + // .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)), + // ) } else { this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| { let client = client.clone(); @@ -425,26 +423,20 @@ impl CollabTitlebarItem { ) -> Option { let followers = project_id.map_or(&[] as &[_], |id| room.followers_for(peer_id, id)); let mut pile = FacePile::default(); - pile.extend( - user.avatar - .clone() - .map(|avatar| { - div() - .child( - Avatar::data(avatar.clone()) - .grayscale(!is_present) - .border_color(if is_speaking { - gpui::blue() - } else if is_muted { - gpui::red() - } else { - Hsla::default() - }), - ) - .into_any_element() - }) - .into_iter() - .chain(followers.iter().filter_map(|follower_peer_id| { + pile.child( + div() + .child( + Avatar::new(user.avatar_uri.clone()) + .grayscale(!is_present) + .border_color(if is_speaking { + gpui::blue() + } else if is_muted { + gpui::red() + } else { + Hsla::default() + }), + ) + .children(followers.iter().filter_map(|follower_peer_id| { let follower = room .remote_participants() .values() @@ -454,10 +446,8 @@ impl CollabTitlebarItem { .then_some(current_user) })? .clone(); - follower - .avatar - .clone() - .map(|avatar| div().child(Avatar::data(avatar.clone())).into_any_element()) + + Some(div().child(Avatar::new(follower.avatar_uri.clone()))) })), ); Some(pile) diff --git a/crates/collab_ui2/src/face_pile.rs b/crates/collab_ui2/src/face_pile.rs index 52b30062ea9105f4c0ede9016fbe25355c5bf273..9b2406024fa4709c759fe1e22602fe233c09bbdc 100644 --- a/crates/collab_ui2/src/face_pile.rs +++ b/crates/collab_ui2/src/face_pile.rs @@ -1,11 +1,12 @@ use gpui::{ - div, AnyElement, Div, ElementId, IntoElement, ParentElement as _, RenderOnce, Styled, - WindowContext, + div, AnyElement, Div, ElementId, IntoElement, ParentElement as _, ParentElement, RenderOnce, + Styled, WindowContext, }; +use smallvec::SmallVec; #[derive(Default, IntoElement)] pub struct FacePile { - pub faces: Vec, + pub faces: SmallVec<[AnyElement; 2]>, } impl RenderOnce for FacePile { @@ -25,8 +26,8 @@ impl RenderOnce for FacePile { } } -impl Extend for FacePile { - fn extend>(&mut self, children: T) { - self.faces.extend(children); +impl ParentElement for FacePile { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.faces } } diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index 2e5058d79108320362e0925d18f74f8001e5262c..279c3cbd90797f73cc706d62984010d4e6c5f6cc 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -6,11 +6,11 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use futures::StreamExt; use gpui::{ - actions, div, img, serde_json, svg, AnyElement, AnyView, AppContext, AsyncAppContext, Context, - CursorStyle, Div, Entity, EventEmitter, Flatten, FocusHandle, FocusableView, - InteractiveElement, IntoElement, ListAlignment, ListState, Model, MouseButton, ParentElement, - Render, Stateful, StatefulInteractiveElement, Task, View, ViewContext, VisualContext, WeakView, - WindowContext, + actions, div, img, px, serde_json, svg, AnyElement, AnyView, AppContext, AsyncAppContext, + AsyncWindowContext, Context, CursorStyle, Div, Element, Entity, EventEmitter, Flatten, + FocusHandle, FocusableView, InteractiveElement, IntoElement, ListAlignment, ListScrollEvent, + ListState, Model, MouseButton, ParentElement, Render, Stateful, StatefulInteractiveElement, + Task, View, ViewContext, VisualContext, WeakView, WindowContext, }; use notifications::{NotificationEntry, NotificationEvent, NotificationStore}; use project::Fs; @@ -80,7 +80,9 @@ impl NotificationPanel { let user_store = workspace.app_state().user_store.clone(); let workspace_handle = workspace.weak_handle(); - cx.build_view(|cx| { + cx.build_view(|cx: &mut ViewContext| { + let view = cx.view().clone(); + let mut status = client.status(); cx.spawn(|this, mut cx| async move { while let Some(_) = status.next().await { @@ -97,25 +99,30 @@ impl NotificationPanel { .detach(); let mut notification_list = - ListState::new(0, ListAlignment::Top, 1000., move |this, ix, cx| { - this.render_notification(ix, cx).unwrap_or_else(|| div()) + ListState::new(0, ListAlignment::Top, px(1000.), move |ix, cx| { + view.update(cx, |this, cx| { + this.render_notification(ix, cx) + .unwrap_or_else(|| div().into_any()) + }) }); - notification_list.set_scroll_handler(|visible_range, count, this, cx| { - if count.saturating_sub(visible_range.end) < LOADING_THRESHOLD { - if let Some(task) = this - .notification_store - .update(cx, |store, cx| store.load_more_notifications(false, cx)) - { - task.detach(); + notification_list.set_scroll_handler(cx.listener( + |this, event: &ListScrollEvent, cx| { + if event.count.saturating_sub(event.visible_range.end) < LOADING_THRESHOLD { + if let Some(task) = this + .notification_store + .update(cx, |store, cx| store.load_more_notifications(false, cx)) + { + task.detach(); + } } - } - }); + }, + )); let mut this = Self { fs, client, user_store, - local_timezone: cx.platform().local_timezone(), + local_timezone: cx.local_timezone(), channel_store: ChannelStore::global(cx), notification_store: NotificationStore::global(cx), notification_list, @@ -146,7 +153,10 @@ impl NotificationPanel { }) } - pub fn load(workspace: WeakView, cx: AsyncAppContext) -> Task>> { + pub fn load( + workspace: WeakView, + cx: AsyncWindowContext, + ) -> Task>> { cx.spawn(|mut cx| async move { let serialized_panel = if let Some(panel) = cx .background_executor() @@ -160,24 +170,22 @@ impl NotificationPanel { None }; - Flatten::flatten(cx.update(|cx| { - workspace.update(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 - }) - })) + 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) { let width = self.width; - self.pending_serialization = cx.background().spawn( + self.pending_serialization = cx.background_executor().spawn( async move { KEY_VALUE_STORE .write_kvp( @@ -217,17 +225,17 @@ impl NotificationPanel { .child( v_stack().child(Label::new(text)).child( h_stack() - .child(Label::from(format_timestamp( + .child(Label::new(format_timestamp( timestamp, now, self.local_timezone, ))) .children(if let Some(is_accepted) = response { - Some(Label::new(if is_accepted { + Some(div().child(Label::new(if is_accepted { "You accepted" } else { "You declined" - })) + }))) } else if needs_response { Some( h_stack() @@ -262,7 +270,8 @@ impl NotificationPanel { None }), ), - ), + ) + .into_any(), ) } @@ -355,7 +364,7 @@ impl NotificationPanel { .or_insert_with(|| { let client = self.client.clone(); cx.spawn(|this, mut cx| async move { - cx.background().timer(MARK_AS_READ_DELAY).await; + cx.background_executor().timer(MARK_AS_READ_DELAY).await; client .request(proto::MarkNotificationRead { notification_id }) .await?; diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index fe3498b930ef76ad7f061aed7af19c5c66aa96a0..4e8a95fcfd5c07b5a19b85bf00cdc1ad09792f96 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -867,7 +867,7 @@ impl Project { languages.set_executor(cx.executor()); let http_client = util::http::FakeHttpClient::with_404_response(); let client = cx.update(|cx| client::Client::new(http_client.clone(), cx)); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http_client, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let project = cx.update(|cx| { Project::local( client, diff --git a/crates/ui2/src/components/avatar.rs b/crates/ui2/src/components/avatar.rs index 454daacc423eee49b5cd003bcfdb86294e4d5a77..4162ee225637908780b45463c88c18542f67aa98 100644 --- a/crates/ui2/src/components/avatar.rs +++ b/crates/ui2/src/components/avatar.rs @@ -58,16 +58,8 @@ impl RenderOnce for Avatar { } impl Avatar { - pub fn uri(src: impl Into) -> Self { - Self::source(src.into().into()) - } - - pub fn data(src: Arc) -> Self { - Self::source(src.into()) - } - - pub fn source(src: ImageSource) -> Self { - Self { + pub fn new(src: impl Into) -> Self { + Avatar { image: img(src), is_available: None, border_color: None, diff --git a/crates/ui2/src/components/list/list_item.rs b/crates/ui2/src/components/list/list_item.rs index 529f2c2a58765caeeb20ce7ecf6f12080c2edc0b..e089a2b479c9181e8e52af822b9b98a0336f48bf 100644 --- a/crates/ui2/src/components/list/list_item.rs +++ b/crates/ui2/src/components/list/list_item.rs @@ -107,7 +107,7 @@ impl ListItem { } pub fn left_avatar(mut self, left_avatar: impl Into) -> Self { - self.left_slot = Some(Avatar::source(left_avatar.into()).into_any_element()); + self.left_slot = Some(Avatar::new(left_avatar).into_any_element()); self } } diff --git a/crates/ui2/src/components/stories/avatar.rs b/crates/ui2/src/components/stories/avatar.rs index 1b5ceec2fd3493aaf44067e120a76a244579e2f4..09adfe480a434491ff6db2b4010ccbc611db51c7 100644 --- a/crates/ui2/src/components/stories/avatar.rs +++ b/crates/ui2/src/components/stories/avatar.rs @@ -13,18 +13,18 @@ impl Render for AvatarStory { Story::container() .child(Story::title_for::()) .child(Story::label("Default")) - .child(Avatar::uri( + .child(Avatar::new( "https://avatars.githubusercontent.com/u/1714999?v=4", )) - .child(Avatar::uri( + .child(Avatar::new( "https://avatars.githubusercontent.com/u/326587?v=4", )) .child( - Avatar::uri("https://avatars.githubusercontent.com/u/326587?v=4") + Avatar::new("https://avatars.githubusercontent.com/u/326587?v=4") .availability_indicator(true), ) .child( - Avatar::uri("https://avatars.githubusercontent.com/u/326587?v=4") + Avatar::new("https://avatars.githubusercontent.com/u/326587?v=4") .availability_indicator(false), ) } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index eb846fbea8b81917351c4e36b881c52521ae790b..adc8b0a38c241b2fe8825f49fdc02f4b658e1565 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -360,7 +360,7 @@ impl AppState { let languages = Arc::new(LanguageRegistry::test()); let http_client = util::http::FakeHttpClient::with_404_response(); let client = Client::new(http_client.clone(), cx); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http_client, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let workspace_store = cx.build_model(|cx| WorkspaceStore::new(client.clone(), cx)); theme::init(theme::LoadThemes::JustBase, cx); diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index b97c4f40c33297684c866977b969ac9751554875..92b20bf271a666408e22fc13fb015023975e7b5b 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -143,7 +143,7 @@ fn main() { language::init(cx); languages::init(languages.clone(), node_runtime.clone(), cx); - let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), cx)); let workspace_store = cx.build_model(|cx| WorkspaceStore::new(client.clone(), cx)); cx.set_global(client.clone()); diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs index 0a44bf6ec0fc7e25fb3135fd91379dc8a4fd7ba9..1414bbaa13fafec1abf0d4d13dd59db4af7edcf2 100644 --- a/crates/zed2/src/zed2.rs +++ b/crates/zed2/src/zed2.rs @@ -165,10 +165,10 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { collab_ui::collab_panel::CollabPanel::load(workspace_handle.clone(), cx.clone()); let chat_panel = collab_ui::chat_panel::ChatPanel::load(workspace_handle.clone(), cx.clone()); - // let notification_panel = collab_ui::notification_panel::NotificationPanel::load( - // workspace_handle.clone(), - // cx.clone(), - // ); + let notification_panel = collab_ui::notification_panel::NotificationPanel::load( + workspace_handle.clone(), + cx.clone(), + ); let ( project_panel, terminal_panel,