Implement setting dialog & make infinite scroll an option on it

Co-authored-by: Bnyro <bnyro@tutanota.com>
This commit is contained in:
BusyVar 2023-08-30 18:26:56 +02:00 committed by Bnyro
parent a7da2a7531
commit 285374a41f
7 changed files with 120 additions and 12 deletions

View File

@ -54,9 +54,9 @@ impl SimpleComponent for CommunityPage {
view! { view! {
gtk::ScrolledWindow { gtk::ScrolledWindow {
set_vexpand: false, set_vexpand: false,
connect_edge_reached[sender] => move |_,pos| { connect_edge_reached[sender] => move |_, pos| {
if pos == gtk::PositionType::Bottom { if pos == gtk::PositionType::Bottom && settings::get_prefs().infinite_scroll {
sender.input(CommunityInput::FetchPosts) sender.input(CommunityInput::FetchPosts);
} }
}, },

View File

@ -7,6 +7,8 @@ use relm4::{factory::FactoryVecDeque, prelude::*};
use crate::api; use crate::api;
use crate::settings::get_prefs;
use super::{ use super::{
post_row::PostRow, post_row::PostRow,
sort_dropdown::{SortDropdown, SortDropdownOutput}, sort_dropdown::{SortDropdown, SortDropdownOutput},
@ -36,12 +38,11 @@ impl SimpleComponent for PostsPage {
view! { view! {
gtk::ScrolledWindow { gtk::ScrolledWindow {
set_hexpand: true, set_hexpand: true,
connect_edge_reached[sender] => move |_,pos| { connect_edge_reached[sender] => move |_, pos| {
if pos == gtk::PositionType::Bottom { if pos == gtk::PositionType::Bottom && get_prefs().infinite_scroll {
sender.input( sender.input(
PostsPageInput::FetchPosts( PostsPageInput::FetchPosts(model.posts_type, model.posts_order, false)
model.posts_type, );
model.posts_order, false))
} }
}, },

View File

@ -9,9 +9,9 @@ use crate::dialogs::editor::EditorDialog;
use crate::dialogs::editor::EditorOutput; use crate::dialogs::editor::EditorOutput;
use crate::dialogs::editor::EditorType; use crate::dialogs::editor::EditorType;
use crate::settings; use crate::settings;
use crate::util::format_elapsed_time;
use crate::util::get_web_image_msg; use crate::util::get_web_image_msg;
use crate::util::markdown_to_pango_markup; use crate::util::markdown_to_pango_markup;
use crate::util::format_elapsed_time;
use super::comment_row::CommentRow; use super::comment_row::CommentRow;
use super::moderates_row::ModeratesRow; use super::moderates_row::ModeratesRow;

View File

@ -1,3 +1,4 @@
pub mod about; pub mod about;
pub mod editor; pub mod editor;
pub mod settings;
pub mod site_info; pub mod site_info;

81
src/dialogs/settings.rs Normal file
View File

@ -0,0 +1,81 @@
use crate::settings::{get_prefs, save_prefs};
use gtk::prelude::*;
use relm4::prelude::*;
pub struct Settings {
visible: bool,
}
#[derive(Debug)]
pub enum SettingsInput {
Show,
Hide,
}
#[relm4::component(pub)]
impl SimpleComponent for Settings {
type Init = ();
type Input = SettingsInput;
type Output = crate::AppMsg;
view! {
dialog = gtk::Dialog {
#[watch]
set_visible: model.visible,
set_modal: true,
set_title: Some("Settings"),
connect_close_request[sender] => move |_| {
sender.input(SettingsInput::Hide);
gtk::Inhibit(false)
},
#[wrap(Some)]
set_titlebar = &gtk::HeaderBar{
set_show_title_buttons: true,
},
gtk::ScrolledWindow {
set_size_request: (400, 400),
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
set_margin_all: 15,
gtk::CheckButton {
set_active: get_prefs().infinite_scroll,
set_margin_all: 12,
set_label: Some("Infinite scroll"),
set_tooltip:"Fetch new content automatically when scrolling down",
connect_toggled => move |checkbox| {
let mut prefs = get_prefs();
prefs.infinite_scroll = checkbox.is_active();
save_prefs(&prefs);
},
},
}
}
}
}
fn init(
_init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = Self { visible: false };
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
match message {
SettingsInput::Show => {
self.visible = true;
}
SettingsInput::Hide => {
self.visible = false;
}
}
}
}

View File

@ -19,6 +19,7 @@ use components::{
}; };
use dialogs::{ use dialogs::{
about::AboutDialog, about::AboutDialog,
settings::Settings,
site_info::{SiteInfo, SiteInfoInput}, site_info::{SiteInfo, SiteInfoInput},
}; };
use gtk::prelude::*; use gtk::prelude::*;
@ -68,6 +69,7 @@ struct App {
login_page: Controller<LoginPage>, login_page: Controller<LoginPage>,
accounts_page: Controller<AccountsPage>, accounts_page: Controller<AccountsPage>,
saved_page: Controller<ProfilePage>, saved_page: Controller<ProfilePage>,
settings_dialog: Controller<Settings>,
about_dialog: Controller<AboutDialog>, about_dialog: Controller<AboutDialog>,
site_info: Controller<SiteInfo>, site_info: Controller<SiteInfo>,
logged_in: bool, logged_in: bool,
@ -222,6 +224,7 @@ impl SimpleComponent for App {
"Login" => LoginAction, "Login" => LoginAction,
"Profile" => ProfileAction, "Profile" => ProfileAction,
"Site Info" => SiteInfoAction, "Site Info" => SiteInfoAction,
"Settings" => SettingsAction,
"About" => AboutAction "About" => AboutAction
} }
} }
@ -262,6 +265,7 @@ impl SimpleComponent for App {
let communities_page = CommunitiesPage::builder() let communities_page = CommunitiesPage::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), |msg| msg); .forward(sender.input_sender(), |msg| msg);
let settings_dialog = dialogs::settings::Settings::builder().launch(()).detach();
let about_dialog = AboutDialog::builder() let about_dialog = AboutDialog::builder()
.launch(root.toplevel_window().unwrap()) .launch(root.toplevel_window().unwrap())
.detach(); .detach();
@ -293,6 +297,7 @@ impl SimpleComponent for App {
accounts_page, accounts_page,
message: None, message: None,
about_dialog, about_dialog,
settings_dialog,
saved_page, saved_page,
site_info, site_info,
logged_in, logged_in,
@ -340,7 +345,6 @@ impl SimpleComponent for App {
}) })
}; };
let login_action: RelmAction<LoginAction> = { let login_action: RelmAction<LoginAction> = {
let sender = sender.clone();
RelmAction::new_stateless(move |_| { RelmAction::new_stateless(move |_| {
sender.input(AppMsg::UpdateState(AppState::Login)); sender.input(AppMsg::UpdateState(AppState::Login));
}) })
@ -351,6 +355,14 @@ impl SimpleComponent for App {
sender.emit(SiteInfoInput::Fetch); sender.emit(SiteInfoInput::Fetch);
}) })
}; };
let settings_action = {
let sender = model.settings_dialog.sender().clone();
RelmAction::<SettingsAction>::new_stateless(move |_| {
sender
.send(dialogs::settings::SettingsInput::Show)
.unwrap_or_default();
})
};
let about_action = { let about_action = {
let sender = model.about_dialog.sender().clone(); let sender = model.about_dialog.sender().clone();
RelmAction::<AboutAction>::new_stateless(move |_| { RelmAction::<AboutAction>::new_stateless(move |_| {
@ -364,6 +376,7 @@ impl SimpleComponent for App {
group.add_action(profile_action); group.add_action(profile_action);
group.add_action(login_action); group.add_action(login_action);
group.add_action(site_info_action); group.add_action(site_info_action);
group.add_action(settings_action);
group.add_action(about_action); group.add_action(about_action);
group.register_for_widget(&widgets.main_window); group.register_for_widget(&widgets.main_window);
@ -493,6 +506,7 @@ relm4::new_stateless_action!(AccountsAction, WindowActionGroup, "accounts");
relm4::new_stateless_action!(LoginAction, WindowActionGroup, "login"); relm4::new_stateless_action!(LoginAction, WindowActionGroup, "login");
relm4::new_stateless_action!(ProfileAction, WindowActionGroup, "profile"); relm4::new_stateless_action!(ProfileAction, WindowActionGroup, "profile");
relm4::new_stateless_action!(SiteInfoAction, WindowActionGroup, "site_info"); relm4::new_stateless_action!(SiteInfoAction, WindowActionGroup, "site_info");
relm4::new_stateless_action!(SettingsAction, WindowActionGroup, "settings");
relm4::new_stateless_action!(AboutAction, WindowActionGroup, "about"); relm4::new_stateless_action!(AboutAction, WindowActionGroup, "about");
fn main() { fn main() {

View File

@ -12,10 +12,21 @@ pub struct Account {
pub name: String, pub name: String,
} }
#[derive(Deserialize, Serialize, Default)] #[derive(Deserialize, Serialize)]
pub struct Preferences { pub struct Preferences {
pub accounts: Vec<Account>, pub accounts: Vec<Account>,
pub current_account_index: u32, pub current_account_index: u32,
pub infinite_scroll: bool,
}
impl Default for Preferences {
fn default() -> Self {
Self {
accounts: vec![],
current_account_index: 0,
infinite_scroll: true,
}
}
} }
pub fn data_path() -> PathBuf { pub fn data_path() -> PathBuf {