From cfa628a8a66b1b289b9d78849c7a89ac6730b4f5 Mon Sep 17 00:00:00 2001 From: reya Date: Wed, 19 Feb 2025 15:35:14 +0700 Subject: [PATCH] feat: automatically load inbox on startup --- crates/app/src/main.rs | 4 +-- crates/app/src/views/chat.rs | 18 ++++++++---- crates/chats/src/registry.rs | 56 ++++++++++++++++++++---------------- crates/state/src/lib.rs | 47 ++++++++++++++---------------- 4 files changed, 67 insertions(+), 58 deletions(-) diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 862d6c6..1a8feaa 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -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::>(100); // Initialize nostr client - let client = initialize_client(); + let client = get_client(); // Initialize application let app = Application::new() diff --git a/crates/app/src/views/chat.rs b/crates/app/src/views/chat.rs index c1c912c..25a4f36 100644 --- a/crates/app/src/views/chat.rs +++ b/crates/app/src/views/chat.rs @@ -39,7 +39,7 @@ pub fn init( ) -> Result>, 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, messages: Entity>, - new_messages: WeakEntity>, + new_messages: Option>>, list_state: ListState, subscriptions: Vec, // New Message @@ -113,9 +113,15 @@ pub struct Chat { } impl Chat { - pub fn new(id: &u64, model: &Entity, window: &mut Window, cx: &mut App) -> Entity { - let room = model.downgrade(); - let new_messages = model.read(cx).new_messages.downgrade(); + pub fn new( + id: &u64, + room: WeakEntity, + window: &mut Window, + cx: &mut App, + ) -> Entity { + 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) { - let Some(model) = self.new_messages.upgrade() else { + let Some(Some(model)) = self.new_messages.as_ref().map(|state| state.upgrade()) else { return; }; diff --git a/crates/chats/src/registry.rs b/crates/chats/src/registry.rs index 9167dd2..164a0e4 100644 --- a/crates/chats/src/registry.rs +++ b/crates/chats/src/registry.rs @@ -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::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> = 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> = 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> { + pub fn get(&self, id: &u64, cx: &App) -> Option> { 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) -> Result<(), anyhow::Error> { diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index a1250cd..7d446cb 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -4,31 +4,26 @@ use std::{fs, sync::OnceLock, time::Duration}; static CLIENT: OnceLock = 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() + }) }