;
+
+ fn render(&mut self, cx: &mut ViewContext
) -> Self::Element {
+ let content = self.content_to_render(cx);
+
+ let mut result = h_stack()
+ .id("activity-indicator")
+ .on_action(cx.listener(Self::show_error_message))
+ .on_action(cx.listener(Self::dismiss_error_message));
+
+ if let Some(on_click) = content.on_click {
+ result = result
+ .cursor(CursorStyle::PointingHand)
+ .on_click(cx.listener(move |this, _, cx| {
+ on_click(this, cx);
+ }))
+ }
+
+ result
+ .children(content.icon.map(|icon| svg().path(icon)))
+ .child(SharedString::from(content.message))
+ }
+}
+
+impl StatusItemView for ActivityIndicator {
+ fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, _: &mut ViewContext) {}
+}
diff --git a/crates/auto_update2/src/update_notification.rs b/crates/auto_update2/src/update_notification.rs
index d15d82e112..4a2efcf807 100644
--- a/crates/auto_update2/src/update_notification.rs
+++ b/crates/auto_update2/src/update_notification.rs
@@ -51,6 +51,6 @@ impl UpdateNotification {
}
pub fn dismiss(&mut self, cx: &mut ViewContext) {
- cx.emit(DismissEvent::Dismiss);
+ cx.emit(DismissEvent);
}
}
diff --git a/crates/call2/src/call2.rs b/crates/call2/src/call2.rs
index 9a89ec7167..df7dd847cf 100644
--- a/crates/call2/src/call2.rs
+++ b/crates/call2/src/call2.rs
@@ -14,8 +14,8 @@ use client::{
use collections::HashSet;
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
use gpui::{
- AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
- View, ViewContext, VisualContext, WeakModel, WeakView,
+ AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, PromptLevel,
+ Subscription, Task, View, ViewContext, VisualContext, WeakModel, WeakView, WindowHandle,
};
pub use participant::ParticipantLocation;
use postage::watch;
@@ -334,12 +334,55 @@ impl ActiveCall {
pub fn join_channel(
&mut self,
channel_id: u64,
+ requesting_window: Option>,
cx: &mut ModelContext,
) -> Task>>> {
if let Some(room) = self.room().cloned() {
if room.read(cx).channel_id() == Some(channel_id) {
- return Task::ready(Ok(Some(room)));
- } else {
+ return cx.spawn(|_, _| async move {
+ todo!();
+ // let future = room.update(&mut cx, |room, cx| {
+ // room.most_active_project(cx).map(|(host, project)| {
+ // room.join_project(project, host, app_state.clone(), cx)
+ // })
+ // })
+
+ // if let Some(future) = future {
+ // future.await?;
+ // }
+
+ // Ok(Some(room))
+ });
+ }
+
+ let should_prompt = room.update(cx, |room, _| {
+ room.channel_id().is_some()
+ && room.is_sharing_project()
+ && room.remote_participants().len() > 0
+ });
+ if should_prompt && requesting_window.is_some() {
+ return cx.spawn(|this, mut cx| async move {
+ let answer = requesting_window.unwrap().update(&mut cx, |_, cx| {
+ cx.prompt(
+ PromptLevel::Warning,
+ "Leaving this call will unshare your current project.\nDo you want to switch channels?",
+ &["Yes, Join Channel", "Cancel"],
+ )
+ })?;
+ if answer.await? == 1 {
+ return Ok(None);
+ }
+
+ room.update(&mut cx, |room, cx| room.clear_state(cx))?;
+
+ this.update(&mut cx, |this, cx| {
+ this.join_channel(channel_id, requesting_window, cx)
+ })?
+ .await
+ });
+ }
+
+ if room.read(cx).channel_id().is_some() {
room.update(cx, |room, cx| room.clear_state(cx));
}
}
@@ -660,9 +703,12 @@ impl CallHandler for Call {
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).log_err();
+ let room = room.clone();
+ cx.spawn(|_, mut cx| async move {
+ room.update(&mut cx, |this, cx| this.toggle_mute(cx))??
+ .await
})
+ .detach_and_log_err(cx);
})
})
});
diff --git a/crates/call2/src/room.rs b/crates/call2/src/room.rs
index b55d3348dc..694966abe9 100644
--- a/crates/call2/src/room.rs
+++ b/crates/call2/src/room.rs
@@ -1,4 +1,7 @@
-use crate::participant::{LocalParticipant, ParticipantLocation, RemoteParticipant};
+use crate::{
+ call_settings::CallSettings,
+ participant::{LocalParticipant, ParticipantLocation, RemoteParticipant},
+};
use anyhow::{anyhow, Result};
use audio::{Audio, Sound};
use client::{
@@ -18,6 +21,7 @@ use live_kit_client::{
};
use postage::{sink::Sink, stream::Stream, watch};
use project::Project;
+use settings::Settings as _;
use std::{future::Future, mem, sync::Arc, time::Duration};
use util::{post_inc, ResultExt, TryFutureExt};
@@ -328,10 +332,8 @@ impl Room {
}
}
- pub fn mute_on_join(_cx: &AppContext) -> bool {
- // todo!() po: This should be uncommented, though then unmuting does not work
- false
- //CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some()
+ pub fn mute_on_join(cx: &AppContext) -> bool {
+ CallSettings::get_global(cx).mute_on_join || client::IMPERSONATE_LOGIN.is_some()
}
fn from_join_response(
@@ -1265,7 +1267,6 @@ impl Room {
.ok_or_else(|| anyhow!("live-kit was not initialized"))?
.await
};
-
let publication = publish_track.await;
this.upgrade()
.ok_or_else(|| anyhow!("room was dropped"))?
diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs
index b31451aa87..4746c9c6e4 100644
--- a/crates/client2/src/client2.rs
+++ b/crates/client2/src/client2.rs
@@ -693,8 +693,8 @@ impl Client {
}
}
- pub async fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool {
- read_credentials_from_keychain(cx).await.is_some()
+ pub fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool {
+ read_credentials_from_keychain(cx).is_some()
}
#[async_recursion(?Send)]
@@ -725,7 +725,7 @@ impl Client {
let mut read_from_keychain = false;
let mut credentials = self.state.read().credentials.clone();
if credentials.is_none() && try_keychain {
- credentials = read_credentials_from_keychain(cx).await;
+ credentials = read_credentials_from_keychain(cx);
read_from_keychain = credentials.is_some();
}
if credentials.is_none() {
@@ -1324,7 +1324,7 @@ impl Client {
}
}
-async fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option {
+fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option {
if IMPERSONATE_LOGIN.is_some() {
return None;
}
diff --git a/crates/collab2/src/tests/channel_tests.rs b/crates/collab2/src/tests/channel_tests.rs
index 8ce5d99b80..43d18ee7d1 100644
--- a/crates/collab2/src/tests/channel_tests.rs
+++ b/crates/collab2/src/tests/channel_tests.rs
@@ -364,7 +364,8 @@ async fn test_joining_channel_ancestor_member(
let active_call_b = cx_b.read(ActiveCall::global);
assert!(active_call_b
- .update(cx_b, |active_call, cx| active_call.join_channel(sub_id, cx))
+ .update(cx_b, |active_call, cx| active_call
+ .join_channel(sub_id, None, cx))
.await
.is_ok());
}
@@ -394,7 +395,9 @@ async fn test_channel_room(
let active_call_b = cx_b.read(ActiveCall::global);
active_call_a
- .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
+ .update(cx_a, |active_call, cx| {
+ active_call.join_channel(zed_id, None, cx)
+ })
.await
.unwrap();
@@ -442,7 +445,9 @@ async fn test_channel_room(
});
active_call_b
- .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
+ .update(cx_b, |active_call, cx| {
+ active_call.join_channel(zed_id, None, cx)
+ })
.await
.unwrap();
@@ -559,12 +564,16 @@ async fn test_channel_room(
});
active_call_a
- .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
+ .update(cx_a, |active_call, cx| {
+ active_call.join_channel(zed_id, None, cx)
+ })
.await
.unwrap();
active_call_b
- .update(cx_b, |active_call, cx| active_call.join_channel(zed_id, cx))
+ .update(cx_b, |active_call, cx| {
+ active_call.join_channel(zed_id, None, cx)
+ })
.await
.unwrap();
@@ -608,7 +617,9 @@ async fn test_channel_jumping(executor: BackgroundExecutor, cx_a: &mut TestAppCo
let active_call_a = cx_a.read(ActiveCall::global);
active_call_a
- .update(cx_a, |active_call, cx| active_call.join_channel(zed_id, cx))
+ .update(cx_a, |active_call, cx| {
+ active_call.join_channel(zed_id, None, cx)
+ })
.await
.unwrap();
@@ -627,7 +638,7 @@ async fn test_channel_jumping(executor: BackgroundExecutor, cx_a: &mut TestAppCo
active_call_a
.update(cx_a, |active_call, cx| {
- active_call.join_channel(rust_id, cx)
+ active_call.join_channel(rust_id, None, cx)
})
.await
.unwrap();
@@ -793,7 +804,7 @@ async fn test_call_from_channel(
let active_call_b = cx_b.read(ActiveCall::global);
active_call_a
- .update(cx_a, |call, cx| call.join_channel(channel_id, cx))
+ .update(cx_a, |call, cx| call.join_channel(channel_id, None, cx))
.await
.unwrap();
@@ -1286,7 +1297,7 @@ async fn test_guest_access(
// Non-members should not be allowed to join
assert!(active_call_b
- .update(cx_b, |call, cx| call.join_channel(channel_a, cx))
+ .update(cx_b, |call, cx| call.join_channel(channel_a, None, cx))
.await
.is_err());
@@ -1308,7 +1319,7 @@ async fn test_guest_access(
// Client B joins channel A as a guest
active_call_b
- .update(cx_b, |call, cx| call.join_channel(channel_a, cx))
+ .update(cx_b, |call, cx| call.join_channel(channel_a, None, cx))
.await
.unwrap();
@@ -1341,7 +1352,7 @@ async fn test_guest_access(
assert_channels_list_shape(client_b.channel_store(), cx_b, &[]);
active_call_b
- .update(cx_b, |call, cx| call.join_channel(channel_b, cx))
+ .update(cx_b, |call, cx| call.join_channel(channel_b, None, cx))
.await
.unwrap();
@@ -1372,7 +1383,7 @@ async fn test_invite_access(
// should not be allowed to join
assert!(active_call_b
- .update(cx_b, |call, cx| call.join_channel(channel_b_id, cx))
+ .update(cx_b, |call, cx| call.join_channel(channel_b_id, None, cx))
.await
.is_err());
@@ -1390,7 +1401,7 @@ async fn test_invite_access(
.unwrap();
active_call_b
- .update(cx_b, |call, cx| call.join_channel(channel_b_id, cx))
+ .update(cx_b, |call, cx| call.join_channel(channel_b_id, None, cx))
.await
.unwrap();
diff --git a/crates/collab2/src/tests/integration_tests.rs b/crates/collab2/src/tests/integration_tests.rs
index f2a39f3511..e579c384e3 100644
--- a/crates/collab2/src/tests/integration_tests.rs
+++ b/crates/collab2/src/tests/integration_tests.rs
@@ -510,9 +510,10 @@ async fn test_joining_channels_and_calling_multiple_users_simultaneously(
// Simultaneously join channel 1 and then channel 2
active_call_a
- .update(cx_a, |call, cx| call.join_channel(channel_1, cx))
+ .update(cx_a, |call, cx| call.join_channel(channel_1, None, cx))
.detach();
- let join_channel_2 = active_call_a.update(cx_a, |call, cx| call.join_channel(channel_2, cx));
+ let join_channel_2 =
+ active_call_a.update(cx_a, |call, cx| call.join_channel(channel_2, None, cx));
join_channel_2.await.unwrap();
@@ -538,7 +539,8 @@ async fn test_joining_channels_and_calling_multiple_users_simultaneously(
call.invite(client_c.user_id().unwrap(), None, cx)
});
- let join_channel = active_call_a.update(cx_a, |call, cx| call.join_channel(channel_1, cx));
+ let join_channel =
+ active_call_a.update(cx_a, |call, cx| call.join_channel(channel_1, None, cx));
b_invite.await.unwrap();
c_invite.await.unwrap();
@@ -567,7 +569,8 @@ async fn test_joining_channels_and_calling_multiple_users_simultaneously(
.unwrap();
// Simultaneously join channel 1 and call user B and user C from client A.
- let join_channel = active_call_a.update(cx_a, |call, cx| call.join_channel(channel_1, cx));
+ let join_channel =
+ active_call_a.update(cx_a, |call, cx| call.join_channel(channel_1, None, cx));
let b_invite = active_call_a.update(cx_a, |call, cx| {
call.invite(client_b.user_id().unwrap(), None, cx)
diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs
index e9c17a6589..b62056a3be 100644
--- a/crates/collab_ui2/src/collab_panel.rs
+++ b/crates/collab_ui2/src/collab_panel.rs
@@ -1,5 +1,6 @@
+#![allow(unused)]
// mod channel_modal;
-// mod contact_finder;
+mod contact_finder;
// use crate::{
// channel_view::{self, ChannelView},
@@ -15,7 +16,10 @@
// proto::{self, PeerId},
// Client, Contact, User, UserStore,
// };
-// use contact_finder::ContactFinder;
+use contact_finder::ContactFinder;
+use menu::{Cancel, Confirm, SelectNext, SelectPrev};
+use rpc::proto;
+use theme::{ActiveTheme, ThemeSettings};
// use context_menu::{ContextMenu, ContextMenuItem};
// use db::kvp::KEY_VALUE_STORE;
// use drag_and_drop::{DragAndDrop, Draggable};
@@ -88,10 +92,10 @@
// channel_id: ChannelId,
// }
-// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-// pub struct OpenChannelNotes {
-// pub channel_id: ChannelId,
-// }
+#[derive(Action, PartialEq, Debug, Clone, Serialize, Deserialize)]
+pub struct OpenChannelNotes {
+ pub channel_id: ChannelId,
+}
// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
// pub struct JoinChannelCall {
@@ -148,33 +152,45 @@ actions!(
// ]
// );
-// #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-// struct ChannelMoveClipboard {
-// channel_id: ChannelId,
-// }
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+struct ChannelMoveClipboard {
+ channel_id: ChannelId,
+}
const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
-use std::sync::Arc;
+use std::{iter::once, mem, sync::Arc};
-use client::{Client, Contact, UserStore};
+use call::ActiveCall;
+use channel::{Channel, ChannelEvent, ChannelId, ChannelStore};
+use client::{Client, Contact, User, UserStore};
use db::kvp::KEY_VALUE_STORE;
+use editor::Editor;
+use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt};
+use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
- actions, div, serde_json, AppContext, AsyncWindowContext, Div, EventEmitter, FocusHandle,
- Focusable, FocusableView, InteractiveElement, Model, ParentElement, Render, Styled, View,
- ViewContext, VisualContext, WeakView,
+ actions, div, img, overlay, prelude::*, px, rems, serde_json, Action, AppContext,
+ AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, Div, EventEmitter, FocusHandle,
+ Focusable, FocusableView, InteractiveElement, IntoElement, Model, MouseDownEvent,
+ ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, ScrollHandle, SharedString,
+ Stateful, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
};
-use project::Fs;
+use project::{Fs, Project};
use serde_derive::{Deserialize, Serialize};
-use settings::Settings;
-use ui::{h_stack, Avatar, Label};
-use util::ResultExt;
+use settings::{Settings, SettingsStore};
+use ui::prelude::*;
+use ui::{
+ h_stack, v_stack, Avatar, Button, Color, ContextMenu, Icon, IconButton, IconElement, IconSize,
+ Label, List, ListHeader, ListItem, Tooltip,
+};
+use util::{maybe, ResultExt, TryFutureExt};
use workspace::{
dock::{DockPosition, Panel, PanelEvent},
+ notifications::NotifyResultExt,
Workspace,
};
-use crate::CollaborationPanelSettings;
+use crate::{face_pile::FacePile, CollaborationPanelSettings};
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(|workspace: &mut Workspace, _| {
@@ -217,26 +233,6 @@ pub fn init(cx: &mut AppContext) {
// },
// );
- // cx.add_action(
- // |panel: &mut CollabPanel,
- // action: &StartMoveChannelFor,
- // _: &mut ViewContext| {
- // panel.channel_clipboard = Some(ChannelMoveClipboard {
- // channel_id: action.channel_id,
- // });
- // },
- // );
-
- // cx.add_action(
- // |panel: &mut CollabPanel, _: &StartMoveChannel, _: &mut ViewContext| {
- // if let Some(channel) = panel.selected_channel() {
- // panel.channel_clipboard = Some(ChannelMoveClipboard {
- // channel_id: channel.id,
- // })
- // }
- // },
- // );
-
// cx.add_action(
// |panel: &mut CollabPanel, _: &MoveSelected, cx: &mut ViewContext| {
// let Some(clipboard) = panel.channel_clipboard.take() else {
@@ -268,63 +264,63 @@ pub fn init(cx: &mut AppContext) {
// );
}
-// #[derive(Debug)]
-// pub enum ChannelEditingState {
-// Create {
-// location: Option,
-// pending_name: Option,
-// },
-// Rename {
-// location: ChannelId,
-// pending_name: Option,
-// },
-// }
+#[derive(Debug)]
+pub enum ChannelEditingState {
+ Create {
+ location: Option,
+ pending_name: Option,
+ },
+ Rename {
+ location: ChannelId,
+ pending_name: Option,
+ },
+}
-// impl ChannelEditingState {
-// fn pending_name(&self) -> Option<&str> {
-// match self {
-// ChannelEditingState::Create { pending_name, .. } => pending_name.as_deref(),
-// ChannelEditingState::Rename { pending_name, .. } => pending_name.as_deref(),
-// }
-// }
-// }
+impl ChannelEditingState {
+ fn pending_name(&self) -> Option {
+ match self {
+ ChannelEditingState::Create { pending_name, .. } => pending_name.clone(),
+ ChannelEditingState::Rename { pending_name, .. } => pending_name.clone(),
+ }
+ }
+}
pub struct CollabPanel {
- width: Option,
+ width: Option,
fs: Arc,
focus_handle: FocusHandle,
- // channel_clipboard: Option,
- // pending_serialization: Task