chore: improve handling of user profiles (#146)
* resubscribe metadata for all pubkeys * .
This commit is contained in:
@@ -2,7 +2,7 @@ use std::sync::Mutex;
|
||||
|
||||
use gpui::{actions, App};
|
||||
|
||||
actions!(coop, [DarkMode, Settings, Logout, Quit]);
|
||||
actions!(coop, [ReloadMetadata, DarkMode, Settings, Logout, Quit]);
|
||||
actions!(sidebar, [Reload, RelayStatus]);
|
||||
|
||||
pub fn load_embedded_fonts(cx: &App) {
|
||||
|
||||
@@ -42,7 +42,7 @@ use ui::notification::Notification;
|
||||
use ui::popup_menu::PopupMenuExt;
|
||||
use ui::{h_flex, v_flex, ContextModal, Disableable, IconName, Root, Sizable, StyledExt};
|
||||
|
||||
use crate::actions::{DarkMode, Logout, Settings};
|
||||
use crate::actions::{DarkMode, Logout, ReloadMetadata, Settings};
|
||||
use crate::views::compose::compose_button;
|
||||
use crate::views::setup_relay::setup_nip17_relay;
|
||||
use crate::views::{
|
||||
@@ -439,7 +439,10 @@ impl ChatSpace {
|
||||
}
|
||||
}
|
||||
Kind::Metadata => {
|
||||
ingester.send(Signal::Metadata(event.into_owned())).await;
|
||||
if let Ok(metadata) = Metadata::from_json(&event.content) {
|
||||
let profile = Profile::new(event.pubkey, metadata);
|
||||
ingester.send(Signal::Metadata(profile)).await;
|
||||
}
|
||||
}
|
||||
Kind::GiftWrap => {
|
||||
Self::unwrap_gift_wrap(&event, pubkey_tx).await;
|
||||
@@ -558,9 +561,9 @@ impl ChatSpace {
|
||||
this.set_unwrapping_status(status, cx);
|
||||
});
|
||||
}
|
||||
Signal::Metadata(event) => {
|
||||
Signal::Metadata(profile) => {
|
||||
registry.update(cx, |this, cx| {
|
||||
this.insert_or_update_person(event, cx);
|
||||
this.insert_or_update_person(profile, cx);
|
||||
});
|
||||
}
|
||||
Signal::Message((gift_wrap_id, event)) => {
|
||||
@@ -1090,6 +1093,50 @@ impl ChatSpace {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_reload_metadata(
|
||||
&mut self,
|
||||
_ev: &ReloadMetadata,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
let client = nostr_client();
|
||||
let css = css();
|
||||
|
||||
let filter = Filter::new().kind(Kind::PrivateDirectMessage);
|
||||
|
||||
let pubkeys: Vec<PublicKey> = client
|
||||
.database()
|
||||
.query(filter)
|
||||
.await?
|
||||
.into_iter()
|
||||
.flat_map(|event| event.all_pubkeys())
|
||||
.unique()
|
||||
.collect();
|
||||
|
||||
let filter = Filter::new()
|
||||
.kind(Kind::Metadata)
|
||||
.limit(pubkeys.len())
|
||||
.authors(pubkeys);
|
||||
|
||||
client
|
||||
.subscribe_to(BOOTSTRAP_RELAYS, filter, css.auto_close_opts)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
cx.spawn_in(window, async move |_, cx| {
|
||||
if task.await.is_ok() {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(t!("common.refreshed"), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn on_sign_out(&mut self, _e: &Logout, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
cx.background_spawn(async move {
|
||||
let client = nostr_client();
|
||||
@@ -1309,6 +1356,8 @@ impl ChatSpace {
|
||||
this.menu(t!("user.dark_mode"), Box::new(DarkMode))
|
||||
.menu(t!("user.settings"), Box::new(Settings))
|
||||
.separator()
|
||||
.menu(t!("user.reload_metadata"), Box::new(ReloadMetadata))
|
||||
.separator()
|
||||
.menu(t!("user.sign_out"), Box::new(Logout))
|
||||
}),
|
||||
)
|
||||
@@ -1429,6 +1478,7 @@ impl Render for ChatSpace {
|
||||
.on_action(cx.listener(Self::on_dark_mode))
|
||||
.on_action(cx.listener(Self::on_sign_out))
|
||||
.on_action(cx.listener(Self::on_open_profile))
|
||||
.on_action(cx.listener(Self::on_reload_metadata))
|
||||
.relative()
|
||||
.size_full()
|
||||
.child(
|
||||
|
||||
@@ -164,7 +164,7 @@ impl EditProfile {
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn set_metadata(&mut self, cx: &mut Context<Self>) -> Task<Result<Option<Event>, Error>> {
|
||||
pub fn set_metadata(&mut self, cx: &mut Context<Self>) -> Task<Result<Option<Profile>, Error>> {
|
||||
let avatar = self.avatar_input.read(cx).value().to_string();
|
||||
let name = self.name_input.read(cx).value().to_string();
|
||||
let bio = self.bio_input.read(cx).value().to_string();
|
||||
@@ -189,7 +189,14 @@ impl EditProfile {
|
||||
cx.background_spawn(async move {
|
||||
let client = nostr_client();
|
||||
let output = client.set_metadata(&new_metadata).await?;
|
||||
let event = client.database().event_by_id(&output.val).await?;
|
||||
let event = client
|
||||
.database()
|
||||
.event_by_id(&output.val)
|
||||
.await?
|
||||
.map(|event| {
|
||||
let metadata = Metadata::from_json(&event.content).unwrap_or_default();
|
||||
Profile::new(event.pubkey, metadata)
|
||||
});
|
||||
|
||||
Ok(event)
|
||||
})
|
||||
|
||||
@@ -41,28 +41,28 @@ impl Preferences {
|
||||
fn open_edit_profile(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let view = edit_profile::init(window, cx);
|
||||
let weak_view = view.downgrade();
|
||||
let title = SharedString::new(t!("profile.title"));
|
||||
|
||||
window.open_modal(cx, move |modal, _window, _cx| {
|
||||
let weak_view = weak_view.clone();
|
||||
|
||||
modal
|
||||
.confirm()
|
||||
.title(title.clone())
|
||||
.title(shared_t!("profile.title"))
|
||||
.child(view.clone())
|
||||
.button_props(ModalButtonProps::default().ok_text(t!("common.update")))
|
||||
.on_ok(move |_, window, cx| {
|
||||
weak_view
|
||||
.update(cx, |this, cx| {
|
||||
let set_metadata = this.set_metadata(cx);
|
||||
let registry = Registry::global(cx);
|
||||
|
||||
cx.spawn_in(window, async move |_, cx| {
|
||||
match set_metadata.await {
|
||||
Ok(event) => {
|
||||
if let Some(event) = event {
|
||||
Ok(profile) => {
|
||||
if let Some(profile) = profile {
|
||||
cx.update(|_, cx| {
|
||||
Registry::global(cx).update(cx, |this, cx| {
|
||||
this.insert_or_update_person(event, cx);
|
||||
registry.update(cx, |this, cx| {
|
||||
this.insert_or_update_person(profile, cx);
|
||||
});
|
||||
})
|
||||
.ok();
|
||||
|
||||
@@ -68,8 +68,8 @@ pub enum Signal {
|
||||
/// A signal to notify UI that the browser proxy service is down
|
||||
ProxyDown,
|
||||
|
||||
/// A signal to notify UI that a new metadata event has been received
|
||||
Metadata(Event),
|
||||
/// A signal to notify UI that a new profile has been received
|
||||
Metadata(Profile),
|
||||
|
||||
/// A signal to notify UI that a new gift wrap event has been received
|
||||
Message((EventId, Event)),
|
||||
|
||||
@@ -155,21 +155,19 @@ impl Registry {
|
||||
}
|
||||
|
||||
/// Insert or update a person
|
||||
pub fn insert_or_update_person(&mut self, event: Event, cx: &mut App) {
|
||||
let public_key = event.pubkey;
|
||||
let Ok(metadata) = Metadata::from_json(event.content) else {
|
||||
// Invalid metadata, no need to process further.
|
||||
return;
|
||||
};
|
||||
pub fn insert_or_update_person(&mut self, profile: Profile, cx: &mut App) {
|
||||
let public_key = profile.public_key();
|
||||
|
||||
if let Some(person) = self.persons.get(&public_key) {
|
||||
person.update(cx, |this, cx| {
|
||||
*this = Profile::new(public_key, metadata);
|
||||
cx.notify();
|
||||
});
|
||||
} else {
|
||||
self.persons
|
||||
.insert(public_key, cx.new(|_| Profile::new(public_key, metadata)));
|
||||
match self.persons.get(&public_key) {
|
||||
Some(person) => {
|
||||
person.update(cx, |this, cx| {
|
||||
*this = profile;
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
None => {
|
||||
self.persons.insert(public_key, cx.new(|_| profile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,9 +58,11 @@ auto_update:
|
||||
|
||||
user:
|
||||
dark_mode:
|
||||
en: "Dark Mode"
|
||||
en: "Dark mode"
|
||||
settings:
|
||||
en: "Settings"
|
||||
reload_metadata:
|
||||
en: "Reload metadata"
|
||||
sign_out:
|
||||
en: "Sign out"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user