Support for creating posts

This commit is contained in:
Bnyro 2023-06-20 11:52:17 +02:00
parent 98b621929a
commit 99f35bfe7a
5 changed files with 156 additions and 7 deletions

View File

@ -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<GetPostResponse, reqwest::Error> { pub fn get_post(id: PostId) -> std::result::Result<GetPostResponse, reqwest::Error> {
let params = GetPost { let params = GetPost {
@ -33,13 +35,12 @@ pub fn create_post(
name: String, name: String,
body: String, body: String,
community_id: i32, community_id: i32,
auth: Sensitive<String>,
) -> Result<PostResponse, reqwest::Error> { ) -> Result<PostResponse, reqwest::Error> {
let params = CreatePost { let params = CreatePost {
name, name,
body: Some(body), body: Some(body),
community_id: CommunityId(community_id), community_id: CommunityId(community_id),
auth, auth: util::get_auth_token().unwrap(),
..Default::default() ..Default::default()
}; };
super::post("/post", &params) super::post("/post", &params)

View File

@ -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 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::*;
@ -11,13 +11,18 @@ use super::post_row::PostRow;
pub struct CommunityPage { pub struct CommunityPage {
info: GetCommunityResponse, info: GetCommunityResponse,
avatar: Controller<WebImage>, avatar: Controller<WebImage>,
posts: FactoryVecDeque<PostRow> posts: FactoryVecDeque<PostRow>,
#[allow(dead_code)]
create_post_dialog: Controller<CreatePostDialog>
} }
#[derive(Debug)] #[derive(Debug)]
pub enum CommunityInput { pub enum CommunityInput {
UpdateCommunity(GetCommunityResponse), UpdateCommunity(GetCommunityResponse),
DoneFetchPosts(Vec<PostView>) DoneFetchPosts(Vec<PostView>),
OpenCreatePostDialog,
CreatePostRequest(String, String),
CreatedPost(PostView)
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -67,6 +72,12 @@ impl SimpleComponent for CommunityPage {
#[watch] #[watch]
set_text: &format!("{} posts, {} comments", model.info.community_view.counts.posts, model.info.community_view.counts.comments), 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 {}, gtk::Separator {},
@ -87,7 +98,15 @@ impl SimpleComponent for CommunityPage {
) -> relm4::ComponentParts<Self> { ) -> relm4::ComponentParts<Self> {
let avatar = WebImage::builder().launch("".to_string()).detach(); let avatar = WebImage::builder().launch("".to_string()).detach();
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender()); 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 avatar = model.avatar.widget();
let posts = model.posts.widget(); let posts = model.posts.widget();
let widgets = view_output!(); let widgets = view_output!();
@ -115,6 +134,22 @@ impl SimpleComponent for CommunityPage {
self.posts.guard().push_back(post); 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()) };
});
}
} }
} }
} }

111
src/dialogs/create_post.rs Normal file
View File

@ -0,0 +1,111 @@
use relm4::{prelude::*, MessageBroker};
use gtk::prelude::*;
pub static CREATE_POST_DIALOG_BROKER: MessageBroker<DialogMsg> = 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 = &gtk::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<Self>,
) -> ComponentParts<Self> {
let model = CreatePostDialog { visible: false };
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
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;
}
}
}
}

1
src/dialogs/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod create_post;

View File

@ -2,6 +2,7 @@ pub mod settings;
pub mod api; pub mod api;
pub mod components; pub mod components;
pub mod util; pub mod util;
pub mod dialogs;
use api::{user::default_person, community::default_community, post::default_post}; 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}}; use components::{post_row::PostRow, community_row::CommunityRow, profile_page::{ProfilePage, self}, community_page::{CommunityPage, self}, post_page::{PostPage, self}};