From ec793693c96b0c8395e2a0d8f93bc6fd6af9b469 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Fri, 2 Oct 2026 22:14:00 -0700 Subject: [PATCH] fix: Lock All Sections, Close This Notebook and Notebook Recycle Bin are disabled where they would do nothing Lock All Sections stood enabled with no protected section unlocked; the File menu's and palette's Close This Notebook on an iCloud notebook, which its context menu already disables, since the app's iCloud folder lists every notebook in it; and Notebook Recycle Bin on a notebook whose bin holds no sections, where it ended in an alert. Assisted-by: claude-opus-5.5 --- crates/snowbound/src/commands.rs | 14 +++++++++++--- crates/snowbound/src/library.rs | 5 +++++ crates/snowbound/src/menus.rs | 2 +- crates/snowbound/src/recycle.rs | 11 +++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/crates/snowbound/src/commands.rs b/crates/snowbound/src/commands.rs index 461ccd3a2612702f5f061174126ccecb32aefbb8..46297270be9a13a11a520be307854319f6c86117 100644 --- a/crates/snowbound/src/commands.rs +++ b/crates/snowbound/src/commands.rs @@ -1152,7 +1152,13 @@ impl State { | Id::CustomizeTags | Id::Help | Id::CheckForUpdates => enabled(!modal), - Id::CloseNotebook => enabled(!modal && self.notebook().is_some()), + // The app's iCloud Drive folder lists every notebook in it. + Id::CloseNotebook => enabled( + !modal + && self + .notebook() + .is_some_and(|library| !crate::manage::in_icloud_folder(&library.location)), + ), Id::OpenShared => enabled(!modal && cfg!(feature = "live")), #[cfg(feature = "live")] Id::LiveShare => enabled( @@ -1169,7 +1175,7 @@ impl State { enabled: !modal && self .notebook() - .is_some_and(|library| library.catalog().is_some()), + .is_some_and(|library| self.recycle_bin_available(library)), checked: Some(self.in_recycle_bin()), }, Id::EmptyRecycleBin => enabled( @@ -1195,7 +1201,9 @@ impl State { .is_some_and(|library| self.reads.shown(&library.location)), ), }, - Id::LockAll => enabled(!modal), + Id::LockAll => { + enabled(!modal && self.notebooks.iter().any(|library| library.any_unlocked())) + } Id::ShowNotebook => enabled( !modal && self diff --git a/crates/snowbound/src/library.rs b/crates/snowbound/src/library.rs index 5617e18f523e22fcd93735808b3b3c3072a37bd6..81cc9a57cafd6db1a583a3bd174536a60d352bc3 100644 --- a/crates/snowbound/src/library.rs +++ b/crates/snowbound/src/library.rs @@ -1105,6 +1105,11 @@ impl Library { keys.get(&identity).map(|(key, _)| key.clone()) } + /// Whether any of its password-protected sections is unlocked, which Lock All would lock. + pub fn any_unlocked(&self) -> bool { + self.keys.0.lock().is_ok_and(|keys| !keys.is_empty()) + } + /// Marks the unlocked section at catalog `path` worked in now. pub fn touch(&self, path: &str) { if let (Some(identity), Ok(mut keys)) = (self.section_identity(path), self.keys.0.lock()) diff --git a/crates/snowbound/src/menus.rs b/crates/snowbound/src/menus.rs index e432c9cd934ade9c34ac4222dccc2f89b4e228f8..c3331e2855fe34a5d85e3c0fef1d7a01f33d768e 100644 --- a/crates/snowbound/src/menus.rs +++ b/crates/snowbound/src/menus.rs @@ -587,7 +587,7 @@ impl State { item( Action::RecycleBin, "Notebook Recycle Bin", - library.catalog().is_none(), + !self.recycle_bin_available(library), false, ), item( diff --git a/crates/snowbound/src/recycle.rs b/crates/snowbound/src/recycle.rs index 907430a228f616905289cfe017b6b981bee84753..d963becd9775417ba0af14f8632a75369966bf8e 100644 --- a/crates/snowbound/src/recycle.rs +++ b/crates/snowbound/src/recycle.rs @@ -38,6 +38,17 @@ impl State { (self.session.as_ref()).is_some_and(|session| binned(&session.tabs[session.tab].path)) } + /// Whether Notebook Recycle Bin can do anything on `library`: leave its bin, shown, or + /// show one holding sections. + pub(crate) fn recycle_bin_available(&self, library: &Arc) -> bool { + let shown = self + .session + .as_ref() + .is_some_and(|session| Arc::ptr_eq(&session.library, library)); + library.catalog().is_some() + && (shown && self.in_recycle_bin() || !library.tabs(BIN).is_empty()) + } + /// Notebook Recycle Bin: shows `library`'s bin at its first section holding pages, or /// while it shows, goes back to the notebook. pub(crate) fn toggle_recycle_bin(&mut self, library: Arc) { -- 2.54.0