feat: automatically load inbox on startup

This commit is contained in:
2025-02-19 15:35:14 +07:00
parent 5e1d76bbcd
commit cfa628a8a6
4 changed files with 67 additions and 58 deletions

View File

@@ -20,7 +20,7 @@ use nostr_sdk::{
};
use nostr_sdk::{prelude::NostrEventsDatabaseExt, FromBech32, SubscriptionId};
use smol::Timer;
use state::{get_client, initialize_client};
use state::get_client;
use std::{collections::HashSet, mem, sync::Arc, time::Duration};
use ui::{theme::Theme, Root};
use views::{app, onboarding, startup};
@@ -49,7 +49,7 @@ fn main() {
let (batch_tx, batch_rx) = smol::channel::bounded::<Vec<PublicKey>>(100);
// Initialize nostr client
let client = initialize_client();
let client = get_client();
// Initialize application
let app = Application::new()

View File

@@ -39,7 +39,7 @@ pub fn init(
) -> Result<Arc<Entity<Chat>>, anyhow::Error> {
if let Some(chats) = ChatRegistry::global(cx) {
if let Some(room) = chats.read(cx).get(id, cx) {
Ok(Arc::new(Chat::new(id, &room, window, cx)))
Ok(Arc::new(Chat::new(id, room, window, cx)))
} else {
Err(anyhow!("Chat room is not exist"))
}
@@ -102,7 +102,7 @@ pub struct Chat {
// Chat Room
room: WeakEntity<Room>,
messages: Entity<Vec<Message>>,
new_messages: WeakEntity<Vec<Event>>,
new_messages: Option<WeakEntity<Vec<Event>>>,
list_state: ListState,
subscriptions: Vec<Subscription>,
// New Message
@@ -113,9 +113,15 @@ pub struct Chat {
}
impl Chat {
pub fn new(id: &u64, model: &Entity<Room>, window: &mut Window, cx: &mut App) -> Entity<Self> {
let room = model.downgrade();
let new_messages = model.read(cx).new_messages.downgrade();
pub fn new(
id: &u64,
room: WeakEntity<Room>,
window: &mut Window,
cx: &mut App,
) -> Entity<Self> {
let new_messages = room
.read_with(cx, |this, _| this.new_messages.downgrade())
.ok();
cx.new(|cx| {
let messages = cx.new(|_| vec![Message::placeholder()]);
@@ -371,7 +377,7 @@ impl Chat {
}
fn load_new_messages(&mut self, cx: &mut Context<Self>) {
let Some(model) = self.new_messages.upgrade() else {
let Some(Some(model)) = self.new_messages.as_ref().map(|state| state.upgrade()) else {
return;
};

View File

@@ -1,6 +1,6 @@
use anyhow::anyhow;
use common::utils::{compare, room_hash, signer_public_key};
use gpui::{App, AppContext, Context, Entity, Global};
use gpui::{App, AppContext, Context, Entity, Global, WeakEntity};
use itertools::Itertools;
use nostr_sdk::prelude::*;
use state::get_client;
@@ -29,7 +29,13 @@ impl ChatRegistry {
pub fn register(cx: &mut App) -> Entity<Self> {
Self::global(cx).unwrap_or_else(|| {
let entity = cx.new(Self::new);
let entity = cx.new(|cx| {
let mut this = Self::new(cx);
// Automatically load chat rooms the database when the registry is created
this.load_chat_rooms(cx);
this
});
// Set global state
cx.set_global(GlobalChatRegistry(entity.clone()));
@@ -111,28 +117,30 @@ impl ChatRegistry {
cx.spawn(|this, cx| async move {
if let Ok(events) = rx.await {
_ = cx.update(|cx| {
_ = this.update(cx, |this, cx| {
let current_rooms = this.current_rooms_ids(cx);
let items: Vec<Entity<Room>> = events
.into_iter()
.filter_map(|ev| {
let new = room_hash(&ev);
// Filter all seen events
if !current_rooms.iter().any(|this| this == &new) {
Some(cx.new(|cx| Room::parse(&ev, cx)))
} else {
None
}
})
.collect();
if !events.is_empty() {
_ = cx.update(|cx| {
_ = this.update(cx, |this, cx| {
let current_rooms = this.current_rooms_ids(cx);
let items: Vec<Entity<Room>> = events
.into_iter()
.filter_map(|ev| {
let new = room_hash(&ev);
// Filter all seen events
if !current_rooms.iter().any(|this| this == &new) {
Some(cx.new(|cx| Room::parse(&ev, cx)))
} else {
None
}
})
.collect();
this.rooms.extend(items);
this.is_loading = false;
this.rooms.extend(items);
this.is_loading = false;
cx.notify();
cx.notify();
});
});
});
}
}
})
.detach();
@@ -146,11 +154,11 @@ impl ChatRegistry {
self.is_loading
}
pub fn get(&self, id: &u64, cx: &App) -> Option<Entity<Room>> {
pub fn get(&self, id: &u64, cx: &App) -> Option<WeakEntity<Room>> {
self.rooms
.iter()
.find(|model| &model.read(cx).id == id)
.cloned()
.find(|model| model.read(cx).id == *id)
.map(|room| room.downgrade())
}
pub fn new_room(&mut self, room: Room, cx: &mut Context<Self>) -> Result<(), anyhow::Error> {

View File

@@ -4,31 +4,26 @@ use std::{fs, sync::OnceLock, time::Duration};
static CLIENT: OnceLock<Client> = OnceLock::new();
pub fn initialize_client() -> &'static Client {
// Setup app data folder
let config_dir = config_dir().expect("Config directory not found");
let app_dir = config_dir.join("Coop/");
// Create app directory if it doesn't exist
_ = fs::create_dir_all(&app_dir);
// Setup database
let lmdb = NostrLMDB::open(app_dir.join("nostr")).expect("Database is NOT initialized");
// Client options
let opts = Options::new()
// NIP-65
.gossip(true)
// Skip all very slow relays
.max_avg_latency(Duration::from_millis(800));
// Setup Nostr Client
let client = ClientBuilder::default().database(lmdb).opts(opts).build();
CLIENT.set(client).expect("Client is already initialized!");
CLIENT.get().expect("Client is NOT initialized!")
}
pub fn get_client() -> &'static Client {
CLIENT.get().expect("Client is NOT initialized!")
CLIENT.get_or_init(|| {
// Setup app data folder
let config_dir = config_dir().expect("Config directory not found");
let app_dir = config_dir.join("Coop/");
// Create app directory if it doesn't exist
_ = fs::create_dir_all(&app_dir);
// Setup database
let lmdb = NostrLMDB::open(app_dir.join("nostr")).expect("Database is NOT initialized");
// Client options
let opts = Options::new()
// NIP-65
.gossip(true)
// Skip all very slow relays
.max_avg_latency(Duration::from_millis(800));
// Setup Nostr Client
ClientBuilder::default().database(lmdb).opts(opts).build()
})
}