This commit is contained in:
2026-05-18 08:07:59 +07:00
parent d2a17e54c4
commit eb5d64a3af
15 changed files with 524 additions and 333 deletions

View File

@@ -1,8 +1,7 @@
use anyhow::Error;
use gpui::prelude::FluentBuilder;
use gpui::{
App, AppContext, Context, Entity, InteractiveElement, IntoElement, ParentElement, Render,
SharedString, StatefulInteractiveElement, Styled, Subscription, Task, Window, div, px,
SharedString, StatefulInteractiveElement, Styled, Subscription, Window, div, px,
};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
@@ -28,11 +27,8 @@ pub struct AccountSelector {
/// The error message displayed when an error occurs.
error: Entity<Option<SharedString>>,
/// Async tasks
tasks: Vec<Task<Result<(), Error>>>,
/// Subscription to the signer events
_subscription: Option<Subscription>,
_event_subscription: Option<Subscription>,
}
impl AccountSelector {
@@ -44,7 +40,7 @@ impl AccountSelector {
let nostr = NostrRegistry::global(cx);
let subscription = cx.subscribe_in(&nostr, window, |this, _state, event, window, cx| {
match event {
StateEvent::SignerSet => {
StateEvent::SignerSet(_) => {
window.close_all_modals(cx);
window.refresh();
}
@@ -58,8 +54,7 @@ impl AccountSelector {
Self {
logging_in,
error,
tasks: vec![],
_subscription: Some(subscription),
_event_subscription: Some(subscription),
}
}
@@ -89,20 +84,14 @@ impl AccountSelector {
})
}
fn login(&mut self, public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx);
fn login(&mut self, public_key: PublicKey, _window: &mut Window, cx: &mut Context<Self>) {
// Mark the public key as being logged in
self.set_logging_in(public_key, cx);
match nostr.read(cx).switch_account(public_key, cx) {
Ok(()) => {
//
}
Err(e) => {
self.set_error(e.to_string(), cx);
}
};
let nostr = NostrRegistry::global(cx);
if let Err(e) = nostr.read(cx).switch_account(public_key, cx) {
self.set_error(e.to_string(), cx);
}
}
fn remove(&mut self, public_key: PublicKey, cx: &mut Context<Self>) {

View File

@@ -158,6 +158,9 @@ impl ContactListPanel {
let client = nostr.read(cx).client();
let signer = nostr.read(cx).signer();
let public_key = signer.public_key();
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
// Get contacts
let contacts: Vec<Contact> = self
.contacts
@@ -169,6 +172,7 @@ impl ContactListPanel {
self.set_updating(true, cx);
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let write_relays = write_relays.await;
let signer = signer.get().await;
// Construct contact list event builder
@@ -177,7 +181,7 @@ impl ContactListPanel {
.await?;
// Set contact list
client.send_event(&event).to_nip65().await?;
client.send_event(&event).to(write_relays).await?;
Ok(())
});

View File

@@ -31,21 +31,20 @@ impl GreeterPanel {
fn add_profile_panel(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx);
let signer = nostr.read(cx).signer();
let public_key = signer.public_key();
if let Some(public_key) = signer.public_key() {
cx.spawn_in(window, async move |_this, cx| {
cx.update(|window, cx| {
Workspace::add_panel(
profile::init(public_key, window, cx),
DockPlacement::Right,
window,
cx,
);
})
.ok();
cx.spawn_in(window, async move |_this, cx| {
cx.update(|window, cx| {
Workspace::add_panel(
profile::init(public_key, window, cx),
DockPlacement::Right,
window,
cx,
);
})
.detach();
}
.ok();
})
.detach();
}
}

View File

@@ -172,6 +172,9 @@ impl MessagingRelayPanel {
let client = nostr.read(cx).client();
let signer = nostr.read(cx).signer();
let public_key = signer.public_key();
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
// Construct event tags
let tags: Vec<Tag> = self
.relays
@@ -183,6 +186,7 @@ impl MessagingRelayPanel {
self.set_updating(true, cx);
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let write_relays = write_relays.await;
let signer = signer.get().await;
// Construct nip17 event builder
@@ -192,7 +196,7 @@ impl MessagingRelayPanel {
.await?;
// Set messaging relays
client.send_event(&event).to_nip65().await?;
client.send_event(&event).to(write_relays).await?;
Ok(())
});

View File

@@ -208,9 +208,14 @@ impl ProfilePanel {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let signer = nostr.read(cx).signer();
let public_key = signer.public_key();
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
let metadata = metadata.clone();
cx.background_spawn(async move {
let write_relays = write_relays.await;
let signer = signer.get().await;
// Build and sign the metadata event
@@ -219,7 +224,7 @@ impl ProfilePanel {
.await?;
// Send event to user's relays
client.send_event(&event).await?;
client.send_event(&event).to(write_relays).await?;
Ok(())
})

View File

@@ -11,7 +11,7 @@ use gpui::{
use nostr_sdk::prelude::*;
use serde::Deserialize;
use smallvec::{SmallVec, smallvec};
use state::NostrRegistry;
use state::{BOOTSTRAP_RELAYS, NostrRegistry};
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
@@ -219,7 +219,7 @@ impl RelayListPanel {
let event = EventBuilder::relay_list(relays).sign_async(&signer).await?;
// Set relay list for current user
client.send_event(&event).await?;
client.send_event(&event).to(BOOTSTRAP_RELAYS).await?;
Ok(())
});

View File

@@ -126,7 +126,7 @@ impl Workspace {
window.push_notification(note, cx);
}
StateEvent::SignerSet => {
StateEvent::SignerSet(_) => {
this.set_center_layout(window, cx);
// Clear the signer notification
window.clear_notification::<SignerNotifcation>(cx);
@@ -165,7 +165,7 @@ impl Workspace {
window.push_notification(note, cx);
}
DeviceEvent::Set => {
DeviceEvent::Set(_) => {
let note = Notification::new()
.id::<DeviceNotifcation>()
.message("Encryption Key has been set")
@@ -307,17 +307,16 @@ impl Workspace {
Command::ShowProfile => {
let nostr = NostrRegistry::global(cx);
let signer = nostr.read(cx).signer();
let public_key = signer.public_key();
if let Some(public_key) = signer.public_key() {
self.dock.update(cx, |this, cx| {
this.add_panel(
Arc::new(profile::init(public_key, window, cx)),
DockPlacement::Right,
window,
cx,
);
});
}
self.dock.update(cx, |this, cx| {
this.add_panel(
Arc::new(profile::init(public_key, window, cx)),
DockPlacement::Right,
window,
cx,
);
});
}
Command::ShowContactList => {
self.dock.update(cx, |this, cx| {
@@ -368,8 +367,11 @@ impl Workspace {
}
Command::RefreshEncryption => {
let device = DeviceRegistry::global(cx);
let nostr = NostrRegistry::global(cx);
let public_key = nostr.read(cx).signer().public_key();
device.update(cx, |this, cx| {
this.get_announcement(cx);
this.get_announcement(&public_key, cx);
});
}
Command::ResetEncryption => {
@@ -561,80 +563,78 @@ impl Workspace {
fn titlebar_left(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
let nostr = NostrRegistry::global(cx);
let signer = nostr.read(cx).signer();
let current_user = signer.public_key();
let is_logged_in = signer.is_logged_in();
if !is_logged_in {
return div();
}
let persons = PersonRegistry::global(cx);
let public_key = signer.public_key();
let profile = persons.read(cx).get(&public_key, cx);
let avatar = profile.avatar();
let name = profile.name();
h_flex()
.flex_shrink_0()
.gap_2()
.when_none(&current_user, |this| {
this.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.child(SharedString::from("Choose an account to continue...")),
)
})
.when_some(current_user.as_ref(), |this, public_key| {
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(public_key, cx);
let avatar = profile.avatar();
let name = profile.name();
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.child(SharedString::from("Choose an account to continue...")),
)
.child(
Button::new("current-user")
.child(Avatar::new(avatar.clone()).xsmall())
.small()
.caret()
.compact()
.transparent()
.dropdown_menu(move |this, _window, _cx| {
let avatar = avatar.clone();
let name = name.clone();
this.child(
Button::new("current-user")
.child(Avatar::new(avatar.clone()).xsmall())
.small()
.caret()
.compact()
.transparent()
.dropdown_menu(move |this, _window, _cx| {
let avatar = avatar.clone();
let name = name.clone();
this.min_w(px(256.))
.item(PopupMenuItem::element(move |_window, cx| {
h_flex()
.gap_1p5()
.text_xs()
.text_color(cx.theme().text_muted)
.child(Avatar::new(avatar.clone()).xsmall())
.child(name.clone())
}))
.separator()
.menu_with_icon(
"Profile",
IconName::Profile,
Box::new(Command::ShowProfile),
)
.menu_with_icon(
"Contact List",
IconName::Book,
Box::new(Command::ShowContactList),
)
.menu_with_icon(
"Backup",
IconName::UserKey,
Box::new(Command::ShowBackup),
)
.menu_with_icon(
"Themes",
IconName::Sun,
Box::new(Command::ToggleTheme),
)
.separator()
.menu_with_icon(
"Accounts",
IconName::Group,
Box::new(Command::ToggleAccount),
)
.menu_with_icon(
"Settings",
IconName::Settings,
Box::new(Command::ShowSettings),
)
}),
)
})
this.min_w(px(256.))
.item(PopupMenuItem::element(move |_window, cx| {
h_flex()
.gap_1p5()
.text_xs()
.text_color(cx.theme().text_muted)
.child(Avatar::new(avatar.clone()).xsmall())
.child(name.clone())
}))
.separator()
.menu_with_icon(
"Profile",
IconName::Profile,
Box::new(Command::ShowProfile),
)
.menu_with_icon(
"Contact List",
IconName::Book,
Box::new(Command::ShowContactList),
)
.menu_with_icon(
"Backup",
IconName::UserKey,
Box::new(Command::ShowBackup),
)
.menu_with_icon("Themes", IconName::Sun, Box::new(Command::ToggleTheme))
.separator()
.menu_with_icon(
"Accounts",
IconName::Group,
Box::new(Command::ToggleAccount),
)
.menu_with_icon(
"Settings",
IconName::Settings,
Box::new(Command::ShowSettings),
)
}),
)
}
fn titlebar_right(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
@@ -647,12 +647,14 @@ impl Workspace {
let nostr = NostrRegistry::global(cx);
let signer = nostr.read(cx).signer();
let is_logged_in = signer.is_logged_in();
let Some(public_key) = signer.public_key() else {
if !is_logged_in {
return div();
};
}
let persons = PersonRegistry::global(cx);
let public_key = signer.public_key();
let profile = persons.read(cx).get(&public_key, cx);
let announcement = profile.announcement();