Detailed changes
@@ -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<Client>,
user_store: ModelHandle<UserStore>,
_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;
}
@@ -3155,6 +3155,7 @@ impl Database {
live_kit_room: &str,
creator_id: UserId,
) -> Result<ChannelId> {
+ 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)
@@ -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<Self> {
- 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,
@@ -221,6 +221,7 @@ pub struct CollabPanel {
#[serde(flatten)]
pub container: ContainerStyle,
pub log_in_button: Interactive<ContainedText>,
+ pub channel_editor: ContainerStyle,
pub channel_hash: Icon,
pub channel_modal: ChannelModal,
pub user_query_editor: FieldEditor,
@@ -885,6 +886,7 @@ impl<T> Toggleable<T> {
pub fn active_state(&self) -> &T {
self.in_state(true)
}
+
pub fn inactive_state(&self) -> &T {
self.in_state(false)
}
@@ -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<T: Clone>(arc: &mut Arc<T>, 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<E> {
type Ok;
@@ -316,6 +316,11 @@ export default function contacts_panel(): any {
},
},
}),
- face_overlap: 8
+ face_overlap: 8,
+ channel_editor: {
+ padding: {
+ left: 8,
+ }
+ }
}
}