Add read-only channel notes support
Fix some bugs where ChannelNotes and ChannelChat had old cached channel instances
This commit is contained in:
parent
3853009d92
commit
0eff7c6ca9
12 changed files with 186 additions and 219 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1569,6 +1569,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"settings",
|
||||
"smallvec",
|
||||
"theme",
|
||||
"theme_selector",
|
||||
"time",
|
||||
|
|
|
@ -370,42 +370,15 @@
|
|||
{
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"ctrl-1": [
|
||||
"pane::ActivateItem",
|
||||
0
|
||||
],
|
||||
"ctrl-2": [
|
||||
"pane::ActivateItem",
|
||||
1
|
||||
],
|
||||
"ctrl-3": [
|
||||
"pane::ActivateItem",
|
||||
2
|
||||
],
|
||||
"ctrl-4": [
|
||||
"pane::ActivateItem",
|
||||
3
|
||||
],
|
||||
"ctrl-5": [
|
||||
"pane::ActivateItem",
|
||||
4
|
||||
],
|
||||
"ctrl-6": [
|
||||
"pane::ActivateItem",
|
||||
5
|
||||
],
|
||||
"ctrl-7": [
|
||||
"pane::ActivateItem",
|
||||
6
|
||||
],
|
||||
"ctrl-8": [
|
||||
"pane::ActivateItem",
|
||||
7
|
||||
],
|
||||
"ctrl-9": [
|
||||
"pane::ActivateItem",
|
||||
8
|
||||
],
|
||||
"ctrl-1": ["pane::ActivateItem", 0],
|
||||
"ctrl-2": ["pane::ActivateItem", 1],
|
||||
"ctrl-3": ["pane::ActivateItem", 2],
|
||||
"ctrl-4": ["pane::ActivateItem", 3],
|
||||
"ctrl-5": ["pane::ActivateItem", 4],
|
||||
"ctrl-6": ["pane::ActivateItem", 5],
|
||||
"ctrl-7": ["pane::ActivateItem", 6],
|
||||
"ctrl-8": ["pane::ActivateItem", 7],
|
||||
"ctrl-9": ["pane::ActivateItem", 8],
|
||||
"ctrl-0": "pane::ActivateLastItem",
|
||||
"ctrl--": "pane::GoBack",
|
||||
"ctrl-_": "pane::GoForward",
|
||||
|
@ -416,42 +389,15 @@
|
|||
{
|
||||
"context": "Workspace",
|
||||
"bindings": {
|
||||
"cmd-1": [
|
||||
"workspace::ActivatePane",
|
||||
0
|
||||
],
|
||||
"cmd-2": [
|
||||
"workspace::ActivatePane",
|
||||
1
|
||||
],
|
||||
"cmd-3": [
|
||||
"workspace::ActivatePane",
|
||||
2
|
||||
],
|
||||
"cmd-4": [
|
||||
"workspace::ActivatePane",
|
||||
3
|
||||
],
|
||||
"cmd-5": [
|
||||
"workspace::ActivatePane",
|
||||
4
|
||||
],
|
||||
"cmd-6": [
|
||||
"workspace::ActivatePane",
|
||||
5
|
||||
],
|
||||
"cmd-7": [
|
||||
"workspace::ActivatePane",
|
||||
6
|
||||
],
|
||||
"cmd-8": [
|
||||
"workspace::ActivatePane",
|
||||
7
|
||||
],
|
||||
"cmd-9": [
|
||||
"workspace::ActivatePane",
|
||||
8
|
||||
],
|
||||
"cmd-1": ["workspace::ActivatePane", 0],
|
||||
"cmd-2": ["workspace::ActivatePane", 1],
|
||||
"cmd-3": ["workspace::ActivatePane", 2],
|
||||
"cmd-4": ["workspace::ActivatePane", 3],
|
||||
"cmd-5": ["workspace::ActivatePane", 4],
|
||||
"cmd-6": ["workspace::ActivatePane", 5],
|
||||
"cmd-7": ["workspace::ActivatePane", 6],
|
||||
"cmd-8": ["workspace::ActivatePane", 7],
|
||||
"cmd-9": ["workspace::ActivatePane", 8],
|
||||
"cmd-b": "workspace::ToggleLeftDock",
|
||||
"cmd-r": "workspace::ToggleRightDock",
|
||||
"cmd-j": "workspace::ToggleBottomDock",
|
||||
|
@ -494,38 +440,14 @@
|
|||
},
|
||||
{
|
||||
"bindings": {
|
||||
"cmd-k cmd-left": [
|
||||
"workspace::ActivatePaneInDirection",
|
||||
"Left"
|
||||
],
|
||||
"cmd-k cmd-right": [
|
||||
"workspace::ActivatePaneInDirection",
|
||||
"Right"
|
||||
],
|
||||
"cmd-k cmd-up": [
|
||||
"workspace::ActivatePaneInDirection",
|
||||
"Up"
|
||||
],
|
||||
"cmd-k cmd-down": [
|
||||
"workspace::ActivatePaneInDirection",
|
||||
"Down"
|
||||
],
|
||||
"cmd-k shift-left": [
|
||||
"workspace::SwapPaneInDirection",
|
||||
"Left"
|
||||
],
|
||||
"cmd-k shift-right": [
|
||||
"workspace::SwapPaneInDirection",
|
||||
"Right"
|
||||
],
|
||||
"cmd-k shift-up": [
|
||||
"workspace::SwapPaneInDirection",
|
||||
"Up"
|
||||
],
|
||||
"cmd-k shift-down": [
|
||||
"workspace::SwapPaneInDirection",
|
||||
"Down"
|
||||
]
|
||||
"cmd-k cmd-left": ["workspace::ActivatePaneInDirection", "Left"],
|
||||
"cmd-k cmd-right": ["workspace::ActivatePaneInDirection", "Right"],
|
||||
"cmd-k cmd-up": ["workspace::ActivatePaneInDirection", "Up"],
|
||||
"cmd-k cmd-down": ["workspace::ActivatePaneInDirection", "Down"],
|
||||
"cmd-k shift-left": ["workspace::SwapPaneInDirection", "Left"],
|
||||
"cmd-k shift-right": ["workspace::SwapPaneInDirection", "Right"],
|
||||
"cmd-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
|
||||
"cmd-k shift-down": ["workspace::SwapPaneInDirection", "Down"]
|
||||
}
|
||||
},
|
||||
// Bindings from Atom
|
||||
|
@ -627,14 +549,6 @@
|
|||
"space": "collab_panel::InsertSpace"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "(CollabPanel && not_editing) > Editor",
|
||||
"bindings": {
|
||||
"cmd-c": "collab_panel::StartLinkChannel",
|
||||
"cmd-x": "collab_panel::StartMoveChannel",
|
||||
"cmd-v": "collab_panel::MoveOrLinkToSelected"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ChannelModal",
|
||||
"bindings": {
|
||||
|
@ -655,57 +569,21 @@
|
|||
"cmd-v": "terminal::Paste",
|
||||
"cmd-k": "terminal::Clear",
|
||||
// Some nice conveniences
|
||||
"cmd-backspace": [
|
||||
"terminal::SendText",
|
||||
"\u0015"
|
||||
],
|
||||
"cmd-right": [
|
||||
"terminal::SendText",
|
||||
"\u0005"
|
||||
],
|
||||
"cmd-left": [
|
||||
"terminal::SendText",
|
||||
"\u0001"
|
||||
],
|
||||
"cmd-backspace": ["terminal::SendText", "\u0015"],
|
||||
"cmd-right": ["terminal::SendText", "\u0005"],
|
||||
"cmd-left": ["terminal::SendText", "\u0001"],
|
||||
// Terminal.app compatibility
|
||||
"alt-left": [
|
||||
"terminal::SendText",
|
||||
"\u001bb"
|
||||
],
|
||||
"alt-right": [
|
||||
"terminal::SendText",
|
||||
"\u001bf"
|
||||
],
|
||||
"alt-left": ["terminal::SendText", "\u001bb"],
|
||||
"alt-right": ["terminal::SendText", "\u001bf"],
|
||||
// There are conflicting bindings for these keys in the global context.
|
||||
// these bindings override them, remove at your own risk:
|
||||
"up": [
|
||||
"terminal::SendKeystroke",
|
||||
"up"
|
||||
],
|
||||
"pageup": [
|
||||
"terminal::SendKeystroke",
|
||||
"pageup"
|
||||
],
|
||||
"down": [
|
||||
"terminal::SendKeystroke",
|
||||
"down"
|
||||
],
|
||||
"pagedown": [
|
||||
"terminal::SendKeystroke",
|
||||
"pagedown"
|
||||
],
|
||||
"escape": [
|
||||
"terminal::SendKeystroke",
|
||||
"escape"
|
||||
],
|
||||
"enter": [
|
||||
"terminal::SendKeystroke",
|
||||
"enter"
|
||||
],
|
||||
"ctrl-c": [
|
||||
"terminal::SendKeystroke",
|
||||
"ctrl-c"
|
||||
]
|
||||
"up": ["terminal::SendKeystroke", "up"],
|
||||
"pageup": ["terminal::SendKeystroke", "pageup"],
|
||||
"down": ["terminal::SendKeystroke", "down"],
|
||||
"pagedown": ["terminal::SendKeystroke", "pagedown"],
|
||||
"escape": ["terminal::SendKeystroke", "escape"],
|
||||
"enter": ["terminal::SendKeystroke", "enter"],
|
||||
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -55,7 +55,7 @@ pub enum Event {
|
|||
|
||||
pub struct Room {
|
||||
id: u64,
|
||||
channel_id: Option<u64>,
|
||||
pub channel_id: Option<u64>,
|
||||
live_kit: Option<LiveKitRoom>,
|
||||
status: RoomStatus,
|
||||
shared_projects: HashSet<WeakModelHandle<Project>>,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::Channel;
|
||||
use crate::{Channel, ChannelId, ChannelStore};
|
||||
use anyhow::Result;
|
||||
use client::{Client, Collaborator, UserStore};
|
||||
use collections::HashMap;
|
||||
|
@ -19,10 +19,11 @@ pub(crate) fn init(client: &Arc<Client>) {
|
|||
}
|
||||
|
||||
pub struct ChannelBuffer {
|
||||
pub(crate) channel: Arc<Channel>,
|
||||
pub channel_id: ChannelId,
|
||||
connected: bool,
|
||||
collaborators: HashMap<PeerId, Collaborator>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
channel_store: ModelHandle<ChannelStore>,
|
||||
buffer: ModelHandle<language::Buffer>,
|
||||
buffer_epoch: u64,
|
||||
client: Arc<Client>,
|
||||
|
@ -34,6 +35,7 @@ pub enum ChannelBufferEvent {
|
|||
CollaboratorsChanged,
|
||||
Disconnected,
|
||||
BufferEdited,
|
||||
ChannelChanged,
|
||||
}
|
||||
|
||||
impl Entity for ChannelBuffer {
|
||||
|
@ -46,7 +48,7 @@ impl Entity for ChannelBuffer {
|
|||
}
|
||||
self.client
|
||||
.send(proto::LeaveChannelBuffer {
|
||||
channel_id: self.channel.id,
|
||||
channel_id: self.channel_id,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
@ -58,6 +60,7 @@ impl ChannelBuffer {
|
|||
channel: Arc<Channel>,
|
||||
client: Arc<Client>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
channel_store: ModelHandle<ChannelStore>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<ModelHandle<Self>> {
|
||||
let response = client
|
||||
|
@ -90,9 +93,10 @@ impl ChannelBuffer {
|
|||
connected: true,
|
||||
collaborators: Default::default(),
|
||||
acknowledge_task: None,
|
||||
channel,
|
||||
channel_id: channel.id,
|
||||
subscription: Some(subscription.set_model(&cx.handle(), &mut cx.to_async())),
|
||||
user_store,
|
||||
channel_store,
|
||||
};
|
||||
this.replace_collaborators(response.collaborators, cx);
|
||||
this
|
||||
|
@ -179,7 +183,7 @@ impl ChannelBuffer {
|
|||
let operation = language::proto::serialize_operation(operation);
|
||||
self.client
|
||||
.send(proto::UpdateChannelBuffer {
|
||||
channel_id: self.channel.id,
|
||||
channel_id: self.channel_id,
|
||||
operations: vec![operation],
|
||||
})
|
||||
.log_err();
|
||||
|
@ -223,12 +227,15 @@ impl ChannelBuffer {
|
|||
&self.collaborators
|
||||
}
|
||||
|
||||
pub fn channel(&self) -> Arc<Channel> {
|
||||
self.channel.clone()
|
||||
pub fn channel(&self, cx: &AppContext) -> Option<Arc<Channel>> {
|
||||
self.channel_store
|
||||
.read(cx)
|
||||
.channel_for_id(self.channel_id)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn disconnect(&mut self, cx: &mut ModelContext<Self>) {
|
||||
log::info!("channel buffer {} disconnected", self.channel.id);
|
||||
log::info!("channel buffer {} disconnected", self.channel_id);
|
||||
if self.connected {
|
||||
self.connected = false;
|
||||
self.subscription.take();
|
||||
|
@ -237,6 +244,11 @@ impl ChannelBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn channel_changed(&mut self, cx: &mut ModelContext<Self>) {
|
||||
cx.emit(ChannelBufferEvent::ChannelChanged);
|
||||
cx.notify()
|
||||
}
|
||||
|
||||
pub fn is_connected(&self) -> bool {
|
||||
self.connected
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use time::OffsetDateTime;
|
|||
use util::{post_inc, ResultExt as _, TryFutureExt};
|
||||
|
||||
pub struct ChannelChat {
|
||||
channel: Arc<Channel>,
|
||||
pub channel_id: ChannelId,
|
||||
messages: SumTree<ChannelMessage>,
|
||||
channel_store: ModelHandle<ChannelStore>,
|
||||
loaded_all_messages: bool,
|
||||
|
@ -74,7 +74,7 @@ impl Entity for ChannelChat {
|
|||
fn release(&mut self, _: &mut AppContext) {
|
||||
self.rpc
|
||||
.send(proto::LeaveChannelChat {
|
||||
channel_id: self.channel.id,
|
||||
channel_id: self.channel_id,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ impl ChannelChat {
|
|||
|
||||
Ok(cx.add_model(|cx| {
|
||||
let mut this = Self {
|
||||
channel,
|
||||
channel_id: channel.id,
|
||||
user_store,
|
||||
channel_store,
|
||||
rpc: client,
|
||||
|
@ -116,8 +116,11 @@ impl ChannelChat {
|
|||
}))
|
||||
}
|
||||
|
||||
pub fn channel(&self) -> &Arc<Channel> {
|
||||
&self.channel
|
||||
pub fn channel(&self, cx: &AppContext) -> Option<Arc<Channel>> {
|
||||
self.channel_store
|
||||
.read(cx)
|
||||
.channel_for_id(self.channel_id)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn send_message(
|
||||
|
@ -135,7 +138,7 @@ impl ChannelChat {
|
|||
.current_user()
|
||||
.ok_or_else(|| anyhow!("current_user is not present"))?;
|
||||
|
||||
let channel_id = self.channel.id;
|
||||
let channel_id = self.channel_id;
|
||||
let pending_id = ChannelMessageId::Pending(post_inc(&mut self.next_pending_message_id));
|
||||
let nonce = self.rng.gen();
|
||||
self.insert_messages(
|
||||
|
@ -178,7 +181,7 @@ impl ChannelChat {
|
|||
|
||||
pub fn remove_message(&mut self, id: u64, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
let response = self.rpc.request(proto::RemoveChannelMessage {
|
||||
channel_id: self.channel.id,
|
||||
channel_id: self.channel_id,
|
||||
message_id: id,
|
||||
});
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
|
@ -195,7 +198,7 @@ impl ChannelChat {
|
|||
if !self.loaded_all_messages {
|
||||
let rpc = self.rpc.clone();
|
||||
let user_store = self.user_store.clone();
|
||||
let channel_id = self.channel.id;
|
||||
let channel_id = self.channel_id;
|
||||
if let Some(before_message_id) =
|
||||
self.messages.first().and_then(|message| match message.id {
|
||||
ChannelMessageId::Saved(id) => Some(id),
|
||||
|
@ -236,13 +239,13 @@ impl ChannelChat {
|
|||
{
|
||||
self.rpc
|
||||
.send(proto::AckChannelMessage {
|
||||
channel_id: self.channel.id,
|
||||
channel_id: self.channel_id,
|
||||
message_id: latest_message_id,
|
||||
})
|
||||
.ok();
|
||||
self.last_acknowledged_id = Some(latest_message_id);
|
||||
self.channel_store.update(cx, |store, cx| {
|
||||
store.acknowledge_message_id(self.channel.id, latest_message_id, cx);
|
||||
store.acknowledge_message_id(self.channel_id, latest_message_id, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +254,7 @@ impl ChannelChat {
|
|||
pub fn rejoin(&mut self, cx: &mut ModelContext<Self>) {
|
||||
let user_store = self.user_store.clone();
|
||||
let rpc = self.rpc.clone();
|
||||
let channel_id = self.channel.id;
|
||||
let channel_id = self.channel_id;
|
||||
cx.spawn(|this, mut cx| {
|
||||
async move {
|
||||
let response = rpc.request(proto::JoinChannelChat { channel_id }).await?;
|
||||
|
@ -348,7 +351,7 @@ impl ChannelChat {
|
|||
this.update(&mut cx, |this, cx| {
|
||||
this.insert_messages(SumTree::from_item(message, &()), cx);
|
||||
cx.emit(ChannelChatEvent::NewMessage {
|
||||
channel_id: this.channel.id,
|
||||
channel_id: this.channel_id,
|
||||
message_id,
|
||||
})
|
||||
});
|
||||
|
|
|
@ -72,6 +72,10 @@ impl Channel {
|
|||
|
||||
slug.trim_matches(|c| c == '-').to_string()
|
||||
}
|
||||
|
||||
pub fn can_edit_notes(&self) -> bool {
|
||||
self.role == proto::ChannelRole::Member || self.role == proto::ChannelRole::Admin
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
|
||||
|
@ -265,10 +269,11 @@ impl ChannelStore {
|
|||
) -> Task<Result<ModelHandle<ChannelBuffer>>> {
|
||||
let client = self.client.clone();
|
||||
let user_store = self.user_store.clone();
|
||||
let channel_store = cx.handle();
|
||||
self.open_channel_resource(
|
||||
channel_id,
|
||||
|this| &mut this.opened_buffers,
|
||||
|channel, cx| ChannelBuffer::new(channel, client, user_store, cx),
|
||||
|channel, cx| ChannelBuffer::new(channel, client, user_store, channel_store, cx),
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
@ -778,7 +783,7 @@ impl ChannelStore {
|
|||
let channel_buffer = buffer.read(cx);
|
||||
let buffer = channel_buffer.buffer().read(cx);
|
||||
buffer_versions.push(proto::ChannelBufferVersion {
|
||||
channel_id: channel_buffer.channel().id,
|
||||
channel_id: channel_buffer.channel_id,
|
||||
epoch: channel_buffer.epoch(),
|
||||
version: language::proto::serialize_version(&buffer.version()),
|
||||
});
|
||||
|
@ -805,13 +810,13 @@ impl ChannelStore {
|
|||
};
|
||||
|
||||
channel_buffer.update(cx, |channel_buffer, cx| {
|
||||
let channel_id = channel_buffer.channel().id;
|
||||
let channel_id = channel_buffer.channel_id;
|
||||
if let Some(remote_buffer) = response
|
||||
.buffers
|
||||
.iter_mut()
|
||||
.find(|buffer| buffer.channel_id == channel_id)
|
||||
{
|
||||
let channel_id = channel_buffer.channel().id;
|
||||
let channel_id = channel_buffer.channel_id;
|
||||
let remote_version =
|
||||
language::proto::deserialize_version(&remote_buffer.version);
|
||||
|
||||
|
@ -934,11 +939,27 @@ impl ChannelStore {
|
|||
|
||||
if channels_changed {
|
||||
if !payload.delete_channels.is_empty() {
|
||||
self.channel_index.delete_channels(&payload.delete_channels);
|
||||
self.channel_participants
|
||||
.retain(|channel_id, _| !payload.delete_channels.contains(channel_id));
|
||||
let mut channels_to_delete: Vec<u64> = Vec::new();
|
||||
let mut channels_to_rehome: Vec<u64> = Vec::new();
|
||||
for channel_id in payload.delete_channels {
|
||||
if payload
|
||||
.channels
|
||||
.iter()
|
||||
.any(|channel| channel.id == channel_id)
|
||||
{
|
||||
channels_to_rehome.push(channel_id)
|
||||
} else {
|
||||
channels_to_delete.push(channel_id)
|
||||
}
|
||||
}
|
||||
|
||||
for channel_id in &payload.delete_channels {
|
||||
self.channel_index.delete_channels(&channels_to_delete);
|
||||
self.channel_index
|
||||
.delete_paths_through_channels(&channels_to_rehome);
|
||||
self.channel_participants
|
||||
.retain(|channel_id, _| !channels_to_delete.contains(channel_id));
|
||||
|
||||
for channel_id in &channels_to_delete {
|
||||
let channel_id = *channel_id;
|
||||
if payload
|
||||
.channels
|
||||
|
@ -959,7 +980,16 @@ impl ChannelStore {
|
|||
|
||||
let mut index = self.channel_index.bulk_insert();
|
||||
for channel in payload.channels {
|
||||
index.insert(channel)
|
||||
let id = channel.id;
|
||||
let channel_changed = index.insert(channel);
|
||||
|
||||
if channel_changed {
|
||||
if let Some(OpenedModelHandle::Open(buffer)) = self.opened_buffers.get(&id) {
|
||||
if let Some(buffer) = buffer.upgrade(cx) {
|
||||
buffer.update(cx, ChannelBuffer::channel_changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for unseen_buffer_change in payload.unseen_channel_buffer_changes {
|
||||
|
|
|
@ -24,12 +24,16 @@ impl ChannelIndex {
|
|||
|
||||
/// Delete the given channels from this index.
|
||||
pub fn delete_channels(&mut self, channels: &[ChannelId]) {
|
||||
dbg!("delete_channels", &channels);
|
||||
self.channels_by_id
|
||||
.retain(|channel_id, _| !channels.contains(channel_id));
|
||||
self.paths.retain(|path| {
|
||||
path.iter()
|
||||
.all(|channel_id| self.channels_by_id.contains_key(channel_id))
|
||||
});
|
||||
self.delete_paths_through_channels(channels)
|
||||
}
|
||||
|
||||
pub fn delete_paths_through_channels(&mut self, channels: &[ChannelId]) {
|
||||
dbg!("rehome_channels", &channels);
|
||||
self.paths
|
||||
.retain(|path| !path.iter().any(|channel_id| channels.contains(channel_id)));
|
||||
}
|
||||
|
||||
pub fn bulk_insert(&mut self) -> ChannelPathsInsertGuard {
|
||||
|
@ -121,9 +125,15 @@ impl<'a> ChannelPathsInsertGuard<'a> {
|
|||
insert_new_message(&mut self.channels_by_id, channel_id, message_id)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, channel_proto: proto::Channel) {
|
||||
pub fn insert(&mut self, channel_proto: proto::Channel) -> bool {
|
||||
let mut ret = false;
|
||||
if let Some(existing_channel) = self.channels_by_id.get_mut(&channel_proto.id) {
|
||||
let existing_channel = Arc::make_mut(existing_channel);
|
||||
|
||||
ret = existing_channel.visibility != channel_proto.visibility()
|
||||
|| existing_channel.role != channel_proto.role()
|
||||
|| existing_channel.name != channel_proto.name;
|
||||
|
||||
existing_channel.visibility = channel_proto.visibility();
|
||||
existing_channel.role = channel_proto.role();
|
||||
existing_channel.name = channel_proto.name;
|
||||
|
@ -141,6 +151,7 @@ impl<'a> ChannelPathsInsertGuard<'a> {
|
|||
);
|
||||
self.insert_root(channel_proto.id);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn insert_edge(&mut self, channel_id: ChannelId, parent_id: ChannelId) {
|
||||
|
|
|
@ -412,7 +412,7 @@ async fn test_channel_buffer_disconnect(
|
|||
|
||||
channel_buffer_a.update(cx_a, |buffer, _| {
|
||||
assert_eq!(
|
||||
buffer.channel().as_ref(),
|
||||
buffer.channel(cx).unwrap().as_ref(),
|
||||
&channel(channel_id, "the-channel", proto::ChannelRole::Admin)
|
||||
);
|
||||
assert!(!buffer.is_connected());
|
||||
|
@ -437,7 +437,7 @@ async fn test_channel_buffer_disconnect(
|
|||
// Channel buffer observed the deletion
|
||||
channel_buffer_b.update(cx_b, |buffer, _| {
|
||||
assert_eq!(
|
||||
buffer.channel().as_ref(),
|
||||
buffer.channel(cx).unwrap().as_ref(),
|
||||
&channel(channel_id, "the-channel", proto::ChannelRole::Member)
|
||||
);
|
||||
assert!(!buffer.is_connected());
|
||||
|
|
|
@ -98,7 +98,8 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
|
||||
30..=40 => {
|
||||
if let Some(buffer) = channel_buffers.iter().choose(rng) {
|
||||
let channel_name = buffer.read_with(cx, |b, _| b.channel().name.clone());
|
||||
let channel_name =
|
||||
buffer.read_with(cx, |b, _| b.channel(cx).unwrap().name.clone());
|
||||
break ChannelBufferOperation::LeaveChannelNotes { channel_name };
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +107,7 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
_ => {
|
||||
if let Some(buffer) = channel_buffers.iter().choose(rng) {
|
||||
break buffer.read_with(cx, |b, _| {
|
||||
let channel_name = b.channel().name.clone();
|
||||
let channel_name = b.channel(cx).unwrap().name.clone();
|
||||
let edits = b
|
||||
.buffer()
|
||||
.read_with(cx, |buffer, _| buffer.get_random_edits(rng, 3));
|
||||
|
@ -153,7 +154,7 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
let buffer = cx.update(|cx| {
|
||||
let mut left_buffer = Err(TestError::Inapplicable);
|
||||
client.channel_buffers().retain(|buffer| {
|
||||
if buffer.read(cx).channel().name == channel_name {
|
||||
if buffer.read(cx).channel(cx).unwrap().name == channel_name {
|
||||
left_buffer = Ok(buffer.clone());
|
||||
false
|
||||
} else {
|
||||
|
@ -179,7 +180,9 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
client
|
||||
.channel_buffers()
|
||||
.iter()
|
||||
.find(|buffer| buffer.read(cx).channel().name == channel_name)
|
||||
.find(|buffer| {
|
||||
buffer.read(cx).channel(cx).unwrap().name == channel_name
|
||||
})
|
||||
.cloned()
|
||||
})
|
||||
.ok_or_else(|| TestError::Inapplicable)?;
|
||||
|
@ -250,7 +253,7 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
if let Some(channel_buffer) = client
|
||||
.channel_buffers()
|
||||
.iter()
|
||||
.find(|b| b.read(cx).channel().id == channel_id.to_proto())
|
||||
.find(|b| b.read(cx).channel_id == channel_id.to_proto())
|
||||
{
|
||||
let channel_buffer = channel_buffer.read(cx);
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ postage.workspace = true
|
|||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
time.workspace = true
|
||||
smallvec.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
call = { path = "../call", features = ["test-support"] }
|
||||
|
|
|
@ -15,13 +15,14 @@ use gpui::{
|
|||
ViewContext, ViewHandle,
|
||||
};
|
||||
use project::Project;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use workspace::{
|
||||
item::{FollowableItem, Item, ItemHandle},
|
||||
item::{FollowableItem, Item, ItemEvent, ItemHandle},
|
||||
register_followable_item,
|
||||
searchable::SearchableItemHandle,
|
||||
ItemNavHistory, Pane, SaveIntent, ViewId, Workspace, WorkspaceId,
|
||||
|
@ -140,6 +141,12 @@ impl ChannelView {
|
|||
editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
|
||||
channel_buffer.clone(),
|
||||
)));
|
||||
editor.set_read_only(
|
||||
!channel_buffer
|
||||
.read(cx)
|
||||
.channel(cx)
|
||||
.is_some_and(|c| c.can_edit_notes()),
|
||||
);
|
||||
editor
|
||||
});
|
||||
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
|
||||
|
@ -157,8 +164,8 @@ impl ChannelView {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn channel(&self, cx: &AppContext) -> Arc<Channel> {
|
||||
self.channel_buffer.read(cx).channel()
|
||||
pub fn channel(&self, cx: &AppContext) -> Option<Arc<Channel>> {
|
||||
self.channel_buffer.read(cx).channel(cx)
|
||||
}
|
||||
|
||||
fn handle_channel_buffer_event(
|
||||
|
@ -172,6 +179,13 @@ impl ChannelView {
|
|||
editor.set_read_only(true);
|
||||
cx.notify();
|
||||
}),
|
||||
ChannelBufferEvent::ChannelChanged => {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes()));
|
||||
cx.emit(editor::Event::TitleChanged);
|
||||
cx.notify()
|
||||
});
|
||||
}
|
||||
ChannelBufferEvent::BufferEdited => {
|
||||
if cx.is_self_focused() || self.editor.is_focused(cx) {
|
||||
self.acknowledge_buffer_version(cx);
|
||||
|
@ -179,7 +193,7 @@ impl ChannelView {
|
|||
self.channel_store.update(cx, |store, cx| {
|
||||
let channel_buffer = self.channel_buffer.read(cx);
|
||||
store.notes_changed(
|
||||
channel_buffer.channel().id,
|
||||
channel_buffer.channel_id,
|
||||
channel_buffer.epoch(),
|
||||
&channel_buffer.buffer().read(cx).version(),
|
||||
cx,
|
||||
|
@ -187,7 +201,7 @@ impl ChannelView {
|
|||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
ChannelBufferEvent::CollaboratorsChanged => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +209,7 @@ impl ChannelView {
|
|||
self.channel_store.update(cx, |store, cx| {
|
||||
let channel_buffer = self.channel_buffer.read(cx);
|
||||
store.acknowledge_notes_version(
|
||||
channel_buffer.channel().id,
|
||||
channel_buffer.channel_id,
|
||||
channel_buffer.epoch(),
|
||||
&channel_buffer.buffer().read(cx).version(),
|
||||
cx,
|
||||
|
@ -250,11 +264,17 @@ impl Item for ChannelView {
|
|||
style: &theme::Tab,
|
||||
cx: &gpui::AppContext,
|
||||
) -> AnyElement<V> {
|
||||
let channel_name = &self.channel_buffer.read(cx).channel().name;
|
||||
let label = if self.channel_buffer.read(cx).is_connected() {
|
||||
format!("#{}", channel_name)
|
||||
let label = if let Some(channel) = self.channel(cx) {
|
||||
match (
|
||||
channel.can_edit_notes(),
|
||||
self.channel_buffer.read(cx).is_connected(),
|
||||
) {
|
||||
(true, true) => format!("#{}", channel.name),
|
||||
(false, true) => format!("#{} (read-only)", channel.name),
|
||||
(_, false) => format!("#{} (disconnected)", channel.name),
|
||||
}
|
||||
} else {
|
||||
format!("#{} (disconnected)", channel_name)
|
||||
format!("channel notes (disconnected)")
|
||||
};
|
||||
Label::new(label, style.label.to_owned()).into_any()
|
||||
}
|
||||
|
@ -298,6 +318,10 @@ impl Item for ChannelView {
|
|||
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Vector2F> {
|
||||
self.editor.read(cx).pixel_position_of_cursor(cx)
|
||||
}
|
||||
|
||||
fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
|
||||
editor::Editor::to_item_events(event)
|
||||
}
|
||||
}
|
||||
|
||||
impl FollowableItem for ChannelView {
|
||||
|
@ -313,7 +337,7 @@ impl FollowableItem for ChannelView {
|
|||
|
||||
Some(proto::view::Variant::ChannelView(
|
||||
proto::view::ChannelView {
|
||||
channel_id: channel_buffer.channel().id,
|
||||
channel_id: channel_buffer.channel_id,
|
||||
editor: if let Some(proto::view::Variant::Editor(proto)) =
|
||||
self.editor.read(cx).to_state_proto(cx)
|
||||
{
|
||||
|
|
|
@ -267,11 +267,15 @@ impl ChatPanel {
|
|||
|
||||
fn set_active_chat(&mut self, chat: ModelHandle<ChannelChat>, cx: &mut ViewContext<Self>) {
|
||||
if self.active_chat.as_ref().map(|e| &e.0) != Some(&chat) {
|
||||
let id = chat.read(cx).channel().id;
|
||||
let id = chat.read(cx).channel_id;
|
||||
{
|
||||
let chat = chat.read(cx);
|
||||
self.message_list.reset(chat.message_count());
|
||||
let placeholder = format!("Message #{}", chat.channel().name);
|
||||
let placeholder = if let Some(channel) = chat.channel(cx) {
|
||||
format!("Message #{}", channel.name)
|
||||
} else {
|
||||
"Message Channel".to_string()
|
||||
};
|
||||
self.input_editor.update(cx, move |editor, cx| {
|
||||
editor.set_placeholder_text(placeholder, cx);
|
||||
});
|
||||
|
@ -360,7 +364,7 @@ impl ChatPanel {
|
|||
let is_admin = self
|
||||
.channel_store
|
||||
.read(cx)
|
||||
.is_channel_admin(active_chat.channel().id);
|
||||
.is_channel_admin(active_chat.channel_id);
|
||||
let last_message = active_chat.message(ix.saturating_sub(1));
|
||||
let this_message = active_chat.message(ix);
|
||||
let is_continuation = last_message.id != this_message.id
|
||||
|
@ -645,7 +649,7 @@ impl ChatPanel {
|
|||
cx: &mut ViewContext<ChatPanel>,
|
||||
) -> Task<Result<()>> {
|
||||
if let Some((chat, _)) = &self.active_chat {
|
||||
if chat.read(cx).channel().id == selected_channel_id {
|
||||
if chat.read(cx).channel_id == selected_channel_id {
|
||||
return Task::ready(Ok(()));
|
||||
}
|
||||
}
|
||||
|
@ -664,7 +668,7 @@ impl ChatPanel {
|
|||
|
||||
fn open_notes(&mut self, _: &OpenChannelNotes, cx: &mut ViewContext<Self>) {
|
||||
if let Some((chat, _)) = &self.active_chat {
|
||||
let channel_id = chat.read(cx).channel().id;
|
||||
let channel_id = chat.read(cx).channel_id;
|
||||
if let Some(workspace) = self.workspace.upgrade(cx) {
|
||||
ChannelView::open(channel_id, workspace, cx).detach();
|
||||
}
|
||||
|
@ -673,7 +677,7 @@ impl ChatPanel {
|
|||
|
||||
fn join_call(&mut self, _: &JoinCall, cx: &mut ViewContext<Self>) {
|
||||
if let Some((chat, _)) = &self.active_chat {
|
||||
let channel_id = chat.read(cx).channel().id;
|
||||
let channel_id = chat.read(cx).channel_id;
|
||||
ActiveCall::global(cx)
|
||||
.update(cx, |call, cx| call.join_channel(channel_id, cx))
|
||||
.detach_and_log_err(cx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue