diff --git a/apps/rsnap/src/app.rs b/apps/rsnap/src/app.rs index 06a8a4d3..84ab6808 100644 --- a/apps/rsnap/src/app.rs +++ b/apps/rsnap/src/app.rs @@ -30,7 +30,7 @@ use self::scroll_input_macos::SharedScrollInputState; #[cfg(target_os = "macos")] use crate::permissions_macos; use crate::settings::AppSettings; -use crate::settings_window::SettingsWindow; +use crate::settings_window::{SettingsWindow, SettingsWindowEntry}; use rsnap_overlay::OverlaySession; pub(crate) enum UserEvent { @@ -152,7 +152,9 @@ impl App { return; } - match SettingsWindow::open(event_loop) { + let entry = settings_window_entry(requested_by); + + match SettingsWindow::open(event_loop, entry) { Ok(window) => { tracing::info!(requested_by = %requested_by, "Settings window opened."); @@ -205,3 +207,36 @@ impl App { pub fn run() -> Result<()> { runtime::run() } + +fn settings_window_entry(requested_by: &'static str) -> SettingsWindowEntry { + match requested_by { + "startup-permission-check" => SettingsWindowEntry::Permissions, + _ => SettingsWindowEntry::Standard, + } +} + +#[cfg(test)] +mod tests { + use crate::app::{self, SettingsWindowEntry}; + + #[test] + fn startup_permission_check_uses_permissions_entry() { + assert_eq!( + app::settings_window_entry("startup-permission-check"), + SettingsWindowEntry::Permissions + ); + } + + #[test] + fn non_startup_settings_entries_use_standard_entry() { + assert_eq!( + app::settings_window_entry("tray-permissions-menu"), + SettingsWindowEntry::Standard + ); + assert_eq!( + app::settings_window_entry("menubar-permissions-menu"), + SettingsWindowEntry::Standard + ); + assert_eq!(app::settings_window_entry("tray-settings-menu"), SettingsWindowEntry::Standard); + } +} diff --git a/apps/rsnap/src/settings_window.rs b/apps/rsnap/src/settings_window.rs index ca0d12dc..d920aaa7 100644 --- a/apps/rsnap/src/settings_window.rs +++ b/apps/rsnap/src/settings_window.rs @@ -48,6 +48,20 @@ pub(crate) enum SettingsControl { CloseRequested, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum SettingsWindowEntry { + Standard, + Permissions, +} +impl SettingsWindowEntry { + const fn section_defaults(self) -> sections::SettingsUiSectionDefaults { + match self { + Self::Standard => sections::SettingsUiSectionDefaults::standard(), + Self::Permissions => sections::SettingsUiSectionDefaults::permissions_focused(), + } + } +} + #[derive(Clone, Debug)] pub(crate) enum SettingsWindowAction { Begin, @@ -74,6 +88,7 @@ pub(crate) struct SettingsWindow { last_redraw: Instant, did_autosize: bool, combo_width: f32, + section_defaults: sections::SettingsUiSectionDefaults, requested_theme: Option, effective_theme: Option, theme_icon_system: String, @@ -84,7 +99,7 @@ pub(crate) struct SettingsWindow { action_queue: VecDeque, } impl SettingsWindow { - pub(crate) fn open(event_loop: &ActiveEventLoop) -> Result { + pub(crate) fn open(event_loop: &ActiveEventLoop, entry: SettingsWindowEntry) -> Result { let attrs = platform::settings_window_attributes(); let window = event_loop.create_window(attrs).wrap_err("create settings window")?; let window = std::sync::Arc::new(window); @@ -131,6 +146,7 @@ impl SettingsWindow { last_redraw: Instant::now(), did_autosize: false, combo_width: SETTINGS_COMBO_WIDTH, + section_defaults: entry.section_defaults(), requested_theme: None, effective_theme: None, theme_icon_system, diff --git a/apps/rsnap/src/settings_window/chrome.rs b/apps/rsnap/src/settings_window/chrome.rs index 056fd583..7cf589b0 100644 --- a/apps/rsnap/src/settings_window/chrome.rs +++ b/apps/rsnap/src/settings_window/chrome.rs @@ -29,7 +29,13 @@ impl SettingsWindow { sections::with_settings_density(ui, combo_width, |ui| { changed |= self.render_titlebar_controls(ui, &ctx, settings); ScrollArea::vertical().auto_shrink([false, false]).show(ui, |ui| { - changed |= sections::render_all_sections(self, ui, &ctx, settings); + changed |= sections::render_all_sections_with_defaults( + self, + ui, + &ctx, + settings, + self.section_defaults, + ); }); }); }); diff --git a/apps/rsnap/src/settings_window/sections.rs b/apps/rsnap/src/settings_window/sections.rs index ed7418a8..f295b485 100644 --- a/apps/rsnap/src/settings_window/sections.rs +++ b/apps/rsnap/src/settings_window/sections.rs @@ -6,12 +6,12 @@ use egui::Context; use egui::DragValue; use egui::Pos2; use egui::Rect; -#[cfg(target_os = "macos")] use egui::RichText; use egui::Sense; use egui::Slider; use egui::Stroke; use egui::TextEdit; +use egui::TextStyle; use egui::Ui; use egui::style::HandleShape; @@ -40,24 +40,22 @@ pub(super) struct SettingsUiSectionDefaults { hotkeys: bool, capture: bool, output: bool, - advanced: bool, about: bool, } impl SettingsUiSectionDefaults { pub(super) const fn standard() -> Self { Self { - permissions: true, + permissions: false, general: true, overlay: true, - hotkeys: false, - capture: false, - output: false, - advanced: false, - about: false, + hotkeys: true, + capture: true, + output: true, + about: true, } } - pub(super) const fn all_open() -> Self { + pub(super) const fn permissions_focused() -> Self { Self { permissions: true, general: true, @@ -65,20 +63,30 @@ impl SettingsUiSectionDefaults { hotkeys: true, capture: true, output: true, - advanced: true, about: true, } } - pub(super) const fn hotkeys_expanded() -> Self { + pub(super) const fn all_open() -> Self { Self { permissions: true, general: true, overlay: true, hotkeys: true, + capture: true, + output: true, + about: true, + } + } + + pub(super) const fn hotkeys_expanded() -> Self { + Self { + permissions: false, + general: false, + overlay: false, + hotkeys: true, capture: false, output: false, - advanced: false, about: false, } } @@ -116,15 +124,6 @@ pub(super) fn with_settings_density( .inner } -pub(super) fn render_all_sections( - host: &mut impl SettingsUiHost, - ui: &mut Ui, - ctx: &Context, - settings: &mut AppSettings, -) -> bool { - render_all_sections_with_defaults(host, ui, ctx, settings, SettingsUiSectionDefaults::default()) -} - pub(super) fn render_all_sections_with_defaults( host: &mut impl SettingsUiHost, ui: &mut Ui, @@ -171,14 +170,8 @@ pub(super) fn render_all_sections_with_defaults( ui.add_space(SETTINGS_SECTION_GAP); - CollapsingHeader::new("Advanced").default_open(defaults.advanced).show(ui, |ui| { - ui.label("Advanced options are coming soon."); - }); - - ui.add_space(SETTINGS_SECTION_GAP); - CollapsingHeader::new("About").default_open(defaults.about).show(ui, |ui| { - ui.label(format!("rsnap {}", env!("CARGO_PKG_VERSION"))); + render_about_section(ui); }); changed @@ -469,6 +462,28 @@ fn render_output_section(combo_width: f32, ui: &mut Ui, settings: &mut AppSettin changed } +fn render_about_section(ui: &mut Ui) { + ui.label(format!("Version {}", env!("CARGO_PKG_VERSION"))); + ui.small("Fast screenshots for macOS, built in Rust."); + + ui.scope(|ui| { + ui.style_mut().override_text_style = Some(TextStyle::Small); + + ui.hyperlink_to("Repository: github.com/hack-ink/rsnap", env!("CARGO_PKG_REPOSITORY")); + ui.hyperlink_to("X: @YvetteCipher", "https://x.com/YvetteCipher"); + }); + + ui.small( + "Star the repo, follow Yvette on X, or reach out there if you want to sponsor development.", + ); + ui.label( + RichText::new("Following on X also helps Yvette qualify for X revenue share.") + .small() + .strong() + .color(ui.visuals().warn_fg_color), + ); +} + fn render_general_section( combo_width: f32, ui: &mut Ui, @@ -908,3 +923,34 @@ fn toolbar_placement_label(placement: ToolbarPlacement) -> &'static str { ToolbarPlacement::Bottom => "Bottom", } } + +#[cfg(test)] +mod tests { + use crate::settings_window::sections::SettingsUiSectionDefaults; + + #[test] + fn standard_defaults_focus_regular_capture_sections() { + let defaults = SettingsUiSectionDefaults::standard(); + + assert!(!defaults.permissions); + assert!(defaults.general); + assert!(defaults.overlay); + assert!(defaults.hotkeys); + assert!(defaults.capture); + assert!(defaults.output); + assert!(defaults.about); + } + + #[test] + fn permissions_focused_defaults_expand_permissions_without_collapsing_other_sections() { + let defaults = SettingsUiSectionDefaults::permissions_focused(); + + assert!(defaults.permissions); + assert!(defaults.general); + assert!(defaults.overlay); + assert!(defaults.hotkeys); + assert!(defaults.capture); + assert!(defaults.output); + assert!(defaults.about); + } +}