settings: use timed serializer, handle zoom properly, use custom text style for note body font size, added font size slider, added preview note
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
use crate::account::FALLBACK_PUBKEY;
|
||||
use crate::i18n::Localization;
|
||||
use crate::persist::{AppSizeHandler, ZoomHandler};
|
||||
use crate::persist::{AppSizeHandler, SettingsHandler};
|
||||
use crate::wallet::GlobalWallet;
|
||||
use crate::zaps::Zaps;
|
||||
use crate::JobPool;
|
||||
use crate::{
|
||||
frame_history::FrameHistory, AccountStorage, Accounts, AppContext, Args, DataPath,
|
||||
DataPathType, Directory, Images, NoteAction, NoteCache, RelayDebugView, UnknownIds,
|
||||
};
|
||||
use crate::{JobPool, SettingsHandler};
|
||||
use egui::Margin;
|
||||
use egui::ThemePreference;
|
||||
use egui_winit::clipboard::Clipboard;
|
||||
@@ -40,9 +40,8 @@ pub struct Notedeck {
|
||||
global_wallet: GlobalWallet,
|
||||
path: DataPath,
|
||||
args: Args,
|
||||
settings_handler: SettingsHandler,
|
||||
settings: SettingsHandler,
|
||||
app: Option<Rc<RefCell<dyn App>>>,
|
||||
zoom: ZoomHandler,
|
||||
app_size: AppSizeHandler,
|
||||
unrecognized_args: BTreeSet<String>,
|
||||
clipboard: Clipboard,
|
||||
@@ -99,7 +98,15 @@ impl eframe::App for Notedeck {
|
||||
|
||||
render_notedeck(self, ctx);
|
||||
|
||||
self.zoom.try_save_zoom_factor(ctx);
|
||||
self.settings.update_batch(|settings| {
|
||||
settings.zoom_factor = ctx.zoom_factor();
|
||||
settings.locale = self.i18n.get_current_locale().to_string();
|
||||
settings.theme = if ctx.style().visuals.dark_mode {
|
||||
ThemePreference::Dark
|
||||
} else {
|
||||
ThemePreference::Light
|
||||
};
|
||||
});
|
||||
self.app_size.try_save_app_size(ctx);
|
||||
|
||||
if self.args.relay_debug {
|
||||
@@ -159,7 +166,7 @@ impl Notedeck {
|
||||
1024usize * 1024usize * 1024usize * 1024usize
|
||||
};
|
||||
|
||||
let settings_handler = SettingsHandler::new(&path).load();
|
||||
let settings = SettingsHandler::new(&path).load();
|
||||
|
||||
let config = Config::new().set_ingester_threads(2).set_mapsize(map_size);
|
||||
|
||||
@@ -214,12 +221,8 @@ impl Notedeck {
|
||||
|
||||
let img_cache = Images::new(img_cache_dir);
|
||||
let note_cache = NoteCache::default();
|
||||
let zoom = ZoomHandler::new(&path);
|
||||
let app_size = AppSizeHandler::new(&path);
|
||||
|
||||
if let Some(z) = zoom.get_zoom_factor() {
|
||||
ctx.set_zoom_factor(z);
|
||||
}
|
||||
let app_size = AppSizeHandler::new(&path);
|
||||
|
||||
// migrate
|
||||
if let Err(e) = img_cache.migrate_v0() {
|
||||
@@ -234,7 +237,7 @@ impl Notedeck {
|
||||
let mut i18n = Localization::new();
|
||||
|
||||
let setting_locale: Result<LanguageIdentifier, LanguageIdentifierError> =
|
||||
settings_handler.locale().parse();
|
||||
settings.locale().parse();
|
||||
|
||||
if setting_locale.is_ok() {
|
||||
if let Err(err) = i18n.set_locale(setting_locale.unwrap()) {
|
||||
@@ -261,9 +264,8 @@ impl Notedeck {
|
||||
global_wallet,
|
||||
path: path.clone(),
|
||||
args: parsed_args,
|
||||
settings_handler,
|
||||
settings,
|
||||
app: None,
|
||||
zoom,
|
||||
app_size,
|
||||
unrecognized_args,
|
||||
frame_history: FrameHistory::default(),
|
||||
@@ -290,7 +292,7 @@ impl Notedeck {
|
||||
global_wallet: &mut self.global_wallet,
|
||||
path: &self.path,
|
||||
args: &self.args,
|
||||
settings_handler: &mut self.settings_handler,
|
||||
settings: &mut self.settings,
|
||||
clipboard: &mut self.clipboard,
|
||||
zaps: &mut self.zaps,
|
||||
frame_history: &mut self.frame_history,
|
||||
@@ -308,7 +310,15 @@ impl Notedeck {
|
||||
}
|
||||
|
||||
pub fn theme(&self) -> ThemePreference {
|
||||
self.settings_handler.theme()
|
||||
self.settings.theme()
|
||||
}
|
||||
|
||||
pub fn note_body_font_size(&self) -> f32 {
|
||||
self.settings.note_body_font_size()
|
||||
}
|
||||
|
||||
pub fn zoom_factor(&self) -> f32 {
|
||||
self.settings.zoom_factor()
|
||||
}
|
||||
|
||||
pub fn unrecognized_args(&self) -> &BTreeSet<String> {
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct AppContext<'a> {
|
||||
pub global_wallet: &'a mut GlobalWallet,
|
||||
pub path: &'a DataPath,
|
||||
pub args: &'a Args,
|
||||
pub settings_handler: &'a mut SettingsHandler,
|
||||
pub settings: &'a mut SettingsHandler,
|
||||
pub clipboard: &'a mut Clipboard,
|
||||
pub zaps: &'a mut Zaps,
|
||||
pub frame_history: &'a mut FrameHistory,
|
||||
|
||||
@@ -31,6 +31,7 @@ pub fn desktop_font_size(text_style: &NotedeckTextStyle) -> f32 {
|
||||
NotedeckTextStyle::Button => 13.0,
|
||||
NotedeckTextStyle::Small => 12.0,
|
||||
NotedeckTextStyle::Tiny => 10.0,
|
||||
NotedeckTextStyle::NoteBody => 16.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +47,7 @@ pub fn mobile_font_size(text_style: &NotedeckTextStyle) -> f32 {
|
||||
NotedeckTextStyle::Button => 13.0,
|
||||
NotedeckTextStyle::Small => 12.0,
|
||||
NotedeckTextStyle::Tiny => 10.0,
|
||||
NotedeckTextStyle::NoteBody => 13.0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
mod app_size;
|
||||
mod settings_handler;
|
||||
mod theme_handler;
|
||||
mod token_handler;
|
||||
mod zoom;
|
||||
|
||||
pub use app_size::AppSizeHandler;
|
||||
pub use settings_handler::Settings;
|
||||
pub use settings_handler::SettingsHandler;
|
||||
pub use theme_handler::ThemeHandler;
|
||||
pub use settings_handler::DEFAULT_NOTE_BODY_FONT_SIZE;
|
||||
pub use token_handler::TokenHandler;
|
||||
pub use zoom::ZoomHandler;
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
use crate::{
|
||||
storage::{self, delete_file},
|
||||
DataPath, DataPathType, Directory,
|
||||
storage::delete_file, timed_serializer::TimedSerializer, DataPath, DataPathType, Directory,
|
||||
};
|
||||
use egui::ThemePreference;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{error, info};
|
||||
|
||||
const THEME_FILE: &str = "theme.txt";
|
||||
const ZOOM_FACTOR_FILE: &str = "zoom_level.json";
|
||||
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";
|
||||
const DEFAULT_SHOW_REPLIES_NEWEST_FIRST: bool = false;
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
pub const DEFAULT_NOTE_BODY_FONT_SIZE: f32 = 13.0;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub const DEFAULT_NOTE_BODY_FONT_SIZE: f32 = 16.0;
|
||||
|
||||
fn deserialize_theme(serialized_theme: &str) -> Option<ThemePreference> {
|
||||
match serialized_theme {
|
||||
@@ -23,72 +28,96 @@ fn deserialize_theme(serialized_theme: &str) -> Option<ThemePreference> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Clone)]
|
||||
pub struct Settings {
|
||||
pub theme: ThemePreference,
|
||||
pub locale: String,
|
||||
pub zoom_factor: f32,
|
||||
pub show_source_client: String,
|
||||
pub show_replies_newest_first: bool,
|
||||
pub note_body_font_size: f32,
|
||||
}
|
||||
|
||||
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: DEFAULT_SHOW_SOURCE_CLIENT.to_string(),
|
||||
show_replies_newest_first: false,
|
||||
show_replies_newest_first: DEFAULT_SHOW_REPLIES_NEWEST_FIRST,
|
||||
note_body_font_size: DEFAULT_NOTE_BODY_FONT_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingsHandler {
|
||||
directory: Directory,
|
||||
serializer: TimedSerializer<Settings>,
|
||||
current_settings: Option<Settings>,
|
||||
}
|
||||
|
||||
impl SettingsHandler {
|
||||
fn read_legacy_theme(&self) -> Option<ThemePreference> {
|
||||
fn read_from_theme_file(&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<(), ()> {
|
||||
fn read_from_zomfactor_file(&self) -> Option<f32> {
|
||||
match self.directory.get_file(ZOOM_FACTOR_FILE.to_string()) {
|
||||
Ok(contents) => serde_json::from_str::<f32>(&contents).ok(),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn migrate_to_settings_file(&mut self) -> bool {
|
||||
let mut settings = Settings::default();
|
||||
let mut migrated = false;
|
||||
// if theme.txt exists migrate
|
||||
if let Some(theme_from_file) = self.read_legacy_theme() {
|
||||
if let Some(theme_from_file) = self.read_from_theme_file() {
|
||||
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(())
|
||||
settings.theme = theme_from_file;
|
||||
migrated = true;
|
||||
} else {
|
||||
Err(())
|
||||
info!("theme.txt file not found, using default theme");
|
||||
};
|
||||
|
||||
// if zoom_factor.txt exists migrate
|
||||
if let Some(zom_factor) = self.read_from_zomfactor_file() {
|
||||
info!("migrating theme preference from zom_factor file");
|
||||
_ = delete_file(&self.directory.file_path, ZOOM_FACTOR_FILE.to_string());
|
||||
|
||||
settings.zoom_factor = zom_factor;
|
||||
migrated = true;
|
||||
} else {
|
||||
info!("zoom_factor.txt exists migrate file not found, using default zoom factor");
|
||||
};
|
||||
|
||||
if migrated {
|
||||
self.current_settings = Some(settings);
|
||||
self.try_save_settings();
|
||||
}
|
||||
migrated
|
||||
}
|
||||
|
||||
pub fn new(path: &DataPath) -> Self {
|
||||
let directory = Directory::new(path.path(DataPathType::Setting));
|
||||
let current_settings: Option<Settings> = None;
|
||||
let serializer =
|
||||
TimedSerializer::new(path, DataPathType::Setting, "settings.json".to_owned());
|
||||
|
||||
Self {
|
||||
directory,
|
||||
current_settings,
|
||||
serializer,
|
||||
current_settings: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(mut self) -> Self {
|
||||
if self.migrate_to_settings_file().is_ok() {
|
||||
if self.migrate_to_settings_file() {
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -114,22 +143,9 @@ impl SettingsHandler {
|
||||
self
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
pub(crate) fn try_save_settings(&mut self) {
|
||||
let settings = self.get_settings_mut().clone();
|
||||
self.serializer.try_save(settings);
|
||||
}
|
||||
|
||||
pub fn get_settings_mut(&mut self) -> &mut Settings {
|
||||
@@ -141,7 +157,7 @@ impl SettingsHandler {
|
||||
|
||||
pub fn set_theme(&mut self, theme: ThemePreference) {
|
||||
self.get_settings_mut().theme = theme;
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn set_locale<S>(&mut self, locale: S)
|
||||
@@ -149,12 +165,12 @@ impl SettingsHandler {
|
||||
S: Into<String>,
|
||||
{
|
||||
self.get_settings_mut().locale = locale.into();
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn set_zoom_factor(&mut self, zoom_factor: f32) {
|
||||
self.get_settings_mut().zoom_factor = zoom_factor;
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn set_show_source_client<S>(&mut self, option: S)
|
||||
@@ -162,12 +178,17 @@ impl SettingsHandler {
|
||||
S: Into<String>,
|
||||
{
|
||||
self.get_settings_mut().show_source_client = option.into();
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn set_show_replies_newest_first(&mut self, value: bool) {
|
||||
self.get_settings_mut().show_replies_newest_first = value;
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn set_note_body_font_size(&mut self, value: f32) {
|
||||
self.get_settings_mut().note_body_font_size = value;
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn update_batch<F>(&mut self, update_fn: F)
|
||||
@@ -176,12 +197,12 @@ impl SettingsHandler {
|
||||
{
|
||||
let settings = self.get_settings_mut();
|
||||
update_fn(settings);
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn update_settings(&mut self, new_settings: Settings) {
|
||||
self.current_settings = Some(new_settings);
|
||||
self.save();
|
||||
self.try_save_settings();
|
||||
}
|
||||
|
||||
pub fn theme(&self) -> ThemePreference {
|
||||
@@ -216,10 +237,17 @@ impl SettingsHandler {
|
||||
self.current_settings
|
||||
.as_ref()
|
||||
.map(|s| s.show_replies_newest_first)
|
||||
.unwrap_or(false)
|
||||
.unwrap_or(DEFAULT_SHOW_REPLIES_NEWEST_FIRST)
|
||||
}
|
||||
|
||||
pub fn is_loaded(&self) -> bool {
|
||||
self.current_settings.is_some()
|
||||
}
|
||||
|
||||
pub fn note_body_font_size(&self) -> f32 {
|
||||
self.current_settings
|
||||
.as_ref()
|
||||
.map(|s| s.note_body_font_size)
|
||||
.unwrap_or(DEFAULT_NOTE_BODY_FONT_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
use egui::ThemePreference;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{storage, DataPath, DataPathType, Directory};
|
||||
|
||||
pub struct ThemeHandler {
|
||||
directory: Directory,
|
||||
fallback_theme: ThemePreference,
|
||||
}
|
||||
|
||||
const THEME_FILE: &str = "theme.txt";
|
||||
|
||||
impl ThemeHandler {
|
||||
pub fn new(path: &DataPath) -> Self {
|
||||
let directory = Directory::new(path.path(DataPathType::Setting));
|
||||
let fallback_theme = ThemePreference::Dark;
|
||||
Self {
|
||||
directory,
|
||||
fallback_theme,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(&self) -> ThemePreference {
|
||||
match self.directory.get_file(THEME_FILE.to_owned()) {
|
||||
Ok(contents) => match deserialize_theme(contents) {
|
||||
Some(theme) => theme,
|
||||
None => {
|
||||
error!(
|
||||
"Could not deserialize theme. Using fallback {:?} instead",
|
||||
self.fallback_theme
|
||||
);
|
||||
self.fallback_theme
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Could not read {} file: {:?}\nUsing fallback {:?} instead",
|
||||
THEME_FILE, e, self.fallback_theme
|
||||
);
|
||||
self.fallback_theme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&self, theme: ThemePreference) {
|
||||
match storage::write_file(
|
||||
&self.directory.file_path,
|
||||
THEME_FILE.to_owned(),
|
||||
&theme_to_serialized(&theme),
|
||||
) {
|
||||
Ok(_) => info!(
|
||||
"Successfully saved {:?} theme change to {}",
|
||||
theme, THEME_FILE
|
||||
),
|
||||
Err(_) => error!("Could not save {:?} theme change to {}", theme, THEME_FILE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn theme_to_serialized(theme: &ThemePreference) -> String {
|
||||
match theme {
|
||||
ThemePreference::Dark => "dark",
|
||||
ThemePreference::Light => "light",
|
||||
ThemePreference::System => "system",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
fn deserialize_theme(serialized_theme: String) -> Option<ThemePreference> {
|
||||
match serialized_theme.as_str() {
|
||||
"dark" => Some(ThemePreference::Dark),
|
||||
"light" => Some(ThemePreference::Light),
|
||||
"system" => Some(ThemePreference::System),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use crate::{DataPath, DataPathType};
|
||||
use egui::Context;
|
||||
|
||||
use crate::timed_serializer::TimedSerializer;
|
||||
|
||||
pub struct ZoomHandler {
|
||||
serializer: TimedSerializer<f32>,
|
||||
}
|
||||
|
||||
impl ZoomHandler {
|
||||
pub fn new(path: &DataPath) -> Self {
|
||||
let serializer =
|
||||
TimedSerializer::new(path, DataPathType::Setting, "zoom_level.json".to_owned());
|
||||
|
||||
Self { serializer }
|
||||
}
|
||||
|
||||
pub fn try_save_zoom_factor(&mut self, ctx: &Context) {
|
||||
let cur_zoom_level = ctx.zoom_factor();
|
||||
self.serializer.try_save(cur_zoom_level);
|
||||
}
|
||||
|
||||
pub fn get_zoom_factor(&self) -> Option<f32> {
|
||||
self.serializer.get_item()
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ pub enum NotedeckTextStyle {
|
||||
Button,
|
||||
Small,
|
||||
Tiny,
|
||||
NoteBody,
|
||||
}
|
||||
|
||||
impl NotedeckTextStyle {
|
||||
@@ -29,6 +30,7 @@ impl NotedeckTextStyle {
|
||||
Self::Button => TextStyle::Button,
|
||||
Self::Small => TextStyle::Small,
|
||||
Self::Tiny => TextStyle::Name("Tiny".into()),
|
||||
Self::NoteBody => TextStyle::Name("NoteBody".into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +45,7 @@ impl NotedeckTextStyle {
|
||||
Self::Button => FontFamily::Proportional,
|
||||
Self::Small => FontFamily::Proportional,
|
||||
Self::Tiny => FontFamily::Proportional,
|
||||
Self::NoteBody => FontFamily::Proportional,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@ use crate::debouncer::Debouncer;
|
||||
use crate::{storage, DataPath, DataPathType, Directory};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use tracing::info; // Adjust this import path as needed
|
||||
use tracing::info;
|
||||
|
||||
pub struct TimedSerializer<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> {
|
||||
pub struct TimedSerializer<T: PartialEq + Clone + Serialize + for<'de> Deserialize<'de>> {
|
||||
directory: Directory,
|
||||
file_name: String,
|
||||
debouncer: Debouncer,
|
||||
saved_item: Option<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerializer<T> {
|
||||
impl<T: PartialEq + Clone + Serialize + for<'de> Deserialize<'de>> TimedSerializer<T> {
|
||||
pub fn new(path: &DataPath, path_type: DataPathType, file_name: String) -> Self {
|
||||
let directory = Directory::new(path.path(path_type));
|
||||
let delay = Duration::from_millis(1000);
|
||||
@@ -30,11 +30,11 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
|
||||
self
|
||||
}
|
||||
|
||||
// returns whether successful
|
||||
/// Returns whether it actually wrote the new value
|
||||
pub fn try_save(&mut self, cur_item: T) -> bool {
|
||||
if self.debouncer.should_act() {
|
||||
if let Some(saved_item) = self.saved_item {
|
||||
if saved_item != cur_item {
|
||||
if let Some(ref saved_item) = self.saved_item {
|
||||
if *saved_item != cur_item {
|
||||
return self.save(cur_item);
|
||||
}
|
||||
} else {
|
||||
@@ -45,8 +45,8 @@ impl<T: PartialEq + Copy + Serialize + for<'de> Deserialize<'de>> TimedSerialize
|
||||
}
|
||||
|
||||
pub fn get_item(&self) -> Option<T> {
|
||||
if self.saved_item.is_some() {
|
||||
return self.saved_item;
|
||||
if let Some(ref item) = self.saved_item {
|
||||
return Some(item.clone());
|
||||
}
|
||||
if let Ok(file_contents) = self.directory.get_file(self.file_name.clone()) {
|
||||
if let Ok(item) = serde_json::from_str::<T>(&file_contents) {
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
use crate::NotedeckTextStyle;
|
||||
|
||||
pub const NARROW_SCREEN_WIDTH: f32 = 550.0;
|
||||
/// Determine if the screen is narrow. This is useful for detecting mobile
|
||||
/// contexts, but with the nuance that we may also have a wide android tablet.
|
||||
|
||||
pub fn richtext_small<S>(text: S) -> egui::RichText
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
egui::RichText::new(text).text_style(NotedeckTextStyle::Small.text_style())
|
||||
}
|
||||
|
||||
pub fn is_narrow(ctx: &egui::Context) -> bool {
|
||||
let screen_size = ctx.input(|c| c.screen_rect().size());
|
||||
screen_size.x < 550.0
|
||||
screen_size.x < NARROW_SCREEN_WIDTH
|
||||
}
|
||||
|
||||
pub fn is_oled() -> bool {
|
||||
|
||||
Reference in New Issue
Block a user