wip: refactor

This commit is contained in:
2025-01-01 18:51:19 +07:00
parent 8e6c462177
commit 3a2e5cb4ab
4 changed files with 138 additions and 13 deletions

View File

@@ -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()
};

View File

@@ -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<Option<Metadata>>,
}
impl ContactListItem {
pub fn new(public_key: PublicKey, cx: &mut ViewContext<'_, Self>) -> Self {
let metadata = cx.new_model(|_| None);
// Request metadata
_ = cx.global::<SignalRegistry>().tx.send(public_key);
// Reload when received metadata
cx.observe_global::<MetadataRegistry>(|item, cx| {
item.load_metadata(cx);
})
.detach();
Self {
public_key,
metadata,
}
}
pub fn load_metadata(&mut self, cx: &mut ViewContext<Self>) {
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<Self>) -> 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)
}
}

View File

@@ -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<Option<Vec<Contact>>>,
contacts: Model<Option<Vec<View<ContactListItem>>>>,
}
impl ContactList {
@@ -27,8 +26,17 @@ impl ContactList {
.spawn(async move { client.get_contact_list(Duration::from_secs(3)).await })
.await
{
let views: Vec<View<ContactListItem>> = 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<Self>) -> 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())
})
}
}

View File

@@ -6,6 +6,7 @@ use coop_ui::{
use gpui::*;
use list::ContactList;
mod item;
mod list;
pub struct ContactPanel {