From a3022cf38a589357ade3aa84ce5b64cc12824f9f Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Fri, 6 Mar 2026 15:17:51 +0700 Subject: [PATCH] add change subject --- assets/icons/input.svg | 3 + crates/chat_ui/src/actions.rs | 7 +- crates/chat_ui/src/lib.rs | 178 ++++++++++++++++++++++++++++------ crates/ui/src/icon.rs | 6 +- 4 files changed, 161 insertions(+), 33 deletions(-) create mode 100644 assets/icons/input.svg diff --git a/assets/icons/input.svg b/assets/icons/input.svg new file mode 100644 index 0000000..86efa0e --- /dev/null +++ b/assets/icons/input.svg @@ -0,0 +1,3 @@ + + + diff --git a/crates/chat_ui/src/actions.rs b/crates/chat_ui/src/actions.rs index c2ed059..fdb5fbb 100644 --- a/crates/chat_ui/src/actions.rs +++ b/crates/chat_ui/src/actions.rs @@ -6,12 +6,11 @@ use settings::SignerKind; #[derive(Action, Clone, PartialEq, Eq, Deserialize)] #[action(namespace = chat, no_json)] pub enum Command { - ChangeSubject(&'static str), + Insert(&'static str), + ChangeSubject(String), ChangeSigner(SignerKind), ToggleBackup, - - Insert(&'static str), - + Subject, Copy(PublicKey), Relays(PublicKey), Njump(PublicKey), diff --git a/crates/chat_ui/src/lib.rs b/crates/chat_ui/src/lib.rs index 8d44a42..eb0efd6 100644 --- a/crates/chat_ui/src/lib.rs +++ b/crates/chat_ui/src/lib.rs @@ -72,9 +72,15 @@ pub struct ChatPanel { /// Mapping message (rumor event) ids to their reports reports_by_id: Entity>>, - /// Input state + /// Chat input state input: Entity, + /// Subject input state + subject_input: Entity, + + /// Subject bar visibility + subject_bar: Entity, + /// Sent message ids sent_ids: Arc>>, @@ -91,7 +97,7 @@ pub struct ChatPanel { tasks: Vec>>, /// Event subscriptions - subscriptions: SmallVec<[Subscription; 2]>, + subscriptions: SmallVec<[Subscription; 3]>, } impl ChatPanel { @@ -124,15 +130,34 @@ impl ChatPanel { .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 - let subscriptions = - smallvec![ - cx.subscribe_in(&input, window, move |this, _input, event, window, cx| { + let mut subscriptions = smallvec![]; + + subscriptions.push( + // Subscribe the chat input event + cx.subscribe_in(&input, window, move |this, _input, event, window, cx| { + if let InputEvent::PressEnter { .. } = event { + 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.send_text_message(window, cx); + this.change_subject(window, cx); }; - }) - ]; + }, + ), + ); // Define all functions that will run after the current cycle cx.defer_in(window, |this, window, cx| { @@ -149,6 +174,8 @@ impl ChatPanel { room, list_state, input, + subject_input, + subject_bar, replies_to, attachments, rendered_texts_by_id: BTreeMap::new(), @@ -254,23 +281,21 @@ impl ChatPanel { } fn subscribe_room_events(&mut self, window: &mut Window, cx: &mut Context) { - let Some(room) = self.room.upgrade() else { - return; - }; - - self.subscriptions.push( - // Subscribe to room events - cx.subscribe_in(&room, window, move |this, _room, event, window, cx| { - match event { - RoomEvent::Incoming(message) => { - this.insert_message(message, false, cx); - } - RoomEvent::Reload => { - this.get_messages(window, cx); - } - }; - }), - ); + if let Some(room) = self.room.upgrade() { + self.subscriptions.push( + // Subscribe to room events + cx.subscribe_in(&room, window, move |this, _room, event, window, cx| { + match event { + RoomEvent::Incoming(message) => { + this.insert_message(message, false, cx); + } + RoomEvent::Reload => { + this.get_messages(window, cx); + } + }; + }), + ); + } } /// Load all messages belonging to this room @@ -316,6 +341,16 @@ impl ChatPanel { content } + fn change_subject(&mut self, _window: &mut Window, cx: &mut Context) { + 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) { // Get the message which includes all attachments let content = self.get_input_value(cx); @@ -613,7 +648,7 @@ impl ChatPanel { if self .room .update(cx, |this, cx| { - this.set_subject(*subject, cx); + this.set_subject(subject, cx); }) .is_err() { @@ -642,6 +677,9 @@ impl ChatPanel { window.push_notification(Notification::error("Failed to toggle backup"), cx); } } + Command::Subject => { + self.open_subject(window, cx); + } Command::Copy(public_key) => { self.copy_author(public_key, cx); } @@ -654,6 +692,47 @@ impl ChatPanel { } } + fn open_subject(&mut self, window: &mut Window, cx: &mut Context) { + 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) { let profile = self.profile(public_key, cx); @@ -1349,12 +1428,30 @@ impl Panel for ChatPanel { h_flex() .gap_1p5() - .child(Avatar::new(url).small()) + .child(Avatar::new(url).xsmall()) .child(label) .into_any_element() }) .unwrap_or(div().child("Unknown").into_any_element()) } + + fn toolbar_buttons(&self, _window: &Window, _cx: &App) -> Vec