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;
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) => {

View File

@ -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()),
};

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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 => {

View File

@ -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);
});
}
}

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},
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<String>,
back_queue: Vec<AppMsg>,
posts: FactoryVecDeque<PostRow>,
instances_page: Controller<InstancesPage>,
posts_page: Controller<PostsPage>,
profile_page: Controller<ProfilePage>,
community_page: Controller<CommunityPage>,
communities_page: Controller<CommunitiesPage>,
@ -62,8 +60,6 @@ struct App {
inbox_page: Controller<InboxPage>,
login_page: Controller<LoginPage>,
logged_in: bool,
current_posts_type: Option<ListingType>,
current_posts_page: i64,
about_dialog: Controller<AboutDialog>,
}
@ -74,8 +70,7 @@ pub enum AppMsg {
LoggedIn,
Logout,
ShowMessage(String),
StartFetchPosts(Option<ListingType>, bool),
DoneFetchPosts(Vec<PostView>),
OpenPosts,
OpenCommunity(CommunityId),
DoneFetchCommunity(GetCommunityResponse),
OpenPerson(PersonId),
@ -112,19 +107,13 @@ impl SimpleComponent for App {
set_visible: model.back_queue.len() > 1,
},
pack_start = &gtk::Button {
set_label: "Home",
connect_clicked => AppMsg::StartFetchPosts(None, true),
set_label: "Posts",
connect_clicked => AppMsg::OpenPosts,
},
pack_start = &gtk::Button {
set_label: "Communities",
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 {
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)),
}
}
}