.
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m40s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m50s
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m40s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m50s
This commit is contained in:
@@ -169,7 +169,6 @@ impl CommandBar {
|
||||
|
||||
fn search(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let identity = nostr.read(cx).identity();
|
||||
let query = self.find_input.read(cx).value();
|
||||
|
||||
// Return if the query is empty
|
||||
@@ -191,7 +190,7 @@ impl CommandBar {
|
||||
// Block the input until the search completes
|
||||
self.set_finding(true, window, cx);
|
||||
|
||||
let find_users = if identity.read(cx).owned {
|
||||
let find_users = if nostr.read(cx).owned_signer() {
|
||||
nostr.read(cx).wot_search(&query, cx)
|
||||
} else {
|
||||
nostr.read(cx).search(&query, cx)
|
||||
@@ -245,17 +244,28 @@ impl CommandBar {
|
||||
|
||||
fn create(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let public_key = nostr.read(cx).identity().read(cx).public_key();
|
||||
let async_chat = chat.downgrade();
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let signer_pkey = nostr.read(cx).signer_pkey(cx);
|
||||
|
||||
// Get all selected public keys
|
||||
let receivers = self.selected(cx);
|
||||
|
||||
chat.update(cx, |this, cx| {
|
||||
let room = cx.new(|_| Room::new(public_key, receivers));
|
||||
this.emit_room(room.downgrade(), cx);
|
||||
let task: Task<Result<(), Error>> = cx.spawn_in(window, async move |_this, cx| {
|
||||
let public_key = signer_pkey.await?;
|
||||
|
||||
async_chat.update_in(cx, |this, window, cx| {
|
||||
let room = cx.new(|_| Room::new(public_key, receivers));
|
||||
this.emit_room(room.downgrade(), cx);
|
||||
|
||||
window.close_modal(cx);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
window.close_modal(cx);
|
||||
task.detach();
|
||||
}
|
||||
|
||||
fn select(&mut self, pkey: PublicKey, cx: &mut Context<Self>) {
|
||||
|
||||
@@ -29,6 +29,26 @@ impl GreeterPanel {
|
||||
focus_handle: cx.focus_handle(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_profile_panel(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let signer_pkey = nostr.read(cx).signer_pkey(cx);
|
||||
|
||||
cx.spawn_in(window, async move |_this, cx| {
|
||||
if let Ok(public_key) = signer_pkey.await {
|
||||
cx.update(|window, cx| {
|
||||
Workspace::add_panel(
|
||||
profile::init(public_key, window, cx),
|
||||
DockPlacement::Center,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for GreeterPanel {
|
||||
@@ -62,12 +82,11 @@ impl Render for GreeterPanel {
|
||||
const DESCRIPTION: &str = "Chat Freely, Stay Private on Nostr.";
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let identity = nostr.read(cx).identity();
|
||||
let nip65_state = nostr.read(cx).nip65_state();
|
||||
let nip17_state = nostr.read(cx).nip17_state();
|
||||
|
||||
let relay_list_state = identity.read(cx).relay_list_state();
|
||||
let messaging_relay_state = identity.read(cx).messaging_relays_state();
|
||||
let required_actions =
|
||||
relay_list_state == RelayState::NotSet || messaging_relay_state == RelayState::NotSet;
|
||||
let required_actions = nip65_state.read(cx) == &RelayState::NotConfigured
|
||||
|| nip17_state.read(cx) == &RelayState::NotConfigured;
|
||||
|
||||
h_flex()
|
||||
.size_full()
|
||||
@@ -128,7 +147,7 @@ impl Render for GreeterPanel {
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.w_full()
|
||||
.when(relay_list_state == RelayState::NotSet, |this| {
|
||||
.when(nip65_state.read(cx).not_configured(), |this| {
|
||||
this.child(
|
||||
Button::new("relaylist")
|
||||
.icon(Icon::new(IconName::Relay))
|
||||
@@ -146,31 +165,28 @@ impl Render for GreeterPanel {
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when(
|
||||
messaging_relay_state == RelayState::NotSet,
|
||||
|this| {
|
||||
this.child(
|
||||
Button::new("import")
|
||||
.icon(Icon::new(IconName::Relay))
|
||||
.label("Set up messaging relays")
|
||||
.ghost()
|
||||
.small()
|
||||
.no_center()
|
||||
.on_click(move |_ev, window, cx| {
|
||||
Workspace::add_panel(
|
||||
messaging_relays::init(window, cx),
|
||||
DockPlacement::Center,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
)
|
||||
},
|
||||
),
|
||||
.when(nip17_state.read(cx).not_configured(), |this| {
|
||||
this.child(
|
||||
Button::new("import")
|
||||
.icon(Icon::new(IconName::Relay))
|
||||
.label("Set up messaging relays")
|
||||
.ghost()
|
||||
.small()
|
||||
.no_center()
|
||||
.on_click(move |_ev, window, cx| {
|
||||
Workspace::add_panel(
|
||||
messaging_relays::init(window, cx),
|
||||
DockPlacement::Center,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
)
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(!identity.read(cx).owned, |this| {
|
||||
.when(!nostr.read(cx).owned_signer(), |this| {
|
||||
this.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
@@ -257,14 +273,9 @@ impl Render for GreeterPanel {
|
||||
.ghost()
|
||||
.small()
|
||||
.no_center()
|
||||
.on_click(move |_ev, window, cx| {
|
||||
Workspace::add_panel(
|
||||
profile::init(window, cx),
|
||||
DockPlacement::Center,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.add_profile_panel(window, cx)
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("invite")
|
||||
|
||||
@@ -156,29 +156,20 @@ impl MessagingRelayPanel {
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let client = nostr.read(cx).client();
|
||||
let public_key = nostr.read(cx).identity().read(cx).public_key();
|
||||
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
|
||||
let relays = self.relays.clone();
|
||||
|
||||
let tags: Vec<Tag> = self
|
||||
.relays
|
||||
.iter()
|
||||
.map(|relay| Tag::relay(relay.clone()))
|
||||
.collect();
|
||||
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
let urls = write_relays.await;
|
||||
|
||||
let tags: Vec<Tag> = relays
|
||||
.iter()
|
||||
.map(|relay| Tag::relay(relay.clone()))
|
||||
.collect();
|
||||
|
||||
// Construct nip17 event builder
|
||||
let builder = EventBuilder::new(Kind::InboxRelays, "").tags(tags);
|
||||
let event = client.sign_event_builder(builder).await?;
|
||||
|
||||
// Set messaging relays
|
||||
client.send_event(&event).to(urls).await?;
|
||||
|
||||
// Connect to messaging relays
|
||||
for relay in relays.iter() {
|
||||
client.add_relay(relay).await.ok();
|
||||
client.connect_relay(relay).await.ok();
|
||||
}
|
||||
client.send_event(&event).to_nip65().await?;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
@@ -22,8 +22,8 @@ use ui::input::{InputState, TextInput};
|
||||
use ui::notification::Notification;
|
||||
use ui::{divider, h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension};
|
||||
|
||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<ProfilePanel> {
|
||||
cx.new(|cx| ProfilePanel::new(window, cx))
|
||||
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfilePanel> {
|
||||
cx.new(|cx| ProfilePanel::new(public_key, window, cx))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -31,6 +31,9 @@ pub struct ProfilePanel {
|
||||
name: SharedString,
|
||||
focus_handle: FocusHandle,
|
||||
|
||||
/// User's public key
|
||||
public_key: PublicKey,
|
||||
|
||||
/// User's name text input
|
||||
name_input: Entity<InputState>,
|
||||
|
||||
@@ -51,13 +54,10 @@ pub struct ProfilePanel {
|
||||
}
|
||||
|
||||
impl ProfilePanel {
|
||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
fn new(public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let name_input = cx.new(|cx| InputState::new(window, cx).placeholder("Alice"));
|
||||
let website_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me"));
|
||||
|
||||
// Hidden input for avatar url
|
||||
let avatar_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me/a.jpg"));
|
||||
|
||||
// Use multi-line input for bio
|
||||
let bio_input = cx.new(|cx| {
|
||||
InputState::new(window, cx)
|
||||
@@ -66,13 +66,10 @@ impl ProfilePanel {
|
||||
.placeholder("A short introduce about you.")
|
||||
});
|
||||
|
||||
// Get user's profile and update inputs
|
||||
cx.defer_in(window, move |this, window, cx| {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let public_key = nostr.read(cx).identity().read(cx).public_key();
|
||||
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get(&public_key, cx);
|
||||
|
||||
// Set all input's values with current profile
|
||||
this.set_profile(profile, window, cx);
|
||||
});
|
||||
@@ -80,6 +77,7 @@ impl ProfilePanel {
|
||||
Self {
|
||||
name: "Update Profile".into(),
|
||||
focus_handle: cx.focus_handle(),
|
||||
public_key,
|
||||
name_input,
|
||||
avatar_input,
|
||||
bio_input,
|
||||
@@ -209,7 +207,7 @@ impl ProfilePanel {
|
||||
|
||||
fn set_metadata(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let public_key = nostr.read(cx).identity().read(cx).public_key();
|
||||
let public_key = self.public_key;
|
||||
|
||||
// Get the old metadata
|
||||
let persons = PersonRegistry::global(cx);
|
||||
@@ -289,9 +287,7 @@ impl Focusable for ProfilePanel {
|
||||
|
||||
impl Render for ProfilePanel {
|
||||
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let public_key = nostr.read(cx).identity().read(cx).public_key();
|
||||
let shorten_pkey = SharedString::from(shorten_pubkey(public_key, 8));
|
||||
let shorten_pkey = SharedString::from(shorten_pubkey(self.public_key, 8));
|
||||
|
||||
// Get the avatar
|
||||
let avatar_input = self.avatar_input.read(cx).value();
|
||||
@@ -390,7 +386,7 @@ impl Render for ProfilePanel {
|
||||
.ghost()
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.copy(
|
||||
public_key.to_bech32().unwrap(),
|
||||
this.public_key.to_bech32().unwrap(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
@@ -9,10 +9,11 @@ use gpui::{
|
||||
div, rems, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement,
|
||||
ParentElement, Render, SharedString, Styled, Subscription, Window,
|
||||
};
|
||||
use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use state::NostrRegistry;
|
||||
use theme::{ActiveTheme, Theme, SIDEBAR_WIDTH, TITLEBAR_HEIGHT};
|
||||
use theme::{ActiveTheme, SIDEBAR_WIDTH, TITLEBAR_HEIGHT};
|
||||
use titlebar::TitleBar;
|
||||
use ui::avatar::Avatar;
|
||||
use ui::{h_flex, v_flex, Icon, IconName, Root, Sizable, WindowExtension};
|
||||
@@ -35,6 +36,9 @@ pub struct Workspace {
|
||||
/// App's Command Bar
|
||||
command_bar: Entity<CommandBar>,
|
||||
|
||||
/// Current User
|
||||
current_user: Entity<Option<PublicKey>>,
|
||||
|
||||
/// Event subscriptions
|
||||
_subscriptions: SmallVec<[Subscription; 3]>,
|
||||
}
|
||||
@@ -42,20 +46,23 @@ pub struct Workspace {
|
||||
impl Workspace {
|
||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let current_user = cx.new(|_| None);
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let nip65_state = nostr.read(cx).nip65_state();
|
||||
|
||||
// Titlebar
|
||||
let titlebar = cx.new(|_| TitleBar::new());
|
||||
|
||||
// Command bar
|
||||
let command_bar = cx.new(|cx| CommandBar::new(window, cx));
|
||||
|
||||
// Dock
|
||||
let dock =
|
||||
cx.new(|cx| DockArea::new(window, cx).panel_style(dock::panel::PanelStyle::TabBar));
|
||||
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
subscriptions.push(
|
||||
// Automatically sync theme with system appearance
|
||||
window.observe_window_appearance(|window, cx| {
|
||||
Theme::sync_system_appearance(Some(window), cx);
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Observe all events emitted by the chat registry
|
||||
cx.subscribe_in(&chat, window, move |this, chat, ev, window, cx| {
|
||||
@@ -100,6 +107,15 @@ impl Workspace {
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Observe the NIP-65 state
|
||||
cx.observe(&nip65_state, move |this, state, cx| {
|
||||
if state.read(cx).idle() {
|
||||
this.get_current_user(cx);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Set the default layout for app's dock
|
||||
cx.defer_in(window, |this, window, cx| {
|
||||
this.set_layout(window, cx);
|
||||
@@ -109,6 +125,7 @@ impl Workspace {
|
||||
titlebar,
|
||||
dock,
|
||||
command_bar,
|
||||
current_user,
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
@@ -173,18 +190,35 @@ impl Workspace {
|
||||
});
|
||||
}
|
||||
|
||||
fn titlebar_left(&mut self, _window: &mut Window, cx: &Context<Self>) -> impl IntoElement {
|
||||
fn get_current_user(&self, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let identity = nostr.read(cx).identity();
|
||||
let client = nostr.read(cx).client();
|
||||
let current_user = self.current_user.downgrade();
|
||||
|
||||
cx.spawn(async move |_this, cx| {
|
||||
if let Some(signer) = client.signer() {
|
||||
if let Ok(public_key) = signer.get_public_key().await {
|
||||
current_user
|
||||
.update(cx, |this, cx| {
|
||||
*this = Some(public_key);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn titlebar_left(&mut self, _window: &mut Window, cx: &Context<Self>) -> impl IntoElement {
|
||||
h_flex()
|
||||
.h(TITLEBAR_HEIGHT)
|
||||
.flex_1()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.when_some(identity.read(cx).public_key, |this, public_key| {
|
||||
.when_some(self.current_user.read(cx).as_ref(), |this, public_key| {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get(&public_key, cx);
|
||||
let profile = persons.read(cx).get(public_key, cx);
|
||||
|
||||
this.child(
|
||||
h_flex()
|
||||
|
||||
Reference in New Issue
Block a user