Support for subscribing and unsubscribing communities

This commit is contained in:
Bnyro 2023-06-20 15:46:40 +02:00
parent 0417cea437
commit 99e122ed9a
3 changed files with 61 additions and 24 deletions

View File

@ -12,7 +12,7 @@ pub fn get_community(name: String) -> std::result::Result<GetCommunityResponse,
super::get("/community", &params) super::get("/community", &params)
} }
pub async fn follow_community( pub fn follow_community(
community_id: i32, community_id: i32,
follow: bool, follow: bool,
) -> Result<CommunityResponse, reqwest::Error> { ) -> Result<CommunityResponse, reqwest::Error> {

View File

@ -1,5 +1,5 @@
use crate::{util::markdown_to_pango_markup, dialogs::create_post::{CreatePostDialog, CREATE_POST_DIALOG_BROKER, DialogMsg, CreatePostDialogOutput, DialogType}}; 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::{lemmy_db_views::structs::PostView, lemmy_db_views_actor::structs::CommunityView, lemmy_db_schema::SubscribedType};
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;
@ -9,25 +9,27 @@ use crate::{api, util::get_web_image_msg};
use super::post_row::PostRow; use super::post_row::PostRow;
pub struct CommunityPage { pub struct CommunityPage {
info: GetCommunityResponse, info: CommunityView,
avatar: Controller<WebImage>, avatar: Controller<WebImage>,
posts: FactoryVecDeque<PostRow>, posts: FactoryVecDeque<PostRow>,
#[allow(dead_code)] #[allow(dead_code)]
create_post_dialog: Controller<CreatePostDialog> create_post_dialog: Controller<CreatePostDialog>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum CommunityInput { pub enum CommunityInput {
UpdateCommunity(GetCommunityResponse), UpdateCommunity(CommunityView),
DoneFetchPosts(Vec<PostView>), DoneFetchPosts(Vec<PostView>),
OpenCreatePostDialog, OpenCreatePostDialog,
CreatePostRequest(String, String), CreatePostRequest(String, String),
CreatedPost(PostView) CreatedPost(PostView),
ToggleSubscription,
UpdateSubscriptionState(SubscribedType)
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for CommunityPage { impl SimpleComponent for CommunityPage {
type Init = GetCommunityResponse; type Init = CommunityView;
type Input = CommunityInput; type Input = CommunityInput;
type Output = crate::AppMsg; type Output = crate::AppMsg;
@ -48,29 +50,47 @@ impl SimpleComponent for CommunityPage {
}, },
gtk::Label { gtk::Label {
#[watch] #[watch]
set_text: &model.info.community_view.community.name, set_text: &model.info.community.name,
add_css_class: "font-very-bold", add_css_class: "font-very-bold",
}, },
gtk::Label { gtk::Label {
#[watch] #[watch]
set_markup: &markdown_to_pango_markup(model.info.clone().community_view.community.description.unwrap_or("".to_string())), set_markup: &markdown_to_pango_markup(model.info.clone().community.description.unwrap_or("".to_string())),
set_use_markup: true, set_use_markup: true,
}, },
gtk::Label {
#[watch]
set_text: &format!("{} subscribers", model.info.community_view.counts.subscribers),
},
gtk::Box { gtk::Box {
set_orientation: gtk::Orientation::Horizontal, set_orientation: gtk::Orientation::Horizontal,
set_margin_top: 10,
set_margin_bottom: 10,
set_hexpand: false,
set_halign: gtk::Align::Center, set_halign: gtk::Align::Center,
set_margin_bottom: 10,
gtk::Label { gtk::Label {
#[watch] #[watch]
set_text: &format!("{} posts, {} comments", model.info.community_view.counts.posts, model.info.community_view.counts.comments), set_text: &format!("{} subscribers", model.info.counts.subscribers),
set_margin_end: 10,
},
match model.info.subscribed {
SubscribedType::Subscribed => {
gtk::Button {
set_label: "Unsubscribe",
connect_clicked => CommunityInput::ToggleSubscription,
}
}
SubscribedType::NotSubscribed => {
gtk::Button {
set_label: "Subscribe",
connect_clicked => CommunityInput::ToggleSubscription,
}
}
SubscribedType::Pending => {
gtk::Label {
set_label: "Subscription pending",
}
}
},
gtk::Label {
#[watch]
set_text: &format!("{} posts, {} comments", model.info.counts.posts, model.info.counts.comments),
set_margin_start: 10,
}, },
gtk::Button { gtk::Button {
@ -118,12 +138,12 @@ impl SimpleComponent for CommunityPage {
match message { match message {
CommunityInput::UpdateCommunity(community) => { CommunityInput::UpdateCommunity(community) => {
self.info = community.clone(); self.info = community.clone();
self.avatar.emit(get_web_image_msg(community.community_view.community.icon)); self.avatar.emit(get_web_image_msg(community.community.icon));
self.posts.guard().clear(); self.posts.guard().clear();
std::thread::spawn(move || { std::thread::spawn(move || {
if community.community_view.counts.posts == 0 { return; } if community.counts.posts == 0 { return; }
let community_posts = api::posts::list_posts(1, Some(community.community_view.community.name), None); let community_posts = api::posts::list_posts(1, Some(community.community.name), None);
if let Ok(community_posts) = community_posts { if let Ok(community_posts) = community_posts {
sender.input(CommunityInput::DoneFetchPosts(community_posts)); sender.input(CommunityInput::DoneFetchPosts(community_posts));
} }
@ -141,7 +161,7 @@ impl SimpleComponent for CommunityPage {
self.posts.guard().push_front(post); self.posts.guard().push_front(post);
} }
CommunityInput::CreatePostRequest(name, body) => { CommunityInput::CreatePostRequest(name, body) => {
let id = self.info.community_view.community.id.0.clone(); let id = self.info.community.id.0.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
let message = match api::post::create_post(name, body, id) { let message = match api::post::create_post(name, body, id) {
Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)), Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)),
@ -150,6 +170,23 @@ impl SimpleComponent for CommunityPage {
if message.is_some() { sender.input(message.unwrap()) }; if message.is_some() { sender.input(message.unwrap()) };
}); });
} }
CommunityInput::ToggleSubscription => {
let community_id = self.info.community.id.0;
let new_state = match self.info.subscribed {
SubscribedType::NotSubscribed => true,
_ => false
};
std::thread::spawn(move || {
let message = match api::community::follow_community(community_id, new_state) {
Ok(community) => Some(CommunityInput::UpdateSubscriptionState(community.community_view.subscribed)),
Err(err) => { println!("{}", err.to_string()); None }
};
if message.is_some() { sender.input(message.unwrap()) };
});
}
CommunityInput::UpdateSubscriptionState(state) => {
self.info.subscribed = state;
}
} }
} }
} }

View File

@ -272,7 +272,7 @@ impl SimpleComponent for App {
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()); let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
let communities = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()); let communities = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
let profile_page = ProfilePage::builder().launch(default_person()).forward(sender.input_sender(), |msg| msg); let profile_page = ProfilePage::builder().launch(default_person()).forward(sender.input_sender(), |msg| msg);
let community_page = CommunityPage::builder().launch(default_community()).forward(sender.input_sender(), |msg| msg); let community_page = CommunityPage::builder().launch(default_community().community_view).forward(sender.input_sender(), |msg| msg);
let post_page = PostPage::builder().launch(default_post()).forward(sender.input_sender(), |msg| msg); let post_page = PostPage::builder().launch(default_post()).forward(sender.input_sender(), |msg| msg);
let model = App { state, posts, communities, profile_page, community_page, post_page, message: None, latest_action: None }; let model = App { state, posts, communities, profile_page, community_page, post_page, message: None, latest_action: None };
@ -383,7 +383,7 @@ impl SimpleComponent for App {
}); });
} }
AppMsg::DoneFetchCommunity(community) => { AppMsg::DoneFetchCommunity(community) => {
self.community_page.sender().emit(community_page::CommunityInput::UpdateCommunity(community)); self.community_page.sender().emit(community_page::CommunityInput::UpdateCommunity(community.community_view));
self.state = AppState::Community; self.state = AppState::Community;
} }
AppMsg::OpenPost(post_id) => { AppMsg::OpenPost(post_id) => {