refactor posts/home page

This commit is contained in:
Bnyro 2023-07-06 15:21:16 +02:00
parent b38d225540
commit 6266004dcb
8 changed files with 155 additions and 85 deletions

View File

@ -164,9 +164,7 @@ impl FactoryComponent for CommentRow {
let comment_id = self.comment.comment.id; let comment_id = self.comment.comment.id;
std::thread::spawn(move || { std::thread::spawn(move || {
let _ = api::comment::delete_comment(comment_id); let _ = api::comment::delete_comment(comment_id);
sender sender.output_sender().emit(crate::AppMsg::OpenPosts);
.output_sender()
.emit(crate::AppMsg::StartFetchPosts(None, true));
}); });
} }
CommentRowMsg::OpenEditor(is_new) => { CommentRowMsg::OpenEditor(is_new) => {

View File

@ -128,7 +128,7 @@ impl SimpleComponent for InstancesPage {
current_account.instance_url = url[0..url.len() - 1].to_string(); current_account.instance_url = url[0..url.len() - 1].to_string();
current_account.jwt = None; current_account.jwt = None;
settings::update_current_account(current_account); settings::update_current_account(current_account);
crate::AppMsg::StartFetchPosts(None, true) crate::AppMsg::OpenPosts
} }
Err(err) => crate::AppMsg::ShowMessage(err.to_string()), Err(err) => crate::AppMsg::ShowMessage(err.to_string()),
}; };

View File

@ -119,9 +119,7 @@ impl SimpleComponent for LoginPage {
}); });
} }
LoginPageInput::Cancel => { LoginPageInput::Cancel => {
sender sender.output_sender().emit(crate::AppMsg::OpenPosts);
.output_sender()
.emit(crate::AppMsg::StartFetchPosts(None, true));
} }
} }
} }

View File

@ -10,6 +10,7 @@ pub mod mention_row;
pub mod moderates_row; pub mod moderates_row;
pub mod post_page; pub mod post_page;
pub mod post_row; pub mod post_row;
pub mod posts_page;
pub mod private_message_row; pub mod private_message_row;
pub mod profile_page; pub mod profile_page;
pub mod voting_row; pub mod voting_row;

View File

@ -316,9 +316,7 @@ impl SimpleComponent for PostPage {
let post_id = self.info.post_view.post.id; let post_id = self.info.post_view.post.id;
std::thread::spawn(move || { std::thread::spawn(move || {
let _ = api::post::delete_post(post_id); let _ = api::post::delete_post(post_id);
sender sender.output_sender().emit(crate::AppMsg::OpenPosts);
.output_sender()
.emit(crate::AppMsg::StartFetchPosts(None, true));
}); });
} }
PostPageInput::OpenEditPostDialog => { PostPageInput::OpenEditPostDialog => {

View File

@ -165,9 +165,7 @@ impl FactoryComponent for PostRow {
let post_id = self.post.post.id; let post_id = self.post.post.id;
std::thread::spawn(move || { std::thread::spawn(move || {
let _ = api::post::delete_post(post_id); let _ = api::post::delete_post(post_id);
sender sender.output_sender().emit(crate::AppMsg::OpenPosts);
.output_sender()
.emit(crate::AppMsg::StartFetchPosts(None, true));
}); });
} }
} }

View File

@ -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<PostRow>,
posts_type: ListingType,
posts_page: i64,
}
#[derive(Debug)]
pub enum PostsPageInput {
FetchPosts(ListingType, bool),
DoneFetchPosts(Vec<PostView>),
}
#[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<Self>,
) -> ComponentParts<Self> {
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<Self>) {
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);
}
}
}
}
}

View File

@ -12,7 +12,7 @@ use components::{
inbox_page::{InboxInput, InboxPage}, inbox_page::{InboxInput, InboxPage},
instances_page::{InstancesPage, InstancesPageInput}, instances_page::{InstancesPage, InstancesPageInput},
post_page::{self, PostPage}, post_page::{self, PostPage},
post_row::PostRow, posts_page::{PostsPage, PostsPageInput},
profile_page::{ProfileInput, ProfilePage}, profile_page::{ProfileInput, ProfilePage},
}; };
use dialogs::about::AboutDialog; use dialogs::about::AboutDialog;
@ -23,12 +23,10 @@ use lemmy_api_common::{
newtypes::{CommunityId, PersonId, PostId}, newtypes::{CommunityId, PersonId, PostId},
ListingType, ListingType,
}, },
lemmy_db_views::structs::PostView,
post::GetPostResponse, post::GetPostResponse,
}; };
use relm4::{ use relm4::{
actions::{RelmAction, RelmActionGroup}, actions::{RelmAction, RelmActionGroup},
factory::FactoryVecDeque,
prelude::*, prelude::*,
set_global_css, set_global_css,
}; };
@ -53,8 +51,8 @@ struct App {
state: AppState, state: AppState,
message: Option<String>, message: Option<String>,
back_queue: Vec<AppMsg>, back_queue: Vec<AppMsg>,
posts: FactoryVecDeque<PostRow>,
instances_page: Controller<InstancesPage>, instances_page: Controller<InstancesPage>,
posts_page: Controller<PostsPage>,
profile_page: Controller<ProfilePage>, profile_page: Controller<ProfilePage>,
community_page: Controller<CommunityPage>, community_page: Controller<CommunityPage>,
communities_page: Controller<CommunitiesPage>, communities_page: Controller<CommunitiesPage>,
@ -62,8 +60,6 @@ struct App {
inbox_page: Controller<InboxPage>, inbox_page: Controller<InboxPage>,
login_page: Controller<LoginPage>, login_page: Controller<LoginPage>,
logged_in: bool, logged_in: bool,
current_posts_type: Option<ListingType>,
current_posts_page: i64,
about_dialog: Controller<AboutDialog>, about_dialog: Controller<AboutDialog>,
} }
@ -74,8 +70,7 @@ pub enum AppMsg {
LoggedIn, LoggedIn,
Logout, Logout,
ShowMessage(String), ShowMessage(String),
StartFetchPosts(Option<ListingType>, bool), OpenPosts,
DoneFetchPosts(Vec<PostView>),
OpenCommunity(CommunityId), OpenCommunity(CommunityId),
DoneFetchCommunity(GetCommunityResponse), DoneFetchCommunity(GetCommunityResponse),
OpenPerson(PersonId), OpenPerson(PersonId),
@ -112,19 +107,13 @@ impl SimpleComponent for App {
set_visible: model.back_queue.len() > 1, set_visible: model.back_queue.len() > 1,
}, },
pack_start = &gtk::Button { pack_start = &gtk::Button {
set_label: "Home", set_label: "Posts",
connect_clicked => AppMsg::StartFetchPosts(None, true), connect_clicked => AppMsg::OpenPosts,
}, },
pack_start = &gtk::Button { pack_start = &gtk::Button {
set_label: "Communities", set_label: "Communities",
connect_clicked => AppMsg::OpenCommunities, connect_clicked => AppMsg::OpenCommunities,
}, },
pack_start = &gtk::Button {
set_label: "Recommended",
connect_clicked => AppMsg::StartFetchPosts(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,
@ -134,24 +123,9 @@ impl SimpleComponent for App {
}, },
match model.state { match model.state {
AppState::Posts => gtk::ScrolledWindow { AppState::Posts => gtk::Box {
set_hexpand: true, #[local_ref]
posts_page -> gtk::ScrolledWindow {}
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::Loading => gtk::Box { AppState::Loading => gtk::Box {
set_hexpand: true, set_hexpand: true,
@ -248,8 +222,10 @@ impl SimpleComponent for App {
}; };
let logged_in = current_account.jwt.is_some(); let logged_in = current_account.jwt.is_some();
// initialize all controllers and factories // initialize all controllers for the various components
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()); let posts_page = PostsPage::builder()
.launch(())
.forward(sender.input_sender(), |msg| msg);
let instances_page = InstancesPage::builder() let instances_page = InstancesPage::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |msg| msg); .forward(sender.input_sender(), |msg| msg);
@ -279,7 +255,7 @@ impl SimpleComponent for App {
state, state,
back_queue: vec![], back_queue: vec![],
logged_in, logged_in,
posts, posts_page,
instances_page, instances_page,
profile_page, profile_page,
community_page, community_page,
@ -288,18 +264,16 @@ impl SimpleComponent for App {
communities_page, communities_page,
login_page, login_page,
message: None, message: None,
current_posts_type: None,
current_posts_page: 1,
about_dialog, about_dialog,
}; };
// fetch posts if that's the initial page // fetch posts if that's the initial page
if !current_account.instance_url.is_empty() { if !current_account.instance_url.is_empty() {
sender.input(AppMsg::StartFetchPosts(None, true)) sender.input(AppMsg::OpenPosts)
}; };
// setup all widgets and different stack pages // 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 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();
@ -355,7 +329,7 @@ impl SimpleComponent for App {
| AppMsg::DoneFetchCommunity(_) | AppMsg::DoneFetchCommunity(_)
| AppMsg::OpenPerson(_) | AppMsg::OpenPerson(_)
| AppMsg::DoneFetchPost(_) | AppMsg::DoneFetchPost(_)
| AppMsg::DoneFetchPosts(_) | AppMsg::OpenPosts
| AppMsg::ShowMessage(_) => self.back_queue.push(msg.clone()), | AppMsg::ShowMessage(_) => self.back_queue.push(msg.clone()),
_ => {} _ => {}
} }
@ -367,35 +341,6 @@ impl SimpleComponent for App {
.sender() .sender()
.emit(InstancesPageInput::FetchInstances); .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 => { AppMsg::OpenCommunities => {
self.state = AppState::Communities; self.state = AppState::Communities;
self.communities_page self.communities_page
@ -465,7 +410,7 @@ impl SimpleComponent for App {
AppMsg::LoggedIn => { AppMsg::LoggedIn => {
self.logged_in = true; self.logged_in = true;
self.back_queue.clear(); self.back_queue.clear();
sender.input(AppMsg::StartFetchPosts(None, true)); sender.input(AppMsg::OpenPosts);
} }
AppMsg::PopBackStack => { AppMsg::PopBackStack => {
let action = self.back_queue.get(self.back_queue.len() - 2); let action = self.back_queue.get(self.back_queue.len() - 2);
@ -479,6 +424,10 @@ impl SimpleComponent for App {
AppMsg::UpdateState(state) => { AppMsg::UpdateState(state) => {
self.state = state; self.state = state;
} }
AppMsg::OpenPosts => self
.posts_page
.sender()
.emit(PostsPageInput::FetchPosts(ListingType::Subscribed, true)),
} }
} }
} }