Add channel note indicator and clear changed status

This commit is contained in:
Mikayla 2023-10-01 19:53:32 -07:00
parent 9ba975d6ad
commit e0ff7ba180
No known key found for this signature in database
6 changed files with 119 additions and 11 deletions

View file

@ -43,7 +43,7 @@ pub type ChannelData = (Channel, ChannelPath);
pub struct Channel { pub struct Channel {
pub id: ChannelId, pub id: ChannelId,
pub name: String, pub name: String,
pub has_changed: bool, pub has_note_changed: bool,
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
@ -200,19 +200,27 @@ impl ChannelStore {
) -> Task<Result<ModelHandle<ChannelBuffer>>> { ) -> Task<Result<ModelHandle<ChannelBuffer>>> {
let client = self.client.clone(); let client = self.client.clone();
let user_store = self.user_store.clone(); let user_store = self.user_store.clone();
self.open_channel_resource( let open_channel_buffer = self.open_channel_resource(
channel_id, channel_id,
|this| &mut this.opened_buffers, |this| &mut this.opened_buffers,
|channel, cx| ChannelBuffer::new(channel, client, user_store, cx), |channel, cx| ChannelBuffer::new(channel, client, user_store, cx),
cx, cx,
) );
cx.spawn(|this, mut cx| async move {
let buffer = open_channel_buffer.await?;
this.update(&mut cx, |this, cx| {
this.channel_index.clear_note_changed(channel_id);
cx.notify();
});
Ok(buffer)
})
} }
pub fn has_channel_buffer_changed(&self, channel_id: ChannelId) -> Option<bool> { pub fn has_channel_buffer_changed(&self, channel_id: ChannelId) -> Option<bool> {
self.channel_index self.channel_index
.by_id() .by_id()
.get(&channel_id) .get(&channel_id)
.map(|channel| channel.has_changed) .map(|channel| channel.has_note_changed)
} }
pub fn open_channel_chat( pub fn open_channel_chat(
@ -787,7 +795,7 @@ impl ChannelStore {
Arc::new(Channel { Arc::new(Channel {
id: channel.id, id: channel.id,
name: channel.name, name: channel.name,
has_changed: false, has_note_changed: false,
}), }),
), ),
} }
@ -825,7 +833,7 @@ impl ChannelStore {
} }
for id_changed in payload.notes_changed { for id_changed in payload.notes_changed {
index.has_changed(id_changed); index.note_changed(id_changed);
} }
for edge in payload.insert_edge { for edge in payload.insert_edge {

View file

@ -38,6 +38,12 @@ impl ChannelIndex {
channels_by_id: &mut self.channels_by_id, channels_by_id: &mut self.channels_by_id,
} }
} }
pub fn clear_note_changed(&mut self, channel_id: ChannelId) {
if let Some(channel) = self.channels_by_id.get_mut(&channel_id) {
Arc::make_mut(channel).has_note_changed = false;
}
}
} }
impl Deref for ChannelIndex { impl Deref for ChannelIndex {
@ -76,9 +82,9 @@ impl<'a> ChannelPathsInsertGuard<'a> {
} }
} }
pub fn has_changed(&mut self, channel_id: ChannelId) { pub fn note_changed(&mut self, channel_id: ChannelId) {
if let Some(channel) = self.channels_by_id.get_mut(&channel_id) { if let Some(channel) = self.channels_by_id.get_mut(&channel_id) {
Arc::make_mut(channel).has_changed = true; Arc::make_mut(channel).has_note_changed = true;
} }
} }
@ -91,7 +97,7 @@ impl<'a> ChannelPathsInsertGuard<'a> {
Arc::new(Channel { Arc::new(Channel {
id: channel_proto.id, id: channel_proto.id,
name: channel_proto.name, name: channel_proto.name,
has_changed: false, has_note_changed: false,
}), }),
); );
self.insert_root(channel_proto.id); self.insert_root(channel_proto.id);

View file

@ -445,7 +445,7 @@ fn channel(id: u64, name: &'static str) -> Channel {
Channel { Channel {
id, id,
name: name.to_string(), name: name.to_string(),
has_changed: false, has_note_changed: false,
} }
} }
@ -786,6 +786,7 @@ async fn test_channel_buffer_changes(
.await .await
.unwrap(); .unwrap();
// Client A makes an edit, and client B should see that the note has changed.
channel_buffer_a.update(cx_a, |buffer, cx| { channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| { buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "1")], None, cx); buffer.edit([(0..0, "1")], None, cx);
@ -802,6 +803,66 @@ async fn test_channel_buffer_changes(
}); });
assert!(has_buffer_changed); assert!(has_buffer_changed);
// Opening the buffer should clear the changed flag.
let channel_buffer_b = client_b
.channel_store()
.update(cx_b, |store, cx| store.open_channel_buffer(channel_id, cx))
.await
.unwrap();
deterministic.run_until_parked();
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
.unwrap()
});
assert!(!has_buffer_changed);
// Editing the channel while the buffer is open shuold not show that the buffer has changed.
channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "2")], None, cx);
})
});
deterministic.run_until_parked();
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
.unwrap()
});
assert!(!has_buffer_changed);
// Closing the buffer should re-enable change tracking
cx_b.update(|_| {
drop(channel_buffer_b);
});
deterministic.run_until_parked();
channel_buffer_a.update(cx_a, |buffer, cx| {
buffer.buffer().update(cx, |buffer, cx| {
buffer.edit([(0..0, "3")], None, cx);
})
});
deterministic.run_until_parked();
let has_buffer_changed = cx_b.read(|cx| {
client_b
.channel_store()
.read(cx)
.has_channel_buffer_changed(channel_id)
.unwrap()
});
assert!(has_buffer_changed);
} }
#[track_caller] #[track_caller]

View file

@ -1774,6 +1774,7 @@ impl CollabPanel {
const FACEPILE_LIMIT: usize = 3; const FACEPILE_LIMIT: usize = 3;
enum ChannelCall {} enum ChannelCall {}
enum ChannelNote {}
let mut is_dragged_over = false; let mut is_dragged_over = false;
if cx if cx
@ -1820,7 +1821,7 @@ impl CollabPanel {
channel.name.clone(), channel.name.clone(),
theme theme
.channel_name .channel_name
.in_state(channel.has_changed) .in_state(channel.has_note_changed)
.text .text
.clone(), .clone(),
) )
@ -1863,6 +1864,8 @@ impl CollabPanel {
.with_color(theme.channel_hash.color) .with_color(theme.channel_hash.color)
.constrained() .constrained()
.with_width(theme.channel_hash.width) .with_width(theme.channel_hash.width)
.contained()
.with_margin_right(theme.channel_hash.container.margin.left)
.into_any() .into_any()
} else { } else {
Empty::new().into_any() Empty::new().into_any()
@ -1872,6 +1875,34 @@ impl CollabPanel {
this.join_channel_call(channel_id, cx); this.join_channel_call(channel_id, cx);
}), }),
) )
.with_child(
MouseEventHandler::new::<ChannelNote, _>(ix, cx, move |_, cx| {
let participants =
self.channel_store.read(cx).channel_participants(channel_id);
if participants.is_empty() {
if channel.has_note_changed {
Svg::new("icons/terminal.svg")
.with_color(theme.channel_note_active_color)
.constrained()
.with_width(theme.channel_hash.width)
.into_any()
} else if row_hovered {
Svg::new("icons/terminal.svg")
.with_color(theme.channel_hash.color)
.constrained()
.with_width(theme.channel_hash.width)
.into_any()
} else {
Empty::new().into_any()
}
} else {
Empty::new().into_any()
}
})
.on_click(MouseButton::Left, move |_, this, cx| {
this.open_channel_notes(&OpenChannelNotes { channel_id }, cx);
}),
)
.align_children_center() .align_children_center()
.styleable_component() .styleable_component()
.disclosable( .disclosable(

View file

@ -238,6 +238,7 @@ pub struct CollabPanel {
pub log_in_button: Interactive<ContainedText>, pub log_in_button: Interactive<ContainedText>,
pub channel_editor: ContainerStyle, pub channel_editor: ContainerStyle,
pub channel_hash: Icon, pub channel_hash: Icon,
pub channel_note_active_color: Color,
pub tabbed_modal: TabbedModal, pub tabbed_modal: TabbedModal,
pub contact_finder: ContactFinder, pub contact_finder: ContactFinder,
pub channel_modal: ChannelModal, pub channel_modal: ChannelModal,

View file

@ -194,6 +194,7 @@ export default function contacts_panel(): any {
}, },
user_query_editor: filter_input, user_query_editor: filter_input,
channel_hash: icon_style, channel_hash: icon_style,
channel_note_active_color: foreground(layer, "active"),
user_query_editor_height: 33, user_query_editor_height: 33,
add_contact_button: header_icon_button, add_contact_button: header_icon_button,
add_channel_button: header_icon_button, add_channel_button: header_icon_button,