From 6266004dcb1ec06b66632fa92529789497227531 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Thu, 6 Jul 2023 15:21:16 +0200 Subject: [PATCH] refactor posts/home page --- src/components/comment_row.rs | 4 +- src/components/instances_page.rs | 2 +- src/components/login_page.rs | 4 +- src/components/mod.rs | 1 + src/components/post_page.rs | 4 +- src/components/post_row.rs | 4 +- src/components/posts_page.rs | 128 +++++++++++++++++++++++++++++++ src/main.rs | 93 +++++----------------- 8 files changed, 155 insertions(+), 85 deletions(-) create mode 100644 src/components/posts_page.rs diff --git a/src/components/comment_row.rs b/src/components/comment_row.rs index 3366f56..351f185 100644 --- a/src/components/comment_row.rs +++ b/src/components/comment_row.rs @@ -164,9 +164,7 @@ impl FactoryComponent for CommentRow { let comment_id = self.comment.comment.id; std::thread::spawn(move || { let _ = api::comment::delete_comment(comment_id); - sender - .output_sender() - .emit(crate::AppMsg::StartFetchPosts(None, true)); + sender.output_sender().emit(crate::AppMsg::OpenPosts); }); } CommentRowMsg::OpenEditor(is_new) => { diff --git a/src/components/instances_page.rs b/src/components/instances_page.rs index 1d00d79..d013c7c 100644 --- a/src/components/instances_page.rs +++ b/src/components/instances_page.rs @@ -128,7 +128,7 @@ impl SimpleComponent for InstancesPage { current_account.instance_url = url[0..url.len() - 1].to_string(); current_account.jwt = None; settings::update_current_account(current_account); - crate::AppMsg::StartFetchPosts(None, true) + crate::AppMsg::OpenPosts } Err(err) => crate::AppMsg::ShowMessage(err.to_string()), }; diff --git a/src/components/login_page.rs b/src/components/login_page.rs index 5776ffc..f612be1 100644 --- a/src/components/login_page.rs +++ b/src/components/login_page.rs @@ -119,9 +119,7 @@ impl SimpleComponent for LoginPage { }); } LoginPageInput::Cancel => { - sender - .output_sender() - .emit(crate::AppMsg::StartFetchPosts(None, true)); + sender.output_sender().emit(crate::AppMsg::OpenPosts); } } } diff --git a/src/components/mod.rs b/src/components/mod.rs index c6cb1cb..227c08f 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -10,6 +10,7 @@ pub mod mention_row; pub mod moderates_row; pub mod post_page; pub mod post_row; +pub mod posts_page; pub mod private_message_row; pub mod profile_page; pub mod voting_row; diff --git a/src/components/post_page.rs b/src/components/post_page.rs index b651afc..9c44f5f 100644 --- a/src/components/post_page.rs +++ b/src/components/post_page.rs @@ -316,9 +316,7 @@ impl SimpleComponent for PostPage { let post_id = self.info.post_view.post.id; std::thread::spawn(move || { let _ = api::post::delete_post(post_id); - sender - .output_sender() - .emit(crate::AppMsg::StartFetchPosts(None, true)); + sender.output_sender().emit(crate::AppMsg::OpenPosts); }); } PostPageInput::OpenEditPostDialog => { diff --git a/src/components/post_row.rs b/src/components/post_row.rs index 10840d4..454e4e0 100644 --- a/src/components/post_row.rs +++ b/src/components/post_row.rs @@ -165,9 +165,7 @@ impl FactoryComponent for PostRow { let post_id = self.post.post.id; std::thread::spawn(move || { let _ = api::post::delete_post(post_id); - sender - .output_sender() - .emit(crate::AppMsg::StartFetchPosts(None, true)); + sender.output_sender().emit(crate::AppMsg::OpenPosts); }); } } diff --git a/src/components/posts_page.rs b/src/components/posts_page.rs new file mode 100644 index 0000000..69a77a2 --- /dev/null +++ b/src/components/posts_page.rs @@ -0,0 +1,128 @@ +use gtk::prelude::*; +use lemmy_api_common::{lemmy_db_schema::ListingType, lemmy_db_views::structs::PostView}; +use relm4::{factory::FactoryVecDeque, prelude::*}; + +use crate::api; + +use super::post_row::PostRow; + +pub struct PostsPage { + posts: FactoryVecDeque, + posts_type: ListingType, + posts_page: i64, +} + +#[derive(Debug)] +pub enum PostsPageInput { + FetchPosts(ListingType, bool), + DoneFetchPosts(Vec), +} + +#[relm4::component(pub)] +impl SimpleComponent for PostsPage { + type Init = (); + type Input = PostsPageInput; + type Output = crate::AppMsg; + + view! { + gtk::ScrolledWindow { + set_hexpand: true, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 10, + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + + gtk::ToggleButton { + set_label: "All", + #[watch] + set_active: model.posts_type == ListingType::All, + connect_clicked => PostsPageInput::FetchPosts(ListingType::All, true), + }, + gtk::ToggleButton { + set_label: "Local", + #[watch] + set_active: model.posts_type ==ListingType::Local, + connect_clicked => PostsPageInput::FetchPosts(ListingType::Local, true), + }, + gtk::ToggleButton { + set_label: "Subscribed", + #[watch] + set_active: model.posts_type == ListingType::Subscribed, + connect_clicked => PostsPageInput::FetchPosts(ListingType::Subscribed, true), + } + }, + #[local_ref] + posts_box -> gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + }, + gtk::Button { + set_label: "More", + connect_clicked => PostsPageInput::FetchPosts(model.posts_type, false), + set_margin_all: 10, + } + } + } + } + + fn init( + _init: Self::Init, + root: &Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender()); + let model = Self { + posts, + posts_type: ListingType::Subscribed, + posts_page: 1, + }; + let posts_box = model.posts.widget(); + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + match message { + PostsPageInput::FetchPosts(type_, remove_previous) => { + self.posts_type = type_; + let page = if remove_previous { + 1 + } else { + self.posts_page + 1 + }; + // show the loading indicator if it's the first page + if page == 1 { + sender + .output_sender() + .emit(crate::AppMsg::UpdateState(crate::AppState::Loading)); + } + self.posts_page = page; + std::thread::spawn(move || { + match api::posts::list_posts(page, None, Some(type_)) { + Ok(posts) => { + sender.input(PostsPageInput::DoneFetchPosts(posts)); + } + Err(err) => sender + .output_sender() + .emit(crate::AppMsg::ShowMessage(err.to_string())), + }; + }); + } + PostsPageInput::DoneFetchPosts(posts) => { + sender + .output_sender() + .emit(crate::AppMsg::UpdateState(crate::AppState::Posts)); + if self.posts_page == 1 { + self.posts.guard().clear(); + } + for post in posts { + self.posts.guard().push_back(post); + } + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 5011dd2..3853284 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use components::{ inbox_page::{InboxInput, InboxPage}, instances_page::{InstancesPage, InstancesPageInput}, post_page::{self, PostPage}, - post_row::PostRow, + posts_page::{PostsPage, PostsPageInput}, profile_page::{ProfileInput, ProfilePage}, }; use dialogs::about::AboutDialog; @@ -23,12 +23,10 @@ use lemmy_api_common::{ newtypes::{CommunityId, PersonId, PostId}, ListingType, }, - lemmy_db_views::structs::PostView, post::GetPostResponse, }; use relm4::{ actions::{RelmAction, RelmActionGroup}, - factory::FactoryVecDeque, prelude::*, set_global_css, }; @@ -53,8 +51,8 @@ struct App { state: AppState, message: Option, back_queue: Vec, - posts: FactoryVecDeque, instances_page: Controller, + posts_page: Controller, profile_page: Controller, community_page: Controller, communities_page: Controller, @@ -62,8 +60,6 @@ struct App { inbox_page: Controller, login_page: Controller, logged_in: bool, - current_posts_type: Option, - current_posts_page: i64, about_dialog: Controller, } @@ -74,8 +70,7 @@ pub enum AppMsg { LoggedIn, Logout, ShowMessage(String), - StartFetchPosts(Option, bool), - DoneFetchPosts(Vec), + OpenPosts, OpenCommunity(CommunityId), DoneFetchCommunity(GetCommunityResponse), OpenPerson(PersonId), @@ -112,19 +107,13 @@ impl SimpleComponent for App { set_visible: model.back_queue.len() > 1, }, pack_start = >k::Button { - set_label: "Home", - connect_clicked => AppMsg::StartFetchPosts(None, true), + set_label: "Posts", + connect_clicked => AppMsg::OpenPosts, }, pack_start = >k::Button { set_label: "Communities", connect_clicked => AppMsg::OpenCommunities, }, - pack_start = >k::Button { - set_label: "Recommended", - connect_clicked => AppMsg::StartFetchPosts(Some(ListingType::Subscribed), true), - #[watch] - set_visible: model.logged_in, - }, pack_start = >k::Button { set_label: "Inbox", connect_clicked => AppMsg::OpenInbox, @@ -134,24 +123,9 @@ impl SimpleComponent for App { }, match model.state { - AppState::Posts => gtk::ScrolledWindow { - set_hexpand: true, - - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - - #[local_ref] - posts_box -> gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_spacing: 5, - }, - - gtk::Button { - set_label: "More", - connect_clicked => AppMsg::StartFetchPosts(model.current_posts_type, false), - set_margin_all: 10, - } - } + AppState::Posts => gtk::Box { + #[local_ref] + posts_page -> gtk::ScrolledWindow {} }, AppState::Loading => gtk::Box { set_hexpand: true, @@ -248,8 +222,10 @@ impl SimpleComponent for App { }; let logged_in = current_account.jwt.is_some(); - // initialize all controllers and factories - let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()); + // initialize all controllers for the various components + let posts_page = PostsPage::builder() + .launch(()) + .forward(sender.input_sender(), |msg| msg); let instances_page = InstancesPage::builder() .launch(()) .forward(sender.input_sender(), |msg| msg); @@ -279,7 +255,7 @@ impl SimpleComponent for App { state, back_queue: vec![], logged_in, - posts, + posts_page, instances_page, profile_page, community_page, @@ -288,18 +264,16 @@ impl SimpleComponent for App { communities_page, login_page, message: None, - current_posts_type: None, - current_posts_page: 1, about_dialog, }; // fetch posts if that's the initial page if !current_account.instance_url.is_empty() { - sender.input(AppMsg::StartFetchPosts(None, true)) + sender.input(AppMsg::OpenPosts) }; // setup all widgets and different stack pages - let posts_box = model.posts.widget(); + let posts_page = model.posts_page.widget(); let instances_page = model.instances_page.widget(); let profile_page = model.profile_page.widget(); let community_page = model.community_page.widget(); @@ -355,7 +329,7 @@ impl SimpleComponent for App { | AppMsg::DoneFetchCommunity(_) | AppMsg::OpenPerson(_) | AppMsg::DoneFetchPost(_) - | AppMsg::DoneFetchPosts(_) + | AppMsg::OpenPosts | AppMsg::ShowMessage(_) => self.back_queue.push(msg.clone()), _ => {} } @@ -367,35 +341,6 @@ impl SimpleComponent for App { .sender() .emit(InstancesPageInput::FetchInstances); } - AppMsg::StartFetchPosts(type_, remove_previous) => { - self.current_posts_type = type_; - let page = if remove_previous { - 1 - } else { - self.current_posts_page + 1 - }; - // show the loading indicator if it's the first page - if page == 1 { - self.state = AppState::Loading; - } - self.current_posts_page = page; - std::thread::spawn(move || { - let message = match api::posts::list_posts(page, None, type_) { - Ok(posts) => AppMsg::DoneFetchPosts(posts), - Err(err) => AppMsg::ShowMessage(err.to_string()), - }; - sender.input(message); - }); - } - AppMsg::DoneFetchPosts(posts) => { - self.state = AppState::Posts; - if self.current_posts_page == 1 { - self.posts.guard().clear(); - } - for post in posts { - self.posts.guard().push_back(post); - } - } AppMsg::OpenCommunities => { self.state = AppState::Communities; self.communities_page @@ -465,7 +410,7 @@ impl SimpleComponent for App { AppMsg::LoggedIn => { self.logged_in = true; self.back_queue.clear(); - sender.input(AppMsg::StartFetchPosts(None, true)); + sender.input(AppMsg::OpenPosts); } AppMsg::PopBackStack => { let action = self.back_queue.get(self.back_queue.len() - 2); @@ -479,6 +424,10 @@ impl SimpleComponent for App { AppMsg::UpdateState(state) => { self.state = state; } + AppMsg::OpenPosts => self + .posts_page + .sender() + .emit(PostsPageInput::FetchPosts(ListingType::Subscribed, true)), } } }