mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
feat(app): a text size setting, kept on this computer
Settings > Appearance offers 90% to 150%, applied as egui's zoom factor so controls grow with the text. Ctrl+plus and Ctrl+minus already zoomed through egui; what they settle on is now kept too, so Settings shows it and the next launch opens at it. It lives in the desktop-only settings: what reads well depends on the screen, not on the viewer's other devices.
This commit is contained in:
1 parent
31bdd75559
commit
47c482498b
3 files changed
+64
-3
No files matched your search
@@ -715,6 +715,7 @@ impl App {
|
||||
let (engine, events) = Engine::new(runtime, dirs, cc.egui_ctx.clone())?;
|
||||
theme::install_fonts(&cc.egui_ctx);
|
||||
theme::apply(&cc.egui_ctx, engine.appearance());
|
||||
cc.egui_ctx.set_zoom_factor(engine.desktop_prefs().zoom());
|
||||
|
||||
// Paint from the catalog immediately; the network catches up. A library
|
||||
// that was crawled yesterday is on screen before the shares open.
|
||||
@@ -1829,7 +1830,10 @@ impl App {
|
||||
self.note(ctx, text, false);
|
||||
}
|
||||
}
|
||||
Action::SetDesktopPrefs(prefs) => self.engine.set_desktop_prefs(prefs),
|
||||
Action::SetDesktopPrefs(prefs) => {
|
||||
ctx.set_zoom_factor(prefs.zoom());
|
||||
self.engine.set_desktop_prefs(prefs);
|
||||
}
|
||||
Action::SetTitleWatched { key, watched } => {
|
||||
let Some(title) = self.library.get(&key) else {
|
||||
return;
|
||||
@@ -2101,6 +2105,14 @@ impl eframe::App for App {
|
||||
let ctx = ui.ctx().clone();
|
||||
let ctx = &ctx;
|
||||
self.pump(ctx, frame);
|
||||
// Ctrl+plus and Ctrl+minus zoom too, through egui: keep what they
|
||||
// settled on, so Settings shows it and the next launch opens at it.
|
||||
let mut desktop = self.engine.desktop_prefs();
|
||||
if (ctx.zoom_factor() - desktop.zoom()).abs() > 0.005 {
|
||||
desktop.text_size = ((ctx.zoom_factor() * 100.0).round() as u16).clamp(50, 200);
|
||||
ctx.set_zoom_factor(desktop.zoom());
|
||||
self.engine.set_desktop_prefs(desktop);
|
||||
}
|
||||
// The window manager can leave fullscreen without asking (F11, a
|
||||
// double-click on a title bar), and `F` then toggled the wrong way.
|
||||
if let Some(actual) = ctx.input(|input| input.viewport().fullscreen) {
|
||||
|
||||
@@ -11,6 +11,9 @@ use serde::{Deserialize, Serialize};
|
||||
/// What the settings page offers for the streaming cache, in GiB.
|
||||
pub const CACHE_CHOICES: [u32; 5] = [1, 2, 4, 8, 16];
|
||||
|
||||
/// What the settings page offers for the size of everything, in percent.
|
||||
pub const TEXT_SIZE_CHOICES: [u16; 5] = [90, 100, 115, 130, 150];
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
// A file from an older version, or edited by hand, missing a field: the rest
|
||||
// still counts, and the missing one takes its default.
|
||||
@@ -27,6 +30,9 @@ pub struct DesktopPrefs {
|
||||
pub grouped: bool,
|
||||
/// The library's offer of posters and synopses was turned down.
|
||||
pub metadata_offer_dismissed: bool,
|
||||
/// How large text and controls are drawn, in percent. Per computer, not
|
||||
/// synced: what reads well depends on the screen and how far away it is.
|
||||
pub text_size: u16,
|
||||
}
|
||||
|
||||
impl Default for DesktopPrefs {
|
||||
@@ -40,11 +46,17 @@ impl Default for DesktopPrefs {
|
||||
// of the same picture otherwise.
|
||||
grouped: true,
|
||||
metadata_offer_dismissed: false,
|
||||
text_size: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DesktopPrefs {
|
||||
/// [`Self::text_size`] as egui's zoom factor, kept to what is offered.
|
||||
pub fn zoom(&self) -> f32 {
|
||||
f32::from(self.text_size.clamp(50, 200)) / 100.0
|
||||
}
|
||||
|
||||
pub fn cache_bytes(&self) -> u64 {
|
||||
u64::from(self.cache_gib.clamp(1, 64)) << 30
|
||||
}
|
||||
@@ -105,6 +117,17 @@ mod tests {
|
||||
assert!(prefs.hardware_decoding);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_text_size_from_an_older_file_is_full_size_and_a_wild_one_is_kept_in_range() {
|
||||
let prefs: DesktopPrefs = serde_json::from_str(r#"{ "cache_gib": 8 }"#).unwrap();
|
||||
assert_eq!(prefs.zoom(), 1.0);
|
||||
let wild = DesktopPrefs {
|
||||
text_size: 900,
|
||||
..DesktopPrefs::default()
|
||||
};
|
||||
assert_eq!(wild.zoom(), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_unparseable_file_is_never_overwritten() {
|
||||
let path = std::env::temp_dir().join(format!("pstr-desktop-{}.json", std::process::id()));
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn show(
|
||||
ui.vertical(|ui| {
|
||||
ui.set_width(width);
|
||||
ui.add_space(theme::space::M);
|
||||
appearance_form(ui, prefs.appearance, actions);
|
||||
appearance_form(ui, prefs.appearance, prefs.desktop, actions);
|
||||
playback_form(ui, prefs, actions);
|
||||
storage_form(ui, prefs, actions);
|
||||
metadata_form(ui, settings, api_key, actions);
|
||||
@@ -71,7 +71,12 @@ pub fn show(
|
||||
/// Every control here repaints the whole window the moment it is clicked —
|
||||
/// there is no "apply" — because the preview *is* the app. A swatch row that
|
||||
/// only changed a small square would be asking someone to imagine the result.
|
||||
fn appearance_form(ui: &mut egui::Ui, appearance: Appearance, actions: &mut Vec<Action>) {
|
||||
fn appearance_form(
|
||||
ui: &mut egui::Ui,
|
||||
appearance: Appearance,
|
||||
desktop: DesktopPrefs,
|
||||
actions: &mut Vec<Action>,
|
||||
) {
|
||||
ui::widgets::settings_group(ui, "Appearance", None, |ui| {
|
||||
ui.add_space(theme::space::L);
|
||||
ui.label(theme::Role::Body.rich("Palette").color(theme::text()));
|
||||
@@ -108,6 +113,27 @@ fn appearance_form(ui: &mut egui::Ui, appearance: Appearance, actions: &mut Vec<
|
||||
}
|
||||
});
|
||||
|
||||
ui::widgets::settings_row(
|
||||
ui,
|
||||
"Text size",
|
||||
Some("Everything grows with it. Kept on this computer only."),
|
||||
|ui| {
|
||||
let choices: Vec<(u16, String)> = TEXT_SIZE_CHOICES
|
||||
.iter()
|
||||
.map(|&percent| (percent, format!("{percent}%")))
|
||||
.collect();
|
||||
let labels: Vec<(u16, &str)> = choices
|
||||
.iter()
|
||||
.map(|(percent, label)| (*percent, label.as_str()))
|
||||
.collect();
|
||||
if let Some(text_size) = ui::widgets::segmented(ui, desktop.text_size, &labels) {
|
||||
actions.push(Action::SetDesktopPrefs(DesktopPrefs {
|
||||
text_size,
|
||||
..desktop
|
||||
}));
|
||||
}
|
||||
},
|
||||
);
|
||||
ui::widgets::settings_row(
|
||||
ui,
|
||||
"Library tiles",
|
||||
|
||||
Reference in new issue
Block a user