mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-19 09:34:19 +01:00
feat(settings): persist settings to storage
This commit is contained in:
committed by
William Casarin
parent
5280028a82
commit
b8207106d7
@@ -3,12 +3,11 @@ use crate::i18n::Localization;
|
|||||||
use crate::persist::{AppSizeHandler, ZoomHandler};
|
use crate::persist::{AppSizeHandler, ZoomHandler};
|
||||||
use crate::wallet::GlobalWallet;
|
use crate::wallet::GlobalWallet;
|
||||||
use crate::zaps::Zaps;
|
use crate::zaps::Zaps;
|
||||||
use crate::JobPool;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath,
|
frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath,
|
||||||
DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, ThemeHandler,
|
DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, UnknownIds,
|
||||||
UnknownIds,
|
|
||||||
};
|
};
|
||||||
|
use crate::{JobPool, SettingsHandler};
|
||||||
use egui::Margin;
|
use egui::Margin;
|
||||||
use egui::ThemePreference;
|
use egui::ThemePreference;
|
||||||
use egui_winit::clipboard::Clipboard;
|
use egui_winit::clipboard::Clipboard;
|
||||||
@@ -19,6 +18,7 @@ use std::collections::BTreeSet;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
use unic_langid::{LanguageIdentifier, LanguageIdentifierError};
|
||||||
|
|
||||||
pub enum AppAction {
|
pub enum AppAction {
|
||||||
Note(NoteAction),
|
Note(NoteAction),
|
||||||
@@ -40,7 +40,7 @@ pub struct Notedeck {
|
|||||||
global_wallet: GlobalWallet,
|
global_wallet: GlobalWallet,
|
||||||
path: DataPath,
|
path: DataPath,
|
||||||
args: Args,
|
args: Args,
|
||||||
theme: ThemeHandler,
|
settings_handler: SettingsHandler,
|
||||||
app: Option<Rc<RefCell<dyn App>>>,
|
app: Option<Rc<RefCell<dyn App>>>,
|
||||||
zoom: ZoomHandler,
|
zoom: ZoomHandler,
|
||||||
app_size: AppSizeHandler,
|
app_size: AppSizeHandler,
|
||||||
@@ -159,7 +159,10 @@ impl Notedeck {
|
|||||||
1024usize * 1024usize * 1024usize * 1024usize
|
1024usize * 1024usize * 1024usize * 1024usize
|
||||||
};
|
};
|
||||||
|
|
||||||
let theme = ThemeHandler::new(&path);
|
let mut settings_handler = SettingsHandler::new(&path);
|
||||||
|
|
||||||
|
settings_handler.load();
|
||||||
|
|
||||||
let config = Config::new().set_ingester_threads(2).set_mapsize(map_size);
|
let config = Config::new().set_ingester_threads(2).set_mapsize(map_size);
|
||||||
|
|
||||||
let keystore = if parsed_args.use_keystore {
|
let keystore = if parsed_args.use_keystore {
|
||||||
@@ -231,6 +234,16 @@ impl Notedeck {
|
|||||||
|
|
||||||
// Initialize localization
|
// Initialize localization
|
||||||
let mut i18n = Localization::new();
|
let mut i18n = Localization::new();
|
||||||
|
|
||||||
|
let setting_locale: Result<LanguageIdentifier, LanguageIdentifierError> =
|
||||||
|
settings_handler.locale().parse();
|
||||||
|
|
||||||
|
if setting_locale.is_ok() {
|
||||||
|
if let Err(err) = i18n.set_locale(setting_locale.unwrap()) {
|
||||||
|
error!("{err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(locale) = &parsed_args.locale {
|
if let Some(locale) = &parsed_args.locale {
|
||||||
if let Err(err) = i18n.set_locale(locale.to_owned()) {
|
if let Err(err) = i18n.set_locale(locale.to_owned()) {
|
||||||
error!("{err}");
|
error!("{err}");
|
||||||
@@ -250,7 +263,7 @@ impl Notedeck {
|
|||||||
global_wallet,
|
global_wallet,
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
args: parsed_args,
|
args: parsed_args,
|
||||||
theme,
|
settings_handler,
|
||||||
app: None,
|
app: None,
|
||||||
zoom,
|
zoom,
|
||||||
app_size,
|
app_size,
|
||||||
@@ -279,7 +292,7 @@ impl Notedeck {
|
|||||||
global_wallet: &mut self.global_wallet,
|
global_wallet: &mut self.global_wallet,
|
||||||
path: &self.path,
|
path: &self.path,
|
||||||
args: &self.args,
|
args: &self.args,
|
||||||
theme: &mut self.theme,
|
settings_handler: &mut self.settings_handler,
|
||||||
clipboard: &mut self.clipboard,
|
clipboard: &mut self.clipboard,
|
||||||
zaps: &mut self.zaps,
|
zaps: &mut self.zaps,
|
||||||
frame_history: &mut self.frame_history,
|
frame_history: &mut self.frame_history,
|
||||||
@@ -297,7 +310,7 @@ impl Notedeck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn theme(&self) -> ThemePreference {
|
pub fn theme(&self) -> ThemePreference {
|
||||||
self.theme.load()
|
self.settings_handler.theme()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unrecognized_args(&self) -> &BTreeSet<String> {
|
pub fn unrecognized_args(&self) -> &BTreeSet<String> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
account::accounts::Accounts, frame_history::FrameHistory, i18n::Localization,
|
account::accounts::Accounts, frame_history::FrameHistory, i18n::Localization,
|
||||||
wallet::GlobalWallet, zaps::Zaps, Args, DataPath, Images, JobPool, NoteCache, ThemeHandler,
|
wallet::GlobalWallet, zaps::Zaps, Args, DataPath, Images, JobPool, NoteCache, SettingsHandler,
|
||||||
UnknownIds,
|
UnknownIds,
|
||||||
};
|
};
|
||||||
use egui_winit::clipboard::Clipboard;
|
use egui_winit::clipboard::Clipboard;
|
||||||
@@ -20,7 +20,7 @@ pub struct AppContext<'a> {
|
|||||||
pub global_wallet: &'a mut GlobalWallet,
|
pub global_wallet: &'a mut GlobalWallet,
|
||||||
pub path: &'a DataPath,
|
pub path: &'a DataPath,
|
||||||
pub args: &'a Args,
|
pub args: &'a Args,
|
||||||
pub theme: &'a mut ThemeHandler,
|
pub settings_handler: &'a mut SettingsHandler,
|
||||||
pub clipboard: &'a mut Clipboard,
|
pub clipboard: &'a mut Clipboard,
|
||||||
pub zaps: &'a mut Zaps,
|
pub zaps: &'a mut Zaps,
|
||||||
pub frame_history: &'a mut FrameHistory,
|
pub frame_history: &'a mut FrameHistory,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
mod app_size;
|
mod app_size;
|
||||||
|
mod settings_handler;
|
||||||
mod theme_handler;
|
mod theme_handler;
|
||||||
mod token_handler;
|
mod token_handler;
|
||||||
mod zoom;
|
mod zoom;
|
||||||
|
|
||||||
pub use app_size::AppSizeHandler;
|
pub use app_size::AppSizeHandler;
|
||||||
|
pub use settings_handler::SettingsHandler;
|
||||||
pub use theme_handler::ThemeHandler;
|
pub use theme_handler::ThemeHandler;
|
||||||
pub use token_handler::TokenHandler;
|
pub use token_handler::TokenHandler;
|
||||||
pub use zoom::ZoomHandler;
|
pub use zoom::ZoomHandler;
|
||||||
|
|||||||
208
crates/notedeck/src/persist/settings_handler.rs
Normal file
208
crates/notedeck/src/persist/settings_handler.rs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
use crate::{
|
||||||
|
storage::{self, delete_file},
|
||||||
|
DataPath, DataPathType, Directory,
|
||||||
|
};
|
||||||
|
use egui::ThemePreference;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
const THEME_FILE: &str = "theme.txt";
|
||||||
|
const SETTINGS_FILE: &str = "settings.json";
|
||||||
|
|
||||||
|
const DEFAULT_THEME: ThemePreference = ThemePreference::Dark;
|
||||||
|
const DEFAULT_LOCALE: &str = "es-US";
|
||||||
|
const DEFAULT_ZOOM_FACTOR: f32 = 1.0;
|
||||||
|
const DEFAULT_SHOW_SOURCE_CLIENT: &str = "hide";
|
||||||
|
|
||||||
|
fn deserialize_theme(serialized_theme: &str) -> Option<ThemePreference> {
|
||||||
|
match serialized_theme {
|
||||||
|
"dark" => Some(ThemePreference::Dark),
|
||||||
|
"light" => Some(ThemePreference::Light),
|
||||||
|
"system" => Some(ThemePreference::System),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Settings {
|
||||||
|
pub theme: ThemePreference,
|
||||||
|
pub locale: String,
|
||||||
|
pub zoom_factor: f32,
|
||||||
|
pub show_source_client: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Settings {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Use the same fallback theme as before
|
||||||
|
Self {
|
||||||
|
theme: DEFAULT_THEME,
|
||||||
|
locale: DEFAULT_LOCALE.to_string(),
|
||||||
|
zoom_factor: DEFAULT_ZOOM_FACTOR,
|
||||||
|
show_source_client: "Hide".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct SettingsHandler {
|
||||||
|
directory: Directory,
|
||||||
|
current_settings: Option<Settings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SettingsHandler {
|
||||||
|
fn read_legacy_theme(&self) -> Option<ThemePreference> {
|
||||||
|
match self.directory.get_file(THEME_FILE.to_string()) {
|
||||||
|
Ok(contents) => deserialize_theme(contents.trim()),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_to_settings_file(&mut self) -> Result<(), ()> {
|
||||||
|
// if theme.txt exists migrate
|
||||||
|
if let Some(theme_from_file) = self.read_legacy_theme() {
|
||||||
|
info!("migrating theme preference from theme.txt file");
|
||||||
|
_ = delete_file(&self.directory.file_path, THEME_FILE.to_string());
|
||||||
|
|
||||||
|
self.current_settings = Some(Settings {
|
||||||
|
theme: theme_from_file,
|
||||||
|
..Settings::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
self.save();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(path: &DataPath) -> Self {
|
||||||
|
let directory = Directory::new(path.path(DataPathType::Setting));
|
||||||
|
let current_settings: Option<Settings> = None;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
directory,
|
||||||
|
current_settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&mut self) {
|
||||||
|
if self.migrate_to_settings_file().is_ok() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.directory.get_file(SETTINGS_FILE.to_string()) {
|
||||||
|
Ok(contents_str) => {
|
||||||
|
// Parse JSON content
|
||||||
|
match serde_json::from_str::<Settings>(&contents_str) {
|
||||||
|
Ok(settings) => {
|
||||||
|
self.current_settings = Some(settings);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
error!("Invalid settings format. Using defaults");
|
||||||
|
self.current_settings = Some(Settings::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
error!("Could not read settings. Using defaults");
|
||||||
|
self.current_settings = Some(Settings::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(&self) {
|
||||||
|
let settings = self.current_settings.as_ref().unwrap();
|
||||||
|
match serde_json::to_string(settings) {
|
||||||
|
Ok(serialized) => {
|
||||||
|
if let Err(e) = storage::write_file(
|
||||||
|
&self.directory.file_path,
|
||||||
|
SETTINGS_FILE.to_string(),
|
||||||
|
&serialized,
|
||||||
|
) {
|
||||||
|
error!("Could not save settings: {}", e);
|
||||||
|
} else {
|
||||||
|
info!("Settings saved successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => error!("Failed to serialize settings: {}", e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_settings_mut(&mut self) -> &mut Settings {
|
||||||
|
if self.current_settings.is_none() {
|
||||||
|
self.current_settings = Some(Settings::default());
|
||||||
|
}
|
||||||
|
self.current_settings.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_theme(&mut self, theme: ThemePreference) {
|
||||||
|
self.get_settings_mut().theme = theme;
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_locale<S>(&mut self, locale: S)
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
self.get_settings_mut().locale = locale.into();
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_zoom_factor(&mut self, zoom_factor: f32) {
|
||||||
|
self.get_settings_mut().zoom_factor = zoom_factor;
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_show_source_client<S>(&mut self, option: S)
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
self.get_settings_mut().show_source_client = option.into();
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_batch<F>(&mut self, update_fn: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Settings),
|
||||||
|
{
|
||||||
|
let settings = self.get_settings_mut();
|
||||||
|
update_fn(settings);
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_settings(&mut self, new_settings: Settings) {
|
||||||
|
self.current_settings = Some(new_settings);
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn theme(&self) -> ThemePreference {
|
||||||
|
self.current_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.theme)
|
||||||
|
.unwrap_or(DEFAULT_THEME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn locale(&self) -> String {
|
||||||
|
self.current_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.locale.clone())
|
||||||
|
.unwrap_or_else(|| DEFAULT_LOCALE.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zoom_factor(&self) -> f32 {
|
||||||
|
self.current_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.zoom_factor)
|
||||||
|
.unwrap_or(DEFAULT_ZOOM_FACTOR)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_source_client(&self) -> String {
|
||||||
|
self.current_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.show_source_client.to_string())
|
||||||
|
.unwrap_or(DEFAULT_SHOW_SOURCE_CLIENT.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_loaded(&self) -> bool {
|
||||||
|
self.current_settings.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,7 +115,8 @@ impl ChromePanelAction {
|
|||||||
ui.ctx().options_mut(|o| {
|
ui.ctx().options_mut(|o| {
|
||||||
o.theme_preference = *theme;
|
o.theme_preference = *theme;
|
||||||
});
|
});
|
||||||
ctx.theme.save(*theme);
|
ctx.settings_handler.set_theme(*theme);
|
||||||
|
ctx.settings_handler.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Toolbar(toolbar_action) => match toolbar_action {
|
Self::Toolbar(toolbar_action) => match toolbar_action {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ use crate::{
|
|||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::ui::settings::ShowNoteClientOption;
|
||||||
|
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
||||||
use nostrdb::Transaction;
|
use nostrdb::Transaction;
|
||||||
@@ -506,11 +508,14 @@ impl Damus {
|
|||||||
);
|
);
|
||||||
note_options.set(
|
note_options.set(
|
||||||
NoteOptions::ShowNoteClientTop,
|
NoteOptions::ShowNoteClientTop,
|
||||||
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientTop),
|
ShowNoteClientOption::Top == app_context.settings_handler.show_source_client().into()
|
||||||
|
|| parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientTop),
|
||||||
);
|
);
|
||||||
note_options.set(
|
note_options.set(
|
||||||
NoteOptions::ShowNoteClientBottom,
|
NoteOptions::ShowNoteClientBottom,
|
||||||
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientBottom),
|
ShowNoteClientOption::Bottom
|
||||||
|
== app_context.settings_handler.show_source_client().into()
|
||||||
|
|| parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientBottom),
|
||||||
);
|
);
|
||||||
options.set(AppOptions::Debug, app_context.args.debug);
|
options.set(AppOptions::Debug, app_context.args.debug);
|
||||||
options.set(
|
options.set(
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::{
|
|||||||
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType, QuoteRepostView},
|
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType, QuoteRepostView},
|
||||||
profile::EditProfileView,
|
profile::EditProfileView,
|
||||||
search::{FocusState, SearchView},
|
search::{FocusState, SearchView},
|
||||||
settings::{SettingsAction, ShowNoteClientOptions},
|
settings::SettingsAction,
|
||||||
support::SupportView,
|
support::SupportView,
|
||||||
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
||||||
AccountsView, PostReplyView, PostView, ProfileView, RelayView, SettingsView, ThreadView,
|
AccountsView, PostReplyView, PostView, ProfileView, RelayView, SettingsView, ThreadView,
|
||||||
@@ -30,6 +30,8 @@ use crate::{
|
|||||||
Damus,
|
Damus,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::ui::settings::ShowNoteClientOption;
|
||||||
|
|
||||||
use egui_nav::{Nav, NavAction, NavResponse, NavUiType, Percent, PopupResponse, PopupSheet};
|
use egui_nav::{Nav, NavAction, NavResponse, NavUiType, Percent, PopupResponse, PopupSheet};
|
||||||
use enostr::ProfileState;
|
use enostr::ProfileState;
|
||||||
use nostrdb::{Filter, Ndb, Transaction};
|
use nostrdb::{Filter, Ndb, Transaction};
|
||||||
@@ -37,7 +39,6 @@ use notedeck::{
|
|||||||
get_current_default_msats, tr, ui::is_narrow, Accounts, AppContext, NoteAction, NoteContext,
|
get_current_default_msats, tr, ui::is_narrow, Accounts, AppContext, NoteAction, NoteContext,
|
||||||
RelayAction,
|
RelayAction,
|
||||||
};
|
};
|
||||||
use notedeck_ui::NoteOptions;
|
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
/// The result of processing a nav response
|
/// The result of processing a nav response
|
||||||
@@ -486,9 +487,13 @@ fn process_render_nav_action(
|
|||||||
.process_relay_action(ui.ctx(), ctx.pool, action);
|
.process_relay_action(ui.ctx(), ctx.pool, action);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
RenderNavAction::SettingsAction(action) => {
|
RenderNavAction::SettingsAction(action) => action.process_settings_action(
|
||||||
action.process_settings_action(app, ctx.theme, ctx.i18n, ctx.img_cache, ui.ctx())
|
app,
|
||||||
}
|
ctx.settings_handler,
|
||||||
|
ctx.i18n,
|
||||||
|
ctx.img_cache,
|
||||||
|
ui.ctx(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(action) = router_action {
|
if let Some(action) = router_action {
|
||||||
@@ -583,14 +588,7 @@ fn render_nav_body(
|
|||||||
.map(RenderNavAction::RelayAction),
|
.map(RenderNavAction::RelayAction),
|
||||||
|
|
||||||
Route::Settings => {
|
Route::Settings => {
|
||||||
let mut show_note_client = if app.note_options.contains(NoteOptions::ShowNoteClientTop)
|
let mut show_note_client: ShowNoteClientOption = app.note_options.into();
|
||||||
{
|
|
||||||
ShowNoteClientOptions::Top
|
|
||||||
} else if app.note_options.contains(NoteOptions::ShowNoteClientBottom) {
|
|
||||||
ShowNoteClientOptions::Bottom
|
|
||||||
} else {
|
|
||||||
ShowNoteClientOptions::Hide
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut theme: String = (if ui.visuals().dark_mode {
|
let mut theme: String = (if ui.visuals().dark_mode {
|
||||||
"Dark"
|
"Dark"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ pub use preview::{Preview, PreviewApp, PreviewConfig};
|
|||||||
pub use profile::ProfileView;
|
pub use profile::ProfileView;
|
||||||
pub use relay::RelayView;
|
pub use relay::RelayView;
|
||||||
pub use settings::SettingsView;
|
pub use settings::SettingsView;
|
||||||
|
pub use settings::ShowNoteClientOption;
|
||||||
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
||||||
pub use thread::ThreadView;
|
pub use thread::ThreadView;
|
||||||
pub use timeline::TimelineView;
|
pub use timeline::TimelineView;
|
||||||
|
|||||||
@@ -1,21 +1,73 @@
|
|||||||
use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ThemePreference};
|
use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ThemePreference};
|
||||||
use notedeck::{tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, ThemeHandler};
|
use notedeck::{tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, SettingsHandler};
|
||||||
use notedeck_ui::NoteOptions;
|
use notedeck_ui::NoteOptions;
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|
||||||
use crate::{nav::RouterAction, Damus, Route};
|
use crate::{nav::RouterAction, Damus, Route};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Display)]
|
#[derive(Clone, Copy, PartialEq, Eq, Display)]
|
||||||
pub enum ShowNoteClientOptions {
|
pub enum ShowNoteClientOption {
|
||||||
Hide,
|
Hide,
|
||||||
Top,
|
Top,
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ShowNoteClientOption> for String {
|
||||||
|
fn from(value: ShowNoteClientOption) -> Self {
|
||||||
|
match value {
|
||||||
|
ShowNoteClientOption::Hide => "hide".to_string(),
|
||||||
|
ShowNoteClientOption::Top => "top".to_string(),
|
||||||
|
ShowNoteClientOption::Bottom => "bottom".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NoteOptions> for ShowNoteClientOption {
|
||||||
|
fn from(note_options: NoteOptions) -> Self {
|
||||||
|
if note_options.contains(NoteOptions::ShowNoteClientTop) {
|
||||||
|
ShowNoteClientOption::Top
|
||||||
|
} else if note_options.contains(NoteOptions::ShowNoteClientBottom) {
|
||||||
|
ShowNoteClientOption::Bottom
|
||||||
|
} else {
|
||||||
|
ShowNoteClientOption::Hide
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for ShowNoteClientOption {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
|
"hide" => Self::Hide,
|
||||||
|
"top" => Self::Top,
|
||||||
|
"bottom" => Self::Bottom,
|
||||||
|
_ => Self::Hide, // default fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShowNoteClientOption {
|
||||||
|
pub fn set_note_options(self, note_options: &mut NoteOptions) {
|
||||||
|
match self {
|
||||||
|
Self::Hide => {
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientTop, false);
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientBottom, false);
|
||||||
|
}
|
||||||
|
Self::Bottom => {
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientTop, false);
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientBottom, true);
|
||||||
|
}
|
||||||
|
Self::Top => {
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientTop, true);
|
||||||
|
note_options.set(NoteOptions::ShowNoteClientBottom, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum SettingsAction {
|
pub enum SettingsAction {
|
||||||
SetZoom(f32),
|
SetZoomFactor(f32),
|
||||||
SetTheme(ThemePreference),
|
SetTheme(ThemePreference),
|
||||||
SetShowNoteClient(ShowNoteClientOptions),
|
SetShowSourceClient(ShowNoteClientOption),
|
||||||
SetLocale(LanguageIdentifier),
|
SetLocale(LanguageIdentifier),
|
||||||
OpenRelays,
|
OpenRelays,
|
||||||
OpenCacheFolder,
|
OpenCacheFolder,
|
||||||
@@ -26,7 +78,7 @@ impl SettingsAction {
|
|||||||
pub fn process_settings_action<'a>(
|
pub fn process_settings_action<'a>(
|
||||||
self,
|
self,
|
||||||
app: &mut Damus,
|
app: &mut Damus,
|
||||||
theme_handler: &'a mut ThemeHandler,
|
settings_handler: &'a mut SettingsHandler,
|
||||||
i18n: &'a mut Localization,
|
i18n: &'a mut Localization,
|
||||||
img_cache: &mut Images,
|
img_cache: &mut Images,
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
@@ -37,34 +89,25 @@ impl SettingsAction {
|
|||||||
SettingsAction::OpenRelays => {
|
SettingsAction::OpenRelays => {
|
||||||
route_action = Some(RouterAction::route_to(Route::Relays));
|
route_action = Some(RouterAction::route_to(Route::Relays));
|
||||||
}
|
}
|
||||||
SettingsAction::SetZoom(zoom_level) => {
|
SettingsAction::SetZoomFactor(zoom_factor) => {
|
||||||
ctx.set_zoom_factor(zoom_level);
|
ctx.set_zoom_factor(zoom_factor);
|
||||||
|
settings_handler.set_zoom_factor(zoom_factor);
|
||||||
|
}
|
||||||
|
SettingsAction::SetShowSourceClient(option) => {
|
||||||
|
option.set_note_options(&mut app.note_options);
|
||||||
|
|
||||||
|
settings_handler.set_show_source_client(option);
|
||||||
}
|
}
|
||||||
SettingsAction::SetShowNoteClient(newvalue) => match newvalue {
|
|
||||||
ShowNoteClientOptions::Hide => {
|
|
||||||
app.note_options.set(NoteOptions::ShowNoteClientTop, false);
|
|
||||||
app.note_options
|
|
||||||
.set(NoteOptions::ShowNoteClientBottom, false);
|
|
||||||
}
|
|
||||||
ShowNoteClientOptions::Bottom => {
|
|
||||||
app.note_options.set(NoteOptions::ShowNoteClientTop, false);
|
|
||||||
app.note_options
|
|
||||||
.set(NoteOptions::ShowNoteClientBottom, true);
|
|
||||||
}
|
|
||||||
ShowNoteClientOptions::Top => {
|
|
||||||
app.note_options.set(NoteOptions::ShowNoteClientTop, true);
|
|
||||||
app.note_options
|
|
||||||
.set(NoteOptions::ShowNoteClientBottom, false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SettingsAction::SetTheme(theme) => {
|
SettingsAction::SetTheme(theme) => {
|
||||||
ctx.options_mut(|o| {
|
ctx.options_mut(|o| {
|
||||||
o.theme_preference = theme;
|
o.theme_preference = theme;
|
||||||
});
|
});
|
||||||
theme_handler.save(theme);
|
settings_handler.set_theme(theme);
|
||||||
}
|
}
|
||||||
SettingsAction::SetLocale(language) => {
|
SettingsAction::SetLocale(language) => {
|
||||||
_ = i18n.set_locale(language);
|
if i18n.set_locale(language.clone()).is_ok() {
|
||||||
|
settings_handler.set_locale(language.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SettingsAction::OpenCacheFolder => {
|
SettingsAction::OpenCacheFolder => {
|
||||||
use opener;
|
use opener;
|
||||||
@@ -74,6 +117,7 @@ impl SettingsAction {
|
|||||||
let _ = img_cache.clear_folder_contents();
|
let _ = img_cache.clear_folder_contents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
settings_handler.save();
|
||||||
route_action
|
route_action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +125,7 @@ impl SettingsAction {
|
|||||||
pub struct SettingsView<'a> {
|
pub struct SettingsView<'a> {
|
||||||
theme: &'a mut String,
|
theme: &'a mut String,
|
||||||
selected_language: &'a mut String,
|
selected_language: &'a mut String,
|
||||||
show_note_client: &'a mut ShowNoteClientOptions,
|
show_note_client: &'a mut ShowNoteClientOption,
|
||||||
i18n: &'a mut Localization,
|
i18n: &'a mut Localization,
|
||||||
img_cache: &'a mut Images,
|
img_cache: &'a mut Images,
|
||||||
}
|
}
|
||||||
@@ -91,7 +135,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
img_cache: &'a mut Images,
|
img_cache: &'a mut Images,
|
||||||
selected_language: &'a mut String,
|
selected_language: &'a mut String,
|
||||||
theme: &'a mut String,
|
theme: &'a mut String,
|
||||||
show_note_client: &'a mut ShowNoteClientOptions,
|
show_note_client: &'a mut ShowNoteClientOption,
|
||||||
i18n: &'a mut Localization,
|
i18n: &'a mut Localization,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -115,20 +159,20 @@ impl<'a> SettingsView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the localized label for ShowNoteClientOptions
|
/// Get the localized label for ShowNoteClientOption
|
||||||
fn get_show_note_client_label(&mut self, option: ShowNoteClientOptions) -> String {
|
fn get_show_note_client_label(&mut self, option: ShowNoteClientOption) -> String {
|
||||||
match option {
|
match option {
|
||||||
ShowNoteClientOptions::Hide => tr!(
|
ShowNoteClientOption::Hide => tr!(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
"Hide",
|
"Hide",
|
||||||
"Option in settings section to hide the source client label in note display"
|
"Option in settings section to hide the source client label in note display"
|
||||||
),
|
),
|
||||||
ShowNoteClientOptions::Top => tr!(
|
ShowNoteClientOption::Top => tr!(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
"Top",
|
"Top",
|
||||||
"Option in settings section to show the source client label at the top of the note"
|
"Option in settings section to show the source client label at the top of the note"
|
||||||
),
|
),
|
||||||
ShowNoteClientOptions::Bottom => tr!(
|
ShowNoteClientOption::Bottom => tr!(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
"Bottom",
|
"Bottom",
|
||||||
"Option in settings section to show the source client label at the bottom of the note"
|
"Option in settings section to show the source client label at the bottom of the note"
|
||||||
@@ -179,7 +223,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let new_zoom = (current_zoom - 0.1).max(0.1);
|
let new_zoom = (current_zoom - 0.1).max(0.1);
|
||||||
action = Some(SettingsAction::SetZoom(new_zoom));
|
action = Some(SettingsAction::SetZoomFactor(new_zoom));
|
||||||
};
|
};
|
||||||
|
|
||||||
ui.label(
|
ui.label(
|
||||||
@@ -195,7 +239,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let new_zoom = (current_zoom + 0.1).min(10.0);
|
let new_zoom = (current_zoom + 0.1).min(10.0);
|
||||||
action = Some(SettingsAction::SetZoom(new_zoom));
|
action = Some(SettingsAction::SetZoomFactor(new_zoom));
|
||||||
};
|
};
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
@@ -209,7 +253,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
action = Some(SettingsAction::SetZoom(1.0));
|
action = Some(SettingsAction::SetZoomFactor(1.0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -336,7 +380,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
if !notedeck::ui::is_compiled_as_mobile() &&
|
if !notedeck::ui::is_compiled_as_mobile() &&
|
||||||
ui.button(RichText::new(tr!(self.i18n, "View folder:", "Label for view folder button, Storage settings section"))
|
ui.button(RichText::new(tr!(self.i18n, "View folder", "Label for view folder button, Storage settings section"))
|
||||||
.text_style(NotedeckTextStyle::Small.text_style())).clicked() {
|
.text_style(NotedeckTextStyle::Small.text_style())).clicked() {
|
||||||
action = Some(SettingsAction::OpenCacheFolder);
|
action = Some(SettingsAction::OpenCacheFolder);
|
||||||
}
|
}
|
||||||
@@ -419,9 +463,9 @@ impl<'a> SettingsView<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for option in [
|
for option in [
|
||||||
ShowNoteClientOptions::Hide,
|
ShowNoteClientOption::Hide,
|
||||||
ShowNoteClientOptions::Top,
|
ShowNoteClientOption::Top,
|
||||||
ShowNoteClientOptions::Bottom,
|
ShowNoteClientOption::Bottom,
|
||||||
] {
|
] {
|
||||||
let label = self.get_show_note_client_label(option);
|
let label = self.get_show_note_client_label(option);
|
||||||
|
|
||||||
@@ -434,7 +478,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
)
|
)
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
action = Some(SettingsAction::SetShowNoteClient(option));
|
action = Some(SettingsAction::SetShowSourceClient(option));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user