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:
@@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user