chore: improve room kind handling (#48)

* chore: improve room kind handling

* .

* add some tooltips

* .

* fix button hovered style

* .

* improve prevent duplicate message

* .
This commit is contained in:
reya
2025-05-29 09:05:08 +07:00
committed by GitHub
parent 7a447da447
commit 557ff18714
6 changed files with 197 additions and 81 deletions

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use account::Account;
use anyhow::Error;
use chats::ChatRegistry;
use chats::{ChatRegistry, RoomEmitter};
use global::{
constants::{DEFAULT_MODAL_WIDTH, DEFAULT_SIDEBAR_WIDTH},
get_client,
@@ -101,13 +101,16 @@ impl ChatSpace {
&chats,
window,
|this, _state, event, window, cx| {
if let Some(room) = event.0.upgrade() {
this.dock.update(cx, |this, cx| {
let panel = chat::init(room, window, cx);
this.add_panel(panel, DockPlacement::Center, window, cx);
});
} else {
window.push_notification("Failed to open room. Please retry later.", cx);
if let RoomEmitter::Open(room) = event {
if let Some(room) = room.upgrade() {
this.dock.update(cx, |this, cx| {
let panel = chat::init(room, window, cx);
this.add_panel(panel, DockPlacement::Center, window, cx);
});
} else {
window
.push_notification("Failed to open room. Please retry later.", cx);
}
}
},
));

View File

@@ -1,9 +1,10 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
use account::Account;
use async_utility::task::spawn;
use chats::{
message::Message,
room::{Room, SendError},
room::{Room, RoomKind, SendError},
};
use common::{nip96_upload, profile::RenderProfile};
use global::get_client;
@@ -214,17 +215,39 @@ impl Chat {
content
}
// TODO: find a better way to prevent duplicate messages during optimistic updates
fn prevent_duplicate_message(&self, new_msg: &Message, cx: &Context<Self>) -> bool {
let min_timestamp = new_msg.created_at.as_u64().saturating_sub(2);
let Some(current_user) = Account::get_global(cx).profile_ref() else {
return false;
};
self.messages.read(cx).iter().any(|existing| {
let existing = existing.borrow();
// Check if messages are within the time window
(existing.created_at.as_u64() >= min_timestamp) &&
// Compare content and author
(existing.content == new_msg.content) &&
(existing.author == new_msg.author)
})
let Some(author) = new_msg.author.as_ref() else {
return false;
};
if current_user.public_key() != author.public_key() {
return false;
}
let min_timestamp = new_msg.created_at.as_u64().saturating_sub(10);
self.messages
.read(cx)
.iter()
.filter(|m| {
m.borrow()
.author
.as_ref()
.is_some_and(|p| p.public_key() == current_user.public_key())
})
.any(|existing| {
let existing = existing.borrow();
// Check if messages are within the time window
(existing.created_at.as_u64() >= min_timestamp) &&
// Compare content and author
(existing.content == new_msg.content) &&
(existing.author == new_msg.author)
})
}
fn send_message(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -263,6 +286,13 @@ impl Chat {
if let Ok(reports) = send_message.await {
if !reports.is_empty() {
this.update(cx, |this, cx| {
this.room.update(cx, |this, cx| {
if this.kind != RoomKind::Ongoing {
this.kind = RoomKind::Ongoing;
cx.notify();
}
});
this.messages.update(cx, |this, cx| {
if let Some(msg) = id.and_then(|id| {
this.iter().find(|msg| msg.borrow().id == Some(id)).cloned()

View File

@@ -4,7 +4,7 @@ use account::Account;
use async_utility::task::spawn;
use chats::{
room::{Room, RoomKind},
ChatRegistry,
ChatRegistry, RoomEmitter,
};
use common::{debounced_delay::DebouncedDelay, profile::RenderProfile};
@@ -18,6 +18,7 @@ use gpui::{
use itertools::Itertools;
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
use theme::ActiveTheme;
use ui::{
avatar::Avatar,
button::{Button, ButtonRounded, ButtonVariants},
@@ -48,13 +49,14 @@ pub struct Sidebar {
local_result: Entity<Option<Vec<Entity<Room>>>>,
global_result: Entity<Option<Vec<Entity<Room>>>>,
// Rooms
indicator: Entity<Option<RoomKind>>,
active_filter: Entity<RoomKind>,
trusted_only: bool,
// GPUI
focus_handle: FocusHandle,
image_cache: Entity<RetainAllImageCache>,
#[allow(dead_code)]
subscriptions: SmallVec<[Subscription; 1]>,
subscriptions: SmallVec<[Subscription; 2]>,
}
impl Sidebar {
@@ -64,14 +66,29 @@ impl Sidebar {
fn view(window: &mut Window, cx: &mut Context<Self>) -> Self {
let active_filter = cx.new(|_| RoomKind::Ongoing);
let indicator = cx.new(|_| None);
let local_result = cx.new(|_| None);
let global_result = cx.new(|_| None);
let find_input =
cx.new(|cx| InputState::new(window, cx).placeholder("Find or start a conversation"));
let chats = ChatRegistry::global(cx);
let mut subscriptions = smallvec![];
subscriptions.push(cx.subscribe_in(
&chats,
window,
move |this, _chats, event, _window, cx| {
if let RoomEmitter::Request(kind) = event {
this.indicator.update(cx, |this, cx| {
*this = Some(kind.to_owned());
cx.notify();
});
}
},
));
subscriptions.push(cx.subscribe_in(
&find_input,
window,
@@ -103,6 +120,7 @@ impl Sidebar {
find_debouncer: DebouncedDelay::new(),
finding: false,
trusted_only: false,
indicator,
active_filter,
find_input,
local_result,
@@ -275,10 +293,14 @@ impl Sidebar {
}
fn set_filter(&mut self, kind: RoomKind, cx: &mut Context<Self>) {
self.indicator.update(cx, |this, cx| {
*this = None;
cx.notify();
});
self.active_filter.update(cx, |this, cx| {
*this = kind;
cx.notify();
})
});
}
fn set_trusted_only(&mut self, cx: &mut Context<Self>) {
@@ -532,6 +554,20 @@ impl Render for Sidebar {
.child(
Button::new("all")
.label("All")
.tooltip("All ongoing conversations")
.when_some(
self.indicator.read(cx).as_ref(),
|this, kind| {
this.when(kind == &RoomKind::Ongoing, |this| {
this.child(
div()
.size_1()
.rounded_full()
.bg(cx.theme().cursor),
)
})
},
)
.small()
.bold()
.secondary()
@@ -544,6 +580,20 @@ impl Render for Sidebar {
.child(
Button::new("requests")
.label("Requests")
.tooltip("Incoming new conversations")
.when_some(
self.indicator.read(cx).as_ref(),
|this, kind| {
this.when(kind != &RoomKind::Ongoing, |this| {
this.child(
div()
.size_1()
.rounded_full()
.bg(cx.theme().cursor),
)
})
},
)
.small()
.bold()
.secondary()