Support for commenting on posts

This commit is contained in:
Bnyro 2023-06-20 12:20:28 +02:00
parent 99f35bfe7a
commit 10b5059420
4 changed files with 99 additions and 29 deletions

View File

@ -1,17 +1,18 @@
use lemmy_api_common::{sensitive::Sensitive, comment::{CommentResponse, CreateComment}, lemmy_db_schema::newtypes::{PostId, CommentId}}; use lemmy_api_common::{comment::{CommentResponse, CreateComment}, lemmy_db_schema::newtypes::{PostId, CommentId}};
use crate::util;
pub fn create_comment( pub fn create_comment(
post_id: i32, post_id: i32,
content: String, content: String,
parent_id: Option<i32>, parent_id: Option<i32>,
auth: Sensitive<String>,
) -> Result<CommentResponse, reqwest::Error> { ) -> Result<CommentResponse, reqwest::Error> {
let params = CreateComment { let params = CreateComment {
post_id: PostId(post_id), post_id: PostId(post_id),
content, content,
parent_id: parent_id.map(CommentId), parent_id: parent_id.map(CommentId),
auth, auth: util::get_auth_token().unwrap(),
..Default::default() ..Default::default()
}; };
super::post("/comment", &params) super::post("/comment", &params)

View File

@ -1,4 +1,4 @@
use crate::{util::markdown_to_pango_markup, dialogs::create_post::{CreatePostDialog, CREATE_POST_DIALOG_BROKER, DialogMsg, CreatePostDialogOutput}}; use crate::{util::markdown_to_pango_markup, dialogs::create_post::{CreatePostDialog, CREATE_POST_DIALOG_BROKER, DialogMsg, CreatePostDialogOutput, DialogType}};
use lemmy_api_common::{community::GetCommunityResponse, lemmy_db_views::structs::PostView}; use lemmy_api_common::{community::GetCommunityResponse, lemmy_db_views::structs::PostView};
use relm4::{prelude::*, factory::FactoryVecDeque}; use relm4::{prelude::*, factory::FactoryVecDeque};
use gtk::prelude::*; use gtk::prelude::*;
@ -101,9 +101,9 @@ impl SimpleComponent for CommunityPage {
let dialog = CreatePostDialog::builder() let dialog = CreatePostDialog::builder()
.transient_for(root) .transient_for(root)
.launch_with_broker((), &CREATE_POST_DIALOG_BROKER) .launch_with_broker(DialogType::Post, &CREATE_POST_DIALOG_BROKER)
.forward(sender.input_sender(), |msg| match msg { .forward(sender.input_sender(), |msg| match msg {
CreatePostDialogOutput::CreatePostRequest(name, body) => CommunityInput::CreatePostRequest(name, body) CreatePostDialogOutput::CreateRequest(name, body) => CommunityInput::CreatePostRequest(name, body)
}); });
let model = CommunityPage { info: init, avatar, posts, create_post_dialog: dialog }; let model = CommunityPage { info: init, avatar, posts, create_post_dialog: dialog };

View File

@ -1,9 +1,9 @@
use lemmy_api_common::{lemmy_db_views::structs::{CommentView}, post::GetPostResponse}; use lemmy_api_common::{lemmy_db_views::structs::CommentView, post::GetPostResponse};
use relm4::{prelude::*, factory::FactoryVecDeque}; use relm4::{prelude::*, factory::FactoryVecDeque};
use gtk::prelude::*; use gtk::prelude::*;
use relm4_components::web_image::WebImage; use relm4_components::web_image::WebImage;
use crate::{api, util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup}}; use crate::{api, util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup}, dialogs::create_post::{CreatePostDialog, CreatePostDialogOutput, DialogMsg, CREATE_COMMENT_DIALOG_BROKER, DialogType}};
use super::comment_row::CommentRow; use super::comment_row::CommentRow;
@ -12,7 +12,9 @@ pub struct PostPage {
image: Controller<WebImage>, image: Controller<WebImage>,
creator_avatar: Controller<WebImage>, creator_avatar: Controller<WebImage>,
community_avatar: Controller<WebImage>, community_avatar: Controller<WebImage>,
comments: FactoryVecDeque<CommentRow> comments: FactoryVecDeque<CommentRow>,
#[allow(dead_code)]
create_comment_dialog: Controller<CreatePostDialog>
} }
#[derive(Debug)] #[derive(Debug)]
@ -21,7 +23,10 @@ pub enum PostInput {
DoneFetchComments(Vec<CommentView>), DoneFetchComments(Vec<CommentView>),
OpenPerson, OpenPerson,
OpenCommunity, OpenCommunity,
OpenLink OpenLink,
OpenCreateCommentDialog,
CreateCommentRequest(String),
CreatedComment(CommentView)
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -123,6 +128,12 @@ impl SimpleComponent for PostPage {
#[watch] #[watch]
set_text: &format!("{} score", model.info.post_view.counts.score), set_text: &format!("{} score", model.info.post_view.counts.score),
}, },
gtk::Button {
set_label: "Comment",
set_margin_start: 10,
connect_clicked => PostInput::OpenCreateCommentDialog,
}
}, },
gtk::Separator {}, gtk::Separator {},
@ -144,7 +155,13 @@ impl SimpleComponent for PostPage {
let comments = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender()); let comments = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
let creator_avatar = WebImage::builder().launch("".to_string()).detach(); let creator_avatar = WebImage::builder().launch("".to_string()).detach();
let community_avatar = WebImage::builder().launch("".to_string()).detach(); let community_avatar = WebImage::builder().launch("".to_string()).detach();
let model = PostPage { info: init, image, comments, creator_avatar, community_avatar }; let dialog = CreatePostDialog::builder()
.transient_for(root)
.launch_with_broker(DialogType::Comment, &CREATE_COMMENT_DIALOG_BROKER)
.forward(sender.input_sender(), |msg| match msg {
CreatePostDialogOutput::CreateRequest(_name, body) => PostInput::CreateCommentRequest(body)
});
let model = PostPage { info: init, image, comments, creator_avatar, community_avatar, create_comment_dialog: dialog, };
let image = model.image.widget(); let image = model.image.widget();
let comments = model.comments.widget(); let comments = model.comments.widget();
@ -199,6 +216,22 @@ impl SimpleComponent for PostPage {
if link.is_empty() { return; } if link.is_empty() { return; }
gtk::show_uri(None::<&relm4::gtk::Window>, &link, 0); gtk::show_uri(None::<&relm4::gtk::Window>, &link, 0);
} }
PostInput::OpenCreateCommentDialog => {
CREATE_COMMENT_DIALOG_BROKER.send(DialogMsg::Show)
}
PostInput::CreatedComment(comment) => {
self.comments.guard().push_front(comment);
}
PostInput::CreateCommentRequest(body) => {
let id = self.info.post_view.post.id.0;
std::thread::spawn(move || {
let message = match api::comment::create_comment(id, body, None) {
Ok(comment) => Some(PostInput::CreatedComment(comment.comment_view)),
Err(err) => { println!("{}", err.to_string()); None }
};
if message.is_some() { sender.input(message.unwrap()) };
});
}
} }
} }
} }

View File

@ -2,11 +2,20 @@ use relm4::{prelude::*, MessageBroker};
use gtk::prelude::*; use gtk::prelude::*;
pub static CREATE_POST_DIALOG_BROKER: MessageBroker<DialogMsg> = MessageBroker::new(); pub static CREATE_POST_DIALOG_BROKER: MessageBroker<DialogMsg> = MessageBroker::new();
pub static CREATE_COMMENT_DIALOG_BROKER: MessageBroker<DialogMsg> = MessageBroker::new();
pub struct CreatePostDialog { pub struct CreatePostDialog {
type_: DialogType,
visible: bool, visible: bool,
} }
#[derive(Debug, Clone, Copy)]
pub enum DialogType {
Post,
Comment
}
#[derive(Debug)] #[derive(Debug)]
pub enum DialogMsg { pub enum DialogMsg {
Show, Show,
@ -16,12 +25,12 @@ pub enum DialogMsg {
#[derive(Debug)] #[derive(Debug)]
pub enum CreatePostDialogOutput { pub enum CreatePostDialogOutput {
CreatePostRequest(String, String) CreateRequest(String, String)
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for CreatePostDialog { impl SimpleComponent for CreatePostDialog {
type Init = (); type Init = DialogType;
type Input = DialogMsg; type Input = DialogMsg;
type Output = CreatePostDialogOutput; type Output = CreatePostDialogOutput;
@ -38,24 +47,43 @@ impl SimpleComponent for CreatePostDialog {
set_width_request: 600, set_width_request: 600,
set_margin_all: 20, set_margin_all: 20,
gtk::Label { match model.type_ {
set_halign: gtk::Align::Center, DialogType::Post => {
set_valign: gtk::Align::Center, gtk::Box {
set_label: "Create post", set_orientation: gtk::Orientation::Vertical,
add_css_class: "font-bold" gtk::Label {
}, set_halign: gtk::Align::Center,
#[name(name)] set_valign: gtk::Align::Center,
gtk::Entry { set_label: "Create post",
set_placeholder_text: Some("Title"), add_css_class: "font-bold"
set_margin_top: 10, },
set_margin_bottom: 10, #[name(name)]
gtk::Entry {
set_placeholder_text: Some("Title"),
set_margin_top: 10,
set_margin_bottom: 10,
},
}
}
DialogType::Comment => {
gtk::Box {
gtk::Label {
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_label: "Create comment",
add_css_class: "font-bold"
},
}
}
}, },
gtk::Label { gtk::Label {
set_text: "Body:", set_text: "Body:",
set_halign: gtk::Align::Start,
}, },
#[name(body)] #[name(body)]
gtk::TextView { gtk::TextView {
set_editable: true, set_editable: true,
set_margin_top: 5,
set_margin_bottom: 10, set_margin_bottom: 10,
set_vexpand: true, set_vexpand: true,
}, },
@ -74,8 +102,16 @@ impl SimpleComponent for CreatePostDialog {
let body_buffer = body.buffer(); let body_buffer = body.buffer();
let (start, end) = &body_buffer.bounds(); let (start, end) = &body_buffer.bounds();
let body = body_buffer.text(start, end, true).to_string(); let body = body_buffer.text(start, end, true).to_string();
if name.is_empty() || body.is_empty() { return; } match model.type_ {
sender.input(DialogMsg::Okay(name, body)) DialogType::Post => {
if name.is_empty() || body.is_empty() { return; }
sender.input(DialogMsg::Okay(name, body))
}
DialogType::Comment => {
if name.is_empty() { return; }
sender.input(DialogMsg::Okay(name, body))
}
}
}, },
} }
} }
@ -89,11 +125,11 @@ impl SimpleComponent for CreatePostDialog {
} }
fn init( fn init(
_init: Self::Init, init: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = CreatePostDialog { visible: false }; let model = CreatePostDialog { type_: init, visible: false };
let widgets = view_output!(); let widgets = view_output!();
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }
@ -103,7 +139,7 @@ impl SimpleComponent for CreatePostDialog {
DialogMsg::Show => self.visible = true, DialogMsg::Show => self.visible = true,
DialogMsg::Hide => self.visible = false, DialogMsg::Hide => self.visible = false,
DialogMsg::Okay(name, body) => { DialogMsg::Okay(name, body) => {
let _ = sender.output(CreatePostDialogOutput::CreatePostRequest(name, body)); let _ = sender.output(CreatePostDialogOutput::CreateRequest(name, body));
self.visible = false; self.visible = false;
} }
} }