feat: add relay tracking for gift wrap events #21

Merged
reya merged 5 commits from chat-patch into master 2026-03-14 08:18:20 +00:00
5 changed files with 59 additions and 16 deletions
Showing only changes of commit 0fc7d2f6d1 - Show all commits

View File

@@ -27,9 +27,9 @@ use crate::dialogs::{accounts, settings};
use crate::panels::{backup, contact_list, greeter, messaging_relays, profile, relay_list}; use crate::panels::{backup, contact_list, greeter, messaging_relays, profile, relay_list};
use crate::sidebar; use crate::sidebar;
const PREPARE_MSG: &str = "Coop is preparing a new identity for you. This may take a moment...";
const ENC_MSG: &str = "Encryption Key is a special key that used to encrypt and decrypt your messages. \ const ENC_MSG: &str = "Encryption Key is a special key that used to encrypt and decrypt your messages. \
Your identity is completely decoupled from all encryption processes to protect your privacy."; Your identity is completely decoupled from all encryption processes to protect your privacy.";
const ENC_WARN: &str = "By resetting your encryption key, you will lose access to \ const ENC_WARN: &str = "By resetting your encryption key, you will lose access to \
all your encrypted messages before. This action cannot be undone."; all your encrypted messages before. This action cannot be undone.";
@@ -37,6 +37,7 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
cx.new(|cx| Workspace::new(window, cx)) cx.new(|cx| Workspace::new(window, cx))
} }
struct SignerNotifcation;
struct RelayNotifcation; struct RelayNotifcation;
#[derive(Action, Clone, PartialEq, Eq, Deserialize)] #[derive(Action, Clone, PartialEq, Eq, Deserialize)]
@@ -107,21 +108,29 @@ impl Workspace {
// Subscribe to the signer events // Subscribe to the signer events
cx.subscribe_in(&nostr, window, move |this, _state, event, window, cx| { cx.subscribe_in(&nostr, window, move |this, _state, event, window, cx| {
match event { match event {
StateEvent::Creating => {
let note = Notification::new()
.id::<SignerNotifcation>()
.title("Preparing a new identity")
.message(PREPARE_MSG)
.autohide(false)
.with_kind(NotificationKind::Info);
window.push_notification(note, cx);
}
StateEvent::Connecting => { StateEvent::Connecting => {
let note = Notification::new() let note = Notification::new()
.id::<RelayNotifcation>() .id::<RelayNotifcation>()
.message("Connecting to the bootstrap relay...") .message("Connecting to the bootstrap relays...")
.with_kind(NotificationKind::Info) .with_kind(NotificationKind::Info);
.icon(IconName::Relay);
window.push_notification(note, cx); window.push_notification(note, cx);
} }
StateEvent::Connected => { StateEvent::Connected => {
let note = Notification::new() let note = Notification::new()
.id::<RelayNotifcation>() .id::<RelayNotifcation>()
.message("Connected to the bootstrap relay") .message("Connected to the bootstrap relays")
.with_kind(NotificationKind::Success) .with_kind(NotificationKind::Success);
.icon(IconName::Relay);
window.push_notification(note, cx); window.push_notification(note, cx);
} }
@@ -136,6 +145,8 @@ impl Workspace {
this.set_center_layout(window, cx); this.set_center_layout(window, cx);
this.set_relay_connected(false, cx); this.set_relay_connected(false, cx);
this.set_inbox_connected(false, cx); this.set_inbox_connected(false, cx);
// Clear the signer notification
window.clear_notification::<SignerNotifcation>(cx);
} }
_ => {} _ => {}
}; };

View File

@@ -6,11 +6,13 @@ use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error, anyhow}; use anyhow::{Context as AnyhowContext, Error, anyhow};
use gpui::{ use gpui::{
App, AppContext, Context, Entity, EventEmitter, Global, IntoElement, ParentElement, App, AppContext, Context, Entity, EventEmitter, Global, IntoElement, ParentElement,
SharedString, Styled, Task, Window, div, relative, SharedString, Styled, Subscription, Task, Window, div, relative,
}; };
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use person::PersonRegistry; use person::PersonRegistry;
use state::{Announcement, DEVICE_GIFTWRAP, DeviceState, NostrRegistry, TIMEOUT, app_name}; use state::{
Announcement, DEVICE_GIFTWRAP, DeviceState, NostrRegistry, StateEvent, TIMEOUT, app_name,
};
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
@@ -48,6 +50,9 @@ pub struct DeviceRegistry {
/// Async tasks /// Async tasks
tasks: Vec<Task<Result<(), Error>>>, tasks: Vec<Task<Result<(), Error>>>,
/// Event subscription
_subscription: Option<Subscription>,
} }
impl EventEmitter<DeviceEvent> for DeviceRegistry {} impl EventEmitter<DeviceEvent> for DeviceRegistry {}
@@ -65,16 +70,26 @@ impl DeviceRegistry {
/// Create a new device registry instance /// Create a new device registry instance
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self { fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let nostr = NostrRegistry::global(cx);
let state = DeviceState::default(); let state = DeviceState::default();
let subscription =
Some(
cx.subscribe_in(&nostr, window, |this, _state, ev, _window, cx| {
if let StateEvent::SignerSet = ev {
this.get_announcement(cx);
}
}),
);
cx.defer_in(window, |this, window, cx| { cx.defer_in(window, |this, window, cx| {
this.handle_notifications(window, cx); this.handle_notifications(window, cx);
this.get_announcement(cx);
}); });
Self { Self {
state, state,
tasks: vec![], tasks: vec![],
_subscription: subscription,
} }
} }

View File

@@ -17,7 +17,7 @@ use state::NostrRegistry;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::notification::Notification; use ui::notification::Notification;
use ui::{Disableable, IconName, Sizable, WindowExtension, v_flex}; use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, v_flex};
const AUTH_MESSAGE: &str = const AUTH_MESSAGE: &str =
"Approve the authentication request to allow Coop to continue sending or receiving events."; "Approve the authentication request to allow Coop to continue sending or receiving events.";
@@ -344,8 +344,9 @@ impl RelayAuth {
.px_1p5() .px_1p5()
.rounded_sm() .rounded_sm()
.text_xs() .text_xs()
.font_semibold()
.bg(cx.theme().elevated_surface_background) .bg(cx.theme().elevated_surface_background)
.text_color(cx.theme().text_accent) .text_color(cx.theme().text)
.child(url.clone()), .child(url.clone()),
) )
.into_any_element() .into_any_element()

View File

@@ -44,6 +44,8 @@ impl Global for GlobalNostrRegistry {}
/// Signer event. /// Signer event.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum StateEvent { pub enum StateEvent {
/// Creating the signer
Creating,
/// Connecting to the bootstrapping relay /// Connecting to the bootstrapping relay
Connecting, Connecting,
/// Connected to the bootstrapping relay /// Connected to the bootstrapping relay
@@ -289,6 +291,9 @@ impl NostrRegistry {
// Create a write credential task // Create a write credential task
let write_credential = cx.write_credentials(&username, &username, &secret); let write_credential = cx.write_credentials(&username, &username, &secret);
// Emit creating event
cx.emit(StateEvent::Creating);
// Run async tasks in background // Run async tasks in background
let task: Task<Result<(), Error>> = cx.background_spawn(async move { let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let signer = async_keys.into_nostr_signer(); let signer = async_keys.into_nostr_signer();
@@ -301,7 +306,7 @@ impl NostrRegistry {
client client
.send_event(&event) .send_event(&event)
.to(BOOTSTRAP_RELAYS) .to(BOOTSTRAP_RELAYS)
.ok_timeout(Duration::from_secs(TIMEOUT)) .ack_policy(AckPolicy::none())
.await?; .await?;
// Construct the default metadata // Construct the default metadata

View File

@@ -330,7 +330,12 @@ impl Render for Notification {
.items_start() .items_start()
.refine_style(&self.style) .refine_style(&self.style)
.when_some(icon, |this, icon| { .when_some(icon, |this, icon| {
this.child(div().flex_shrink_0().child(icon)) this.child(
div()
.flex_shrink_0()
.when(self.message.is_some(), |this| this.pt_0p5())
.child(icon),
)
}) })
.child( .child(
v_flex() v_flex()
@@ -340,7 +345,13 @@ impl Render for Notification {
this.child(div().text_sm().font_semibold().child(title)) this.child(div().text_sm().font_semibold().child(title))
}) })
.when_some(self.message.clone(), |this, message| { .when_some(self.message.clone(), |this, message| {
this.child(div().text_sm().line_height(relative(1.25)).child(message)) this.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.line_height(relative(1.3))
.child(message),
)
}) })
.when_some(content, |this, content| this.child(content)) .when_some(content, |this, content| this.child(content))
.when_some(action, |this, action| { .when_some(action, |this, action| {