198 lines
7.6 KiB
Rust
198 lines
7.6 KiB
Rust
use crate::{util::markdown_to_pango_markup, dialogs::editor::{EditorDialog, DialogMsg, EditorOutput, DialogType, EditorData}};
|
|
use lemmy_api_common::{lemmy_db_views::structs::PostView, lemmy_db_views_actor::structs::CommunityView, lemmy_db_schema::SubscribedType};
|
|
use relm4::{prelude::*, factory::FactoryVecDeque, MessageBroker};
|
|
use gtk::prelude::*;
|
|
use relm4_components::web_image::WebImage;
|
|
|
|
use crate::{api, util::get_web_image_msg};
|
|
|
|
use super::post_row::PostRow;
|
|
|
|
static COMMUNITY_PAGE_BROKER: MessageBroker<DialogMsg> = MessageBroker::new();
|
|
|
|
pub struct CommunityPage {
|
|
info: CommunityView,
|
|
avatar: Controller<WebImage>,
|
|
posts: FactoryVecDeque<PostRow>,
|
|
#[allow(dead_code)]
|
|
create_post_dialog: Controller<EditorDialog>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum CommunityInput {
|
|
UpdateCommunity(CommunityView),
|
|
DoneFetchPosts(Vec<PostView>),
|
|
OpenCreatePostDialog,
|
|
CreatePostRequest(EditorData),
|
|
CreatedPost(PostView),
|
|
ToggleSubscription,
|
|
UpdateSubscriptionState(SubscribedType),
|
|
None
|
|
}
|
|
|
|
#[relm4::component(pub)]
|
|
impl SimpleComponent for CommunityPage {
|
|
type Init = CommunityView;
|
|
type Input = CommunityInput;
|
|
type Output = crate::AppMsg;
|
|
|
|
view! {
|
|
gtk::ScrolledWindow {
|
|
set_vexpand: false,
|
|
|
|
gtk::Box {
|
|
set_orientation: gtk::Orientation::Vertical,
|
|
set_vexpand: false,
|
|
set_margin_all: 10,
|
|
|
|
#[local_ref]
|
|
avatar -> gtk::Box {
|
|
set_size_request: (100, 100),
|
|
set_margin_bottom: 20,
|
|
set_margin_top: 20,
|
|
},
|
|
gtk::Label {
|
|
#[watch]
|
|
set_text: &model.info.community.name,
|
|
add_css_class: "font-very-bold",
|
|
},
|
|
gtk::Label {
|
|
#[watch]
|
|
set_markup: &markdown_to_pango_markup(model.info.clone().community.description.unwrap_or("".to_string())),
|
|
set_use_markup: true,
|
|
},
|
|
gtk::Box {
|
|
set_orientation: gtk::Orientation::Horizontal,
|
|
set_halign: gtk::Align::Center,
|
|
set_margin_bottom: 10,
|
|
|
|
gtk::Label {
|
|
#[watch]
|
|
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 {
|
|
set_label: "Create post",
|
|
set_margin_start: 10,
|
|
connect_clicked => CommunityInput::OpenCreatePostDialog,
|
|
}
|
|
},
|
|
|
|
gtk::Separator {},
|
|
|
|
#[local_ref]
|
|
posts -> gtk::Box {
|
|
set_orientation: gtk::Orientation::Vertical,
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
fn init(
|
|
init: Self::Init,
|
|
root: &Self::Root,
|
|
sender: relm4::ComponentSender<Self>,
|
|
) -> relm4::ComponentParts<Self> {
|
|
let avatar = WebImage::builder().launch("".to_string()).detach();
|
|
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
|
|
|
|
let dialog = EditorDialog::builder()
|
|
.transient_for(root)
|
|
.launch_with_broker(DialogType::Post, &COMMUNITY_PAGE_BROKER)
|
|
.forward(sender.input_sender(), |msg| match msg {
|
|
EditorOutput::CreateRequest(post) => CommunityInput::CreatePostRequest(post),
|
|
_ => CommunityInput::None
|
|
});
|
|
|
|
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!();
|
|
|
|
ComponentParts { model, widgets }
|
|
}
|
|
|
|
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
|
match message {
|
|
CommunityInput::UpdateCommunity(community) => {
|
|
self.info = community.clone();
|
|
self.avatar.emit(get_web_image_msg(community.community.icon));
|
|
self.posts.guard().clear();
|
|
|
|
std::thread::spawn(move || {
|
|
if community.counts.posts == 0 { return; }
|
|
let community_posts = api::posts::list_posts(1, Some(community.community.name), None);
|
|
if let Ok(community_posts) = community_posts {
|
|
sender.input(CommunityInput::DoneFetchPosts(community_posts));
|
|
}
|
|
});
|
|
}
|
|
CommunityInput::DoneFetchPosts(posts) => {
|
|
for post in posts {
|
|
self.posts.guard().push_back(post);
|
|
}
|
|
}
|
|
CommunityInput::OpenCreatePostDialog => {
|
|
COMMUNITY_PAGE_BROKER.send(DialogMsg::Show)
|
|
}
|
|
CommunityInput::CreatedPost(post) => {
|
|
self.posts.guard().push_front(post);
|
|
}
|
|
CommunityInput::CreatePostRequest(post) => {
|
|
let id = self.info.community.id.0.clone();
|
|
std::thread::spawn(move || {
|
|
let message = match api::post::create_post(post.name, post.body, post.url, id) {
|
|
Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)),
|
|
Err(err) => { println!("{}", err.to_string()); None }
|
|
};
|
|
if let Some(message) = message { sender.input(message) };
|
|
});
|
|
}
|
|
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;
|
|
}
|
|
CommunityInput::None => {}
|
|
}
|
|
}
|
|
}
|