From 60426b6c180e02f03b3fead2a08c6fe0b4daa5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 8 May 2026 22:35:42 -0400 Subject: [PATCH] Clear private profile download index on exit --- crates/ely_browser_core/src/state.rs | 1 + .../ely_browser_core/src/state/downloads.rs | 8 ++- crates/ely_browser_core/src/state/profiles.rs | 10 ++++ .../src/state/tab_selection.rs | 59 +++++++++++++++++++ crates/ely_browser_core/src/state/tabs.rs | 46 --------------- crates/ely_browser_core/tests/profiles.rs | 44 ++++++++++++++ 6 files changed, 120 insertions(+), 48 deletions(-) create mode 100644 crates/ely_browser_core/src/state/tab_selection.rs diff --git a/crates/ely_browser_core/src/state.rs b/crates/ely_browser_core/src/state.rs index b2bf2d1..6275afb 100644 --- a/crates/ely_browser_core/src/state.rs +++ b/crates/ely_browser_core/src/state.rs @@ -28,6 +28,7 @@ mod tab_group_order; mod tab_groups; mod tab_lifecycle; mod tab_order; +mod tab_selection; mod tabs; pub use plugins::{InstalledPlugin, PluginAuditAction, PluginAuditEvent}; diff --git a/crates/ely_browser_core/src/state/downloads.rs b/crates/ely_browser_core/src/state/downloads.rs index d22b75e..2f807a1 100644 --- a/crates/ely_browser_core/src/state/downloads.rs +++ b/crates/ely_browser_core/src/state/downloads.rs @@ -1,6 +1,6 @@ use std::{path::PathBuf, time::SystemTime}; -use ely_domain::{DownloadChecksum, DownloadEntry, DownloadId, UrlText}; +use ely_domain::{DownloadChecksum, DownloadEntry, DownloadId, ProfileId, UrlText}; use crate::CoreError; @@ -107,8 +107,12 @@ impl BrowserCore { pub fn clear_downloads_for_active_profile(&mut self) -> usize { let active_profile_id = self.active_profile_id.clone(); + self.clear_downloads_for_profile(&active_profile_id) + } + + pub(super) fn clear_downloads_for_profile(&mut self, profile_id: &ProfileId) -> usize { let before_count = self.download_entries.len(); - self.download_entries.retain(|entry| entry.profile_id() != &active_profile_id); + self.download_entries.retain(|entry| entry.profile_id() != profile_id); before_count - self.download_entries.len() } diff --git a/crates/ely_browser_core/src/state/profiles.rs b/crates/ely_browser_core/src/state/profiles.rs index a537bcb..ae3ab33 100644 --- a/crates/ely_browser_core/src/state/profiles.rs +++ b/crates/ely_browser_core/src/state/profiles.rs @@ -107,4 +107,14 @@ impl BrowserCore { profile.set_sync_policy(sync_policy); Ok(()) } + + pub(super) fn cleanup_private_profile_session_data(&mut self, profile_id: &ProfileId) { + if self + .profiles + .iter() + .any(|profile| profile.id() == profile_id && profile.kind() == &ProfileKind::Private) + { + self.clear_downloads_for_profile(profile_id); + } + } } diff --git a/crates/ely_browser_core/src/state/tab_selection.rs b/crates/ely_browser_core/src/state/tab_selection.rs new file mode 100644 index 0000000..97de7cb --- /dev/null +++ b/crates/ely_browser_core/src/state/tab_selection.rs @@ -0,0 +1,59 @@ +use std::time::SystemTime; + +use ely_domain::TabId; + +use super::BrowserCore; +use crate::CoreError; + +impl BrowserCore { + pub fn select_tab(&mut self, tab_id: &TabId) -> Result<(), CoreError> { + let previous_profile_id = self.active_profile_id.clone(); + let tab = self + .tabs + .iter() + .find(|tab| tab.id() == tab_id) + .ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?; + let active_space_id = tab.space_id().clone(); + let active_profile_id = tab.profile_id().clone(); + let active_tab_id = tab.id().clone(); + + self.active_tab_id = active_tab_id.clone(); + self.active_space_id = active_space_id.clone(); + self.active_profile_id = active_profile_id.clone(); + self.active_tabs_by_space_profile + .insert((active_space_id.clone(), active_profile_id.clone()), active_tab_id.clone()); + self.active_tabs_by_space.insert(active_space_id, active_tab_id); + self.record_tab_activity(tab_id, SystemTime::now()); + + if previous_profile_id != active_profile_id { + self.cleanup_private_profile_session_data(&previous_profile_id); + } + Ok(()) + } + + pub fn select_next_tab(&mut self) -> Result { + self.select_tab_by_offset(1) + } + + pub fn select_previous_tab(&mut self) -> Result { + self.select_tab_by_offset(-1) + } + + fn select_tab_by_offset(&mut self, offset: isize) -> Result { + let visible_tab_ids = self + .tabs + .iter() + .filter(|tab| tab.space_id() == &self.active_space_id) + .map(|tab| tab.id().clone()) + .collect::>(); + let active_index = visible_tab_ids + .iter() + .position(|tab_id| tab_id == &self.active_tab_id) + .ok_or(CoreError::MissingActiveTab)?; + let tab_count = visible_tab_ids.len() as isize; + let next_index = (active_index as isize + offset).rem_euclid(tab_count) as usize; + let next_tab_id = visible_tab_ids[next_index].clone(); + self.select_tab(&next_tab_id)?; + Ok(next_tab_id) + } +} diff --git a/crates/ely_browser_core/src/state/tabs.rs b/crates/ely_browser_core/src/state/tabs.rs index e261268..9b7d908 100644 --- a/crates/ely_browser_core/src/state/tabs.rs +++ b/crates/ely_browser_core/src/state/tabs.rs @@ -197,34 +197,6 @@ impl BrowserCore { Ok(archived_count) } - pub fn select_tab(&mut self, tab_id: &TabId) -> Result<(), CoreError> { - let tab = self - .tabs - .iter() - .find(|tab| tab.id() == tab_id) - .ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?; - let active_space_id = tab.space_id().clone(); - let active_profile_id = tab.profile_id().clone(); - let active_tab_id = tab.id().clone(); - - self.active_tab_id = active_tab_id.clone(); - self.active_space_id = active_space_id.clone(); - self.active_profile_id = active_profile_id.clone(); - self.active_tabs_by_space_profile - .insert((active_space_id.clone(), active_profile_id), active_tab_id.clone()); - self.active_tabs_by_space.insert(active_space_id, active_tab_id); - self.record_tab_activity(tab_id, SystemTime::now()); - Ok(()) - } - - pub fn select_next_tab(&mut self) -> Result { - self.select_tab_by_offset(1) - } - - pub fn select_previous_tab(&mut self) -> Result { - self.select_tab_by_offset(-1) - } - pub fn toggle_active_tab_favorite(&mut self) -> Result { let active_index = self.active_tab_index()?; let favorite_count = self.tabs.iter().filter(|tab| tab.flags().favorite).count(); @@ -358,24 +330,6 @@ impl BrowserCore { self.restore_tab(archived_tab.into_tab()) } - fn select_tab_by_offset(&mut self, offset: isize) -> Result { - let visible_tab_ids = self - .tabs - .iter() - .filter(|tab| tab.space_id() == &self.active_space_id) - .map(|tab| tab.id().clone()) - .collect::>(); - let active_index = visible_tab_ids - .iter() - .position(|tab_id| tab_id == &self.active_tab_id) - .ok_or(CoreError::MissingActiveTab)?; - let tab_count = visible_tab_ids.len() as isize; - let next_index = (active_index as isize + offset).rem_euclid(tab_count) as usize; - let next_tab_id = visible_tab_ids[next_index].clone(); - self.select_tab(&next_tab_id)?; - Ok(next_tab_id) - } - pub(super) fn active_tab_index(&self) -> Result { self.tabs .iter() diff --git a/crates/ely_browser_core/tests/profiles.rs b/crates/ely_browser_core/tests/profiles.rs index 025abcf..33b1e9f 100644 --- a/crates/ely_browser_core/tests/profiles.rs +++ b/crates/ely_browser_core/tests/profiles.rs @@ -47,6 +47,50 @@ fn private_profiles_do_not_record_history() -> Result<(), Box> { Ok(()) } +#[test] +fn private_profile_download_index_clears_when_leaving_profile() -> Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + let default_profile_id = core.snapshot()?.active_profile_id; + let private_profile_id = core.create_profile("Private", 0x807d72, ProfileKind::Private)?; + + core.record_download_started( + UrlText::parse("https://example.com/private.dmg")?, + "private.dmg", + Some(4096), + )?; + assert_eq!(core.snapshot()?.download_entries.len(), 1); + + core.select_profile(&default_profile_id)?; + assert_eq!(core.snapshot()?.active_profile_id, default_profile_id); + assert!(core.snapshot()?.download_entries.is_empty()); + + core.select_profile(&private_profile_id)?; + assert_eq!(core.snapshot()?.active_profile_id, private_profile_id); + assert!(core.snapshot()?.download_entries.is_empty()); + Ok(()) +} + +#[test] +fn selecting_standard_tab_clears_private_profile_download_index() -> Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + let default_tab_id = core.snapshot()?.active_tab_id; + let private_profile_id = core.create_profile("Private", 0x807d72, ProfileKind::Private)?; + + core.record_download_started( + UrlText::parse("https://example.com/private.zip")?, + "private.zip", + Some(1024), + )?; + assert_eq!(core.snapshot()?.download_entries.len(), 1); + + core.select_tab(&default_tab_id)?; + assert!(core.snapshot()?.download_entries.is_empty()); + + core.select_profile(&private_profile_id)?; + assert!(core.snapshot()?.download_entries.is_empty()); + Ok(()) +} + #[test] fn private_profile_starts_with_sync_paused() -> Result<(), Box> { let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;