diff --git a/src/api/post.rs b/src/api/post.rs index 1cb98f0..46833e4 100644 --- a/src/api/post.rs +++ b/src/api/post.rs @@ -1,4 +1,6 @@ -use lemmy_api_common::{post::{GetPost, GetPostResponse, PostResponse, CreatePost}, lemmy_db_schema::{newtypes::{PostId, CommunityId}, CommentSortType, ListingType}, comment::{GetComments, GetCommentsResponse}, lemmy_db_views::structs::CommentView, sensitive::Sensitive}; +use lemmy_api_common::{post::{GetPost, GetPostResponse, PostResponse, CreatePost}, lemmy_db_schema::{newtypes::{PostId, CommunityId}, CommentSortType, ListingType}, comment::{GetComments, GetCommentsResponse}, lemmy_db_views::structs::CommentView}; + +use crate::util; pub fn get_post(id: PostId) -> std::result::Result { let params = GetPost { @@ -33,13 +35,12 @@ pub fn create_post( name: String, body: String, community_id: i32, - auth: Sensitive, ) -> Result { let params = CreatePost { name, body: Some(body), community_id: CommunityId(community_id), - auth, + auth: util::get_auth_token().unwrap(), ..Default::default() }; super::post("/post", ¶ms) diff --git a/src/components/community_page.rs b/src/components/community_page.rs index f3290f7..119a289 100644 --- a/src/components/community_page.rs +++ b/src/components/community_page.rs @@ -1,4 +1,4 @@ -use crate::util::markdown_to_pango_markup; +use crate::{util::markdown_to_pango_markup, dialogs::create_post::{CreatePostDialog, CREATE_POST_DIALOG_BROKER, DialogMsg, CreatePostDialogOutput}}; use lemmy_api_common::{community::GetCommunityResponse, lemmy_db_views::structs::PostView}; use relm4::{prelude::*, factory::FactoryVecDeque}; use gtk::prelude::*; @@ -11,13 +11,18 @@ use super::post_row::PostRow; pub struct CommunityPage { info: GetCommunityResponse, avatar: Controller, - posts: FactoryVecDeque + posts: FactoryVecDeque, + #[allow(dead_code)] + create_post_dialog: Controller } #[derive(Debug)] pub enum CommunityInput { UpdateCommunity(GetCommunityResponse), - DoneFetchPosts(Vec) + DoneFetchPosts(Vec), + OpenCreatePostDialog, + CreatePostRequest(String, String), + CreatedPost(PostView) } #[relm4::component(pub)] @@ -67,6 +72,12 @@ impl SimpleComponent for CommunityPage { #[watch] set_text: &format!("{} posts, {} comments", model.info.community_view.counts.posts, model.info.community_view.counts.comments), }, + + gtk::Button { + set_label: "Create post", + set_margin_start: 10, + connect_clicked => CommunityInput::OpenCreatePostDialog, + } }, gtk::Separator {}, @@ -87,7 +98,15 @@ impl SimpleComponent for CommunityPage { ) -> relm4::ComponentParts { let avatar = WebImage::builder().launch("".to_string()).detach(); let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender()); - let model = CommunityPage { info: init, avatar, posts }; + + let dialog = CreatePostDialog::builder() + .transient_for(root) + .launch_with_broker((), &CREATE_POST_DIALOG_BROKER) + .forward(sender.input_sender(), |msg| match msg { + CreatePostDialogOutput::CreatePostRequest(name, body) => CommunityInput::CreatePostRequest(name, body) + }); + + let model = CommunityPage { info: init, avatar, posts, create_post_dialog: dialog }; let avatar = model.avatar.widget(); let posts = model.posts.widget(); let widgets = view_output!(); @@ -115,6 +134,22 @@ impl SimpleComponent for CommunityPage { self.posts.guard().push_back(post); } } + CommunityInput::OpenCreatePostDialog => { + CREATE_POST_DIALOG_BROKER.send(DialogMsg::Show) + } + CommunityInput::CreatedPost(post) => { + self.posts.guard().push_front(post); + } + CommunityInput::CreatePostRequest(name, body) => { + let id = self.info.community_view.community.id.0.clone(); + std::thread::spawn(move || { + let message = match api::post::create_post(name, body, id) { + Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)), + Err(err) => { println!("{}", err.to_string()); None } + }; + if message.is_some() { sender.input(message.unwrap()) }; + }); + } } } } diff --git a/src/dialogs/create_post.rs b/src/dialogs/create_post.rs new file mode 100644 index 0000000..20e0868 --- /dev/null +++ b/src/dialogs/create_post.rs @@ -0,0 +1,111 @@ +use relm4::{prelude::*, MessageBroker}; +use gtk::prelude::*; + +pub static CREATE_POST_DIALOG_BROKER: MessageBroker = MessageBroker::new(); + +pub struct CreatePostDialog { + visible: bool, +} + +#[derive(Debug)] +pub enum DialogMsg { + Show, + Hide, + Okay(String, String) +} + +#[derive(Debug)] +pub enum CreatePostDialogOutput { + CreatePostRequest(String, String) +} + +#[relm4::component(pub)] +impl SimpleComponent for CreatePostDialog { + type Init = (); + type Input = DialogMsg; + type Output = CreatePostDialogOutput; + + view! { + dialog = gtk::Dialog { + #[watch] + set_visible: model.visible, + set_modal: true, + + #[wrap(Some)] + set_child = >k::Box { + set_orientation: gtk::Orientation::Vertical, + set_height_request: 400, + set_width_request: 600, + set_margin_all: 20, + + gtk::Label { + set_halign: gtk::Align::Center, + set_valign: gtk::Align::Center, + set_label: "Create post", + add_css_class: "font-bold" + }, + #[name(name)] + gtk::Entry { + set_placeholder_text: Some("Title"), + set_margin_top: 10, + set_margin_bottom: 10, + }, + gtk::Label { + set_text: "Body:", + }, + #[name(body)] + gtk::TextView { + set_editable: true, + set_margin_bottom: 10, + set_vexpand: true, + }, + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_halign: gtk::Align::End, + gtk::Button { + set_label: "Cancel", + set_margin_end: 10, + connect_clicked => DialogMsg::Hide, + }, + gtk::Button { + set_label: "Okay", + connect_clicked[sender, name, body] => move |_| { + let name = name.text().to_string(); + let body_buffer = body.buffer(); + let (start, end) = &body_buffer.bounds(); + let body = body_buffer.text(start, end, true).to_string(); + if name.is_empty() || body.is_empty() { return; } + sender.input(DialogMsg::Okay(name, body)) + }, + } + } + }, + + connect_close_request[sender] => move |_| { + sender.input(DialogMsg::Hide); + gtk::Inhibit(false) + } + } + } + + fn init( + _init: Self::Init, + root: &Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let model = CreatePostDialog { visible: false }; + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, msg: Self::Input, sender: ComponentSender) { + match msg { + DialogMsg::Show => self.visible = true, + DialogMsg::Hide => self.visible = false, + DialogMsg::Okay(name, body) => { + let _ = sender.output(CreatePostDialogOutput::CreatePostRequest(name, body)); + self.visible = false; + } + } + } +} \ No newline at end of file diff --git a/src/dialogs/mod.rs b/src/dialogs/mod.rs new file mode 100644 index 0000000..8cb9102 --- /dev/null +++ b/src/dialogs/mod.rs @@ -0,0 +1 @@ +pub mod create_post; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f6083c4..7d170f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ pub mod settings; pub mod api; pub mod components; pub mod util; +pub mod dialogs; use api::{user::default_person, community::default_community, post::default_post}; use components::{post_row::PostRow, community_row::CommunityRow, profile_page::{ProfilePage, self}, community_page::{CommunityPage, self}, post_page::{PostPage, self}};