mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
commit
2e00da5a79
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -12071,6 +12071,7 @@ dependencies = [
|
||||
"lsp2",
|
||||
"menu2",
|
||||
"node_runtime",
|
||||
"notifications2",
|
||||
"num_cpus",
|
||||
"outline2",
|
||||
"parking_lot 0.11.2",
|
||||
|
@ -345,7 +345,7 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
|
||||
fn init_test(cx: &mut AppContext) -> Model<ChannelStore> {
|
||||
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);
|
||||
|
@ -8,7 +8,6 @@ use rpc::{
|
||||
ConnectionId, Peer, Receipt, TypedEnvelope,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use util::http::FakeHttpClient;
|
||||
|
||||
pub struct FakeServer {
|
||||
peer: Arc<Peer>,
|
||||
@ -195,8 +194,7 @@ impl FakeServer {
|
||||
client: Arc<Client>,
|
||||
cx: &mut TestAppContext,
|
||||
) -> Model<UserStore> {
|
||||
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::<proto::GetUsers>()
|
||||
.await
|
||||
|
@ -2,13 +2,12 @@ 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, Future, StreamExt};
|
||||
use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, SharedString, Task};
|
||||
use postage::{sink::Sink, watch};
|
||||
use rpc::proto::{RequestMessage, UsersResponse};
|
||||
use std::sync::{Arc, Weak};
|
||||
use text::ReplicaId;
|
||||
use util::http::HttpClient;
|
||||
use util::TryFutureExt as _;
|
||||
|
||||
pub type UserId = u64;
|
||||
@ -20,7 +19,7 @@ pub struct ParticipantIndex(pub u32);
|
||||
pub struct User {
|
||||
pub id: UserId,
|
||||
pub github_login: String,
|
||||
pub avatar: Option<Arc<ImageData>>,
|
||||
pub avatar_uri: SharedString,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -76,7 +75,6 @@ pub struct UserStore {
|
||||
pending_contact_requests: HashMap<u64, usize>,
|
||||
invite_info: Option<InviteInfo>,
|
||||
client: Weak<Client>,
|
||||
http: Arc<dyn HttpClient>,
|
||||
_maintain_contacts: Task<()>,
|
||||
_maintain_current_user: Task<Result<()>>,
|
||||
}
|
||||
@ -112,11 +110,7 @@ enum UpdateContacts {
|
||||
}
|
||||
|
||||
impl UserStore {
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
http: Arc<dyn HttpClient>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
|
||||
let (mut current_user_tx, current_user_rx) = watch::channel();
|
||||
let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded();
|
||||
let rpc_subscriptions = vec![
|
||||
@ -134,7 +128,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 +438,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 +615,14 @@ impl UserStore {
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<Arc<User>>>> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
this.update(&mut cx, |this, _| {
|
||||
for user in &users {
|
||||
@ -659,11 +655,11 @@ impl UserStore {
|
||||
}
|
||||
|
||||
impl User {
|
||||
async fn new(message: proto::User, http: &dyn HttpClient) -> Arc<Self> {
|
||||
fn new(message: proto::User) -> Arc<Self> {
|
||||
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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -696,25 +692,3 @@ impl Collaborator {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// todo!("we probably don't need this now that we fetch")
|
||||
async fn fetch_avatar(http: &dyn HttpClient, url: &str) -> Result<Arc<ImageData>> {
|
||||
let mut response = http
|
||||
.get(url, Default::default(), true)
|
||||
.await
|
||||
.map_err(|e| anyhow!("failed to send user avatar request: {}", e))?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow!("avatar request failed {:?}", response.status()));
|
||||
}
|
||||
|
||||
let mut body = Vec::new();
|
||||
response
|
||||
.body_mut()
|
||||
.read_to_end(&mut body)
|
||||
.await
|
||||
.map_err(|e| anyhow!("failed to read user avatar response body: {}", e))?;
|
||||
let format = image::guess_format(&body)?;
|
||||
let image = image::load_from_memory_with_format(&body, format)?.into_bgra8();
|
||||
Ok(Arc::new(ImageData::new(image)))
|
||||
}
|
||||
|
@ -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()]
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -19,6 +19,7 @@ mod contact_finder;
|
||||
use contact_finder::ContactFinder;
|
||||
use menu::{Cancel, Confirm, SelectNext, SelectPrev};
|
||||
use rpc::proto::{self, PeerId};
|
||||
use smallvec::SmallVec;
|
||||
use theme::{ActiveTheme, ThemeSettings};
|
||||
// use context_menu::{ContextMenu, ContextMenuItem};
|
||||
// use db::kvp::KEY_VALUE_STORE;
|
||||
@ -1155,7 +1156,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()
|
||||
@ -2349,44 +2350,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())
|
||||
@ -2458,7 +2460,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(
|
||||
@ -2516,7 +2518,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.
|
||||
@ -2524,7 +2528,7 @@ impl CollabPanel {
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
.collect::<SmallVec<_>>(),
|
||||
};
|
||||
|
||||
Some(result)
|
||||
|
@ -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))),
|
||||
)
|
||||
|
@ -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();
|
||||
@ -424,27 +422,21 @@ impl CollabTitlebarItem {
|
||||
current_user: &Arc<User>,
|
||||
) -> Option<FacePile> {
|
||||
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| {
|
||||
|
||||
let pile = FacePile::default().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,12 +446,11 @@ 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)
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
|
||||
collab_panel::init(cx);
|
||||
channel_view::init(cx);
|
||||
chat_panel::init(cx);
|
||||
notification_panel::init(cx);
|
||||
notifications::init(&app_state, cx);
|
||||
|
||||
// cx.add_global_action(toggle_screen_sharing);
|
||||
|
@ -1,11 +1,11 @@
|
||||
use gpui::{
|
||||
div, AnyElement, Div, ElementId, IntoElement, ParentElement as _, RenderOnce, Styled,
|
||||
WindowContext,
|
||||
div, AnyElement, Div, ElementId, IntoElement, ParentElement, RenderOnce, Styled, WindowContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
#[derive(Default, IntoElement)]
|
||||
pub struct FacePile {
|
||||
pub faces: Vec<AnyElement>,
|
||||
pub faces: SmallVec<[AnyElement; 2]>,
|
||||
}
|
||||
|
||||
impl RenderOnce for FacePile {
|
||||
@ -25,8 +25,8 @@ impl RenderOnce for FacePile {
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<AnyElement> for FacePile {
|
||||
fn extend<T: IntoIterator<Item = AnyElement>>(&mut self, children: T) {
|
||||
self.faces.extend(children);
|
||||
impl ParentElement for FacePile {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
|
||||
&mut self.faces
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -114,14 +114,7 @@ impl IncomingCallNotification {
|
||||
}
|
||||
fn render_caller(&self, cx: &mut ViewContext<Self>) -> impl Element {
|
||||
h_stack()
|
||||
.children(
|
||||
self.state
|
||||
.call
|
||||
.calling_user
|
||||
.avatar
|
||||
.as_ref()
|
||||
.map(|avatar| Avatar::data(avatar.clone())),
|
||||
)
|
||||
.child(Avatar::new(self.state.call.calling_user.avatar_uri.clone()))
|
||||
.child(
|
||||
v_stack()
|
||||
.child(Label::new(format!(
|
||||
|
@ -119,12 +119,7 @@ impl ProjectSharedNotification {
|
||||
|
||||
fn render_owner(&self) -> impl Element {
|
||||
h_stack()
|
||||
.children(
|
||||
self.owner
|
||||
.avatar
|
||||
.clone()
|
||||
.map(|avatar| Avatar::data(avatar.clone())),
|
||||
)
|
||||
.child(Avatar::new(self.owner.avatar_uri.clone()))
|
||||
.child(
|
||||
v_stack()
|
||||
.child(Label::new(self.owner.github_login.clone()))
|
||||
|
@ -868,7 +868,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,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use gpui::{img, Div, Hsla, ImageData, ImageSource, Img, IntoElement, Styled};
|
||||
use std::sync::Arc;
|
||||
use gpui::{img, Div, Hsla, ImageSource, Img, IntoElement, Styled};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub enum Shape {
|
||||
@ -58,16 +57,8 @@ impl RenderOnce for Avatar {
|
||||
}
|
||||
|
||||
impl Avatar {
|
||||
pub fn uri(src: impl Into<SharedString>) -> Self {
|
||||
Self::source(src.into().into())
|
||||
}
|
||||
|
||||
pub fn data(src: Arc<ImageData>) -> Self {
|
||||
Self::source(src.into())
|
||||
}
|
||||
|
||||
pub fn source(src: ImageSource) -> Self {
|
||||
Self {
|
||||
pub fn new(src: impl Into<ImageSource>) -> Self {
|
||||
Avatar {
|
||||
image: img(src),
|
||||
is_available: None,
|
||||
border_color: None,
|
||||
|
@ -111,7 +111,7 @@ impl ListItem {
|
||||
}
|
||||
|
||||
pub fn left_avatar(mut self, left_avatar: impl Into<ImageSource>) -> 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
|
||||
}
|
||||
}
|
||||
|
@ -13,18 +13,18 @@ impl Render for AvatarStory {
|
||||
Story::container()
|
||||
.child(Story::title_for::<Avatar>())
|
||||
.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),
|
||||
)
|
||||
}
|
||||
|
@ -363,7 +363,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);
|
||||
|
@ -49,6 +49,7 @@ lsp = { package = "lsp2", path = "../lsp2" }
|
||||
menu = { package = "menu2", path = "../menu2" }
|
||||
# language_tools = { path = "../language_tools" }
|
||||
node_runtime = { path = "../node_runtime" }
|
||||
notifications = { package = "notifications2", path = "../notifications2" }
|
||||
assistant = { package = "assistant2", path = "../assistant2" }
|
||||
outline = { package = "outline2", path = "../outline2" }
|
||||
# plugin_runtime = { path = "../plugin_runtime",optional = true }
|
||||
|
@ -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());
|
||||
@ -220,6 +220,7 @@ fn main() {
|
||||
// activity_indicator::init(cx);
|
||||
// language_tools::init(cx);
|
||||
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
|
||||
notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx);
|
||||
collab_ui::init(&app_state, cx);
|
||||
feedback::init(cx);
|
||||
welcome::init(cx);
|
||||
|
@ -164,24 +164,24 @@ pub fn initialize_workspace(app_state: Arc<AppState>, 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,
|
||||
assistant_panel,
|
||||
channels_panel,
|
||||
chat_panel,
|
||||
// notification_panel,
|
||||
notification_panel,
|
||||
) = futures::try_join!(
|
||||
project_panel,
|
||||
terminal_panel,
|
||||
assistant_panel,
|
||||
channels_panel,
|
||||
chat_panel,
|
||||
// notification_panel,
|
||||
notification_panel,
|
||||
)?;
|
||||
|
||||
workspace_handle.update(&mut cx, |workspace, cx| {
|
||||
@ -191,7 +191,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
workspace.add_panel(assistant_panel, cx);
|
||||
workspace.add_panel(channels_panel, cx);
|
||||
workspace.add_panel(chat_panel, cx);
|
||||
// workspace.add_panel(notification_panel, cx);
|
||||
workspace.add_panel(notification_panel, cx);
|
||||
|
||||
// if !was_deserialized
|
||||
// && workspace
|
||||
|
Loading…
Reference in New Issue
Block a user