feat: implemented nip17 group chat
This commit is contained in:
@@ -40,7 +40,8 @@ impl ChatRegistry {
|
|||||||
|
|
||||||
cx.observe_new_models::<Room>(|this, cx| {
|
cx.observe_new_models::<Room>(|this, cx| {
|
||||||
// Get all pubkeys to load metadata
|
// Get all pubkeys to load metadata
|
||||||
let pubkeys: Vec<PublicKey> = this.members.iter().map(|m| m.public_key()).collect();
|
let mut pubkeys: Vec<PublicKey> = this.members.iter().map(|m| m.public_key()).collect();
|
||||||
|
pubkeys.push(this.owner.public_key());
|
||||||
|
|
||||||
cx.spawn(|weak_model, mut async_cx| async move {
|
cx.spawn(|weak_model, mut async_cx| async move {
|
||||||
let query: Result<Vec<(PublicKey, Metadata)>, Error> = async_cx
|
let query: Result<Vec<(PublicKey, Metadata)>, Error> = async_cx
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ impl Member {
|
|||||||
pub struct Room {
|
pub struct Room {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub title: Option<SharedString>,
|
pub title: Option<SharedString>,
|
||||||
pub owner: PublicKey,
|
pub owner: Member, // Owner always match current user
|
||||||
pub members: Vec<Member>,
|
pub members: Vec<Member>, // Extract from event's tags
|
||||||
pub last_seen: Timestamp,
|
pub last_seen: Timestamp,
|
||||||
pub is_group: bool,
|
pub is_group: bool,
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ impl Room {
|
|||||||
let id = room_hash(&event.tags);
|
let id = room_hash(&event.tags);
|
||||||
let last_seen = event.created_at;
|
let last_seen = event.created_at;
|
||||||
|
|
||||||
let owner = event.pubkey;
|
let owner = Member::new(event.pubkey, Metadata::default());
|
||||||
let members: Vec<Member> = event
|
let members: Vec<Member> = event
|
||||||
.tags
|
.tags
|
||||||
.public_keys()
|
.public_keys()
|
||||||
@@ -91,6 +91,10 @@ impl Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_metadata(&mut self, public_key: PublicKey, metadata: Metadata) {
|
pub fn set_metadata(&mut self, public_key: PublicKey, metadata: Metadata) {
|
||||||
|
if self.owner.public_key() == public_key {
|
||||||
|
self.owner.update(&metadata);
|
||||||
|
}
|
||||||
|
|
||||||
for member in self.members.iter_mut() {
|
for member in self.members.iter_mut() {
|
||||||
if member.public_key() == public_key {
|
if member.public_key() == public_key {
|
||||||
member.update(&metadata);
|
member.update(&metadata);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub struct ChatPanel {
|
|||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
// Chat Room
|
// Chat Room
|
||||||
id: SharedString,
|
id: SharedString,
|
||||||
owner: PublicKey,
|
owner: Member,
|
||||||
members: Arc<[Member]>,
|
members: Arc<[Member]>,
|
||||||
input: View<TextInput>,
|
input: View<TextInput>,
|
||||||
list: ListState,
|
list: ListState,
|
||||||
@@ -48,7 +48,7 @@ impl ChatPanel {
|
|||||||
pub fn new(room: Model<Room>, cx: &mut WindowContext) -> View<Self> {
|
pub fn new(room: Model<Room>, cx: &mut WindowContext) -> View<Self> {
|
||||||
let room = room.read(cx);
|
let room = room.read(cx);
|
||||||
let id = room.id.to_string().into();
|
let id = room.id.to_string().into();
|
||||||
let owner = room.owner;
|
let owner = room.owner.clone();
|
||||||
let members = room.members.clone().into();
|
let members = room.members.clone().into();
|
||||||
let name = room.title.clone().unwrap_or("Untitled".into());
|
let name = room.title.clone().unwrap_or("Untitled".into());
|
||||||
|
|
||||||
@@ -117,10 +117,14 @@ impl ChatPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_messages(&self, cx: &mut ViewContext<Self>) {
|
fn load_messages(&self, cx: &mut ViewContext<Self>) {
|
||||||
let mut all_keys: Vec<_> = self.members.iter().map(|m| m.public_key()).collect();
|
|
||||||
all_keys.push(self.owner);
|
|
||||||
|
|
||||||
let members = Arc::clone(&self.members);
|
let members = Arc::clone(&self.members);
|
||||||
|
let owner = self.owner.clone();
|
||||||
|
|
||||||
|
// Get all public keys
|
||||||
|
let mut all_keys: Vec<_> = self.members.iter().map(|m| m.public_key()).collect();
|
||||||
|
all_keys.push(self.owner.public_key());
|
||||||
|
|
||||||
|
// Async
|
||||||
let async_state = self.state.clone();
|
let async_state = self.state.clone();
|
||||||
let mut async_cx = cx.to_async();
|
let mut async_cx = cx.to_async();
|
||||||
|
|
||||||
@@ -167,6 +171,8 @@ impl ChatPanel {
|
|||||||
members.iter().find(|&m| m.public_key() == ev.pubkey)
|
members.iter().find(|&m| m.public_key() == ev.pubkey)
|
||||||
{
|
{
|
||||||
member.metadata()
|
member.metadata()
|
||||||
|
} else if ev.pubkey == owner.public_key() {
|
||||||
|
owner.metadata()
|
||||||
} else {
|
} else {
|
||||||
Metadata::default()
|
Metadata::default()
|
||||||
};
|
};
|
||||||
@@ -195,7 +201,68 @@ impl ChatPanel {
|
|||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(&mut self, cx: &mut ViewContext<Self>) {}
|
fn send_message(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
|
let content = Arc::new(self.input.read(cx).text().to_string());
|
||||||
|
let owner = self.owner.clone();
|
||||||
|
|
||||||
|
let mut members = self.members.to_vec();
|
||||||
|
members.push(owner.clone());
|
||||||
|
|
||||||
|
// Async
|
||||||
|
let async_input = self.input.clone();
|
||||||
|
let async_state = self.state.clone();
|
||||||
|
let mut async_cx = cx.to_async();
|
||||||
|
|
||||||
|
cx.foreground_executor()
|
||||||
|
.spawn(async move {
|
||||||
|
// Send message to all members
|
||||||
|
async_cx
|
||||||
|
.background_executor()
|
||||||
|
.spawn({
|
||||||
|
let client = get_client();
|
||||||
|
let content = Arc::clone(&content).to_string();
|
||||||
|
let tags: Vec<Tag> = members
|
||||||
|
.iter()
|
||||||
|
.filter_map(|m| {
|
||||||
|
if m.public_key() != owner.public_key() {
|
||||||
|
Some(Tag::public_key(m.public_key()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
// Send message to all members
|
||||||
|
for member in members.iter() {
|
||||||
|
_ = client
|
||||||
|
.send_private_msg(member.public_key(), &content, tags.clone())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
_ = async_cx.update_model(&async_state, |model, cx| {
|
||||||
|
let created_at = Timestamp::now();
|
||||||
|
let message = RoomMessage::new(
|
||||||
|
owner.public_key(),
|
||||||
|
owner.metadata(),
|
||||||
|
content.to_string(),
|
||||||
|
created_at,
|
||||||
|
);
|
||||||
|
|
||||||
|
model.items.extend(vec![message]);
|
||||||
|
model.count = model.items.len();
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = async_cx.update_view(&async_input, |input, cx| {
|
||||||
|
input.set_text("", cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Panel for ChatPanel {
|
impl Panel for ChatPanel {
|
||||||
|
|||||||
Reference in New Issue
Block a user