Detailed changes
@@ -17,6 +17,7 @@ use gpui::{
Subscription, Task, View, ViewContext, WeakModel, WeakView,
};
pub use participant::ParticipantLocation;
+use participant::RemoteParticipant;
use postage::watch;
use project::Project;
use room::Event;
@@ -628,6 +629,42 @@ impl CallHandler for Call {
this.invite(called_user_id, initial_project, cx)
})
}
+ fn remote_participants(&self, cx: &AppContext) -> Option<Vec<Arc<User>>> {
+ self.active_call
+ .as_ref()
+ .map(|call| {
+ call.0.read(cx).room().map(|room| {
+ room.read(cx)
+ .remote_participants()
+ .iter()
+ .map(|participant| participant.1.user.clone())
+ .collect()
+ })
+ })
+ .flatten()
+ }
+ fn is_muted(&self, cx: &AppContext) -> Option<bool> {
+ self.active_call
+ .as_ref()
+ .map(|call| {
+ call.0
+ .read(cx)
+ .room()
+ .map(|room| room.read(cx).is_muted(cx))
+ })
+ .flatten()
+ }
+ fn toggle_mute(&self, cx: &mut AppContext) {
+ self.active_call.as_ref().map(|call| {
+ call.0.update(cx, |this, cx| {
+ this.room().map(|room| {
+ room.update(cx, |this, cx| {
+ this.toggle_mute(cx);
+ })
+ })
+ })
+ });
+ }
}
#[cfg(test)]
@@ -333,7 +333,8 @@ impl Room {
}
pub fn mute_on_join(cx: &AppContext) -> bool {
- CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some()
+ false
+ //CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some()
}
fn from_join_response(
@@ -551,7 +551,6 @@ impl Client {
F: 'static + Future<Output = Result<()>>,
{
let message_type_id = TypeId::of::<M>();
-
let mut state = self.state.write();
state
.models_by_message_type
@@ -37,7 +37,8 @@ use gpui::{
};
use project::Project;
use theme::ActiveTheme;
-use ui::{h_stack, Button, ButtonVariant, Color, IconButton, KeyBinding, Tooltip};
+use ui::{h_stack, Avatar, Button, ButtonVariant, Color, IconButton, KeyBinding, Label, Tooltip};
+use util::ResultExt;
use workspace::Workspace;
// const MAX_PROJECT_NAME_LENGTH: usize = 40;
@@ -92,6 +93,23 @@ impl Render for CollabTitlebarItem {
let is_shared = is_in_room && self.project.read(cx).is_shared();
let current_user = self.user_store.read(cx).current_user();
let client = self.client.clone();
+ let users = self
+ .workspace
+ .update(cx, |this, cx| this.call_state().remote_participants(cx))
+ .log_err()
+ .flatten();
+ let mic_icon = if self
+ .workspace
+ .update(cx, |this, cx| this.call_state().is_muted(cx))
+ .log_err()
+ .flatten()
+ .unwrap_or_default()
+ {
+ ui::Icon::MicMute
+ } else {
+ ui::Icon::Mic
+ };
+ let workspace = self.workspace.clone();
h_stack()
.id("titlebar")
.justify_between()
@@ -157,22 +175,23 @@ impl Render for CollabTitlebarItem {
}),
),
)
- .map(|this| {
- if let Some(user) = current_user {
- this.when_some(user.avatar.clone(), |this, avatar| {
- this.child(ui::Avatar::new(avatar))
- })
- } else {
- this.child(Button::new("Sign in").on_click(move |_, cx| {
- let client = client.clone();
- cx.spawn(move |cx| async move {
- client.authenticate_and_connect(true, &cx).await?;
- Ok::<(), anyhow::Error>(())
- })
- .detach_and_log_err(cx);
- }))
- }
- })
+ .when_some(
+ users.zip(current_user.clone()),
+ |this, (remote_participants, current_user)| {
+ this.children(
+ current_user
+ .avatar
+ .clone()
+ .map(|avatar| Avatar::new(avatar.clone()))
+ .into_iter()
+ .chain(remote_participants.into_iter().flat_map(|user| {
+ user.avatar
+ .as_ref()
+ .map(|avatar| Avatar::new(avatar.clone()))
+ })),
+ )
+ },
+ )
.when(is_in_room, |this| {
this.child(
h_stack()
@@ -183,13 +202,35 @@ impl Render for CollabTitlebarItem {
)
.child(
h_stack()
- .child(IconButton::new("mute-microphone", ui::Icon::Mic))
+ .child(IconButton::new("mute-microphone", mic_icon).on_click(
+ move |_, cx| {
+ workspace.update(cx, |this, cx| {
+ this.call_state().toggle_mute(cx);
+ });
+ },
+ ))
.child(IconButton::new("mute-sound", ui::Icon::AudioOn))
.child(IconButton::new("screen-share", ui::Icon::Screen))
.pl_2(),
),
)
})
+ .map(|this| {
+ if let Some(user) = current_user {
+ this.when_some(user.avatar.clone(), |this, avatar| {
+ this.child(ui::Avatar::new(avatar))
+ })
+ } else {
+ this.child(Button::new("Sign in").on_click(move |_, cx| {
+ let client = client.clone();
+ cx.spawn(move |cx| async move {
+ client.authenticate_and_connect(true, &cx).await?;
+ Ok::<(), anyhow::Error>(())
+ })
+ .detach_and_log_err(cx);
+ }))
+ }
+ })
}
}
@@ -19,7 +19,7 @@ use anyhow::{anyhow, Context as _, Result};
use async_trait::async_trait;
use client2::{
proto::{self, PeerId},
- Client, TypedEnvelope, UserStore,
+ Client, TypedEnvelope, User, UserStore,
};
use collections::{hash_map, HashMap, HashSet};
use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle};
@@ -351,7 +351,27 @@ impl CallHandler for TestCallHandler {
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
None
}
+
+ fn invite(
+ &mut self,
+ called_user_id: u64,
+ initial_project: Option<Model<Project>>,
+ cx: &mut AppContext,
+ ) -> Task<Result<()>> {
+ unimplemented!()
+ }
+
+ fn remote_participants(&self, cx: &AppContext) -> Option<Vec<User>> {
+ None
+ }
+
+ fn is_muted(&self, cx: &AppContext) -> Option<bool> {
+ None
+ }
+
+ fn toggle_mute(&self, cx: &mut AppContext) {}
}
+
impl AppState {
#[cfg(any(test, feature = "test-support"))]
pub fn test(cx: &mut AppContext) -> Arc<Self> {
@@ -460,6 +480,9 @@ pub trait CallHandler {
initial_project: Option<Model<Project>>,
cx: &mut AppContext,
) -> Task<Result<()>>;
+ fn remote_participants(&self, cx: &AppContext) -> Option<Vec<Arc<User>>>;
+ fn is_muted(&self, cx: &AppContext) -> Option<bool>;
+ fn toggle_mute(&self, cx: &mut AppContext);
}
pub struct Workspace {