From 0755f2a0de408ef66c7b8bfe794a528a1ef5474e Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 1 Jul 2023 11:31:25 +0200 Subject: [PATCH] Move communities page into a separate component --- src/components/communities_page.rs | 152 +++++++++++++++++++++++++++++ src/components/mod.rs | 1 + src/main.rs | 110 ++++----------------- 3 files changed, 172 insertions(+), 91 deletions(-) create mode 100644 src/components/communities_page.rs diff --git a/src/components/communities_page.rs b/src/components/communities_page.rs new file mode 100644 index 0000000..48097f1 --- /dev/null +++ b/src/components/communities_page.rs @@ -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, + communities_page: i64, + communities_type: ListingType, + community_search_buffer: gtk::EntryBuffer, +} + +#[derive(Debug)] +pub enum CommunitiesPageInput { + DoneFetchCommunities(Vec), + 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, + ) -> ComponentParts { + 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) { + 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); + } + } + } + } +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 4c624c5..76f8966 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,4 +1,5 @@ pub mod comment_row; +pub mod communities_page; pub mod community_page; pub mod community_row; pub mod inbox_page; diff --git a/src/main.rs b/src/main.rs index 053ea17..1516cf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ pub mod util; use api::{community::default_community, post::default_post, user::default_person}; use components::{ + communities_page::{CommunitiesPage, CommunitiesPageInput}, community_page::{self, CommunityPage}, - community_row::CommunityRow, inbox_page::{InboxInput, InboxPage}, instances_page::{InstancePageInput, InstancesPage}, post_page::{self, PostPage}, @@ -24,7 +24,6 @@ use lemmy_api_common::{ ListingType, }, lemmy_db_views::structs::PostView, - lemmy_db_views_actor::structs::CommunityView, person::GetPersonDetailsResponse, post::GetPostResponse, }; @@ -55,18 +54,15 @@ struct App { message: Option, back_queue: Vec, posts: FactoryVecDeque, - communities: FactoryVecDeque, instances_page: Controller, profile_page: Controller, community_page: Controller, + communities_page: Controller, post_page: Controller, inbox_page: Controller, logged_in: bool, - current_communities_type: Option, current_posts_type: Option, - current_communities_page: i64, current_posts_page: i64, - community_search_buffer: gtk::EntryBuffer, about_dialog: Controller, } @@ -81,8 +77,6 @@ pub enum AppMsg { DoneChoosingInstance(String), StartFetchPosts(Option, bool), DoneFetchPosts(Vec), - DoneFetchCommunities(Vec), - FetchCommunities(Option, bool), OpenCommunity(CommunityId), DoneFetchCommunity(GetCommunityResponse), OpenPerson(PersonId), @@ -90,6 +84,7 @@ pub enum AppMsg { OpenPost(PostId), DoneFetchPost(GetPostResponse), OpenInbox, + OpenCommunities, PopBackStack, ShowAbout, } @@ -124,7 +119,7 @@ impl SimpleComponent for App { }, pack_start = >k::Button { set_label: "Communities", - connect_clicked => AppMsg::FetchCommunities(None, true), + connect_clicked => AppMsg::OpenCommunities, }, pack_start = >k::Button { set_label: "Recommended", @@ -132,12 +127,6 @@ impl SimpleComponent for App { #[watch] set_visible: model.logged_in, }, - pack_start = >k::Button { - set_label: "Joined", - connect_clicked => AppMsg::FetchCommunities(Some(ListingType::Subscribed), true), - #[watch] - set_visible: model.logged_in, - }, pack_start = >k::Button { set_label: "Inbox", connect_clicked => AppMsg::OpenInbox, @@ -233,42 +222,8 @@ impl SimpleComponent for App { } }, AppState::Communities => gtk::Box { - gtk::ScrolledWindow { - set_vexpand: true, - 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, - } - } - } + #[local_ref] + communities_page -> gtk::Box {} } AppState::Person => { @@ -340,7 +295,6 @@ impl SimpleComponent for App { // initialize all controllers and factories 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() .launch(()) .forward(sender.input_sender(), |msg| msg); @@ -356,7 +310,9 @@ impl SimpleComponent for App { let inbox_page = InboxPage::builder() .launch(()) .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() .launch(root.toplevel_window().unwrap()) .detach(); @@ -366,18 +322,15 @@ impl SimpleComponent for App { back_queue: vec![], logged_in, posts, - communities, instances_page, profile_page, community_page, post_page, inbox_page, + communities_page, message: None, - current_communities_type: None, current_posts_type: None, - current_communities_page: 1, current_posts_page: 1, - community_search_buffer, about_dialog, }; @@ -388,12 +341,12 @@ impl SimpleComponent for App { // setup all widgets and different stack pages let posts_box = model.posts.widget(); - let communities_box = model.communities.widget(); let instances_page = model.instances_page.widget(); let profile_page = model.profile_page.widget(); let community_page = model.community_page.widget(); let post_page = model.post_page.widget(); let inbox_page = model.inbox_page.widget(); + let communities_page = model.communities_page.widget(); let widgets = view_output!(); @@ -438,7 +391,7 @@ impl SimpleComponent for App { fn update(&mut self, msg: Self::Input, sender: ComponentSender) { // save the back queue match msg { - AppMsg::DoneFetchCommunities(_) + AppMsg::OpenCommunities | AppMsg::DoneFetchCommunity(_) | AppMsg::DoneFetchPerson(_) | AppMsg::DoneFetchPost(_) @@ -506,39 +459,14 @@ impl SimpleComponent for App { self.posts.guard().push_back(post); } } - AppMsg::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) - }; + AppMsg::OpenCommunities => { self.state = AppState::Communities; - let page = if remove_previous { - 1 - } else { - self.current_communities_page + 1 - }; - 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); - } + self.communities_page + .sender() + .emit(CommunitiesPageInput::FetchCommunities( + ListingType::Local, + true, + )); } AppMsg::OpenPerson(person_id) => { self.state = AppState::Loading;