Track history favicon keys

This commit is contained in:
2026-05-08 05:58:05 -04:00
parent e62d64874f
commit a236e6a53b
5 changed files with 87 additions and 9 deletions
@@ -445,6 +445,7 @@ mod tests {
tab.id().clone(), tab.id().clone(),
"example.com", "example.com",
UrlText::parse("https://example.com/research")?, UrlText::parse("https://example.com/research")?,
None,
UNIX_EPOCH, UNIX_EPOCH,
); );
@@ -473,6 +474,7 @@ mod tests {
tab.id().clone(), tab.id().clone(),
"example.com", "example.com",
UrlText::parse("https://example.com/closed")?, UrlText::parse("https://example.com/closed")?,
None,
UNIX_EPOCH, UNIX_EPOCH,
); );
let archived_tab = ArchivedTab::new(tab, ArchiveSource::ManualClose); let archived_tab = ArchivedTab::new(tab, ArchiveSource::ManualClose);
+27 -1
View File
@@ -44,7 +44,7 @@ impl BrowserCore {
&& entry.space_id() == tab.space_id() && entry.space_id() == tab.space_id()
&& entry.url() == tab.url() && entry.url() == tab.url()
}) { }) {
entry.record_visit(tab.id().clone(), tab.title(), visited_at); entry.record_visit(tab.id().clone(), tab.title(), tab.favicon_key(), visited_at);
return; return;
} }
@@ -54,10 +54,36 @@ impl BrowserCore {
tab.id().clone(), tab.id().clone(),
tab.title(), tab.title(),
tab.url().clone(), tab.url().clone(),
tab.favicon_key().map(ToOwned::to_owned),
visited_at, visited_at,
)); ));
} }
pub(super) fn set_history_favicon_key_for_tab(
&mut self,
tab: &BrowserTab,
favicon_key: impl Into<String>,
) {
let favicon_key = favicon_key.into();
if let Some(entry) = self.history_entries.iter_mut().find(|entry| {
entry.profile_id() == tab.profile_id()
&& entry.space_id() == tab.space_id()
&& entry.url() == tab.url()
}) {
entry.set_favicon_key(favicon_key);
}
}
pub(super) fn clear_history_favicon_key_for_tab(&mut self, tab: &BrowserTab) {
if let Some(entry) = self.history_entries.iter_mut().find(|entry| {
entry.profile_id() == tab.profile_id()
&& entry.space_id() == tab.space_id()
&& entry.url() == tab.url()
}) {
entry.clear_favicon_key();
}
}
pub(super) fn find_history_match(&self, query: &str) -> Option<UrlText> { pub(super) fn find_history_match(&self, query: &str) -> Option<UrlText> {
let normalized_query = query.trim().to_lowercase(); let normalized_query = query.trim().to_lowercase();
if normalized_query.is_empty() { if normalized_query.is_empty() {
+13 -8
View File
@@ -279,22 +279,27 @@ impl BrowserCore {
tab_id: &TabId, tab_id: &TabId,
favicon_key: impl Into<String>, favicon_key: impl Into<String>,
) -> Result<(), CoreError> { ) -> Result<(), CoreError> {
let tab = self let favicon_key = favicon_key.into();
let tab_index = self
.tabs .tabs
.iter_mut() .iter()
.find(|tab| tab.id() == tab_id) .position(|tab| tab.id() == tab_id)
.ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?; .ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?;
tab.set_favicon_key(favicon_key)?; self.tabs[tab_index].set_favicon_key(favicon_key.clone())?;
let tab = self.tabs[tab_index].clone();
self.set_history_favicon_key_for_tab(&tab, favicon_key);
Ok(()) Ok(())
} }
pub fn clear_tab_favicon_key(&mut self, tab_id: &TabId) -> Result<(), CoreError> { pub fn clear_tab_favicon_key(&mut self, tab_id: &TabId) -> Result<(), CoreError> {
let tab = self let tab_index = self
.tabs .tabs
.iter_mut() .iter()
.find(|tab| tab.id() == tab_id) .position(|tab| tab.id() == tab_id)
.ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?; .ok_or_else(|| CoreError::TabNotFound { id: tab_id.clone() })?;
tab.clear_favicon_key(); self.tabs[tab_index].clear_favicon_key();
let tab = self.tabs[tab_index].clone();
self.clear_history_favicon_key_for_tab(&tab);
Ok(()) Ok(())
} }
+25
View File
@@ -25,6 +25,31 @@ fn navigation_records_profile_and_space_history() -> Result<(), Box<dyn Error>>
Ok(()) Ok(())
} }
#[test]
fn history_entry_updates_favicon_key_after_navigation() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let tab_id = core.open_tab(UrlText::parse("https://example.com/research")?);
core.set_tab_favicon_key(&tab_id, "favicons/example.ico")?;
let snapshot = core.snapshot()?;
assert_eq!(snapshot.history_entries[0].favicon_key(), Some("favicons/example.ico"));
Ok(())
}
#[test]
fn history_entry_clears_favicon_key_with_source_tab() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let tab_id = core.open_tab(UrlText::parse("https://example.com/research")?);
core.set_tab_favicon_key(&tab_id, "favicons/example.ico")?;
core.clear_tab_favicon_key(&tab_id)?;
let snapshot = core.snapshot()?;
assert_eq!(snapshot.history_entries[0].favicon_key(), None);
Ok(())
}
#[test] #[test]
fn repeated_history_visits_increment_count_in_active_context() -> Result<(), Box<dyn Error>> { fn repeated_history_visits_increment_count_in_active_context() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
+20
View File
@@ -9,6 +9,7 @@ pub struct HistoryEntry {
source_tab_id: TabId, source_tab_id: TabId,
title: String, title: String,
url: UrlText, url: UrlText,
favicon_key: Option<String>,
visited_at: SystemTime, visited_at: SystemTime,
visit_count: u32, visit_count: u32,
} }
@@ -21,6 +22,7 @@ impl HistoryEntry {
source_tab_id: TabId, source_tab_id: TabId,
title: impl Into<String>, title: impl Into<String>,
url: UrlText, url: UrlText,
favicon_key: Option<String>,
visited_at: SystemTime, visited_at: SystemTime,
) -> Self { ) -> Self {
Self { Self {
@@ -29,6 +31,7 @@ impl HistoryEntry {
source_tab_id, source_tab_id,
title: title.into(), title: title.into(),
url, url,
favicon_key,
visited_at, visited_at,
visit_count: 1, visit_count: 1,
} }
@@ -38,10 +41,14 @@ impl HistoryEntry {
&mut self, &mut self,
source_tab_id: TabId, source_tab_id: TabId,
title: impl Into<String>, title: impl Into<String>,
favicon_key: Option<&str>,
visited_at: SystemTime, visited_at: SystemTime,
) { ) {
self.source_tab_id = source_tab_id; self.source_tab_id = source_tab_id;
self.title = title.into(); self.title = title.into();
if let Some(favicon_key) = favicon_key {
self.favicon_key = Some(favicon_key.to_string());
}
self.visited_at = visited_at; self.visited_at = visited_at;
self.visit_count = self.visit_count.saturating_add(1); self.visit_count = self.visit_count.saturating_add(1);
} }
@@ -71,6 +78,19 @@ impl HistoryEntry {
&self.url &self.url
} }
#[must_use]
pub fn favicon_key(&self) -> Option<&str> {
self.favicon_key.as_deref()
}
pub fn set_favicon_key(&mut self, favicon_key: impl Into<String>) {
self.favicon_key = Some(favicon_key.into());
}
pub fn clear_favicon_key(&mut self) {
self.favicon_key = None;
}
#[must_use] #[must_use]
pub fn visited_at(&self) -> SystemTime { pub fn visited_at(&self) -> SystemTime {
self.visited_at self.visited_at