chore: re-add missing actions #17

Merged
reya merged 4 commits from add-missing-actions into master 2026-03-06 08:25:32 +00:00
4 changed files with 161 additions and 33 deletions
Showing only changes of commit a3022cf38a - Show all commits

3
assets/icons/input.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M11.75 6.75H19.25C20.3546 6.75 21.25 7.64543 21.25 8.75V15.25C21.25 16.3546 20.3546 17.25 19.25 17.25H11.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M5.75 6.75H4.75C3.64543 6.75 2.75 7.64543 2.75 8.75V15.25C2.75 16.3546 3.64543 17.25 4.75 17.25H5.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.75 3.75V20.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 604 B

View File

@@ -6,12 +6,11 @@ use settings::SignerKind;
#[derive(Action, Clone, PartialEq, Eq, Deserialize)] #[derive(Action, Clone, PartialEq, Eq, Deserialize)]
#[action(namespace = chat, no_json)] #[action(namespace = chat, no_json)]
pub enum Command { pub enum Command {
ChangeSubject(&'static str), Insert(&'static str),
ChangeSubject(String),
ChangeSigner(SignerKind), ChangeSigner(SignerKind),
ToggleBackup, ToggleBackup,
Subject,
Insert(&'static str),
Copy(PublicKey), Copy(PublicKey),
Relays(PublicKey), Relays(PublicKey),
Njump(PublicKey), Njump(PublicKey),

View File

@@ -72,9 +72,15 @@ pub struct ChatPanel {
/// Mapping message (rumor event) ids to their reports /// Mapping message (rumor event) ids to their reports
reports_by_id: Entity<BTreeMap<EventId, Vec<SendReport>>>, reports_by_id: Entity<BTreeMap<EventId, Vec<SendReport>>>,
/// Input state /// Chat input state
input: Entity<InputState>, input: Entity<InputState>,
/// Subject input state
subject_input: Entity<InputState>,
/// Subject bar visibility
subject_bar: Entity<bool>,
/// Sent message ids /// Sent message ids
sent_ids: Arc<RwLock<Vec<EventId>>>, sent_ids: Arc<RwLock<Vec<EventId>>>,
@@ -91,7 +97,7 @@ pub struct ChatPanel {
tasks: Vec<Task<Result<(), Error>>>, tasks: Vec<Task<Result<(), Error>>>,
/// Event subscriptions /// Event subscriptions
subscriptions: SmallVec<[Subscription; 2]>, subscriptions: SmallVec<[Subscription; 3]>,
} }
impl ChatPanel { impl ChatPanel {
@@ -124,15 +130,34 @@ impl ChatPanel {
.clean_on_escape() .clean_on_escape()
}); });
// Define subject input state
let subject_input = cx.new(|cx| InputState::new(window, cx).placeholder("Nostr Meetup"));
let subject_bar = cx.new(|_cx| false);
// Define subscriptions // Define subscriptions
let subscriptions = let mut subscriptions = smallvec![];
smallvec![
subscriptions.push(
// Subscribe the chat input event
cx.subscribe_in(&input, window, move |this, _input, event, window, cx| { cx.subscribe_in(&input, window, move |this, _input, event, window, cx| {
if let InputEvent::PressEnter { .. } = event { if let InputEvent::PressEnter { .. } = event {
this.send_text_message(window, cx); this.send_text_message(window, cx);
}; };
}) }),
]; );
subscriptions.push(
// Subscribe the subject input event
cx.subscribe_in(
&subject_input,
window,
move |this, _input, event, window, cx| {
if let InputEvent::PressEnter { .. } = event {
this.change_subject(window, cx);
};
},
),
);
// Define all functions that will run after the current cycle // Define all functions that will run after the current cycle
cx.defer_in(window, |this, window, cx| { cx.defer_in(window, |this, window, cx| {
@@ -149,6 +174,8 @@ impl ChatPanel {
room, room,
list_state, list_state,
input, input,
subject_input,
subject_bar,
replies_to, replies_to,
attachments, attachments,
rendered_texts_by_id: BTreeMap::new(), rendered_texts_by_id: BTreeMap::new(),
@@ -254,10 +281,7 @@ impl ChatPanel {
} }
fn subscribe_room_events(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn subscribe_room_events(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(room) = self.room.upgrade() else { if let Some(room) = self.room.upgrade() {
return;
};
self.subscriptions.push( self.subscriptions.push(
// Subscribe to room events // Subscribe to room events
cx.subscribe_in(&room, window, move |this, _room, event, window, cx| { cx.subscribe_in(&room, window, move |this, _room, event, window, cx| {
@@ -272,6 +296,7 @@ impl ChatPanel {
}), }),
); );
} }
}
/// Load all messages belonging to this room /// Load all messages belonging to this room
fn get_messages(&mut self, _window: &mut Window, cx: &mut Context<Self>) { fn get_messages(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
@@ -316,6 +341,16 @@ impl ChatPanel {
content content
} }
fn change_subject(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
let subject = self.subject_input.read(cx).value();
self.room
.update(cx, |this, cx| {
this.set_subject(subject, cx);
})
.ok();
}
fn send_text_message(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn send_text_message(&mut self, window: &mut Window, cx: &mut Context<Self>) {
// Get the message which includes all attachments // Get the message which includes all attachments
let content = self.get_input_value(cx); let content = self.get_input_value(cx);
@@ -613,7 +648,7 @@ impl ChatPanel {
if self if self
.room .room
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.set_subject(*subject, cx); this.set_subject(subject, cx);
}) })
.is_err() .is_err()
{ {
@@ -642,6 +677,9 @@ impl ChatPanel {
window.push_notification(Notification::error("Failed to toggle backup"), cx); window.push_notification(Notification::error("Failed to toggle backup"), cx);
} }
} }
Command::Subject => {
self.open_subject(window, cx);
}
Command::Copy(public_key) => { Command::Copy(public_key) => {
self.copy_author(public_key, cx); self.copy_author(public_key, cx);
} }
@@ -654,6 +692,47 @@ impl ChatPanel {
} }
} }
fn open_subject(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let subject_input = self.subject_input.clone();
window.open_modal(cx, move |this, _window, cx| {
let subject = subject_input.read(cx).value();
this.title("Change subject")
.show_close(true)
.confirm()
.child(
v_flex()
.gap_2()
.child(
v_flex()
.gap_1p5()
.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.child(SharedString::from("Subject:")),
)
.child(TextInput::new(&subject_input).small()),
)
.child(
div()
.italic()
.text_xs()
.text_color(cx.theme().text_placeholder)
.child(SharedString::from(
"Subject will be updated when you send a new message.",
)),
),
)
.on_ok(move |_ev, window, cx| {
window
.dispatch_action(Box::new(Command::ChangeSubject(subject.to_string())), cx);
true
})
});
}
fn open_relays(&mut self, public_key: &PublicKey, window: &mut Window, cx: &mut Context<Self>) { fn open_relays(&mut self, public_key: &PublicKey, window: &mut Window, cx: &mut Context<Self>) {
let profile = self.profile(public_key, cx); let profile = self.profile(public_key, cx);
@@ -1349,12 +1428,30 @@ impl Panel for ChatPanel {
h_flex() h_flex()
.gap_1p5() .gap_1p5()
.child(Avatar::new(url).small()) .child(Avatar::new(url).xsmall())
.child(label) .child(label)
.into_any_element() .into_any_element()
}) })
.unwrap_or(div().child("Unknown").into_any_element()) .unwrap_or(div().child("Unknown").into_any_element())
} }
fn toolbar_buttons(&self, _window: &Window, _cx: &App) -> Vec<Button> {
let subject_bar = self.subject_bar.clone();
vec![
Button::new("subject")
.icon(IconName::Input)
.tooltip("Change subject")
.small()
.ghost()
.on_click(move |_ev, _window, cx| {
subject_bar.update(cx, |this, cx| {
*this = !*this;
cx.notify();
});
}),
]
}
} }
impl EventEmitter<PanelEvent> for ChatPanel {} impl EventEmitter<PanelEvent> for ChatPanel {}
@@ -1370,6 +1467,33 @@ impl Render for ChatPanel {
v_flex() v_flex()
.on_action(cx.listener(Self::on_command)) .on_action(cx.listener(Self::on_command))
.size_full() .size_full()
.when(*self.subject_bar.read(cx), |this| {
this.child(
h_flex()
.h_12()
.w_full()
.px_2()
.gap_2()
.border_b_1()
.border_color(cx.theme().border)
.child(
TextInput::new(&self.subject_input)
.text_sm()
.small()
.bordered(false),
)
.child(
Button::new("change")
.icon(IconName::CheckCircle)
.label("Change")
.secondary()
.disabled(self.uploading)
.on_click(cx.listener(move |this, _ev, window, cx| {
this.change_subject(window, cx);
})),
),
)
})
.child( .child(
v_flex() v_flex()
.flex_1() .flex_1()

View File

@@ -1,7 +1,7 @@
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
svg, AnyElement, App, AppContext, Context, Entity, Hsla, IntoElement, Radians, Render, AnyElement, App, AppContext, Context, Entity, Hsla, IntoElement, Radians, Render, RenderOnce,
RenderOnce, SharedString, StyleRefinement, Styled, Svg, Transformation, Window, SharedString, StyleRefinement, Styled, Svg, Transformation, Window, svg,
}; };
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -39,6 +39,7 @@ pub enum IconName {
Ellipsis, Ellipsis,
Emoji, Emoji,
Eye, Eye,
Input,
Info, Info,
Invite, Invite,
Inbox, Inbox,
@@ -110,6 +111,7 @@ impl IconNamed for IconName {
Self::Ellipsis => "icons/ellipsis.svg", Self::Ellipsis => "icons/ellipsis.svg",
Self::Emoji => "icons/emoji.svg", Self::Emoji => "icons/emoji.svg",
Self::Eye => "icons/eye.svg", Self::Eye => "icons/eye.svg",
Self::Input => "icons/input.svg",
Self::Info => "icons/info.svg", Self::Info => "icons/info.svg",
Self::Invite => "icons/invite.svg", Self::Invite => "icons/invite.svg",
Self::Inbox => "icons/inbox.svg", Self::Inbox => "icons/inbox.svg",