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