feat: add action to compose modal

This commit is contained in:
2025-01-21 15:15:37 +07:00
parent 5f6ba4f0a6
commit 582db29209
7 changed files with 265 additions and 172 deletions

View File

@@ -1,8 +1,15 @@
use crate::{get_client, states::chat::room::Member};
use crate::{
get_client,
states::{
app::AppRegistry,
chat::room::{Member, Room},
},
utils::{random_name, room_hash},
};
use gpui::{
div, img, impl_internal_actions, px, uniform_list, Context, FocusHandle, InteractiveElement,
IntoElement, Model, ParentElement, Render, StatefulInteractiveElement, Styled, View,
ViewContext, VisualContext, WindowContext,
IntoElement, Model, ParentElement, Render, SharedString, StatefulInteractiveElement, Styled,
View, ViewContext, VisualContext, WindowContext,
};
use nostr_sdk::prelude::*;
use serde::Deserialize;
@@ -44,17 +51,19 @@ impl Compose {
});
let title_input = cx.new_view(|cx| {
TextInput::new(cx)
.appearance(false)
.text_size(Size::XSmall)
.placeholder("Family...")
let name = random_name(2);
let mut input = TextInput::new(cx).appearance(false).text_size(Size::XSmall);
input.set_placeholder("Family... . (Optional)");
input.set_text(name, cx);
input
});
let message_input = cx.new_view(|cx| {
TextInput::new(cx)
.appearance(false)
.text_size(Size::XSmall)
.placeholder("Hello...")
.placeholder("Hello... (Optional)")
});
cx.subscribe(&user_input, move |this, _, input_event, cx| {
@@ -110,8 +119,51 @@ impl Compose {
}
}
pub fn selected<'a>(&self, cx: &'a WindowContext) -> Vec<&'a PublicKey> {
self.selected.read(cx).iter().collect()
pub fn room(&self, cx: &WindowContext) -> Option<Room> {
let weak_user = cx.global::<AppRegistry>().current_user();
if let Some(user) = weak_user.upgrade() {
let public_key = user.read(cx).unwrap();
// Convert selected pubkeys into nostr tags
let tags: Vec<Tag> = self
.selected
.read(cx)
.iter()
.map(|pk| Tag::public_key(*pk))
.collect();
let tags = Tags::new(tags);
// Convert selected pubkeys into members
let members: Vec<Member> = self
.selected
.read(cx)
.clone()
.into_iter()
.map(|pk| Member::new(pk, Metadata::new()))
.collect();
// Get room's id
let id = room_hash(&tags);
// Get room's owner (current user)
let owner = Member::new(public_key, Metadata::new());
// Get room's title
let title = self.title_input.read(cx).text().to_string().into();
Some(Room::new(id, owner, members, Some(title), Timestamp::now()))
} else {
None
}
}
pub fn label(&self, cx: &WindowContext) -> SharedString {
if self.selected.read(cx).len() > 1 {
"Create Group DM".into()
} else {
"Create DM".into()
}
}
fn add(&mut self, cx: &mut ViewContext<Self>) {

View File

@@ -22,7 +22,7 @@ pub struct Inbox {
impl Inbox {
pub fn new(_cx: &mut ViewContext<'_, Self>) -> Self {
Self {
label: "Direct Messages".into(),
label: "Inbox".into(),
is_collapsed: false,
}
}
@@ -138,11 +138,6 @@ impl Render for Inbox {
.rounded(px(cx.theme().radius))
.text_xs()
.font_semibold()
.hover(|this| this.bg(cx.theme().base.step(cx, ColorScaleStep::THREE)))
.on_click(cx.listener(move |view, _event, cx| {
view.is_collapsed = !view.is_collapsed;
cx.notify();
}))
.child(
Icon::new(IconName::ChevronDown)
.size_6()
@@ -150,7 +145,12 @@ impl Render for Inbox {
this.rotate(percentage(270. / 360.))
}),
)
.child(self.label.clone()),
.child(self.label.clone())
.hover(|this| this.bg(cx.theme().base.step(cx, ColorScaleStep::THREE)))
.on_click(cx.listener(move |view, _event, cx| {
view.is_collapsed = !view.is_collapsed;
cx.notify();
})),
)
.when(!self.is_collapsed, |this| this.child(self.render_item(cx)))
}

View File

@@ -1,9 +1,9 @@
use crate::views::sidebar::inbox::Inbox;
use crate::{states::chat::ChatRegistry, views::sidebar::inbox::Inbox};
use compose::Compose;
use gpui::{
div, px, AnyElement, AppContext, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
IntoElement, ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext,
WindowContext,
div, px, AnyElement, AppContext, BorrowAppContext, Entity, EntityId, EventEmitter, FocusHandle,
FocusableView, InteractiveElement, IntoElement, ParentElement, Render, SharedString,
StatefulInteractiveElement, Styled, View, ViewContext, VisualContext, WindowContext,
};
use ui::{
button::{Button, ButtonRounded, ButtonVariants},
@@ -53,12 +53,7 @@ impl Sidebar {
let compose = cx.new_view(Compose::new);
cx.open_modal(move |modal, cx| {
let selected = compose.model.read(cx).selected(cx);
let label = if selected.len() > 1 {
"Create Group DM"
} else {
"Create DM"
};
let label = compose.read(cx).label(cx);
modal
.title("Direct Messages")
@@ -75,7 +70,16 @@ impl Sidebar {
.primary()
.bold()
.rounded(ButtonRounded::Large)
.w_full(),
.w_full()
.on_click(cx.listener_for(&compose, |this, _, cx| {
if let Some(room) = this.room(cx) {
cx.update_global::<ChatRegistry, _>(|this, cx| {
this.new_room(room, cx);
});
cx.close_modal();
}
})),
),
)
})
@@ -127,13 +131,33 @@ impl Render for Sidebar {
.py_3()
.gap_3()
.child(
v_flex().px_2().gap_0p5().child(
Button::new("compose")
.small()
.ghost()
.not_centered()
.icon(Icon::new(IconName::ComposeFill))
.label("Compose")
v_flex().px_2().gap_1().child(
div()
.id("new")
.flex()
.items_center()
.gap_2()
.px_1()
.h_7()
.text_xs()
.font_semibold()
.rounded(px(cx.theme().radius))
.child(
div()
.size_6()
.flex()
.items_center()
.justify_center()
.rounded_full()
.bg(cx.theme().accent.step(cx, ColorScaleStep::NINE))
.child(
Icon::new(IconName::ComposeFill)
.small()
.text_color(cx.theme().base.darken(cx)),
),
)
.child("New Message")
.hover(|this| this.bg(cx.theme().base.step(cx, ColorScaleStep::THREE)))
.on_click(cx.listener(|this, _, cx| this.show_compose(cx))),
),
)