From 3a2e5cb4abb0100826c4827c0f086a142e76f776 Mon Sep 17 00:00:00 2001 From: reya Date: Wed, 1 Jan 2025 18:51:19 +0700 Subject: [PATCH] wip: refactor --- crates/app/src/main.rs | 13 +-- crates/app/src/views/contact/item.rs | 115 +++++++++++++++++++++++++++ crates/app/src/views/contact/list.rs | 22 +++-- crates/app/src/views/contact/mod.rs | 1 + 4 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 crates/app/src/views/contact/item.rs diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index efbab6c..3e45206 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -129,21 +129,21 @@ async fn main() { if subscription_id == new_message { if let Err(e) = signal_tx.send(Signal::RecvEvent(ev)).await { - println!("Error: {}", e) + println!("Send error: {}", e) } } } } - Err(e) => println!("Error: {}", e), + Err(e) => println!("Unwrap error: {}", e), } } else if event.kind == Kind::Metadata { if let Err(e) = signal_tx.send(Signal::RecvMetadata(event.pubkey)).await { - println!("Error: {}", e) + println!("Send error: {}", e) } } } else if let RelayMessage::EndOfStoredEvents(subscription_id) = message { if let Err(e) = signal_tx.send(Signal::RecvEose(subscription_id)).await { - println!("Error: {}", e) + println!("Send error: {}", e) } } } @@ -177,6 +177,7 @@ async fn main() { .authors(authors) .kind(Kind::Metadata) .limit(total); + let opts = SubscribeAutoCloseOptions::default() .exit_policy(ReqExitPolicy::WaitDurationAfterEOSE(Duration::from_secs(2))); @@ -211,7 +212,7 @@ async fn main() { cx.spawn(|async_cx| async move { let accounts = get_all_accounts_from_keyring(); - // Automatically Login if only habe 1 account + // Automatically Login if only have 1 account if let Some(account) = accounts.into_iter().next() { if let Ok(keys) = get_keys_by_account(account) { get_client().set_signer(keys).await; @@ -292,8 +293,8 @@ async fn main() { window_decorations: Some(WindowDecorations::Client), titlebar: Some(TitlebarOptions { title: Some(SharedString::new_static(APP_NAME)), - appears_transparent: true, traffic_light_position: Some(point(px(9.0), px(9.0))), + appears_transparent: true, }), ..Default::default() }; diff --git a/crates/app/src/views/contact/item.rs b/crates/app/src/views/contact/item.rs new file mode 100644 index 0000000..3303e98 --- /dev/null +++ b/crates/app/src/views/contact/item.rs @@ -0,0 +1,115 @@ +use coop_ui::StyledExt; +use gpui::*; +use nostr_sdk::prelude::*; +use prelude::FluentBuilder; + +use crate::{ + constants::IMAGE_SERVICE, + get_client, + states::{metadata::MetadataRegistry, signal::SignalRegistry}, + utils::show_npub, +}; + +pub struct ContactListItem { + public_key: PublicKey, + metadata: Model>, +} + +impl ContactListItem { + pub fn new(public_key: PublicKey, cx: &mut ViewContext<'_, Self>) -> Self { + let metadata = cx.new_model(|_| None); + + // Request metadata + _ = cx.global::().tx.send(public_key); + + // Reload when received metadata + cx.observe_global::(|item, cx| { + item.load_metadata(cx); + }) + .detach(); + + Self { + public_key, + metadata, + } + } + + pub fn load_metadata(&mut self, cx: &mut ViewContext) { + let public_key = self.public_key; + let async_metadata = self.metadata.clone(); + let mut async_cx = cx.to_async(); + + cx.foreground_executor() + .spawn({ + let client = get_client(); + + async move { + let query = async_cx + .background_executor() + .spawn(async move { client.database().metadata(public_key).await }) + .await; + + if let Ok(metadata) = query { + _ = async_cx.update_model(&async_metadata, |a, b| { + *a = metadata; + b.notify(); + }); + }; + } + }) + .detach(); + } +} + +impl Render for ContactListItem { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + let fallback = show_npub(self.public_key, 16); + let mut content = div(); + + if let Some(metadata) = self.metadata.read(cx).as_ref() { + content = content + .flex() + .items_center() + .gap_2() + .map(|this| { + if let Some(picture) = metadata.picture.clone() { + this.flex_shrink_0().child( + img(format!("{}/?url={}&w=72&h=72&n=-1", IMAGE_SERVICE, picture)) + .size_6() + .rounded_full() + .object_fit(ObjectFit::Cover), + ) + } else { + this.flex_shrink_0() + .child(img("brand/avatar.png").size_6().rounded_full()) + } + }) + .map(|this| { + if let Some(display_name) = metadata.display_name.clone() { + this.child(display_name) + } else { + this.child(fallback) + } + }) + } else { + content = content + .flex() + .items_center() + .gap_2() + .child( + img("brand/avatar.png") + .flex_shrink_0() + .size_6() + .rounded_full(), + ) + .child(fallback) + } + + div() + .scrollable( + cx.view().entity_id(), + coop_ui::scroll::ScrollbarAxis::Vertical, + ) + .child(content) + } +} diff --git a/crates/app/src/views/contact/list.rs b/crates/app/src/views/contact/list.rs index 21834a4..2550789 100644 --- a/crates/app/src/views/contact/list.rs +++ b/crates/app/src/views/contact/list.rs @@ -1,13 +1,12 @@ +use gpui::*; +use prelude::FluentBuilder; use std::time::Duration; -use gpui::*; -use nostr_sdk::prelude::*; -use prelude::FluentBuilder; - +use super::item::ContactListItem; use crate::get_client; pub struct ContactList { - contacts: Model>>, + contacts: Model>>>, } impl ContactList { @@ -27,8 +26,17 @@ impl ContactList { .spawn(async move { client.get_contact_list(Duration::from_secs(3)).await }) .await { + let views: Vec> = contacts + .into_iter() + .map(|contact| { + async_cx + .new_view(|cx| ContactListItem::new(contact.public_key, cx)) + .unwrap() + }) + .collect(); + _ = async_cx.update_model(&async_contacts, |model, cx| { - *model = Some(contacts); + *model = Some(views); cx.notify(); }); } @@ -43,7 +51,7 @@ impl ContactList { impl Render for ContactList { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { div().when_some(self.contacts.read(cx).as_ref(), |this, contacts| { - this.child("Total").child(contacts.len().to_string()) + this.children(contacts.clone()) }) } } diff --git a/crates/app/src/views/contact/mod.rs b/crates/app/src/views/contact/mod.rs index d3437dd..3c74fb1 100644 --- a/crates/app/src/views/contact/mod.rs +++ b/crates/app/src/views/contact/mod.rs @@ -6,6 +6,7 @@ use coop_ui::{ use gpui::*; use list::ContactList; +mod item; mod list; pub struct ContactPanel {