Move communities page into a separate component

This commit is contained in:
Bnyro 2023-07-01 11:31:25 +02:00
parent ae6bf45879
commit 0755f2a0de
3 changed files with 172 additions and 91 deletions

View File

@ -0,0 +1,152 @@
use gtk::prelude::*;
use lemmy_api_common::{
lemmy_db_schema::ListingType, lemmy_db_views_actor::structs::CommunityView,
};
use relm4::{factory::FactoryVecDeque, prelude::*};
use crate::api;
use super::community_row::CommunityRow;
pub struct CommunitiesPage {
communities: FactoryVecDeque<CommunityRow>,
communities_page: i64,
communities_type: ListingType,
community_search_buffer: gtk::EntryBuffer,
}
#[derive(Debug)]
pub enum CommunitiesPageInput {
DoneFetchCommunities(Vec<CommunityView>),
FetchCommunities(ListingType, bool),
}
#[relm4::component(pub)]
impl SimpleComponent for CommunitiesPage {
type Init = ();
type Input = CommunitiesPageInput;
type Output = crate::AppMsg;
view! {
gtk::Box {
gtk::ScrolledWindow {
set_vexpand: true,
set_hexpand: true,
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,
set_margin_all: 10,
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 10,
gtk::ToggleButton {
set_label: "All",
#[watch]
set_active: model.communities_type == ListingType::All,
connect_clicked => CommunitiesPageInput::FetchCommunities(ListingType::All, true),
},
gtk::ToggleButton {
set_label: "Local",
#[watch]
set_active: model.communities_type == ListingType::Local,
connect_clicked => CommunitiesPageInput::FetchCommunities(ListingType::Local, true),
},
gtk::ToggleButton {
set_label: "Subscribed",
#[watch]
set_active: model.communities_type == ListingType::Subscribed,
connect_clicked => CommunitiesPageInput::FetchCommunities(ListingType::Subscribed, true),
}
},
gtk::Box {
set_spacing: 10,
gtk::Entry {
set_hexpand: true,
set_tooltip_text: Some("Search"),
set_buffer: &model.community_search_buffer,
},
gtk::Button {
set_label: "Search",
connect_clicked => CommunitiesPageInput::FetchCommunities(model.communities_type, true),
}
},
#[local_ref]
communities_box -> gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
},
gtk::Button {
set_label: "More",
connect_clicked => CommunitiesPageInput::FetchCommunities(model.communities_type, false),
set_margin_top: 10,
set_margin_bottom: 10,
}
}
}
}
}
fn init(
_init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let communities = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
let community_search_buffer = gtk::EntryBuffer::builder().build();
let model = CommunitiesPage {
communities,
community_search_buffer,
communities_page: 1,
communities_type: ListingType::Local,
};
let communities_box = model.communities.widget();
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
match message {
CommunitiesPageInput::FetchCommunities(listing_type, remove_previous) => {
let query_text = self.community_search_buffer.text().as_str().to_owned();
let query = if query_text.is_empty() {
None
} else {
Some(query_text)
};
let page = if remove_previous {
1
} else {
self.communities_page + 1
};
self.communities_page = page;
self.communities_type = listing_type;
std::thread::spawn(move || {
match api::communities::fetch_communities(page, query, Some(listing_type)) {
Ok(communities) => {
sender.input(CommunitiesPageInput::DoneFetchCommunities(communities));
}
Err(err) => {
let _ = sender.output(crate::AppMsg::ShowMessage(err.to_string()));
}
};
});
}
CommunitiesPageInput::DoneFetchCommunities(communities) => {
if self.communities_page == 1 {
self.communities.guard().clear();
}
for community in communities {
self.communities.guard().push_back(community);
}
}
}
}
}

View File

@ -1,4 +1,5 @@
pub mod comment_row; pub mod comment_row;
pub mod communities_page;
pub mod community_page; pub mod community_page;
pub mod community_row; pub mod community_row;
pub mod inbox_page; pub mod inbox_page;

View File

@ -7,8 +7,8 @@ pub mod util;
use api::{community::default_community, post::default_post, user::default_person}; use api::{community::default_community, post::default_post, user::default_person};
use components::{ use components::{
communities_page::{CommunitiesPage, CommunitiesPageInput},
community_page::{self, CommunityPage}, community_page::{self, CommunityPage},
community_row::CommunityRow,
inbox_page::{InboxInput, InboxPage}, inbox_page::{InboxInput, InboxPage},
instances_page::{InstancePageInput, InstancesPage}, instances_page::{InstancePageInput, InstancesPage},
post_page::{self, PostPage}, post_page::{self, PostPage},
@ -24,7 +24,6 @@ use lemmy_api_common::{
ListingType, ListingType,
}, },
lemmy_db_views::structs::PostView, lemmy_db_views::structs::PostView,
lemmy_db_views_actor::structs::CommunityView,
person::GetPersonDetailsResponse, person::GetPersonDetailsResponse,
post::GetPostResponse, post::GetPostResponse,
}; };
@ -55,18 +54,15 @@ struct App {
message: Option<String>, message: Option<String>,
back_queue: Vec<AppMsg>, back_queue: Vec<AppMsg>,
posts: FactoryVecDeque<PostRow>, posts: FactoryVecDeque<PostRow>,
communities: FactoryVecDeque<CommunityRow>,
instances_page: Controller<InstancesPage>, instances_page: Controller<InstancesPage>,
profile_page: Controller<ProfilePage>, profile_page: Controller<ProfilePage>,
community_page: Controller<CommunityPage>, community_page: Controller<CommunityPage>,
communities_page: Controller<CommunitiesPage>,
post_page: Controller<PostPage>, post_page: Controller<PostPage>,
inbox_page: Controller<InboxPage>, inbox_page: Controller<InboxPage>,
logged_in: bool, logged_in: bool,
current_communities_type: Option<ListingType>,
current_posts_type: Option<ListingType>, current_posts_type: Option<ListingType>,
current_communities_page: i64,
current_posts_page: i64, current_posts_page: i64,
community_search_buffer: gtk::EntryBuffer,
about_dialog: Controller<AboutDialog>, about_dialog: Controller<AboutDialog>,
} }
@ -81,8 +77,6 @@ pub enum AppMsg {
DoneChoosingInstance(String), DoneChoosingInstance(String),
StartFetchPosts(Option<ListingType>, bool), StartFetchPosts(Option<ListingType>, bool),
DoneFetchPosts(Vec<PostView>), DoneFetchPosts(Vec<PostView>),
DoneFetchCommunities(Vec<CommunityView>),
FetchCommunities(Option<ListingType>, bool),
OpenCommunity(CommunityId), OpenCommunity(CommunityId),
DoneFetchCommunity(GetCommunityResponse), DoneFetchCommunity(GetCommunityResponse),
OpenPerson(PersonId), OpenPerson(PersonId),
@ -90,6 +84,7 @@ pub enum AppMsg {
OpenPost(PostId), OpenPost(PostId),
DoneFetchPost(GetPostResponse), DoneFetchPost(GetPostResponse),
OpenInbox, OpenInbox,
OpenCommunities,
PopBackStack, PopBackStack,
ShowAbout, ShowAbout,
} }
@ -124,7 +119,7 @@ impl SimpleComponent for App {
}, },
pack_start = &gtk::Button { pack_start = &gtk::Button {
set_label: "Communities", set_label: "Communities",
connect_clicked => AppMsg::FetchCommunities(None, true), connect_clicked => AppMsg::OpenCommunities,
}, },
pack_start = &gtk::Button { pack_start = &gtk::Button {
set_label: "Recommended", set_label: "Recommended",
@ -132,12 +127,6 @@ impl SimpleComponent for App {
#[watch] #[watch]
set_visible: model.logged_in, set_visible: model.logged_in,
}, },
pack_start = &gtk::Button {
set_label: "Joined",
connect_clicked => AppMsg::FetchCommunities(Some(ListingType::Subscribed), true),
#[watch]
set_visible: model.logged_in,
},
pack_start = &gtk::Button { pack_start = &gtk::Button {
set_label: "Inbox", set_label: "Inbox",
connect_clicked => AppMsg::OpenInbox, connect_clicked => AppMsg::OpenInbox,
@ -233,42 +222,8 @@ impl SimpleComponent for App {
} }
}, },
AppState::Communities => gtk::Box { AppState::Communities => gtk::Box {
gtk::ScrolledWindow { #[local_ref]
set_vexpand: true, communities_page -> gtk::Box {}
set_hexpand: true,
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,
gtk::Box {
set_margin_all: 10,
gtk::Entry {
set_hexpand: true,
set_tooltip_text: Some("Search"),
set_margin_end: 10,
set_buffer: &model.community_search_buffer,
},
gtk::Button {
set_label: "Search",
connect_clicked => AppMsg::FetchCommunities(model.current_communities_type, true),
}
},
#[local_ref]
communities_box -> gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
},
gtk::Button {
set_label: "More",
connect_clicked => AppMsg::FetchCommunities(model.current_communities_type, false),
set_margin_all: 10,
}
}
}
} }
AppState::Person => { AppState::Person => {
@ -340,7 +295,6 @@ impl SimpleComponent for App {
// initialize all controllers and factories // initialize all controllers and factories
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 instances_page = InstancesPage::builder() let instances_page = InstancesPage::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |msg| msg); .forward(sender.input_sender(), |msg| msg);
@ -356,7 +310,9 @@ impl SimpleComponent for App {
let inbox_page = InboxPage::builder() let inbox_page = InboxPage::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |msg| msg); .forward(sender.input_sender(), |msg| msg);
let community_search_buffer = gtk::EntryBuffer::builder().build(); let communities_page = CommunitiesPage::builder()
.launch(())
.forward(sender.input_sender(), |msg| msg);
let about_dialog = AboutDialog::builder() let about_dialog = AboutDialog::builder()
.launch(root.toplevel_window().unwrap()) .launch(root.toplevel_window().unwrap())
.detach(); .detach();
@ -366,18 +322,15 @@ impl SimpleComponent for App {
back_queue: vec![], back_queue: vec![],
logged_in, logged_in,
posts, posts,
communities,
instances_page, instances_page,
profile_page, profile_page,
community_page, community_page,
post_page, post_page,
inbox_page, inbox_page,
communities_page,
message: None, message: None,
current_communities_type: None,
current_posts_type: None, current_posts_type: None,
current_communities_page: 1,
current_posts_page: 1, current_posts_page: 1,
community_search_buffer,
about_dialog, about_dialog,
}; };
@ -388,12 +341,12 @@ impl SimpleComponent for App {
// setup all widgets and different stack pages // setup all widgets and different stack pages
let posts_box = model.posts.widget(); let posts_box = model.posts.widget();
let communities_box = model.communities.widget();
let instances_page = model.instances_page.widget(); let instances_page = model.instances_page.widget();
let profile_page = model.profile_page.widget(); let profile_page = model.profile_page.widget();
let community_page = model.community_page.widget(); let community_page = model.community_page.widget();
let post_page = model.post_page.widget(); let post_page = model.post_page.widget();
let inbox_page = model.inbox_page.widget(); let inbox_page = model.inbox_page.widget();
let communities_page = model.communities_page.widget();
let widgets = view_output!(); let widgets = view_output!();
@ -438,7 +391,7 @@ impl SimpleComponent for App {
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) { fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
// save the back queue // save the back queue
match msg { match msg {
AppMsg::DoneFetchCommunities(_) AppMsg::OpenCommunities
| AppMsg::DoneFetchCommunity(_) | AppMsg::DoneFetchCommunity(_)
| AppMsg::DoneFetchPerson(_) | AppMsg::DoneFetchPerson(_)
| AppMsg::DoneFetchPost(_) | AppMsg::DoneFetchPost(_)
@ -506,39 +459,14 @@ impl SimpleComponent for App {
self.posts.guard().push_back(post); self.posts.guard().push_back(post);
} }
} }
AppMsg::FetchCommunities(listing_type, remove_previous) => { AppMsg::OpenCommunities => {
let query_text = self.community_search_buffer.text().as_str().to_owned();
let query = if query_text.is_empty() {
None
} else {
Some(query_text)
};
self.state = AppState::Communities; self.state = AppState::Communities;
let page = if remove_previous { self.communities_page
1 .sender()
} else { .emit(CommunitiesPageInput::FetchCommunities(
self.current_communities_page + 1 ListingType::Local,
}; true,
self.current_communities_page = page; ));
self.current_communities_type = listing_type;
std::thread::spawn(move || {
let message =
match api::communities::fetch_communities(page, query, listing_type) {
Ok(communities) => AppMsg::DoneFetchCommunities(communities),
Err(err) => AppMsg::ShowMessage(err.to_string()),
};
sender.input(message);
});
}
AppMsg::DoneFetchCommunities(communities) => {
self.state = AppState::Communities;
if self.current_communities_page == 1 {
self.communities.guard().clear();
}
for community in communities {
self.communities.guard().push_back(community);
}
} }
AppMsg::OpenPerson(person_id) => { AppMsg::OpenPerson(person_id) => {
self.state = AppState::Loading; self.state = AppState::Loading;