diff --git a/crates/client/src/channel_store.rs b/crates/client/src/channel_store.rs index 93b96fc629..1beb1bc8ea 100644 --- a/crates/client/src/channel_store.rs +++ b/crates/client/src/channel_store.rs @@ -4,8 +4,10 @@ use anyhow::Result; use collections::HashMap; use collections::HashSet; use futures::Future; +use futures::StreamExt; use gpui::{AsyncAppContext, Entity, ModelContext, ModelHandle, Task}; use rpc::{proto, TypedEnvelope}; +use std::mem; use std::sync::Arc; pub type ChannelId = u64; @@ -19,6 +21,7 @@ pub struct ChannelStore { client: Arc, user_store: ModelHandle, _rpc_subscription: Subscription, + _maintain_user: Task<()>, } #[derive(Clone, Debug, PartialEq)] @@ -55,6 +58,20 @@ impl ChannelStore { let rpc_subscription = client.add_message_handler(cx.handle(), Self::handle_update_channels); + let mut current_user = user_store.read(cx).watch_current_user(); + let maintain_user = cx.spawn(|this, mut cx| async move { + while let Some(current_user) = current_user.next().await { + if current_user.is_none() { + this.update(&mut cx, |this, cx| { + this.channels.clear(); + this.channel_invitations.clear(); + this.channel_participants.clear(); + this.outgoing_invites.clear(); + cx.notify(); + }); + } + } + }); Self { channels: vec![], channel_invitations: vec![], @@ -63,6 +80,7 @@ impl ChannelStore { client, user_store, _rpc_subscription: rpc_subscription, + _maintain_user: maintain_user, } } @@ -301,10 +319,10 @@ impl ChannelStore { .iter_mut() .find(|c| c.id == channel.id) { - let existing_channel = Arc::get_mut(existing_channel) - .expect("channel is shared, update would have been lost"); - existing_channel.name = channel.name; - existing_channel.user_is_admin = channel.user_is_admin; + util::make_arc_mut(existing_channel, |new_existing_channel| { + new_existing_channel.name = channel.name; + new_existing_channel.user_is_admin = channel.user_is_admin; + }); continue; } @@ -322,10 +340,10 @@ impl ChannelStore { for channel in payload.channels { if let Some(existing_channel) = self.channels.iter_mut().find(|c| c.id == channel.id) { - let existing_channel = Arc::get_mut(existing_channel) - .expect("channel is shared, update would have been lost"); - existing_channel.name = channel.name; - existing_channel.user_is_admin = channel.user_is_admin; + util::make_arc_mut(existing_channel, |new_existing_channel| { + new_existing_channel.name = channel.name; + new_existing_channel.user_is_admin = channel.user_is_admin; + }); continue; } diff --git a/crates/collab/src/db.rs b/crates/collab/src/db.rs index eb40587ea7..ed5e7e8e3d 100644 --- a/crates/collab/src/db.rs +++ b/crates/collab/src/db.rs @@ -3155,6 +3155,7 @@ impl Database { live_kit_room: &str, creator_id: UserId, ) -> Result { + let name = name.trim().trim_start_matches('#'); self.transaction(move |tx| async move { if let Some(parent) = parent { self.check_user_is_channel_admin(parent, creator_id, &*tx) diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index f745420eeb..2b39678f5e 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -308,7 +308,7 @@ impl CollabPanel { cx, ), ListEntry::ChannelEditor { depth } => { - this.render_channel_editor(&theme.collab_panel, *depth, cx) + this.render_channel_editor(&theme, *depth, cx) } } }); @@ -1280,11 +1280,37 @@ impl CollabPanel { fn render_channel_editor( &self, - _theme: &theme::CollabPanel, - _depth: usize, + theme: &theme::Theme, + depth: usize, cx: &AppContext, ) -> AnyElement { - ChildView::new(&self.channel_name_editor, cx).into_any() + Flex::row() + .with_child( + Svg::new("icons/channel_hash.svg") + .with_color(theme.collab_panel.channel_hash.color) + .constrained() + .with_width(theme.collab_panel.channel_hash.width) + .aligned() + .left(), + ) + .with_child( + ChildView::new(&self.channel_name_editor, cx) + .contained() + .with_style(theme.collab_panel.channel_editor) + .flex(1.0, true), + ) + .align_children_center() + .contained() + .with_padding_left( + theme.collab_panel.contact_row.default_style().padding.left + + theme.collab_panel.channel_indent * depth as f32, + ) + .contained() + .with_style(gpui::elements::ContainerStyle { + background_color: Some(theme.editor.background), + ..Default::default() + }) + .into_any() } fn render_channel( @@ -1331,7 +1357,7 @@ impl CollabPanel { .constrained() .with_height(theme.row_height) .contained() - .with_style(*theme.contact_row.in_state(is_selected).style_for(state)) + .with_style(*theme.contact_row.style_for(is_selected, state)) .with_padding_left( theme.contact_row.default_style().padding.left + theme.channel_indent * channel.depth as f32, diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c554f77fe4..cf8da6233a 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -221,6 +221,7 @@ pub struct CollabPanel { #[serde(flatten)] pub container: ContainerStyle, pub log_in_button: Interactive, + pub channel_editor: ContainerStyle, pub channel_hash: Icon, pub channel_modal: ChannelModal, pub user_query_editor: FieldEditor, @@ -885,6 +886,7 @@ impl Toggleable { pub fn active_state(&self) -> &T { self.in_state(true) } + pub fn inactive_state(&self) -> &T { self.in_state(false) } diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index c8beb86aef..2766cee295 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -9,9 +9,11 @@ pub mod test; use std::{ borrow::Cow, cmp::{self, Ordering}, + mem, ops::{AddAssign, Range, RangeInclusive}, panic::Location, pin::Pin, + sync::Arc, task::{Context, Poll}, }; @@ -118,6 +120,19 @@ pub fn merge_non_null_json_value_into(source: serde_json::Value, target: &mut se } } +/// Mutates through the arc if no other references exist, +/// otherwise clones the value and swaps out the reference with a new Arc +/// Useful for mutating the elements of a list while using iter_mut() +pub fn make_arc_mut(arc: &mut Arc, mutate: impl FnOnce(&mut T)) { + if let Some(t) = Arc::get_mut(arc) { + mutate(t); + return; + } + let mut new_t = (**arc).clone(); + mutate(&mut new_t); + mem::swap(&mut Arc::new(new_t), arc); +} + pub trait ResultExt { type Ok; diff --git a/styles/src/style_tree/collab_panel.ts b/styles/src/style_tree/collab_panel.ts index 2c543356b0..a859f6d670 100644 --- a/styles/src/style_tree/collab_panel.ts +++ b/styles/src/style_tree/collab_panel.ts @@ -316,6 +316,11 @@ export default function contacts_panel(): any { }, }, }), - face_overlap: 8 + face_overlap: 8, + channel_editor: { + padding: { + left: 8, + } + } } }